def compile_multi3(context): """ Compile the multi3() helper function used by LLVM for 128-bit multiplication on 32-bit platforms. """ codegen = context.codegen() library = codegen.create_library("multi3") ir_mod = library.create_ir_module("multi3") i64 = ir.IntType(64) i128 = ir.IntType(128) lower_mask = ir.Constant(i64, 0xffffffff) _32 = ir.Constant(i64, 32) _64 = ir.Constant(i128, 64) fn_type = ir.FunctionType(i128, [i128, i128]) fn = ir.Function(ir_mod, fn_type, name="multi3") a, b = fn.args bb = fn.append_basic_block() builder = ir.IRBuilder(bb) # This implementation mimicks compiler-rt's. al = builder.trunc(a, i64) bl = builder.trunc(b, i64) ah = builder.trunc(builder.ashr(a, _64), i64) bh = builder.trunc(builder.ashr(b, _64), i64) # Compute {rh, rl} = al * bl (unsigned 64-bit multiplication) # rl = (al & 0xffffffff) * (bl & 0xffffffff) rl = builder.mul(builder.and_(al, lower_mask), builder.and_(bl, lower_mask)) # t = rl >> 32 t = builder.lshr(rl, _32) # rl &= 0xffffffff rl = builder.and_(rl, lower_mask) # t += (al >> 32) * (bl & 0xffffffff) t = builder.add( t, builder.mul(builder.lshr(al, _32), builder.and_(bl, lower_mask))) # rl += t << 32 rl = builder.add(rl, builder.shl(t, _32)) # rh = t >> 32 rh = builder.lshr(t, _32) # t = rl >> 32 t = builder.lshr(rl, _32) # rl &= 0xffffffff rl = builder.and_(rl, lower_mask) # t += (bl >> 32) * (al & 0xffffffff) t = builder.add( t, builder.mul(builder.lshr(bl, _32), builder.and_(al, lower_mask))) # rl += t << 32 rl = builder.add(rl, builder.shl(t, _32)) # rh += t >> 32 rh = builder.add(rh, builder.lshr(t, _32)) # rh += (al >> 32) * (bl >> 32) rh = builder.add(rh, builder.mul(builder.lshr(al, _32), builder.lshr(bl, _32))) # rh += (bh * al) + (bl * ah) rh = builder.add(rh, builder.mul(bh, al)) rh = builder.add(rh, builder.mul(bl, ah)) # r = rl + (rh << 64) r = builder.zext(rl, i128) r = builder.add(r, builder.shl(builder.zext(rh, i128), _64)) builder.ret(r) library.add_ir_module(ir_mod) library.finalize() return library
def call_external_function(): """ 调用foo.c的外部函数foo void foo(int a){ printf("in foo: %d\n",a); } 运行:make run1 此函数会生成test.s汇编文件,Makefile中和foo.c文件一起组成可执行文件。 奇怪的现象: 1. ll.Block() 似乎不会生成块 :return: """ # 1.生成一个module module = ll.Module(name="call_external_function") # 2.定义函数类型 function_type = ll.FunctionType(ll.IntType(32), [ll.IntType(32)]) # 3.创建main函数块 main_function_type = ll.FunctionType(ll.IntType(32), [ll.IntType(32)]) main_func = ll.Function(module, main_function_type, name="main") bb_entry = main_func.append_basic_block() # function = ll.NamedValue(module, type=function_type, name="x") # llvm.load_library_permanently("/tmp/foo.so") # 4.插入函数调用 builder = ll.IRBuilder() builder.position_at_end(bb_entry) # func = CFUNCTYPE(c_int, c_int)(foo_function) # 失败的尝试 # func = ll.GlobalVariable(module, function_type, 'func') # 失败的尝试 func = ll.Function(module, function_type, "foo") builder = ll.IRBuilder(bb_entry) a = builder.function.args[0] builder.call(func, [a]) # builder.call(func, [ll.Constant(ll.IntType(32), 1)]) # 5.main函数return builder.position_at_end(bb_entry) builder.ret(ll.Constant(ll.IntType(32), 1)) # print(str(module)) x_module = llvm.parse_assembly(str(module)) # 还不明白这一行的意思 target_machine = llvm.Target.from_default_triple().create_target_machine() with llvm.create_mcjit_compiler(x_module, target_machine) as ee: ee.finalize_object() # 保存汇编代码 with open("main.s", "w") as f: f.write(target_machine.emit_assembly(x_module)) return module
def astToLLVM(jast): """ Convert the input json encoded AST to LLVM code properly, using llvm-lite JSON jast: the AST in JSON form produced by the main Haskell routine Returns the new function name, and an ir module containing the LLVM code matching the input json encoded AST """ # create a module for the output l_module = ir.Module(name=__file__) curBlock = jast parents = [] knownFuncs = ["print", "seq"] funcs = [] annotations = [] # traverse the AST matching functions to their corresponding body contents """ expression: Will contain a function. If it is built in, will have the tag "BuiltIn" and its "contents" Otherwise, will contain 3 fields: "function", "tag", "body" function: Will contain 2 fields: "annotation", "expression" body: Will contain 2 fields: "annotation", "expression" "Arrow" tag: Defines an input and output "Constructor" tag: Defines a type "Application" tag: Defines a function "BuiltIn" tag: Defines a function literal Perhaps the best way to go is look at the tag first, then decide what to do next """ try: if (curBlock.get("Right")): curBlock = curBlock["Right"]["expression"] while (True): if (curBlock.get("function")): parents.append(curBlock) annot = curBlock["function"]["annotation"] curBlock = curBlock["function"]["expression"] if (annot["tag"] == "Arrow"): #grab arrow types arrow_in = "NONE" arrow_out = "NONE" if (annot["input"]["tag"] == "Constructor"): arrow_in = annot["input"]["contents"] else: pass #TODO figure out what goes here if (annot["output"]["tag"] == "Constructor"): arrow_out = annot["output"]["contents"] else: pass #TODO figure out what goes here if (arrow_in != "NONE" and arrow_out != "NONE"): annotations.append((arrow_in, arrow_out)) if (curBlock["tag"] == "BuiltIn"): if (curBlock["contents"] in knownFuncs): funcs.append([curBlock["contents"]]) else: curBlock = parents.pop() curBlock = curBlock["body"]["expression"] if (curBlock["tag"] == "BuiltIn"): funcs[-1].append(curBlock["contents"]) else: #error occurred pass except: print("finished parsing AST. discovered code:", funcs) #now each function matched with it's input/output type. Use for more complex compilation func_and_types = list(zip(funcs, annotations)) # define llvm types l_int = ir.IntType( 32 ) # TODO: replace hard-coded int with a type extracted from the AST, once type info is merged in l_funcType = ir.FunctionType(l_int, []) #l_funcType = ir.FunctionType(l_int, [*([l_int]*len(funcArgs))]) # match number of function arguments # declare our new function funcName = "main" l_func = ir.Function(l_module, l_funcType, name=funcName) # function entry point block = l_func.append_basic_block(name="entry") # create a builder for constructing the function code builder = ir.IRBuilder(block) #add printing support if our code uses it anywhere if ("print" == f[0] for f in funcs): # Source: https://blog.usejournal.com/writing-your-own-programming-language-and-compiler-with-python-a468970ae6df voidptr_ty = ir.IntType(8).as_pointer() fmt = "%i \n\0" c_fmt = ir.Constant(ir.ArrayType(ir.IntType(8), len(fmt)), bytearray(fmt.encode("utf8"))) global_fmt = ir.GlobalVariable(l_module, c_fmt.type, name="fstr") global_fmt.linkage = 'internal' global_fmt.global_constant = True global_fmt.initializer = c_fmt fmt_arg = builder.bitcast(global_fmt, voidptr_ty) printf_ty = ir.FunctionType(ir.IntType(32), [voidptr_ty], var_arg=True) printf = ir.Function(l_module, printf_ty, name="printf") # now add the code from our ast for f in funcs: if (f[0] == "print"): if (getTypeFromStr(f[1]) == "int"): builder.call( printf, [fmt_arg, ir.Constant(ir.IntType(32), int(f[1]))]) else: #TODO: printing non-int primitives pass # return 0 builder.ret(l_int(0)) return funcName, l_module
def _generic_array(context, builder, shape, dtype, symbol_name, addrspace, can_dynsized=False): elemcount = reduce(operator.mul, shape, 1) # Check for valid shape for this type of allocation. # Only 1d arrays can be dynamic. dynamic_smem = elemcount <= 0 and can_dynsized and len(shape) == 1 if elemcount <= 0 and not dynamic_smem: raise ValueError("array length <= 0") # Check that we support the requested dtype other_supported_type = isinstance(dtype, (types.Record, types.Boolean)) if dtype not in types.number_domain and not other_supported_type: raise TypeError("unsupported type: %s" % dtype) lldtype = context.get_data_type(dtype) laryty = ir.ArrayType(lldtype, elemcount) if addrspace == nvvm.ADDRSPACE_LOCAL: # Special case local address space allocation to use alloca # NVVM is smart enough to only use local memory if no register is # available dataptr = cgutils.alloca_once(builder, laryty, name=symbol_name) else: lmod = builder.module # Create global variable in the requested address space gvmem = cgutils.add_global_variable(lmod, laryty, symbol_name, addrspace) # Specify alignment to avoid misalignment bug align = context.get_abi_sizeof(lldtype) # Alignment is required to be a power of 2 for shared memory. If it is # not a power of 2 (e.g. for a Record array) then round up accordingly. gvmem.align = 1 << (align - 1).bit_length() if dynamic_smem: gvmem.linkage = 'external' else: ## Comment out the following line to workaround a NVVM bug ## which generates a invalid symbol name when the linkage ## is internal and in some situation. ## See _get_unique_smem_id() # gvmem.linkage = lc.LINKAGE_INTERNAL gvmem.initializer = ir.Constant(laryty, ir.Undefined) # Convert to generic address-space conv = nvvmutils.insert_addrspace_conv(lmod, ir.IntType(8), addrspace) addrspaceptr = gvmem.bitcast(ir.PointerType(ir.IntType(8), addrspace)) dataptr = builder.call(conv, [addrspaceptr]) targetdata = _get_target_data(context) lldtype = context.get_data_type(dtype) itemsize = lldtype.get_abi_size(targetdata) # Compute strides laststride = itemsize rstrides = [] for i, lastsize in enumerate(reversed(shape)): rstrides.append(laststride) laststride *= lastsize strides = [s for s in reversed(rstrides)] kstrides = [context.get_constant(types.intp, s) for s in strides] # Compute shape if dynamic_smem: # Compute the shape based on the dynamic shared memory configuration. # Unfortunately NVVM does not provide an intrinsic for the # %dynamic_smem_size register, so we must read it using inline # assembly. get_dynshared_size = ir.InlineAsm(ir.FunctionType(ir.IntType(32), []), "mov.u32 $0, %dynamic_smem_size;", '=r', side_effect=True) dynsmem_size = builder.zext(builder.call(get_dynshared_size, []), ir.IntType(64)) # Only 1-D dynamic shared memory is supported so the following is a # sufficient construction of the shape kitemsize = context.get_constant(types.intp, itemsize) kshape = [builder.udiv(dynsmem_size, kitemsize)] else: kshape = [context.get_constant(types.intp, s) for s in shape] # Create array object ndim = len(shape) aryty = types.Array(dtype=dtype, ndim=ndim, layout='C') ary = context.make_array(aryty)(context, builder) context.populate_array(ary, data=builder.bitcast(dataptr, ary.data.type), shape=kshape, strides=kstrides, itemsize=context.get_constant(types.intp, itemsize), meminfo=None) return ary._getvalue()
def box_record(c, typ, val): # Note we will create a copy of the record # This is the only safe way. size = ir.Constant(ir.IntType(32), val.type.pointee.count) ptr = c.builder.bitcast(val, ir.PointerType(ir.IntType(8))) return c.pyapi.recreate_record(ptr, size, typ.dtype, c.env_manager)
def from_argument(self, builder, value): out = ir.Constant(self.get_value_type(), ir.Undefined) for i, v in enumerate(value): v = self._elem_model.from_argument(builder, v) out = builder.insert_value(out, v, [i]) return out
def get_data(value): valid = get_valid(value) data = self.get(builder, value, "data") return builder.select(valid, data, ir.Constant(data.type, None))
def __init__(self, llvm_module, vex_procedure): if debug_mode: self.emit_print = logger_emit_print else: self.emit_print = nothing_emit_print assert (isinstance(llvm_module, LLVMModule)) self._llvm_module = llvm_module self._arch = llvm_module._arch if self._arch.__repr__() != '<Arch AMD64 (LE)>': assert_verbose(False, getframeinfo( currentframe())), "No support for {} arch yet".format( self._arch.__repr__()) # this is a fancy way to get rax self._ret_register_name = self._arch.translate_register_name( self._arch.ret_offset) self._register_type = llvm_module._register_type self._proc_name = vex_procedure[IndexedProcedure.name] # we start with the out val - rax, it must be kept as a register self._used_register_names = [self._ret_register_name] # collect all "imported" registers - ones we think are read before written into, # along with type, they will be allocated and imported from arguments we create for block in vex_procedure[IndexedProcedure.blocks]: for inst in block[IndexedProcedure.Block.vex]: if isinstance(inst, pyvex.stmt.WrTmp) and isinstance( inst.data, pyvex.expr.Get): register_name = self._arch.translate_register_name( inst.data.offset) if register_name not in self._used_register_names: if "I64" not in inst.data.ty: # This means we encountered a float register usage.. if "_F" in inst.data.ty: raise FloatException( inst, "Encountered a float register usage (proc={}" .format(self._proc_name)) # logging.debug( # "Got a non 64bit register in registers collection - {} (inst={}, proc={})".format( # inst.data.ty, inst, self._proc_name)) # assert_verbose(False, getframeinfo((currentframe())), # "Got a non 64bit register in registers collection") self._used_register_names.append(register_name) # create the llvm function for the strand self._function = ir.Function( self._llvm_module, ir.types.FunctionType(llvm_module._register_type, []), vex_procedure[IndexedProcedure.name]) # create a mapping register -> argument in the llvm function, # after we get the first bb, we will replace this pointer to the alloca var (which will store this val) self._argument_register_name_prefix = "arg." self._ret_register_index = -1 for index, reg_name in enumerate( self._used_register_names): # add the registers as arguments arg = ir.Argument(self._function, self._register_type, self._argument_register_name_prefix + reg_name) self._function.args += (arg, ) if reg_name == self._ret_register_name: # this is the index of the reg register self._ret_register_index = index def create_def_for_cond_func(xxx_todo_changeme): (name, number_of_params) = xxx_todo_changeme cond_func_type_copy = ir.types.FunctionType( self._register_type, [self._register_type] * number_of_params) logger.debug("Creating {} cond function, {} params".format( name, number_of_params)) return ir.Function( self._llvm_module, cond_func_type_copy, self._proc_name + "." + name + "." + str(number_of_params)) self._cond_functions_dict = AwareDefaultDict(create_def_for_cond_func) def create_called_function(xxx_todo_changeme1): # TODO: handle floating inputs.. (name, number_of_d_regs, number_of_f_regs) = xxx_todo_changeme1 called_function = ir.types.FunctionType( self._register_type, [self._register_type] * number_of_d_regs) logger.debug( "Creating {} called function ({} input registers)".format( name, number_of_d_regs)) return ir.Function( self._llvm_module, called_function, self._proc_name + "." + name + "." + str(number_of_d_regs)) self._called_functions_dict = AwareDefaultDict(create_called_function) self._tmps = OrderedDict() self._calc_condition_args = {} logger.debug("Init ready, starting vex2llvm for {}".format( self._proc_name)) # A list of all bbs we created dynamically self._dynamic_bbs = [] # A dict of startEA -> block instance for all blocks already translated in this module self._original_bbs_ea = {} self._original_bbs_index = {} self._init_bb = self._function.append_basic_block("ob-1.initialize") # we need to alloca all the registers & put the input values.. self._init_bb_builder = ir.IRBuilder(self._init_bb) self._stored_register_name_prefix = "sr." def alloca_register(register_name): return self._init_bb_builder.alloca( self._register_type, name="{}{}".format(self._stored_register_name_prefix, register_name)) self._register_as_allocated_var = AwareDefaultDict(alloca_register) # we need this ptr to perform the store from calls along the way.. self._ret_register_ptr = None for index, reg_name in enumerate(self._used_register_names): reg_store_ptr = self._register_as_allocated_var[reg_name] self._init_bb_builder.store(self._function.args[index], reg_store_ptr) if index == self._ret_register_index: self._ret_register_ptr = reg_store_ptr bb_0 = None # hack - create all bbs now to preserve order and to allow for entry bb (bb=0) to be appended first for block in vex_procedure[IndexedProcedure.blocks]: new_bb = self._function.append_basic_block("ob{}".format( block[IndexedProcedure.Block.index])) if bb_0 is None: bb_0 = new_bb self._original_bbs_ea[block[ IndexedProcedure.start_address]] = new_bb self._original_bbs_index[block[ IndexedProcedure.Block.index]] = new_bb # TODO: think if now that we have bb-1 we can just do normal order... # traverse blocks in reverse so we will always have a block to jump to when needed for block in reversed(vex_procedure[IndexedProcedure.blocks]): try: self._curbb_part = 0 self._curr_irsb = block[IndexedProcedure.Block.irsb] self._curbb = self._original_bbs_index[block[ IndexedProcedure.Block.index]] self._bb_builder = ir.IRBuilder(self._curbb) self._cur_block = block self._cur_block_name = "ob{}".format( block[IndexedProcedure.Block.index]) self.tmp_prefix = "{}.t".format(self._cur_block_name) self.tmp_prefix_internal_counter = 0 # copy all instructions, one by one for instruction in block[IndexedProcedure.Block.vex]: logger.debug("VEX.in: " + str(instruction)) if getattr(instruction, 'tag', None) is None: raise NotImplementedError("Call nimrod") getattr( self, '_copy_' + str(instruction.tag), self._missing_instruction_implementation)(instruction) # pyvex will do a if() {} exit and follow it with get(pc).. if self._curbb.is_terminated: break self._error_state = False logger.debug("Strand translating done, emitting ret") if not self._curbb.is_terminated: if len(self._cur_block[ IndexedProcedure.Block.successor]) == 0: # TODO: this is intel only syntax! if "call" in block['dsm'][-1][1]: # this is an error exit node (_abort/_exit etc.) pass elif any([ block['dsm'][-1][1].startswith(x) for x in ["ret", "leave", "rep retn", "hlt"] ]): # why "rep retn"? -> http://repzret.org/p/repzret/ # this is a "normal" exit node pass elif block['dsm'][-1][1].startswith("jmp"): # we have an unresolved jump table or indirect jump, or weird call as jump split_inst = [ x for x in block['dsm'][-1][1].split(" ") if len(x) > 0 ] if len(split_inst) < 2: # jmp eax OK, jmp short <some func> OK. raise hell else: if split_inst[-1] in self._arch.registers: raise IndirectJump( block['dsm'][-1][1], "Incountered Indirect jump at bb end.") elif split_inst[-1].startswith("_"): # this is a hack to detect jumps to imported procs pass else: # TODO check that this is a jump to a func and not an offset. # for now pass pass else: # This is just any termination of a bb caused by IDA's error.. # e.g., gcc-5__Ou__apwal-0.4.5__apwal__sub_415AB0 => NOP # e.g., gcc-5__Ou__apwal-0.4.5__apwal__sub_40D9C0 => XCH raise SPAnalysisFail( block['dsm'][-1][1], "Encountered IDA-SP-ERROR at bb end.") out_reg_val = self.emit_print( self._bb_builder.load(self._ret_register_ptr)) self._bb_builder.ret(out_reg_val) elif len(self._cur_block[ IndexedProcedure.Block.successor]) == 1: # this is a fall through bb, we bridge it to the next bb succ = str(self._cur_block[ IndexedProcedure.Block.successor][0]) try: self._bb_builder.branch( self._original_bbs_index[succ]) except KeyError as e: raise CodeOutSideProcException( "<no inst>", "Looking for bb={} in proc {} (404)".format( succ, vex_procedure['full_name'])) else: last_inst_dsm = block['dsm'][-1][1] last_inst_addr = block['dsm'][-1][0] dsm_split = last_inst_dsm.split(";") dsm_has_comment = len(dsm_split) > 1 # tar__tar___update_archive has a pretty interesting case of multiple jumptables.. if dsm_has_comment and "switch" in dsm_split[1]: my_index = int(block[IndexedProcedure.Block.index]) for pred_index in reversed(list(range(0, my_index))): pred_block = vex_procedure[ IndexedProcedure.blocks][pred_index] if my_index in pred_block[ IndexedProcedure.Block.successor]: other_succs = [ x for x in pred_block[ IndexedProcedure.Block.successor] if x != my_index ] break else: raise SwitchJumpException( block['dsm'][-1][1], "Switch case encountered - bad structure") if len(other_succs) != 1: raise SwitchJumpException( block['dsm'][-1][1], "Switch case encountered - bad default connection" ) pred_last_inst_dsm = vex_procedure[ IndexedProcedure. blocks][pred_index]['dsm'][-1][1] pred_dsm_split = pred_last_inst_dsm.split(";") pred_dsm_has_comment = len(pred_dsm_split) > 1 if not pred_dsm_has_comment or "default case" not in pred_dsm_split[ 1]: raise SwitchJumpException( block['dsm'][-1][1], "Switch case encountered - bad default comment" ) register_name = dsm_split[0].split( "jmp")[1].strip() loaded_reg = self.emit_print( self._bb_builder.load( self. _register_as_allocated_var[register_name])) switch_inst = self._bb_builder.switch( loaded_reg, self._original_bbs_index[str(other_succs[0])]) for switch_target in self._cur_block[ IndexedProcedure.Block.successor]: target_comment_dsm_line = \ vex_procedure[IndexedProcedure.blocks][int(switch_target)]['dsm'][0][ 1].split(";")[1] target_comment_dsm_line_split = [ x for x in [ str(x).strip() for x in target_comment_dsm_line.split(" ") ] if len(x) > 0 ] # 0==jumptable, 1==addr of jumptable, 2+3=="cases <int> || <int,int>" || "deafult case" # jumptable 0000000000426639 default case # jumptable 0000000000426639 cases 1, 3 # jumptable 0000000000426639 cases 1-5, 8 # jumptable 0000000000426639 case 0 if target_comment_dsm_line_split[ 0] != "jumptable": raise SwitchJumpException( block['dsm'][-1][1], "Switch case encountered - jumptable out of place" ) jumptable_addr = int( target_comment_dsm_line_split[1], 16) if jumptable_addr != last_inst_addr: raise SwitchJumpException( block['dsm'][-1][1], "Case confusion - jt={} vs case={}". format(last_inst_addr, jumptable_addr)) cases_ints = [] if target_comment_dsm_line_split[2] == "cases": cases_list = target_comment_dsm_line_split[ 3].split(",") for case_struct in cases_list: if "-" in case_struct: case_split = case_struct.split("-") cases_ints.extend( list( range( int(case_split[0]), int(case_split[1]) + 1))) else: cases_ints.append(int(case_struct)) elif target_comment_dsm_line_split[ 2] == "default" and target_comment_dsm_line_split[ 3] == "case": pass # this happens some time when you have some ranges (i.e., 2-6) with holes (0-1 and 7) # example - get_status_for_err@wget else: cases_ints.append( int(target_comment_dsm_line_split[3])) for case_int in cases_ints: switch_inst.add_case( ir.Constant(self._register_type, case_int), self._original_bbs_index[str( switch_target)]) self.emit_print(switch_inst) else: # what is this?! raise hell except InstructionException as ie: self._function._set_name(self._function._get_name() + function_dropped_prefix) self._error_state = True raise # we finished creating all basic blocks, we now have all registers we used, we can connect bb-1 to bb0 self._init_bb_builder.branch(bb_0)
def _copy_Ist_WrTmp(self, inst): my_tyenv = self._curr_irsb.get_stmt_irsb(inst)._tyenv for condition_arg in list(self._calc_condition_args.keys()): if condition_arg in list(map(str, extract_uses(inst, self._arch))): if isinstance(inst.data, pyvex.expr.Get): self._calc_condition_args[str(extract_def( inst))] = self._calc_condition_args[condition_arg] elif isinstance(inst.data, pyvex.expr.Binop) and \ inst.data.op.startswith("Iop_Or") and isinstance(inst.data.args[1], pyvex.expr.Const): self._calc_condition_args[str(extract_def(inst))] = self._calc_condition_args[condition_arg] | \ int(str(inst.data.args[1]), 16) if isinstance(inst.data, pyvex.expr.Get): register_as_input = self._register_as_allocated_var[ self._arch.translate_register_name(inst.data.offset)] register_loaded_val = self._bb_builder.load( register_as_input, self.tmp_prefix + str(inst.tmp)) self.emit_print(register_loaded_val) result_type = translate_var_type(inst.data.result_type(my_tyenv)) if result_type.width == self._arch.bits: out_tmp = register_loaded_val else: # we need to convert, this is really a "!r?x" not "r?x?" (ie eax not rax) logger.debug( "LLVM.EMIT: getting full register before trunc/ext - " + str(register_loaded_val)) out_tmp = self._var_width_helper( register_loaded_val, result_type, self.tmp_prefix + str(inst.tmp)) elif isinstance(inst.data, pyvex.expr.GetI): raise FloatException( inst, "isinstance(inst.data, pyvex.expr.GetI):@_copy_Ist_WrTmp") elif isinstance(inst.data, pyvex.expr.Binop): args = inst.data.args assert (len(args) == 2) def do_binary_op(func): translated_args = list(map(self.get_translated_arg, args)) return self.emit_print( func( translated_args[0], self._var_width_helper(translated_args[1], translated_args[0].type), self.tmp_prefix + str(inst.tmp))) if inst.data.op.startswith("Iop_Sub"): out_tmp = do_binary_op(self._bb_builder.sub) elif inst.data.op.startswith("Iop_Add"): out_tmp = do_binary_op(self._bb_builder.add) elif inst.data.op.startswith("Iop_And"): out_tmp = do_binary_op(self._bb_builder.and_) elif inst.data.op.startswith("Iop_Or"): out_tmp = do_binary_op(self._bb_builder.or_) elif inst.data.op.startswith("Iop_Shl"): out_tmp = do_binary_op(self._bb_builder.shl) elif inst.data.op.startswith("Iop_Shr"): out_tmp = do_binary_op(self._bb_builder.lshr) elif inst.data.op.startswith("Iop_Xor"): out_tmp = do_binary_op(self._bb_builder.xor) elif inst.data.op.startswith("Iop_Sar"): out_tmp = do_binary_op(self._bb_builder.ashr) elif inst.data.op.startswith("Iop_Mul"): if inst.data.op.startswith("Iop_Mull"): # we need to do widening here and not in the binop because CMP has a result op of i1 # widening translated_args = list(map(self.get_translated_arg, args)) res_type = translate_var_type( inst.data.result_type(my_tyenv)) widen_translated_args = self._var_width_helper( translated_args[0], res_type), self._var_width_helper( translated_args[1], res_type) out_tmp = self.emit_print( self._bb_builder.mul(widen_translated_args[0], widen_translated_args[1], self.tmp_prefix + str(inst.tmp))) else: out_tmp = do_binary_op(self._bb_builder.mul) # elif inst.data.op.startswith("Iop_Div?"): elif inst.data.op.startswith("Iop_CmpORD"): """ CmpORD32{S,U} does PowerPC-style 3-way comparisons: CmpORD32S(x,y) = 1<<3 if x <s y = 1<<2 if x >s y = 1<<1 if x == y and similarly the unsigned variant. """ # TODO: think what to do with this raise InstructionException(inst, "") elif inst.data.op.startswith("Iop_Cmp"): cond_type = translate_cond_type(inst.data.op, inst) out_tmp = do_binary_op( partial(self._bb_builder.icmp_signed, cond_type)) elif inst.data.op.startswith("Iop_ExpCmp"): cond_type = translate_exp_cond_type(inst.data.op, inst) out_tmp = do_binary_op( partial(self._bb_builder.icmp_signed, cond_type)) elif inst.data.op.startswith("Iop_DivU"): out_tmp = do_binary_op(self._bb_builder.udiv) elif inst.data.op.startswith("Iop_DivS"): out_tmp = do_binary_op(self._bb_builder.sdiv) elif inst.data.op.startswith("Iop_Interleave"): # TODO: think what to do with this raise InstructionException(inst, "") elif inst.data.op.startswith("Iop_QAdd"): # TODO: think what to do with this raise InstructionException(inst, "") elif inst.data.op.startswith("Iop_QSub"): # TODO: think what to do with this raise InstructionException(inst, "") elif inst.data.op.startswith("Iop_DivMod"): # TODO: think what to do with this raise InstructionException(inst, "") elif inst.data.op.startswith("Iop_Avg"): # TODO: think what to do with this raise InstructionException(inst, "") elif inst.data.op.startswith("Iop_QNarrowBin"): # TODO: think what to do with this raise InstructionException(inst, "") elif inst.data.op.startswith("Iop_CasCmp"): # TODO: think what to do with this raise CASException(inst, "") elif "HLto" in inst.data.op: # TODO: think what to do with this raise FloatException(inst, "HLto in inst.data.op:@_copy_Ist_WrTmp") elif "toF" in inst.data.op: # TODO: think what to do with this raise FloatException(inst, "toF in inst.data.op:@_copy_Ist_WrTmp") elif SIMD_re.match(inst.data.op): raise VectorException( inst, "SIMD_re.match(inst.data.op)@_copy_Ist_WrTmp") elif any([ inst.data.op.split("Iop_")[1].startswith(x) for x in ["Min", "Max", "Perm"] ]): # Iop_Min8Ux8, #Iop_Max8Sx8, #Iop_Perm8x8 raise InstructionException(inst, "") elif "Max" in inst.data.op: raise InstructionException(inst, "") else: raise NotImplementedError( "Unknown vex Binary operator {}".format(inst.data.op)) elif isinstance(inst.data, pyvex.expr.RdTmp): out_tmp = self._tmps[inst.data.tmp] logger.debug("LLVM.EMIT: Not emiting tmp assignment") elif isinstance(inst.data, pyvex.expr.Const): out_tmp = ir.Constant( translate_var_type(inst.data.result_type(my_tyenv)), inst.data.con.value) elif isinstance(inst.data, pyvex.expr.Load): translated_addr = self.get_translated_arg(inst.data.addr) addr = self._addr_helper(translated_addr, inst.data.result_type(my_tyenv)) out_tmp = self.emit_print( self._bb_builder.load(addr, self.tmp_prefix + str(inst.tmp))) elif isinstance(inst.data, pyvex.expr.Unop): assert len(inst.data.args) == 1 cast_match = cast_re.match(inst.data.op) if cast_match is not None: assert len(inst.data.args) == 1 translated_value = self.get_translated_arg(inst.data.args[0]) llvm_result_type = translate_var_type( inst.data.result_type(my_tyenv)) if translated_value.type.width < llvm_result_type.width: if cast_match.groups()[2] == "U": if cast_match.groups()[3] is not None: pass out_tmp = self.emit_print( self._bb_builder.zext( translated_value, llvm_result_type, self.tmp_prefix + str(inst.tmp))) else: out_tmp = self.emit_print( self._bb_builder.sext( translated_value, llvm_result_type, self.tmp_prefix + str(inst.tmp))) elif translated_value.type.width > llvm_result_type.width: out_tmp = self.emit_print( self._bb_builder.trunc( translated_value, llvm_result_type, self.tmp_prefix + str(inst.tmp))) else: raise NotImplementedError("extend to same size?") elif inst.data.op.startswith("Iop_Not"): translated_value = self.get_translated_arg(inst.data.args[0]) llvm_result_type = translate_var_type( inst.data.result_type(my_tyenv)) var_width_value = self._var_width_helper( translated_value, llvm_result_type) out_tmp = self.emit_print( self._bb_builder.neg(var_width_value, self.tmp_prefix + str(inst.tmp))) elif inst.data.op.startswith("Iop_Clz"): out_tmp = ir.Constant( translate_var_type(inst.data.result_type(my_tyenv)), 0) logger.debug("LLVM.EMIT: side-stepping Iop_Clz") elif inst.data.op.startswith("Iop_Ctz"): out_tmp = ir.Constant( translate_var_type(inst.data.result_type(my_tyenv)), 0) logger.debug("LLVM.EMIT: side-stepping Iop_Ctz") elif inst.data.op.startswith("Iop_Reinterp"): out_tmp = ir.Constant( translate_var_type(inst.data.result_type(my_tyenv)), 0) logger.debug("LLVM.EMIT: side-stepping Iop_Reinterp") elif inst.data.op.startswith("Iop_Dup"): raise VectorException( inst, "inst.data.op.startswith(Iop_Dup)@_copy_Ist_WrTmp") else: raise NotImplementedError("Unknown vex Unop {}".format( inst.data.op)) elif isinstance(inst.data, pyvex.expr.Triop): if inst.data.op.startswith("Iop_SetElem"): raise VectorException( inst, "inst.data.op.startswith(Iop_SetElem)@_copy_Ist_WrTmp") else: raise NotImplementedError("Unknown vex Triop {}".format( inst.data.op)) elif isinstance(inst.data, pyvex.expr.Qop): if inst.data.op.startswith("Iop_64x4toV256"): raise VectorException( inst, "inst.data.op.startswith(Iop_64x4toV256)@_copy_Ist_WrTmp") else: raise NotImplementedError("Unknown vex Qop {}".format( inst.data.op)) elif isinstance(inst.data, pyvex.expr.ITE): phi_var_type = translate_var_type(inst.data.result_type(my_tyenv)) pred = self.get_translated_arg(inst.data.cond) bb = self._bb_builder.basic_block bb_prefix = "{}.{}".format(bb.name, self._curbb_part) bbif = self._bb_builder.append_basic_block( name=bb_prefix + '.if.' + self.tmp_prefix + str(inst.tmp)) if_arg = self._var_width_helper( self.get_translated_arg(inst.data.iftrue), phi_var_type) bbelse = self._bb_builder.append_basic_block( name=bb_prefix + '.else.' + self.tmp_prefix + str(inst.tmp)) else_arg = self._var_width_helper( self.get_translated_arg(inst.data.iffalse), phi_var_type) self._curbb_part += 1 # in the move to python3 & new LLVM (3.8 -> 10) it seems the long name broke phi nodes # (created by multiple ITEs, e.g., in ydhms_diff@wget) bb_new_prefix = "ob{}.{}".format(self._cur_block['index'], self._curbb_part) bbend = self._bb_builder.append_basic_block(name=bb_new_prefix + '.endif') self._dynamic_bbs.extend([bbif, bbelse, bbend]) self.emit_print(self._bb_builder.cbranch(pred, bbif, bbelse)) self._bb_builder.position_at_end(bbif) self.emit_print(bbif) self.emit_print(self._bb_builder.branch(bbend)) self._bb_builder.position_at_end(bbelse) self.emit_print(bbif) self.emit_print(self._bb_builder.branch(bbend)) self._bb_builder.position_at_end(bbend) self._curbb = bbend # builder was moved to the end basic block (then & otherwise are connected to it) phi = self._bb_builder.phi(phi_var_type, self.tmp_prefix + str(inst.tmp)) phi.add_incoming(if_arg, bbif) phi.add_incoming(else_arg, bbelse) self.emit_print(phi) out_tmp = phi elif isinstance(inst.data, pyvex.expr.CCall): if inst.data.callee.name.startswith("amd64g"): translated_args = list( map(self.get_translated_arg, inst.data.args)) cond_func = self._cond_functions_dict[(inst.data.callee.name, len(translated_args))] out_tmp = self.emit_print( self._bb_builder.call(cond_func, translated_args, self.tmp_prefix + str(inst.tmp))) else: raise UnknownCallException( inst, "Unknown call - " + str(inst.data.callee.name) + "@_copy_Ist_WrTmp") else: raise NotImplementedError("Unknown op {} in Ist_WrTmp".format( inst.data)) self._last_tmp = out_tmp self._tmps[inst.tmp] = out_tmp
def generate_declaration(self, n, status=0, motifiers=[]): """ status == 0: allocate local status == 1: allocate global status == 2: return element type """ typ = type(n) if typ == ast.IdentifierType: current = self.get_element(n.spec[0], None) decl = motifiers.pop(0) name = decl.name for m in motifiers: current = self.get_element(m, current) if status == 0: self.g_named_memory[n.name] = self.g_llvm_builder.alloca(current, name=name) elif status == 1: self.g_global_variable[name] = \ ir.GlobalVariable(self.g_llvm_module, current, name=name) self.g_global_variable[name].initializer = ir.Constant(current, None) elif status == 2: if len(motifiers) > 0 and type(motifiers[0]) == ast.FuncDecl: function = ir.Function(self.g_llvm_module, current, name=name) if motifiers[0].args: paranames = [param.name for param in motifiers[0].args.params] for arg, arg_name in zip(function.args, paranames): arg.name = arg_name # Add arguments to variable symbol table. self.g_named_argument[arg_name] = arg # Set signed extension for char if isinstance(arg.type, ir.IntType) and arg.type.width == 8: arg.add_attribute('signext') self.g_named_function[name] = function return function else: return current elif typ == ast.Struct: context = self.g_llvm_module.context current = context.get_identified_type(n.name) # define struct if n.name not in self.g_type_define: self.g_type_define[n.name] = [ele.name for ele in n.decls] types = [self.generate_declaration(ele, status=2) for ele in n.decls] current.set_body(*types) decl = motifiers.pop(0) name = decl.name for m in motifiers: current = self.get_element(m, current) if status == 0: return current elif status == 1: self.g_global_variable[name] = \ ir.GlobalVariable(self.g_llvm_module, current, name=name) self.g_global_variable[name].initializer = ir.Constant(current, None) elif len(motifiers) > 0 and type(motifiers[0]) == ast.FuncDecl: function = ir.Function(self.g_llvm_module, current, name=name) paranames = [param.name for param in motifiers[0].args] for arg, arg_name in zip(function.args, paranames): arg.name = arg_name # Add arguments to variable symbol table. self.g_named_argument[arg_name] = arg self.g_named_function[name] = function return function else: return current elif typ in {ast.ArrayDecl, ast.FuncDecl, ast.PtrDecl, ast.Decl}: return self.generate_declaration(n.type, status, motifiers+[n])
def _python_list_to_native(typ, obj, c, size, listptr, errorptr): """ Construct a new native list from a Python list. """ def check_element_type(nth, itemobj, expected_typobj): typobj = nth.typeof(itemobj) # Check if *typobj* is NULL with c.builder.if_then( cgutils.is_null(c.builder, typobj), likely=False, ): c.builder.store(cgutils.true_bit, errorptr) loop.do_break() # Mandate that objects all have the same exact type type_mismatch = c.builder.icmp_signed('!=', typobj, expected_typobj) with c.builder.if_then(type_mismatch, likely=False): c.builder.store(cgutils.true_bit, errorptr) if IS_PY3: c.pyapi.err_format( "PyExc_TypeError", "can't unbox heterogeneous list: %S != %S", expected_typobj, typobj, ) else: # Python2 doesn't have "%S" format string. c.pyapi.err_set_string( "PyExc_TypeError", "can't unbox heterogeneous list", ) c.pyapi.decref(typobj) loop.do_break() c.pyapi.decref(typobj) # Allocate a new native list ok, list = listobj.ListInstance.allocate_ex(c.context, c.builder, typ, size) with c.builder.if_else(ok, likely=True) as (if_ok, if_not_ok): with if_ok: list.size = size zero = ir.Constant(size.type, 0) with c.builder.if_then(c.builder.icmp_signed('>', size, zero), likely=True): # Traverse Python list and unbox objects into native list with _NumbaTypeHelper(c) as nth: # Note: *expected_typobj* can't be NULL expected_typobj = nth.typeof( c.pyapi.list_getitem(obj, zero)) with cgutils.for_range(c.builder, size) as loop: itemobj = c.pyapi.list_getitem(obj, loop.index) check_element_type(nth, itemobj, expected_typobj) # XXX we don't call native cleanup for each # list element, since that would require keeping # of which unboxings have been successful. native = c.unbox(typ.dtype, itemobj) with c.builder.if_then(native.is_error, likely=False): c.builder.store(cgutils.true_bit, errorptr) loop.do_break() # The reference is borrowed so incref=False list.setitem(loop.index, native.value, incref=False) c.pyapi.decref(expected_typobj) if typ.reflected: list.parent = obj # Stuff meminfo pointer into the Python object for # later reuse. with c.builder.if_then(c.builder.not_(c.builder.load(errorptr)), likely=False): c.pyapi.object_set_private_data(obj, list.meminfo) list.set_dirty(False) c.builder.store(list.value, listptr) with if_not_ok: c.builder.store(cgutils.true_bit, errorptr) # If an error occurred, drop the whole native list with c.builder.if_then(c.builder.load(errorptr)): c.context.nrt.decref(c.builder, typ, list.value)
def extern_function(self, n): """ NOTE: since we don't have pre-processing, so we write hard code to support the following external functions: printf, gets, isdigital, atoi, memcpy, strlen """ if n.name.name == 'printf': func_type = ir.FunctionType(ir.IntType(32), [ir.IntType(8).as_pointer()], var_arg=True) args = [] for index, arg in enumerate(n.args.exprs): if index == 0: args.append(self.visit(arg)) else: args.append(self.visit(arg, status=1)) return self.g_llvm_module.declare_intrinsic(n.name.name, (), func_type), args if n.name.name == 'gets': func_type = ir.FunctionType(ir.IntType(32), [], var_arg=True) args = [] for arg in n.args.exprs: zero = ir.Constant(ir.IntType(32), 0) ptr = self.g_llvm_builder.gep(self.visit(arg, status=0), [zero, zero], inbounds=True) args.append(ptr) return self.g_llvm_module.declare_intrinsic(n.name.name, (), func_type), args if n.name.name == 'isdigit': func_type = ir.FunctionType(ir.IntType(32), [ir.IntType(32)], var_arg=False) args = [] for arg in n.args.exprs: ext = self.g_llvm_builder.sext(self.visit(arg, status=1), ir.IntType(32)) args.append(ext) return self.g_llvm_module.declare_intrinsic(n.name.name, (), func_type), args if n.name.name == 'atoi': func_type = ir.FunctionType(ir.IntType(32), [], var_arg=True) args = [] for arg in n.args.exprs: zero = ir.Constant(ir.IntType(32), 0) ptr = self.g_llvm_builder.gep(self.visit(arg, status=0), [zero, zero], inbounds=True) args.append(ptr) return self.g_llvm_module.declare_intrinsic(n.name.name, (), func_type), args if n.name.name == 'memcpy': args = [] for index, arg in enumerate(n.args.exprs): if index == 2: args.append(self.visit(arg, status=1)) else: array_addr = self.visit(arg, status=0) if isinstance(array_addr.type, ir.PointerType) and \ isinstance(array_addr.type.pointee, ir.ArrayType): zero = ir.Constant(ir.IntType(32), 0) array_addr = self.g_llvm_builder.gep(array_addr, [zero, zero], inbounds=True) args.append(array_addr) args.append(ir.Constant(ir.IntType(32), 1)) args.append(ir.Constant(ir.IntType(1), 0)) pint8 = ir.PointerType(ir.IntType(8)) k = self.g_llvm_module.declare_intrinsic('llvm.memcpy', [pint8, pint8, ir.IntType(32)]), args return k if n.name.name == 'strlen': func_type = ir.FunctionType(ir.IntType(32), [ir.IntType(8).as_pointer()], var_arg=False) args = [] for arg in n.args.exprs: zero = ir.Constant(ir.IntType(32), 0) ptr = self.g_llvm_builder.gep(self.visit(arg, status=0), [zero, zero], inbounds=True) args.append(ptr) return self.g_llvm_module.declare_intrinsic(n.name.name, (), func_type), args
llvm.initialize_native_target() llvm.initialize_native_asmprinter() # yes, even this one module = ll.Module() mainfn_type = ll.FunctionType(ll.IntType(64), []) func = ll.Function(module, mainfn_type, name='main') bb_entry = func.append_basic_block('entry') builder = ll.IRBuilder() builder.position_at_end(bb_entry) # builder.ret(mulinstr) ll.Constant(ll.IntType(64), 190) stackint = builder.alloca(ll.IntType(64), name='myint') builder.store(ll.Constant(stackint.type.pointee, 123), stackint) myint = builder.load(stackint, 'myint') builder.ret(myint) # ------------------------------------------------------------------------------------------------------------------------- # fntype = ll.FunctionType(ll.IntType(32), [ll.IntType(32), ll.IntType(32)]) # # module = ll.Module() # # func = ll.Function(module, fntype, name='foo') # bb_entry = func.append_basic_block() # # builder = ll.IRBuilder()
def traverse(self, builder, value): data = self.get(builder, value, "data") valid = self.get(builder, value, "valid") data = builder.select(valid, data, ir.Constant(data.type, None)) return [(self.get_type("data"), data), (self.get_type("valid"), valid)]
def visit_num(node): return ir.Constant(type_map[node.val_type], node.value)
def visit_Cst(self, e): return ll.Constant(IntType(e.nbits), e.n)
g = 10; h = 10.0; a = a + 10; b = b + h; return 0; } ''' # Cria o módulo. module = ir.Module('meu_modulo.bc') # Variável inteira global g g = ir.GlobalVariable(module, ir.IntType(32), "g") # Inicializa a variavel g g.initializer = ir.Constant(ir.IntType(32), 0) # Linkage = common g.linkage = "common" # Define o alinhamento em 4 g.align = 4 # Variável float global h h = ir.GlobalVariable(module, ir.FloatType(), "h") # Inicializa a variavel h h.initializer = ir.Constant(ir.FloatType(), 0.0) # Linkage = common h.linkage = "common" # Define o alinhamento em 4 h.align = 4 # Define o retorno da função main
builder = ll.IRBuilder() builder.position_at_end(bb_entry) # 引数のx, y x, y = func.args # 変数a,b,c,dを定義 ptr_a = builder.alloca(i32) ptr_b = builder.alloca(i32) ptr_c = builder.alloca(i32) ptr_d = builder.alloca(i32) # store builder.store(x, ptr_a) builder.store(y, ptr_b) builder.store(ll.Constant(i32, 1000), ptr_c) # load a = builder.load(ptr_a) b = builder.load(ptr_b) c = builder.load(ptr_c) # またstore builder.store(a, ptr_d) # 加算して、Returnする ret1 = builder.add(a, b, name="res") ret2 = builder.add(ret1, c, name="res2") ret3 = builder.add(ret2, builder.load(ptr_d), name="res3") builder.ret(ret3)
def as_return(self, builder, value): elems = self._as("as_data", builder, value) struct = ir.Constant(self.get_data_type(), ir.Undefined) for i, el in enumerate(elems): struct = builder.insert_value(struct, el, [i]) return struct
def int_as_bool(context, builder, sig, args): [val] = args return builder.icmp_unsigned('!=', val, ir.Constant(val.type, 0))
def g(node, mod): if isinstance(node, list): for stmt in node: code = g(stmt, mod) return None elif isinstance(node, Integer): return ir.Constant(int_type, int(node.value)) elif isinstance(node, Float): return ir.Constant(float_type, float(node.value)) elif isinstance(node, UnaryOp): nodetype = node.type llvmtype = mod.getllvmtype(nodetype) operand = g(node.operand, mod) op = node.op if nodetype == 'int': if op == '-': return mod.builder.sub(ir.Constant(llvmtype, 0), operand) elif nodetype == 'float': if op == '-': return mod.builder.fsub(ir.Constant(llvmtype, 0), operand) elif isinstance(node, Print): node_type = mod.gettype(node.expression) value = g(node.expression, mod) if node_type == 'int': return mod.builder.call(mod._printi, [value]) elif node_type == 'float': return mod.builder.call(mod._printf, [value]) else: raise RuntimeError(f"Cannot print expression {node}") elif isinstance(node, BinOp): leftval = g(node.left, mod) rightval = g(node.right, mod) lefttype = mod.gettype(node.left) if lefttype in {'int'}: if node.op == '+': return mod.builder.add(leftval, rightval) if node.op == '-': return mod.builder.sub(leftval, rightval) if node.op == '*': return mod.builder.mul(leftval, rightval) if node.op == '/': return mod.builder.sdiv(leftval, rightval) elif lefttype in {'float'}: if node.op == '+': return mod.builder.fadd(leftval, rightval) if node.op == '-': return mod.builder.fsub(leftval, rightval) if node.op == '*': return mod.builder.fmul(leftval, rightval) if node.op == '/': return mod.builder.fdiv(leftval, rightval) else: raise RuntimeError(f"Cannot evaluate BinOp operator {node}") elif isinstance(node, (DeclareConst, DeclareVar)): # Get node type and llvm type nodetype = mod.gettype(node) llvmtype = mod.getllvmtype(nodetype) # Declare variable with name, node.name var = mod.builder.alloca(llvmtype, name=node.name) if node.value: value = g(node.value, mod) mod.builder.store(value, var) mod.env[node.name] = var # Store variable in environment elif isinstance(node, Load): return mod.builder.load(mod.env[node.location]) else: raise RuntimeError(f"Can't generate code for {node}")
def float_as_bool(context, builder, sig, args): [val] = args return builder.fcmp(lc.FCMP_UNE, val, ir.Constant(val.type, 0.0))
class LLVMConstants: ZERO_INT = ir.Constant(LLVMTypes.T_INT, 0) ZERO_REAL = ir.Constant(LLVMTypes.T_REAL, 0) NIL = ir.Constant(LLVMTypes.T_NIL, 0)
def _codegen_NumberExprAST(self, node): return ir.Constant(ir.DoubleType(), float(node.val))
def unbox_boolean(c, typ, obj): istrue = c.pyapi.object_istrue(obj) zero = ir.Constant(istrue.type, 0) val = c.builder.icmp_signed('!=', istrue, zero) return NativeValue(val, is_error=c.pyapi.c_api_error())
def _codegen_ForExprAST(self, node): # Output this as: # var = alloca double # ... # start = startexpr # store start -> var # goto loop # loop: # ... # bodyexpr # ... # loopend: # step = stepexpr # endcond = endexpr # curvar = load var # nextvariable = curvar + step # store nextvar -> var # br endcond, loop, afterloop # afterloop: # Create an alloca for the induction var. Save and restore location of # our builder because _create_entry_block_alloca may modify it (llvmlite # issue #44). saved_block = self.builder.block var_addr = self._create_entry_block_alloca(node.id_name) self.builder.position_at_end(saved_block) # Emit the start expr first, without the variable in scope. Store it # into the var. start_val = self._codegen(node.start_expr) self.builder.store(start_val, var_addr) loop_bb = self.builder.function.append_kalei_block('loop') # Insert an explicit fall through from the current block to loop_bb self.builder.branch(loop_bb) self.builder.position_at_start(loop_bb) # Within the loop, the variable now refers to our alloca slot. If it # shadows an existing variable, we'll have to restore, so save it now. old_var_addr = self.func_symtab.get(node.id_name) self.func_symtab[node.id_name] = var_addr # Emit the body of the loop. This, like any other expr, can change the # current BB. Note that we ignore the value computed by the body. body_val = self._codegen(node.body) # Compute the end condition endcond = self._codegen(node.end_expr) cmp = self.builder.fcmp_ordered( '!=', endcond, ir.Constant(ir.DoubleType(), 0.0), 'loopcond') if node.step_expr is None: stepval = ir.Constant(ir.DoubleType(), 1.0) else: stepval = self._codegen(node.step_expr) cur_var = self.builder.load(var_addr, node.id_name) nextval = self.builder.fadd(cur_var, stepval, 'nextvar') self.builder.store(nextval, var_addr) # Create the 'after loop' block and insert it after_bb = self.builder.function.append_kalei_block('afterloop') # Insert the conditional branch into the end of loop_end_bb self.builder.cbranch(cmp, loop_bb, after_bb) # New code will be inserted into after_bb self.builder.position_at_start(after_bb) # Restore the old var address if it was shadowed. if old_var_addr is not None: self.func_symtab[node.id_name] = old_var_addr else: del self.func_symtab[node.id_name] # The 'for' expression always returns 0 return ir.Constant(ir.DoubleType(), 0.0)
def _const_int(code): return ir.Constant(errcode_t, code)
def stringz(string): n = len(string) + 1 buf = bytearray((' ' * n).encode('ascii')) buf[-1] = 0 buf[:-1] = string.encode('utf-8') return ir.Constant(ir.ArrayType(type_map[INT8], n), buf)
from llvmlite import ir from oxygen.compiler.base import type_map from oxygen.grammar import * ARRAY_INITIAL_CAPACITY = ir.Constant(type_map[INT], 16) zero = ir.Constant(type_map[INT], 0) one = ir.Constant(type_map[INT], 1) two = ir.Constant(type_map[INT], 2) eight = ir.Constant(type_map[INT], 8) ten = ir.Constant(type_map[INT], 10) zero_32 = ir.Constant(type_map[INT32], 0) one_32 = ir.Constant(type_map[INT32], 1) two_32 = ir.Constant(type_map[INT32], 2) array_types = [type_map[INT]] def define_builtins(self): str_struct = self.module.context.get_identified_type('i64.array') str_struct.name = 'i64.array' str_struct.type = OBJECT str_struct.set_body(type_map[INT], type_map[INT], type_map[INT].as_pointer()) self.define('str', str_struct) self.define('i64.array', str_struct) str_struct_ptr = str_struct.as_pointer() self.define('str_ptr', str_struct_ptr) type_map[STR] = str_struct
def setitem_list(context, builder, sig, args): dest = ListInstance(context, builder, sig.args[0], args[0]) src = ListInstance(context, builder, sig.args[2], args[2]) slice = context.make_helper(builder, sig.args[1], args[1]) slicing.guard_invalid_slice(context, builder, sig.args[1], slice) dest.fix_slice(slice) src_size = src.size avail_size = slicing.get_slice_length(builder, slice) size_delta = builder.sub(src.size, avail_size) zero = ir.Constant(size_delta.type, 0) one = ir.Constant(size_delta.type, 1) with builder.if_else(builder.icmp_signed('==', slice.step, one)) as (then, otherwise): with then: # Slice step == 1 => we can resize # Compute the real stop, e.g. for dest[2:0] = [...] real_stop = builder.add(slice.start, avail_size) # Size of the list tail, after the end of slice tail_size = builder.sub(dest.size, real_stop) with builder.if_then(builder.icmp_signed('>', size_delta, zero)): # Grow list then move list tail dest.resize(builder.add(dest.size, size_delta)) dest.move(builder.add(real_stop, size_delta), real_stop, tail_size) with builder.if_then(builder.icmp_signed('<', size_delta, zero)): # Move list tail then shrink list dest.move(builder.add(real_stop, size_delta), real_stop, tail_size) dest.resize(builder.add(dest.size, size_delta)) dest_offset = slice.start with cgutils.for_range(builder, src_size) as loop: value = src.getitem(loop.index) dest.setitem(builder.add(loop.index, dest_offset), value, incref=True) with otherwise: with builder.if_then(builder.icmp_signed('!=', size_delta, zero)): msg = "cannot resize extended list slice with step != 1" context.call_conv.return_user_exc(builder, ValueError, (msg, )) with cgutils.for_range_slice_generic(builder, slice.start, slice.stop, slice.step) as (pos_range, neg_range): with pos_range as (index, count): value = src.getitem(count) dest.setitem(index, value, incref=True) with neg_range as (index, count): value = src.getitem(count) dest.setitem(index, value, incref=True) return context.get_dummy_value()