def testCreateVectorType(self): ty = Type.int8() a = Type.vector(ty, 2) self.assertEqual(2, a.vector_size()) t = a.element_type() self.assertEqual(ty.name, t.name)
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 testCreateArrayType(self): ty = Type.int8() a = Type.array(ty, 2) self.assertEqual(2, a.array_length()) t = a.element_type() self.assertEqual(ty.name, t.name)
def test_issue100(self): m = Module.new('a') pm = FunctionPassManager.new(m) ee = ExecutionEngine.new(m) pm.add(ee.target_data) ti = Type.int() tf = Type.function(ti, []) f = m.add_function(tf, "func1") bb = f.append_basic_block('entry') b = Builder.new(bb) b.ret(Constant.int(ti, 0)) f.verify() pm.run(f) assert ee.run_function(f, []).as_int() == 0
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 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_exit(mod): '''libc: cause normal process termination''' ret = Type.void() args = [Type.int(32)] type_ = Type.function(ret, args) return mod.get_or_insert_function(type_, "exit")
def f_fabs(mod): '''libc: absolute value of floating-point number''' ret = Type.double() args = [Type.double()] type_ = Type.function(ret, args) return mod.get_or_insert_function(type_, "fabs")
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 call_function_pointer(self, builder, funcptr, signature, args): retty = self.get_value_type(signature.return_type) fnty = Type.function(retty, [a.type for a in args]) fnptrty = Type.pointer(fnty) addr = self.get_constant(types.intp, funcptr) ptr = builder.inttoptr(addr, fnptrty) return builder.call(ptr, args)
def f_roundf(mod): '''libc: round to nearest integer, away from zero''' ret = Type.float() args = [Type.float()] type_ = Type.function(ret, args) return mod.get_or_insert_function(type_, "roundf")
def insert_string_const_addrspace(self, builder, string): """ Insert a constant string in the constant addresspace and return a generic i8 pointer to the data. This function attempts to deduplicate. """ lmod = builder.basic_block.function.module text = Constant.stringz(string) name = "__conststring__.%s" % string charty = Type.int(8) for gv in lmod.global_variables: if gv.name == name and gv.type.pointee == text.type: break else: gl = lmod.add_global_variable(text.type, name=name, addrspace=nvvm.ADDRSPACE_CONSTANT) gl.linkage = LINKAGE_INTERNAL gl.global_constant = True gl.initializer = text constcharptrty = Type.pointer(charty, nvvm.ADDRSPACE_CONSTANT) charptr = builder.bitcast(gl, constcharptrty) conv = nvvmutils.insert_addrspace_conv(lmod, charty, nvvm.ADDRSPACE_CONSTANT) return builder.call(conv, [charptr])
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 args_to_kernel_data_struct(kinds, argtypes): # Build up the kernel data structure. Currently, this means # adding a shape field for each array argument. First comes # the kernel data prefix with a spot for the 'owner' reference added. input_field_indices = [] kernel_data_fields = [Type.struct([int8_p_type]*3)] kernel_data_ctypes_fields = [('base', JITCKernelData)] for i, (kind, a) in enumerate(izip(kinds, argtypes)): if isinstance(kind, tuple): if kind[0] != lla.C_CONTIGUOUS: raise ValueError('only support C contiguous array presently') input_field_indices.append(len(kernel_data_fields)) kernel_data_fields.append(Type.array( intp_type, len(bek.dshapes[i])-1)) kernel_data_ctypes_fields.append(('operand_%d' % i, c_ssize_t * (len(bek.dshapes[i])-1))) elif kind in [lla.SCALAR, lla.POINTER]: input_field_indices.append(None) else: raise TypeError(("unbound_single_ckernel codegen doesn't " + "support the parameter kind %r yet") % (k,)) # Make an LLVM and ctypes type for the extra data pointer. kernel_data_llvmtype = Type.struct(kernel_data_fields) class kernel_data_ctypestype(ctypes.Structure): _fields_ = kernel_data_ctypes_fields return (kernel_data_llvmtype, kernel_data_ctypestype)
def complex128_power_impl(context, builder, sig, args): [ca, cb] = args a = Complex128(context, builder, value=ca) b = Complex128(context, builder, value=cb) c = Complex128(context, builder) module = cgutils.get_module(builder) pa = a._getpointer() pb = b._getpointer() pc = c._getpointer() # Optimize for square because cpow looses a lot of precsiion TWO = context.get_constant(types.float64, 2) ZERO = context.get_constant(types.float64, 0) b_real_is_two = builder.fcmp(lc.FCMP_OEQ, b.real, TWO) b_imag_is_zero = builder.fcmp(lc.FCMP_OEQ, b.imag, ZERO) b_is_two = builder.and_(b_real_is_two, b_imag_is_zero) with cgutils.ifelse(builder, b_is_two) as (then, otherwise): with then: # Lower as multiplication res = complex_mul_impl(context, builder, sig, (ca, ca)) cres = Complex128(context, builder, value=res) c.real = cres.real c.imag = cres.imag with otherwise: # Lower with call to external function fnty = Type.function(Type.void(), [pa.type] * 3) cpow = module.get_or_insert_function(fnty, name="numba.math.cpow") builder.call(cpow, (pa, pb, pc)) return builder.load(pc)
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 is_scalar_zero(builder, value): nullval = Constant.null(value.type) if value.type in (Type.float(), Type.double()): isnull = builder.fcmp(lc.FCMP_OEQ, nullval, value) else: isnull = builder.icmp(lc.ICMP_EQ, nullval, value) return isnull
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_uses(self): m = Module.new("a") t = Type.int() ft = Type.function(t, [t, t, t]) f = m.add_function(ft, "func") b = f.append_basic_block("entry") bld = Builder.new(b) tmp1 = bld.add(Constant.int(t, 100), f.args[0], "tmp1") tmp2 = bld.add(tmp1, f.args[1], "tmp2") tmp3 = bld.add(tmp1, f.args[2], "tmp3") bld.ret(tmp3) # Testing use count self.assertEqual(f.args[0].use_count, 1) self.assertEqual(f.args[1].use_count, 1) self.assertEqual(f.args[2].use_count, 1) self.assertEqual(tmp1.use_count, 2) self.assertEqual(tmp2.use_count, 0) self.assertEqual(tmp3.use_count, 1) # Testing uses self.assert_(f.args[0].uses[0] is tmp1) self.assertEqual(len(f.args[0].uses), 1) self.assert_(f.args[1].uses[0] is tmp2) self.assertEqual(len(f.args[1].uses), 1) self.assert_(f.args[2].uses[0] is tmp3) self.assertEqual(len(f.args[2].uses), 1) self.assertEqual(len(tmp1.uses), 2) self.assertEqual(len(tmp2.uses), 0) self.assertEqual(len(tmp3.uses), 1)
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 __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 object_dump(self, obj): """ Dump a Python object on C stderr. For debugging purposes. """ fnty = Type.function(Type.void(), [self.pyobj]) fn = self._get_function(fnty, name="_PyObject_Dump") return self.builder.call(fn, (obj,))
def testAppendBasicBlock(self): mod = Module.CreateWithName('module') ty = Type.int8(context=mod.context) ft = Type.function(ty, [ty], False) f = mod.add_function('timestwo', ft) bb = f.append_basic_block('body') self.assertEqual('body', bb.name)
def _long_from_native_int(self, ival, func_name, native_int_type, signed): fnty = Type.function(self.pyobj, [native_int_type]) fn = self._get_function(fnty, name=func_name) resptr = cgutils.alloca_once(self.builder, self.pyobj) if PYVERSION < (3, 0): # Under Python 2, we try to return a PyInt object whenever # the given number fits in a C long. pyint_fnty = Type.function(self.pyobj, [self.long]) pyint_fn = self._get_function(pyint_fnty, name="PyInt_FromLong") long_max = Constant.int(native_int_type, _helperlib.long_max) if signed: long_min = Constant.int(native_int_type, _helperlib.long_min) use_pyint = self.builder.and_( self.builder.icmp(lc.ICMP_SGE, ival, long_min), self.builder.icmp(lc.ICMP_SLE, ival, long_max), ) else: use_pyint = self.builder.icmp(lc.ICMP_ULE, ival, long_max) with cgutils.ifelse(self.builder, use_pyint) as (then, otherwise): with then: downcast_ival = self.builder.trunc(ival, self.long) res = self.builder.call(pyint_fn, [downcast_ival]) self.builder.store(res, resptr) with otherwise: res = self.builder.call(fn, [ival]) self.builder.store(res, resptr) else: fn = self._get_function(fnty, name=func_name) self.builder.store(self.builder.call(fn, [ival]), resptr) return self.builder.load(resptr)
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 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 code_gen(self): condition = self.condition.code_gen() condition_bool = g_llvm_builder.fcmp(FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcmd') function = g_llvm_builder.basic_block.function then_block = function.append_basic_block('then') else_block = function.append_basic_block('else') merge_block = function.append_basic_block('ifcond') g_llvm_builder.cbranch(condition_bool, then_block, else_block) g_llvm_builder.position_at_end(then_block) then_value = self.then_branch.code_gen() g_llvm_builder.branch(merge_block) then_block = g_llvm_builder.basic_block g_llvm_builder.position_at_end(else_block) else_value = self.else_branch.code_gen() g_llvm_builder.branch(merge_block) else_block = g_llvm_builder.basic_block g_llvm_builder.position_at_end(merge_block) phi = g_llvm_builder.phi(Type.double(), 'iftmp') phi.add_incoming(then_value, then_block) phi.add_incoming(else_value, else_block) return phi
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 CodeGen(self): # Make the function type, eg. double(double,double). funct_type = Type.function(Type.double(), [Type.double()] * len(self.args), False) function = Function.new(g_llvm_module, funct_type, self.name) # If the name conflicted, there was already something with the same name. # If it has a body, don't allow redefinition or reextern. if function.name != self.name: function.delete() function = g_llvm_module.get_function_named(self.name) # If the function already has a body, reject this. if not function.is_declaration: raise RuntimeError('Redefinition of function.') # If the function took a different number of args, reject. if len(function.args) != len(self.args): raise RuntimeError('Redeclaration of a function with different number of args.') # Set names for all arguments and add them to the variables symbol table. for arg, arg_name in zip(function.args, self.args): arg.name = arg_name return function
def number_float(self, val): fnty = Type.function(self.pyobj, [self.pyobj]) fn = self._get_function(fnty, name="PyNumber_Float") return self.builder.call(fn, [val])
def number_positive(self, obj): fnty = Type.function(self.pyobj, [self.pyobj]) fn = self._get_function(fnty, name="PyNumber_Positive") return self.builder.call(fn, (obj, ))
def number_power(self, lhs, rhs, inplace=False): fnty = Type.function(self.pyobj, [self.pyobj] * 3) fname = "PyNumber_InPlacePower" if inplace else "PyNumber_Power" fn = self._get_function(fnty, fname) return self.builder.call(fn, [lhs, rhs, self.borrow_none()])
def _get_number_operator(self, name): fnty = Type.function(self.pyobj, [self.pyobj, self.pyobj]) fn = self._get_function(fnty, name="PyNumber_%s" % name) return fn
def long_as_longlong(self, numobj): fnty = Type.function(self.ulonglong, [self.pyobj]) fn = self._get_function(fnty, name="PyLong_AsLongLong") return self.builder.call(fn, [numobj])
import llvm.ee as le import llvm.core as lc import llvm.passes as lp from llvm import LLVMException from llvm.core import Module, Builder, Function, Type, Constant, GlobalVariable from collections import defaultdict #------------------------------------------------------------------------ # LLVM Types #------------------------------------------------------------------------ ptrsize = ctypes.sizeof(ctypes.c_void_p) int_type = Type.int() float_type = Type.double() bool_type = Type.int(1) void_type = Type.void() char_type = Type.int(8) pointer = Type.pointer any_type = pointer(Type.int(ptrsize)) string_type = pointer(char_type) # { i32*, i32, i32* } array_type = lambda elt_type: Type.struct( [ pointer(elt_type), # data | (<type>)* int_type, # dimensions | int
def bool_from_long(self, ival): fnty = Type.function(self.pyobj, [self.long]) fn = self._get_function(fnty, name="PyBool_FromLong") return self.builder.call(fn, [ival])
def dict_setitem(self, dictobj, nameobj, valobj): fnty = Type.function(Type.int(), (self.pyobj, self.pyobj, self.pyobj)) fn = self._get_function(fnty, name="PyDict_SetItem") return self.builder.call(fn, (dictobj, nameobj, valobj))
def err_set_object(self, exctype, excval): fnty = Type.function(Type.void(), [self.pyobj, self.pyobj]) fn = self._get_function(fnty, name="PyErr_SetObject") return self.builder.call(fn, (exctype, excval))
def err_occurred(self): fnty = Type.function(self.pyobj, ()) fn = self._get_function(fnty, name="PyErr_Occurred") return self.builder.call(fn, ())
def op_DEF_FOREIGN(self, name, retty, argtys): largtys = map(arg_typemap, argtys) lretty = arg_typemap(retty) func_type = Type.function(lretty, largtys, False) self.globals[name] = Function.new(self.module, func_type, name)
def number_invert(self, obj): fnty = Type.function(self.pyobj, [self.pyobj]) fn = self._get_function(fnty, name="PyNumber_Invert") return self.builder.call(fn, (obj, ))
def float_as_double(self, fobj): fnty = Type.function(self.double, [self.pyobj]) fn = self._get_function(fnty, name="PyFloat_AsDouble") return self.builder.call(fn, [fobj])
def test_mysin(self): if sys.platform == 'win32' and BITS == 32: # float32 support is known to fail on 32-bit Windows return # mysin(x) = sqrt(1.0 - pow(cos(x), 2)) mod = Module.new('test') float = Type.float() 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) #logging.debug(mod) # ; ModuleID = 'test' # # define void @showme() { # entry: # call i32 @llvm.bswap.i32( i32 42 ) ; <i32>:0 [#uses # } # # declare i32 @llvm.bswap.i32(i32) nounwind readnone # # define float @mysin(float %x) { # entry: # %cosx = call float @llvm.cos.f32( float %x ) ; <float # %cos2 = call float @llvm.powi.f32( float %cosx, i32 2 ) # %onemc2 = sub float 1.000000e+00, %cos2 ; <float> [#uses # %sin = call float @llvm.sqrt.f32( float %onemc2 ) # ret float %sin # } # # declare float @llvm.sqrt.f32(float) nounwind readnone # # declare float @llvm.powi.f32(float, i32) nounwind readnone # # declare float @llvm.cos.f32(float) nounwind readnone # let's run the function from llvm.workaround.avx_support import detect_avx_support if not detect_avx_support(): ee = le.EngineBuilder.new(mod).mattrs("-avx").create() else: ee = le.EngineBuilder.new(mod).create() arg = le.GenericValue.real(Type.float(), 1.234) retval = ee.run_function(mysin, [arg]) golden = math.sin(1.234) answer = retval.as_real(Type.float()) self.assertTrue(abs(answer - golden) / golden < 1e-5)
def create_ckernel_interface(bek, strided): """Create a function wrapper with a CKernel interface according to `strided`. Parameters ---------- bek : BlazeElementKernel The blaze kernel to compile into an unbound single ckernel. strided : bool If true, returns an ExprStridedOperation, otherwise an ExprSingleOperation. """ # TODO: Decouple this from BlazeElementKernel inarg_count = len(bek.kinds)-1 module = bek.module.clone() if strided: ck_func_name = bek.func.name +"_strided_ckernel" ck_func = Function.new(module, strided_ckernel_func_type, name=ck_func_name) else: ck_func_name = bek.func.name +"_single_ckernel" ck_func = Function.new(module, single_ckernel_func_type, name=ck_func_name) entry_block = ck_func.append_basic_block('entry') builder = lc.Builder.new(entry_block) if strided: dst_ptr_arg, dst_stride_arg, \ src_ptr_arr_arg, src_stride_arr_arg, \ count_arg, extra_ptr_arg = ck_func.args dst_stride_arg.name = 'dst_stride' src_stride_arr_arg.name = 'src_strides' count_arg.name = 'count' else: dst_ptr_arg, src_ptr_arr_arg, extra_ptr_arg = ck_func.args dst_ptr_arg.name = 'dst_ptr' src_ptr_arr_arg.name = 'src_ptrs' extra_ptr_arg.name = 'extra_ptr' if strided: # Allocate an array of pointer counters for the # strided loop src_ptr_arr_tmp = builder.alloca_array(int8_p_type, lc.Constant.int(int32_type, inarg_count), 'src_ptr_arr') # Copy the pointers for i in range(inarg_count): builder.store(builder.load(builder.gep(src_ptr_arr_arg, (lc.Constant.int(int32_type, i),))), builder.gep(src_ptr_arr_tmp, (lc.Constant.int(int32_type, i),))) # Get all the src strides src_stride_vals = [builder.load(builder.gep(src_stride_arr_arg, (lc.Constant.int(int32_type, i),))) for i in range(inarg_count)] # Replace src_ptr_arr_arg with this local variable src_ptr_arr_arg = src_ptr_arr_tmp # Initialize some more basic blocks for the strided loop looptest_block = ck_func.append_basic_block('looptest') loopbody_block = ck_func.append_basic_block('loopbody') end_block = ck_func.append_basic_block('finish') # Finish the entry block by branching # to the looptest block builder.branch(looptest_block) # The looptest block continues the loop while counter != 0 builder.position_at_end(looptest_block) counter_phi = builder.phi(count_arg.type) counter_phi.add_incoming(count_arg, entry_block) dst_ptr_phi = builder.phi(dst_ptr_arg.type) dst_ptr_phi.add_incoming(dst_ptr_arg, entry_block) dst_ptr_arg = dst_ptr_phi kzero = lc.Constant.int(count_arg.type, 0) pred = builder.icmp(lc.ICMP_NE, counter_phi, kzero) builder.cbranch(pred, loopbody_block, end_block) # The loopbody block decrements the counter, and executes # one kernel iteration builder.position_at_end(loopbody_block) kone = lc.Constant.int(counter_phi.type, 1) counter_dec = builder.sub(counter_phi, kone) counter_phi.add_incoming(counter_dec, loopbody_block) # Convert the src pointer args to the # appropriate kinds for the llvm call args = build_llvm_src_ptrs(builder, src_ptr_arr_arg, bek.dshapes, bek.kinds[:-1], bek.argtypes) # Call the function and store in the dst kind = bek.kinds[-1] func = module.get_function_named(bek.func.name) if kind == lla.SCALAR: dst_ptr = builder.bitcast(dst_ptr_arg, Type.pointer(bek.return_type)) dst_val = builder.call(func, args) builder.store(dst_val, dst_ptr) else: dst_ptr = build_llvm_arg_ptr(builder, dst_ptr_arg, bek.dshapes[-1], kind, bek.argtypes[-1]) builder.call(func, args + [dst_ptr]) if strided: # Finish the loopbody block by incrementing all the pointers # and branching to the looptest block dst_ptr_inc = builder.gep(dst_ptr_arg, (dst_stride_arg,)) dst_ptr_phi.add_incoming(dst_ptr_inc, loopbody_block) # Increment the src pointers for i in range(inarg_count): src_ptr_val = builder.load(builder.gep(src_ptr_arr_tmp, (lc.Constant.int(int32_type, i),))) src_ptr_inc = builder.gep(src_ptr_val, (src_stride_vals[i],)) builder.store(src_ptr_inc, builder.gep(src_ptr_arr_tmp, (lc.Constant.int(int32_type, i),))) builder.branch(looptest_block) # The end block just returns builder.position_at_end(end_block) builder.ret_void() #print("Function before optimization passes:") #print(ck_func) #module.verify() return module, ck_func
def int_utruediv_impl(context, builder, sig, args): x, y = args fx = builder.uitofp(x, Type.double()) fy = builder.uitofp(y, Type.double()) cgutils.guard_zero(context, builder, y) return builder.fdiv(fx, fy)
from __future__ import print_function, absolute_import import sys from llvm.core import Type, Function, Builder, Module import llvm.core as lc import llvm.ee as le import multiprocessing from ctypes import * INTRINSICS = {} CTYPES_MAP = { Type.int(): c_int32, Type.int(64): c_int64, Type.float(): c_float, Type.double(): c_double, } def register(name, retty, *args): def wrap(fn): INTRINSICS[name] = (retty, args), fn return fn return wrap def intr_impl(intrcode, *types): def impl(module, builder, args): intr = Function.intrinsic(module, intrcode, types) r = builder.call(intr, args) return r return impl
import sys import ctypes import struct as struct_ from llvm.core import Type _trace_refs_ = hasattr(sys, 'getobjects') _plat_bits = struct_.calcsize('@P') * 8 _int8 = Type.int(8) _int32 = Type.int(32) _void_star = Type.pointer(_int8) _int8_star = _void_star _pyobject_head_struct_p = _void_star _sizeof_py_ssize_t = ctypes.sizeof(getattr(ctypes, 'c_size_t')) _llvm_py_ssize_t = Type.int(_sizeof_py_ssize_t * 8)
def number_long(self, numobj): fnty = Type.function(self.pyobj, [self.pyobj]) fn = self._get_function(fnty, name="PyNumber_Long") return self.builder.call(fn, [numobj])
def create_module(self): # create a module m = Module.new('module1') m.add_global_variable(Type.int(), 'i') return m
def as_bool_byte(builder, value): return builder.zext(value, Type.int(8))
def value(self, backend): '''Representation when used in a function and as a return value. ''' return Type.pointer(Type.vector(Type.float(), 4))
from __future__ import print_function, division, absolute_import from contextlib import contextmanager import functools from llvm.core import Constant, Type import llvm.core as lc from . import errcode true_bit = Constant.int(Type.int(1), 1) false_bit = Constant.int(Type.int(1), 0) true_byte = Constant.int(Type.int(8), 1) false_byte = Constant.int(Type.int(8), 0) def _block_terminator(bb): # XXX: replace this with bb.terminator when llvmpy 0.12.6 (or 0.13) is # released. inst = bb._ptr.getTerminator() return lc._make_value(inst) if inst is not None else None def as_bool_byte(builder, value): return builder.zext(value, Type.int(8)) class Structure(object): def __init__(self, context, builder, value=None, ref=None): self._type = context.get_struct_type(self) self._builder = builder if ref is None: self._value = alloca_once(builder, self._type) if value is not None:
def get_record_member(builder, record, offset, typ): pdata = get_record_data(builder, record) pval = inbound_gep(builder, pdata, 0, offset) assert not is_pointer(pval.type.pointee) return builder.bitcast(pval, Type.pointer(typ))
def dict_setitem_string(self, dictobj, name, valobj): fnty = Type.function(Type.int(), (self.pyobj, self.cstring, self.pyobj)) fn = self._get_function(fnty, name="PyDict_SetItemString") cstr = self.context.insert_const_string(self.module, name) return self.builder.call(fn, (dictobj, cstr, valobj))
def argument(self, backend): '''Representation when used as an argument. ''' return Type.pointer(Type.float())
def float_from_double(self, fval): fnty = Type.function(self.pyobj, [self.double]) fn = self._get_function(fnty, name="PyFloat_FromDouble") return self.builder.call(fn, [fval])
def number_as_ssize_t(self, numobj): fnty = Type.function(self.py_ssize_t, [self.pyobj]) fn = self._get_function(fnty, name="PyNumber_AsSsize_t") return self.builder.call(fn, [numobj])
def err_clear(self): fnty = Type.function(Type.void(), ()) fn = self._get_function(fnty, name="PyErr_Clear") return self.builder.call(fn, ())
def vector(ty, ct): return Type.vector(ty, 4)