def set_branch_weight(builder, brinst, trueweight, falseweight): module = get_module(builder) mdid = lc.MetaDataString.get(module, "branch_weights") trueweight = lc.Constant.int(Type.int(), trueweight) falseweight = lc.Constant.int(Type.int(), falseweight) md = lc.MetaData.get(module, [mdid, trueweight, falseweight]) brinst.set_metadata("prof", md)
def code_gen(self): if self.context.parent_context is None: if self.var_name_token.word in self.context.type_table: raise cmexception.RedefineException(self.var_name_token, 'Global Variable') else: t = Helper.get_type(self.typo.word) gv = GlobalVariable.new(g_llvm_module, t, self.var_name_token.word) self.context.type_table[self.var_name_token.word] = t self.context.value_table[self.var_name_token.word] = gv if self.typo.word == 'int': gv.initializer = Constant.int(Type.int(32), 0) elif self.typo.word == 'double': gv.initializer = Constant.real(Type.double(), 0) elif self.typo.word == 'char': gv.initializer = Constant.int(Type.int(8), 0) else: gv.initializer = Constant.stringz("") else: if not self.var_name_token.word in self.context.type_table: t = Helper.get_type(self.typo.word) var_address = g_llvm_builder.alloca(t, name=self.var_name_token.word) self.context.type_table[self.var_name_token.word] = t self.context.value_table[self.var_name_token.word] = var_address else: raise cmexception.RedefineException(self.var_name_token)
def test_bswap(self): # setup a function and a builder mod = Module.new("test") functy = Type.function(Type.int(), []) func = mod.add_function(functy, "showme") block = func.append_basic_block("entry") b = Builder.new(block) # let's do bswap on a 32-bit integer using llvm.bswap val = Constant.int(Type.int(), 0x42) bswap = Function.intrinsic(mod, lc.INTR_BSWAP, [Type.int()]) bswap_res = b.call(bswap, [val]) b.ret(bswap_res) # logging.debug(mod) # the output is: # # ; ModuleID = 'test' # # define void @showme() { # entry: # %0 = call i32 @llvm.bswap.i32(i32 42) # ret i32 %0 # } # let's run the function ee = le.ExecutionEngine.new(mod) retval = ee.run_function(func, []) self.assertEqual(retval.as_int(), 0x42000000)
def scanf(mod, bu, s): v = mod.get_global_variable_named(s) sf = mod.get_function_named("scanf") t1 = bu.alloca(Type.int()) t2 = bu.gep(v, [Constant.int(Type.int(), 0), Constant.int(Type.int(), 0)]) bu.call(sf, [t2, t1]) return bu.load(t1)
def test_atomic_rmw(self): mod = Module.new("mod") functype = Type.function(Type.void(), []) func = mod.add_function(functype, name="foo") bb = func.append_basic_block("entry") bldr = Builder.new(bb) ptr = bldr.alloca(Type.int()) old = bldr.load(ptr) val = Constant.int(Type.int(), 1234) for ordering in self.orderings: inst = bldr.atomic_rmw("xchg", ptr, val, ordering) self.assertEqual(ordering, str(inst).split(" ")[-1]) for op in self.atomic_op: inst = bldr.atomic_rmw(op, ptr, val, ordering) self.assertEqual(op, str(inst).strip().split(" ")[3]) inst = bldr.atomic_rmw("xchg", ptr, val, ordering, crossthread=False) self.assertEqual("singlethread", str(inst).strip().split(" ")[-2]) for op in self.atomic_op: atomic_op = getattr(bldr, "atomic_%s" % op) inst = atomic_op(ptr, val, ordering) self.assertEqual(op, str(inst).strip().split(" ")[3])
def test_atomic_ldst(self): mod = Module.new('mod') functype = Type.function(Type.void(), []) func = mod.add_function(functype, name='foo') bb = func.append_basic_block('entry') bldr = Builder.new(bb) ptr = bldr.alloca(Type.int()) val = Constant.int(Type.int(), 1234) for ordering in self.orderings: loaded = bldr.atomic_load(ptr, ordering) self.assert_('load atomic' in str(loaded)) self.assertEqual(ordering, str(loaded).strip().split(' ')[-3].rstrip(',')) self.assert_('align 1' in str(loaded)) stored = bldr.atomic_store(loaded, ptr, ordering) self.assert_('store atomic' in str(stored)) self.assertEqual(ordering, str(stored).strip().split(' ')[-3].rstrip(',')) self.assert_('align 1' in str(stored)) fenced = bldr.fence(ordering) self.assertEqual(['fence', ordering], str(fenced).strip().split(' '))
def body(self, idx): get_id = self.get_function_named('P86.getmutationid') get_cnt = self.get_function_named('P86.getmutationcount') set_mut = self.get_function_named('P86.setmutation') index = self.var(Type.int(32), 0) one = self.constant(Type.int(32), 1) zero = self.constant(Type.int(32), 0) cnt = get_cnt() with self.loop() as loop: with loop.condition() as setcond: setcond(index <= cnt) with loop.body(): set_mut(index) with self.ifelse(get_id() == idx) as ifelse: with ifelse.then(): set_mut(index) self.ret() index += one set_mut(zero) self.ret()
def __init__(self): self.nbranch = 0 self.nlabel = 0 self.op_assign = { 'ASSIGN': '', 'ASSIGN_PLUS': '', 'ASSIGN_MINUS': '' } self.op_arithmetic = { 'PLUS': 'add', 'MINUS': 'sub', 'MULT': 'imul', 'DIV': 'idiv' } self.op_compare = { 'EQ': IPRED_EQ, 'NEQ': IPRED_NE, 'LT': IPRED_SLT, 'LTE': IPRED_SLE, 'GT': IPRED_SGT, 'GTE': IPRED_SGE } self.op_logical = { 'LAND': '', 'LOR': '' } self.types = { 'bool': Type.int(1), 'int': Type.int(32) } self.undefined_functions = {} self.returns = {}
def _generic_array(context, builder, shape, dtype, symbol_name, addrspace, can_dynsized=False): elemcount = reduce(operator.mul, shape) lldtype = context.get_data_type(dtype) laryty = Type.array(lldtype, elemcount) if addrspace == nvvm.ADDRSPACE_LOCAL: # Special case local addrespace allocation to use alloca # NVVM is smart enough to only use local memory if no register is # available dataptr = builder.alloca(laryty, name=symbol_name) else: lmod = cgutils.get_module(builder) # Create global variable in the requested address-space gvmem = lmod.add_global_variable(laryty, symbol_name, addrspace) if elemcount <= 0: if can_dynsized: # dynamic shared memory gvmem.linkage = lc.LINKAGE_EXTERNAL else: raise ValueError("array length <= 0") else: gvmem.linkage = lc.LINKAGE_INTERNAL gvmem.initializer = lc.Constant.undef(laryty) if dtype not in types.number_domain: raise TypeError("unsupported type: %s" % dtype) # Convert to generic address-space conv = nvvmutils.insert_addrspace_conv(lmod, Type.int(8), addrspace) addrspaceptr = gvmem.bitcast(Type.pointer(Type.int(8), addrspace)) dataptr = builder.call(conv, [addrspaceptr]) return _make_array(context, builder, dataptr, dtype, shape)
def parse_tuple_and_keywords(self, args, kws, fmt, keywords, *objs): charptr = Type.pointer(Type.int(8)) charptrary = Type.pointer(charptr) argtypes = [self.pyobj, self.pyobj, charptr, charptrary] fnty = Type.function(Type.int(), argtypes, var_arg=True) fn = self._get_function(fnty, name="PyArg_ParseTupleAndKeywords") return self.builder.call(fn, [args, kws, fmt, keywords] + list(objs))
def __init__(self, context, builder, value=None, ref=None, cast_ref=False): self._type = context.get_struct_type(self) self._context = context self._builder = builder if ref is None: self._value = alloca_once(builder, self._type) if value is not None: assert not is_pointer(value.type) assert value.type == self._type, (value.type, self._type) builder.store(value, self._value) else: assert value is None assert is_pointer(ref.type) if self._type != ref.type.pointee: if cast_ref: ref = builder.bitcast(ref, Type.pointer(self._type)) else: raise TypeError( "mismatching pointer type: got %s, expected %s" % (ref.type.pointee, self._type)) self._value = ref self._namemap = {} self._fdmap = [] self._typemap = [] base = Constant.int(Type.int(), 0) for i, (k, tp) in enumerate(self._fields): self._namemap[k] = i self._fdmap.append((base, Constant.int(Type.int(), i))) self._typemap.append(tp)
def numba_array_adaptor(self, ary, ptr): voidptr = Type.pointer(Type.int(8)) fnty = Type.function(Type.int(), [self.pyobj, voidptr]) fn = self._get_function(fnty, name="NumbaArrayAdaptor") fn.args[0].add_attribute(lc.ATTR_NO_CAPTURE) fn.args[1].add_attribute(lc.ATTR_NO_CAPTURE) return self.builder.call(fn, (ary, ptr))
def f_atoi(mod): '''libc: convert a string to an integer''' ret = Type.int(32) args = [Type.pointer(Type.int(8))] type_ = Type.function(ret, args) return mod.get_or_insert_function(type_, "atoi")
def f_main(mod): '''main function''' argc = Type.int(32) argv = Type.pointer(Type.pointer(Type.int(8))) type_ = Type.function(Type.void(), [argc, argv]) return mod.get_or_insert_function(type_, "main")
def f_abs(mod): '''libc: compute the absolute value of an integer''' ret = Type.int() args = [Type.int()] type_ = Type.function(ret, args) return mod.get_or_insert_function(type_, "abs")
def f_scanf(mod): '''libc: input format conversion''' ret = Type.int(32) arg = Type.pointer(Type.int(8)) type_ = Type.function(ret, [arg], True) return mod.get_or_insert_function(type_, "scanf")
def f_printf(mod): '''libc: formatted output conversion''' ret = Type.int(32) arg = Type.pointer(Type.int(8)) type_ = Type.function(ret, [arg], True) return mod.get_or_insert_function(type_, "printf")
def code_gen(self): if self.context.parent_context is None: if self.array_name_token.word in self.context.type_table: raise cmexception.RedefineException(self.array_name_token) else: t = Helper.get_array_type(self.typo.word, int(self.length.word)) gv = GlobalVariable.new(g_llvm_module, t, self.array_name_token.word) initials = [i.code_gen() for i in self.initial_value if True] constant_array = ConstantArray.array(Helper.get_type(self.typo.word), initials) gv.initializer = constant_array self.context.type_table[self.array_name_token.word] = t self.context.value_table[self.array_name_token.word] = gv else: if self.array_name_token.word in self.context.type_table: raise cmexception.RedefineException(self.array_name_token) else: t = Helper.get_array_type(self.typo.word, int(self.length.word)) array_address = g_llvm_builder.alloca(t, name=self.array_name_token.word) inx = 0 for i in self.initial_value: value = i.code_gen() if value in g_llvm_module.global_variables: string_value_ptr = g_llvm_builder.gep( value, [Constant.int(Type.int(32), 0), Constant.int(Type.int(32), 0)]) var_address = g_llvm_builder.gep( array_address, [Constant.int(Type.int(32), 0), Constant.int(Type.int(32), inx)]) g_llvm_builder.store(string_value_ptr, var_address) else: var_address = g_llvm_builder.gep( array_address, [Constant.int(Type.int(32), 0), Constant.int(Type.int(32), inx)]) g_llvm_builder.store(value, var_address) inx += 1 self.context.type_table[self.array_name_token.word] = t self.context.value_table[self.array_name_token.word] = array_address
def test_constexpr_opcode(self): mod = Module.new("test_constexpr_opcode") func = mod.add_function(Type.function(Type.void(), []), name="foo") builder = Builder.new(func.append_basic_block("entry")) a = builder.inttoptr(Constant.int(Type.int(), 123), Type.pointer(Type.int())) self.assertTrue(isinstance(a, lc.ConstantExpr)) self.assertEqual(a.opcode, lc.OPCODE_INTTOPTR) self.assertEqual(a.opcode_name, "inttoptr")
def tuple_setitem(self, tuple_val, index, item): """ Steals a reference to `item`. """ fnty = Type.function(Type.int(), [self.pyobj, Type.int(), self.pyobj]) setitem_fn = self._get_function(fnty, name='PyTuple_SetItem') index = self.context.get_constant(types.int32, index) self.builder.call(setitem_fn, [tuple_val, index, item])
def body(self): mod = self.function.module cnt_var = mod.add_global_variable(Type.int(32), "P86.mutant_count") cnt_var.initializer = Constant.int(Type.int(32), 0) cnt_var.linkage = core.LINKAGE_EXTERNAL self.ret(CTemp(self, self.builder.load(cnt_var)))
def int_upower_impl(context, builder, sig, args): module = cgutils.get_module(builder) x, y = args if y.type.width > 32: y = builder.trunc(y, Type.int(32)) elif y.type.width < 32: y = builder.zext(y, Type.int(32)) powerfn = lc.Function.intrinsic(module, lc.INTR_POWI, [x.type]) return builder.call(powerfn, (x, y))
def test_scalar_type(self): i32a = Type.int(32) i32b = Type.int(32) i64a = Type.int(64) i64b = Type.int(64) ts = set([i32a, i32b, i64a, i64b]) self.assertTrue(len(ts)) self.assertTrue(i32a in ts) self.assertTrue(i64b in ts)
def test_struct_type(self): ta = Type.struct([Type.int(32), Type.float()]) tb = Type.struct([Type.int(32), Type.float()]) tc = Type.struct([Type.int(32), Type.int(32), Type.float()]) ts = set([ta, tb, tc]) self.assertTrue(len(ts) == 2) self.assertTrue(ta in ts) self.assertTrue(tb in ts) self.assertTrue(tc in ts)
def get_data_type(self, ty): """ Get a data representation of the type Returns None if it is an opaque pointer """ if (isinstance(ty, types.Dummy) or isinstance(ty, types.Module) or isinstance(ty, types.Function) or isinstance(ty, types.Dispatcher) or isinstance(ty, types.Object) or isinstance(ty, types.Macro)): return Type.pointer(Type.int(8)) elif isinstance(ty, types.CPointer): dty = self.get_data_type(ty.dtype) return Type.pointer(dty) elif isinstance(ty, types.Optional): return self.get_data_type(ty.type) elif isinstance(ty, types.Array): return self.get_struct_type(self.make_array(ty)) elif isinstance(ty, types.UniTuple): dty = self.get_value_type(ty.dtype) return Type.array(dty, ty.count) elif isinstance(ty, types.Tuple): dtys = [self.get_value_type(t) for t in ty] return Type.struct(dtys) elif isinstance(ty, types.UniTupleIter): stty = self.get_struct_type(self.make_unituple_iter(ty)) return stty elif isinstance(ty, types.Record): # Record are represented as byte array return Type.struct([Type.array(Type.int(8), ty.size)]) elif isinstance(ty, types.UnicodeCharSeq): charty = Type.int(numpy_support.sizeof_unicode_char * 8) return Type.struct([Type.array(charty, ty.count)]) elif isinstance(ty, types.CharSeq): charty = Type.int(8) return Type.struct([Type.array(charty, ty.count)]) elif ty in STRUCT_TYPES: return self.get_struct_type(STRUCT_TYPES[ty]) elif isinstance(ty, types.Pair): pairty = self.make_pair(ty.first_type, ty.second_type) return self.get_struct_type(pairty) else: return LTYPEMAP[ty]
def make_test_module(self): module = Module.new("testmodule") fnty = Type.function(Type.int(), []) function = module.add_function(fnty, "foo") bb_entry = function.append_basic_block("entry") builder = Builder.new(bb_entry) builder.ret(Constant.int(Type.int(), 0xCAFE)) module.verify() return module
def code_gen(self): d = Type.double() i32 = Type.int(32) i1 = Type.int(1) op = self.operator.word left = self.left.code_gen() right = self.right.code_gen() if op == '||' or op == '&&': if left.type != right.type: if left.type == d or right.type == d: left = Helper.auto_cast(g_llvm_builder, left, d) right = Helper.auto_cast(g_llvm_builder, right, d) else: left = Helper.auto_cast(g_llvm_builder, left, i32) right = Helper.auto_cast(g_llvm_builder, right, i32) if left.type == d: if g_llvm_builder is None: return left.fcmp(RPRED_UEQ, right) else: return g_llvm_builder.fcmp(RPRED_UEQ, left, right) else: if g_llvm_builder is None: return left.icmp(IPRED_EQ, right) else: return g_llvm_builder.icmp(IPRED_EQ, left, right) method = Helper.choose_method(left, op, right) if method[0] == 'f': left = Helper.auto_cast(g_llvm_builder, left, d) right = Helper.auto_cast(g_llvm_builder, right, d) elif method == 'and_' or method == 'or_': if left.type == d or right.type == d: raise cmexception.InvalidOperandException(self.operator, str(left.type), str(right.type)) else: if left.type != right.type: left = Helper.auto_cast(g_llvm_builder, left, i32) right = Helper.auto_cast(g_llvm_builder, right, i32) else: if left.type != right.type: left = Helper.auto_cast(g_llvm_builder, left, i32) right = Helper.auto_cast(g_llvm_builder, right, i32) if op == '<' or op == '>' or op == '<=' or op == '>=' or op == '==' or op == '!=': flag = Helper.choose_flag(op, left) if g_llvm_builder is None: return getattr(left, method)(flag, right) else: return getattr(g_llvm_builder, method)(flag, left, right) else: if g_llvm_builder is None: return getattr(left, method)(right) else: return getattr(g_llvm_builder, method)(left, right)
def create_iter_indices(self): intpty = self.context.get_value_type(types.intp) ZERO = Constant.int(Type.int(intpty.width), 0) indices = [] for i in range(self.ndim): x = self.builder.alloca(Type.int(intpty.width)) self.builder.store(ZERO, x) indices.append(x) return _ArrayIndexingHelper(self, indices)
def template(self, iop, fop): inttys = [Type.int(32), Type.int(64)] flttys = [Type.float(), Type.double()] if iop: for ty in inttys: self.func_template(ty, iop) if fop: for ty in flttys: self.func_template(ty, fop)
def get_array_type(typo, length): if typo == 'int': return Type.array(Type.int(32), length) elif typo == 'double': return Type.array(Type.double(), length) elif typo == 'String': ch = Type.int(8) return Type.array(Type.pointer(ch), length) elif typo == 'char': return Type.array(Type.int(8), length)
def test_alloca_alignment(self): m = Module.new('') f = m.add_function(Type.function(Type.void(), []), "foo") b = Builder.new(f.append_basic_block('')) inst = b.alloca(Type.int(32)) inst.alignment = 4 b.ret_void() m.verify() self.assertTrue(inst.is_static) self.assertFalse(inst.is_array) self.assertEqual(inst.alignment, 4) self.assertEqual(str(inst.array_size), 'i32 1')
def func_template(self, ty, op): m = Module.new('dofjaa') fnty = Type.function(ty, [ty, ty]) fn = m.add_function(fnty, 'foo') bldr = Builder.new(fn.append_basic_block('')) bldr.ret(getattr(bldr, op)(*fn.args)) engine = EngineBuilder.new(m).mcjit(True).create() ptr = engine.get_pointer_to_function(fn) from ctypes import c_uint32, c_uint64, c_float, c_double, CFUNCTYPE maptypes = { Type.int(32): c_uint32, Type.int(64): c_uint64, Type.float(): c_float, Type.double(): c_double, } cty = maptypes[ty] prototype = CFUNCTYPE(*[cty] * 3) callee = prototype(ptr) callee(12, 23)
def insert_const_string(self, mod, string): stringtype = Type.pointer(Type.int(8)) text = Constant.stringz(string) name = ".const.%s" % string for gv in mod.global_variables: if gv.name == name and gv.type.pointee == text.type: break else: gv = mod.add_global_variable(text.type, name=name) gv.global_constant = True gv.initializer = text gv.linkage = lc.LINKAGE_INTERNAL return Constant.bitcast(gv, stringtype)
def test_inline_call(self): mod = Module.new(__name__) callee = mod.add_function(Type.function(Type.int(), [Type.int()]), name='bar') builder = Builder.new(callee.append_basic_block('entry')) builder.ret(builder.add(callee.args[0], callee.args[0])) caller = mod.add_function(Type.function(Type.int(), []), name='foo') builder = Builder.new(caller.append_basic_block('entry')) callinst = builder.call(callee, [Constant.int(Type.int(), 1234)]) builder.ret(callinst) pre_inlining = str(caller) self.assertIn('call', pre_inlining) self.assertTrue(inline_function(callinst)) post_inlining = str(caller) self.assertNotIn('call', post_inlining) self.assertIn('2468', post_inlining)
def test_metadata(self): m = Module.new('a') t = Type.int() metadata = MetaData.get( m, [Constant.int(t, 100), MetaDataString.get(m, 'abcdef'), None]) MetaData.add_named_operand(m, 'foo', metadata) self.assertEqual(MetaData.get_named_operands(m, 'foo'), [metadata]) self.assertEqual(MetaData.get_named_operands(m, 'bar'), []) self.assertEqual(len(metadata.operands), 3) self.assertEqual(metadata.operands[0].z_ext_value, 100) self.assertEqual(metadata.operands[1].string, 'abcdef') self.assertTrue(metadata.operands[2] is None)
def pointer_add(builder, ptr, offset, return_type=None): """ Add an integral *offset* to pointer *ptr*, and return a pointer of *return_type* (or, if omitted, the same type as *ptr*). Note the computation is done in bytes, and ignores the width of the pointed item type. """ intptr_t = Type.int(utils.MACHINE_BITS) intptr = builder.ptrtoint(ptr, intptr_t) if isinstance(offset, int): offset = Constant.int(intptr_t, offset) intptr = builder.add(intptr, offset) return builder.inttoptr(intptr, return_type or ptr.type)
def llvm_type(type, memo=None): if memo is None: memo = {} if hashable(type) and type in memo: return memo[type] ty = type.__class__ if ty == Boolean: result = Type.int(1) elif ty == Integral: result = Type.int(type.bits) elif type == Float32: result = Type.float() elif type == Float64: result = Type.double() elif ty == Array: result = Type.array(llvm_type(type.base, memo), type.count) elif ty == Vector: result = Type.vector(llvm_type(type.base, memo), type.count) elif ty == Struct: result = handle_struct(type, memo) elif ty == Pointer: if type.base.is_void: return Type.pointer(Type.int(8)) result = Type.pointer(llvm_type(type.base, memo)) elif ty == Function: result = Type.function( llvm_type(type.restype, memo), [llvm_type(argtype, memo) for argtype in type.argtypes], var_arg=type.varargs) elif ty == VoidT: result = Type.void() else: raise TypeError("Cannot convert type %s" % (type,)) memo[type] = result return result
def auto_cast(builder, value, target_type): if value.type != target_type: d = Type.double() i32 = Type.int(32) i8 = Type.int(8) i1 = Type.int(1) if target_type == d: if value.type != d: if builder: value = builder.sitofp(value, d) else: value = value.sitofp(d) elif target_type == i32: if value.type == d: return None elif value.type == i1: if builder: value = builder.zext(value, i32) else: value = value.zext(i32) else: if builder: value = builder.sext(value, i32) else: value = value.sext(i32) elif target_type == i8: if value.type == i1: if builder: value = builder.zext(value, i8) else: value = value.zext(i8) else: return None elif target_type == Type.pointer(Type.int(8)): return None return value
def test_arg_attr(self): m = Module.new('oifjda') fnty = Type.function(Type.void(), [Type.int()]) func = m.add_function(fnty, 'foo') bb = func.append_basic_block('') bbdef = func.append_basic_block('') bbsw1 = func.append_basic_block('') bbsw2 = func.append_basic_block('') bldr = Builder.new(bb) swt = bldr.switch(func.args[0], bbdef, n=2) swt.add_case(Constant.int(Type.int(), 0), bbsw1) swt.add_case(Constant.int(Type.int(), 1), bbsw2) bldr.position_at_end(bbsw1) bldr.ret_void() bldr.position_at_end(bbsw2) bldr.ret_void() bldr.position_at_end(bbdef) bldr.ret_void() func.verify()
def test_issue10(self): m = Module.new('a') ti = Type.int() tf = Type.function(ti, [ti, ti]) f = m.add_function(tf, "func1") bb = f.append_basic_block('entry') b = Builder.new(bb) # There are no instructions in bb. Positioning of the # builder at beginning (or end) should succeed (trivially). b.position_at_end(bb) b.position_at_beginning(bb)
def to_native_array(self, typ, ary): # TODO check matching dtype. # currently, mismatching dtype will still work and causes # potential memory corruption voidptr = Type.pointer(Type.int(8)) nativearycls = self.context.make_array(typ) nativeary = nativearycls(self.context, self.builder) aryptr = nativeary._getpointer() ptr = self.builder.bitcast(aryptr, voidptr) errcode = self.numba_array_adaptor(ary, ptr) failed = cgutils.is_not_null(self.builder, errcode) with cgutils.if_unlikely(self.builder, failed): # TODO self.builder.unreachable() return self.builder.load(aryptr)
def make_keywords(self, kws): strings = [] stringtype = Type.pointer(Type.int(8)) for k in kws: strings.append(self.make_const_string(k)) strings.append(Constant.null(stringtype)) kwlist = Constant.array(stringtype, strings) gv = self.module.add_global_variable(kwlist.type, name=".kwlist") gv.global_constant = True gv.initializer = kwlist gv.linkage = lc.LINKAGE_INTERNAL return Constant.bitcast(gv, Type.pointer(stringtype))
def lower_inst(self, inst): if isinstance(inst, ir.Assign): value = self.lower_assign(inst) self.storevar(value, inst.target.name) elif isinstance(inst, ir.SetItem): target = self.loadvar(inst.target.name) index = self.loadvar(inst.index.name) value = self.loadvar(inst.value.name) ok = self.pyapi.object_setitem(target, index, value) negone = lc.Constant.int_signextend(ok.type, -1) pred = self.builder.icmp(lc.ICMP_EQ, ok, negone) with cgutils.if_unlikely(self.builder, pred): self.return_exception_raised() elif isinstance(inst, ir.Return): retval = self.loadvar(inst.value.name) self.incref(retval) self.cleanup() self.context.return_value(self.builder, retval) elif isinstance(inst, ir.Branch): cond = self.loadvar(inst.cond.name) if cond.type == Type.int(1): istrue = cond else: istrue = self.pyapi.object_istrue(cond) zero = lc.Constant.null(istrue.type) pred = self.builder.icmp(lc.ICMP_NE, istrue, zero) tr = self.blkmap[inst.truebr] fl = self.blkmap[inst.falsebr] self.builder.cbranch(pred, tr, fl) elif isinstance(inst, ir.Jump): target = self.blkmap[inst.target] self.builder.branch(target) elif isinstance(inst, ir.Del): obj = self.loadvar(inst.value) self.decref(obj) elif isinstance(inst, ir.Raise): self.pyapi.raise_exception(inst.exception, inst.exception) self.return_exception_raised() else: raise NotImplementedError(type(inst), inst)
def test_nvvm_from_llvm(self): m = Module.new("test_nvvm_from_llvm") fty = Type.function(Type.void(), [Type.int()]) kernel = m.add_function(fty, name='mycudakernel') bldr = Builder.new(kernel.append_basic_block('entry')) bldr.ret_void() print(m) set_cuda_kernel(kernel) fix_data_layout(m) ptx = llvm_to_ptx(str(m)).decode('utf8') print(ptx) self.assertTrue('mycudakernel' in ptx) if is64bit: self.assertTrue('.address_size 64' in ptx) else: self.assertTrue('.address_size 32' in ptx)
def unpack_value(self, builder, ty, ptr): """Unpack data from array storage """ if isinstance(ty, types.Record): vt = self.get_value_type(ty) tmp = cgutils.alloca_once(builder, vt) dataptr = cgutils.inbound_gep(builder, ptr, 0, 0) builder.store(dataptr, cgutils.inbound_gep(builder, tmp, 0, 0)) return builder.load(tmp) assert cgutils.is_pointer(ptr.type) value = builder.load(ptr) if ty == types.boolean: return builder.trunc(value, Type.int(1)) else: return value
def get_function_type(self, fndesc): """ Calling Convention ------------------ Returns: -2 for return none in native function; -1 for failure with python exception set; 0 for success; >0 for user error code. Return value is passed by reference as the first argument. It MUST NOT be used if the function is in nopython mode. Actual arguments starts at the 2nd argument position. Caller is responsible to allocate space for return value. """ argtypes = [self.get_argument_type(aty) for aty in fndesc.argtypes] resptr = self.get_return_type(fndesc.restype) fnty = Type.function(Type.int(), [resptr] + argtypes) return fnty
def __init__(self, builder, api, nargs): self.builder = builder self.api = api self.arg_count = 0 # how many function arguments have been processed self.cleanups = [] # set up switch for error processing of function arguments self.elseblk = cgutils.append_basic_block(self.builder, "arg.ok") with cgutils.goto_block(self.builder, self.elseblk): self.builder.ret(self.api.get_null_object()) self.swtblk = cgutils.append_basic_block(self.builder, ".arg.err") with cgutils.goto_block(self.builder, self.swtblk): self.swt_val = cgutils.alloca_once(self.builder, Type.int(32)) self.swt = self.builder.switch(self.builder.load(self.swt_val), self.elseblk, nargs) self.prev = self.elseblk
def test_bitcode(self): # create a module m = Module.new('module1') m.add_global_variable(Type.int(), 'i') # write it's assembly representation to a file asm = str(m) testasm_bc = os.path.join(self.tmpdir, 'testasm.bc') with open(testasm_bc, "wb") as fout: m.to_bitcode(fout) # read it back into a module with open(testasm_bc, "rb") as fin: m2 = Module.from_bitcode(fin) # The default `m.id` is '<string>'. m2.id = m.id # Copy the name from `m` self.assertEqual(str(m2).strip(), asm.strip())
def code_gen(self): if self.context.parent_context is None: if self.array_name_token.word in self.context.type_table: raise cmexception.RedefineException(self.array_name_token) else: t = Helper.get_array_type(self.typo.word, int(self.length.word)) gv = GlobalVariable.new(g_llvm_module, t, self.array_name_token.word) initials = [i.code_gen() for i in self.initial_value if True] constant_array = ConstantArray.array( Helper.get_type(self.typo.word), initials) gv.initializer = constant_array self.context.type_table[self.array_name_token.word] = t self.context.value_table[self.array_name_token.word] = gv else: if self.array_name_token.word in self.context.type_table: raise cmexception.RedefineException(self.array_name_token) else: t = Helper.get_array_type(self.typo.word, int(self.length.word)) array_address = g_llvm_builder.alloca( t, name=self.array_name_token.word) inx = 0 for i in self.initial_value: value = i.code_gen() if value in g_llvm_module.global_variables: string_value_ptr = g_llvm_builder.gep( value, [ Constant.int(Type.int(32), 0), Constant.int(Type.int(32), 0) ]) var_address = g_llvm_builder.gep( array_address, [ Constant.int(Type.int(32), 0), Constant.int(Type.int(32), inx) ]) g_llvm_builder.store(string_value_ptr, var_address) else: var_address = g_llvm_builder.gep( array_address, [ Constant.int(Type.int(32), 0), Constant.int(Type.int(32), inx) ]) g_llvm_builder.store(value, var_address) inx += 1 self.context.type_table[self.array_name_token.word] = t self.context.value_table[ self.array_name_token.word] = array_address
def get_data_type(self, ty): """ Get a data representation of the type Returns None if it is an opaque pointer """ if (isinstance(ty, types.Dummy) or isinstance(ty, types.Module) or isinstance(ty, types.Function) or isinstance(ty, types.Dispatcher) or isinstance(ty, types.Object) or isinstance(ty, types.Macro)): return Type.pointer(Type.int(8)) elif isinstance(ty, types.CPointer): dty = self.get_data_type(ty.dtype) return Type.pointer(dty) elif isinstance(ty, types.Optional): return self.get_data_type(ty.type) elif isinstance(ty, types.Array): return self.get_struct_type(self.make_array(ty)) elif isinstance(ty, types.UniTuple): dty = self.get_value_type(ty.dtype) return Type.array(dty, ty.count) elif isinstance(ty, types.Tuple): dtys = [self.get_value_type(t) for t in ty] return Type.struct(dtys) elif isinstance(ty, types.UniTupleIter): stty = self.get_struct_type(self.make_unituple_iter(ty)) return stty elif ty in STRUCT_TYPES: return self.get_struct_type(STRUCT_TYPES[ty]) else: return LTYPEMAP[ty]
def _build_test_module(self): mod = Module.new('test') float = Type.double() mysinty = Type.function(float, [float]) mysin = mod.add_function(mysinty, "mysin") block = mysin.append_basic_block("entry") b = Builder.new(block) sqrt = Function.intrinsic(mod, lc.INTR_SQRT, [float]) pow = Function.intrinsic(mod, lc.INTR_POWI, [float]) cos = Function.intrinsic(mod, lc.INTR_COS, [float]) mysin.args[0].name = "x" x = mysin.args[0] one = Constant.real(float, "1") cosx = b.call(cos, [x], "cosx") cos2 = b.call(pow, [cosx, Constant.int(Type.int(), 2)], "cos2") onemc2 = b.fsub(one, cos2, "onemc2") # Should use fsub sin = b.call(sqrt, [onemc2], "sin") b.ret(sin) return mod, mysin
def get_function_type(self, fndesc): """ Get the implemented Function type for the high-level *fndesc*. Some parameters can be added or shuffled around. This is kept in sync with call_function() and get_arguments(). Calling Convention ------------------ Returns: -2 for return none in native function; -1 for failure with python exception set; 0 for success; >0 for user error code. Return value is passed by reference as the first argument. Actual arguments starts at the 2rd argument position. Caller is responsible to allocate space for return value. """ argtypes = [self.get_argument_type(aty) for aty in fndesc.argtypes] resptr = self.get_return_type(fndesc.restype) fnty = Type.function(Type.int(), [resptr] + argtypes) return fnty
def get_constant(self, ty, val): assert not self.is_struct_type(ty) lty = self.get_value_type(ty) if ty == types.none: assert val is None return self.get_dummy_value() elif ty == types.boolean: return Constant.int(Type.int(1), int(val)) elif ty in types.signed_domain: return Constant.int_signextend(lty, val) elif ty in types.real_domain: return Constant.real(lty, val) elif isinstance(ty, types.UniTuple): consts = [self.get_constant(ty.dtype, v) for v in val] return Constant.array(consts[0].type, consts) raise NotImplementedError(ty)
def code_gen(self): if self.constant_token.lexme_type == LexmeType.Integer: return Constant.int( Helper.get_type(self.constant_token.lexme_type), self.constant_token.word) elif self.constant_token.lexme_type == LexmeType.Double: return Constant.real( Helper.get_type(self.constant_token.lexme_type), self.constant_token.word) elif self.constant_token.lexme_type == LexmeType.String: s = self.constant_token.word.strip('"') global constant_string_num global_string = GlobalVariable.new( g_llvm_module, Type.array(Type.int(8), len(s) + 1), ".str%d" % constant_string_num) constant_string_num += 1 global_string.initializer = Constant.stringz(s) return global_string elif self.constant_token.lexme_type == LexmeType.Char: ascii = ord(self.constant_token.word.strip("'")) return Constant.int( Helper.get_type(self.constant_token.lexme_type), ascii)
def test_volatile_another(self): mod = Module.new('mod') functype = Type.function(Type.void(), []) func = mod.add_function(functype, name='foo') bb = func.append_basic_block('entry') bldr = Builder.new(bb) ptr = bldr.alloca(Type.int()) # test load inst val = bldr.load(ptr, volatile=True) self.assertTrue(val.is_volatile, "volatile kwarg does not work") val.set_volatile(False) self.assertFalse(val.is_volatile, "fail to unset volatile") val.set_volatile(True) self.assertTrue(val.is_volatile, "fail to set volatile") # test store inst store_inst = bldr.store(val, ptr, volatile=True) self.assertTrue(store_inst.is_volatile, "volatile kwarg does not work") store_inst.set_volatile(False) self.assertFalse(store_inst.is_volatile, "fail to unset volatile") store_inst.set_volatile(True) self.assertTrue(store_inst.is_volatile, "fail to set volatile")
def test_atomic_ldst(self): mod = Module.new('mod') functype = Type.function(Type.void(), []) func = mod.add_function(functype, name='foo') bb = func.append_basic_block('entry') bldr = Builder.new(bb) ptr = bldr.alloca(Type.int()) for ordering in self.orderings: loaded = bldr.atomic_load(ptr, ordering) self.assert_('load atomic' in str(loaded)) self.assertEqual(ordering, str(loaded).strip().split(' ')[-3].rstrip(',')) self.assert_('align 1' in str(loaded)) stored = bldr.atomic_store(loaded, ptr, ordering) self.assert_('store atomic' in str(stored)) self.assertEqual(ordering, str(stored).strip().split(' ')[-3].rstrip(',')) self.assert_('align 1' in str(stored)) fenced = bldr.fence(ordering) self.assertEqual(['fence', ordering], str(fenced).strip().split(' '))
def get_dummy_type(self): return Type.pointer(Type.int(8))
def print_string(self, builder, text): mod = builder.basic_block.function.module cstring = Type.pointer(Type.int(8)) fnty = Type.function(Type.int(), [cstring]) puts = mod.get_or_insert_function(fnty, "puts") return builder.call(puts, [text])
def cast(self, builder, val, fromty, toty): if fromty == toty or toty == types.Any or isinstance(toty, types.Kind): return val elif ((fromty in types.unsigned_domain and toty in types.signed_domain) or (fromty in types.integer_domain and toty in types.unsigned_domain)): lfrom = self.get_value_type(fromty) lto = self.get_value_type(toty) if lfrom.width <= lto.width: return builder.zext(val, lto) elif lfrom.width > lto.width: return builder.trunc(val, lto) elif fromty in types.signed_domain and toty in types.signed_domain: lfrom = self.get_value_type(fromty) lto = self.get_value_type(toty) if lfrom.width <= lto.width: return builder.sext(val, lto) elif lfrom.width > lto.width: return builder.trunc(val, lto) elif fromty in types.real_domain and toty in types.real_domain: lty = self.get_value_type(toty) if fromty == types.float32 and toty == types.float64: return builder.fpext(val, lty) elif fromty == types.float64 and toty == types.float32: return builder.fptrunc(val, lty) elif fromty in types.real_domain and toty in types.complex_domain: if fromty == types.float32: if toty == types.complex128: real = self.cast(builder, val, fromty, types.float64) else: real = val elif fromty == types.float64: if toty == types.complex64: real = self.cast(builder, val, fromty, types.float32) else: real = val if toty == types.complex128: imag = self.get_constant(types.float64, 0) elif toty == types.complex64: imag = self.get_constant(types.float32, 0) else: raise Exception("unreachable") cmplx = self.make_complex(toty)(self, builder) cmplx.real = real cmplx.imag = imag return cmplx._getvalue() elif fromty in types.integer_domain and toty in types.real_domain: lty = self.get_value_type(toty) if fromty in types.signed_domain: return builder.sitofp(val, lty) else: return builder.uitofp(val, lty) elif toty in types.integer_domain and fromty in types.real_domain: lty = self.get_value_type(toty) if toty in types.signed_domain: return builder.fptosi(val, lty) else: return builder.fptoui(val, lty) elif fromty in types.integer_domain and toty in types.complex_domain: cmplxcls, flty = builtins.get_complex_info(toty) cmpl = cmplxcls(self, builder) cmpl.real = self.cast(builder, val, fromty, flty) cmpl.imag = self.get_constant(flty, 0) return cmpl._getvalue() elif fromty in types.complex_domain and toty in types.complex_domain: srccls, srcty = builtins.get_complex_info(fromty) dstcls, dstty = builtins.get_complex_info(toty) src = srccls(self, builder, value=val) dst = dstcls(self, builder) dst.real = self.cast(builder, src.real, srcty, dstty) dst.imag = self.cast(builder, src.imag, srcty, dstty) return dst._getvalue() elif (isinstance(toty, types.UniTuple) and isinstance(fromty, types.UniTuple) and len(fromty) == len(toty)): olditems = cgutils.unpack_tuple(builder, val, len(fromty)) items = [self.cast(builder, i, fromty.dtype, toty.dtype) for i in olditems] tup = self.get_constant_undef(toty) for idx, val in enumerate(items): tup = builder.insert_value(tup, val, idx) return tup elif toty == types.boolean: return self.is_true(builder, fromty, val) elif fromty == types.boolean: # first promote to int32 asint = builder.zext(val, Type.int()) # then promote to number return self.cast(builder, asint, types.int32, toty) raise NotImplementedError("cast", val, fromty, toty)
def return_user_exc(self, builder, code): assert code > 0 builder.ret(Constant.int(Type.int(), code))