def f_sqrtf(mod): '''libc: square root function''' ret = Type.float() args = [Type.float()] type_ = Type.function(ret, args) return mod.get_or_insert_function(type_, "sqrtf")
def f_powf(mod): '''libc: power function''' ret = Type.float() args = [Type.float(), Type.float()] type_ = Type.function(ret, args) return mod.get_or_insert_function(type_, "powf")
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 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 ee = le.ExecutionEngine.new(mod) 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 round_impl_f32(context, builder, sig, args): module = cgutils.get_module(builder) fnty = Type.function(Type.float(), [Type.float()]) if utils.IS_PY3: fn = module.get_or_insert_function(fnty, name="numba.roundf") else: fn = module.get_or_insert_function(fnty, name="roundf") assert fn.is_declaration return builder.call(fn, args)
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 test_mysin(self): # 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 ee = le.ExecutionEngine.new(mod) 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 test_jit_ctypes(self): # This example demonstrates calling an LLVM defined function using # ctypes. It illustrates the common C pattern of having an output # variable in the argument list to the function. The function also # returns an error code upon exit. # setup llvm types ty_errcode = Type.int() ty_float = Type.float() ty_ptr_float = Type.pointer(Type.float()) ty_func = Type.function(ty_errcode, [ty_float, ty_float, ty_ptr_float]) # setup ctypes types ct_errcode = ctypes.c_int ct_float = ctypes.c_float ct_ptr_float = ctypes.POINTER(ct_float) ct_argtypes = [ct_float, ct_float, ct_ptr_float] # generate the function using LLVM my_module = Module.new('my_module') mult = my_module.add_function(ty_func, "mult") mult.args[0].name = "a" mult.args[1].name = "b" mult.args[2].name = "out" # add nocapture to output arg mult.args[2].add_attribute(llvm.core.ATTR_NO_CAPTURE) mult.does_not_throw = True # add nounwind attribute to function bb = mult.append_basic_block("entry") builder = Builder.new(bb) tmp = builder.fmul(mult.args[0], mult.args[1]) builder.store(tmp, mult.args[2]) builder.ret(llvm.core.Constant.int(ty_errcode, 0)) # print the created module logging.debug(my_module) # compile the function ee = ExecutionEngine.new(my_module) # let ctypes know about the function func_ptr_int = ee.get_pointer_to_function(mult) FUNC_TYPE = ctypes.CFUNCTYPE(ct_errcode, *ct_argtypes) py_mult = FUNC_TYPE(func_ptr_int) # now run the function, calling via ctypes output_value = ct_float(123456.0) errcode = py_mult(2.0, 3.0, ctypes.byref(output_value)) self.assertEqual(errcode, 0, msg='unexpected error') self.assertEqual(output_value.value, 6.0)
def test_jit_ctypes(self): # This example demonstrates calling an LLVM defined function using # ctypes. It illustrates the common C pattern of having an output # variable in the argument list to the function. The function also # returns an error code upon exit. # setup llvm types ty_errcode = Type.int() ty_float = Type.float() ty_ptr_float = Type.pointer(Type.float()) ty_func = Type.function(ty_errcode, [ty_float, ty_float, ty_ptr_float]) # setup ctypes types ct_errcode = ctypes.c_int ct_float = ctypes.c_float ct_ptr_float = ctypes.POINTER(ct_float) ct_argtypes = [ct_float, ct_float, ct_ptr_float] # generate the function using LLVM my_module = Module.new('my_module') mult = my_module.add_function(ty_func, "mult") mult.args[0].name = "a" mult.args[1].name = "b" mult.args[2].name = "out" # add nocapture to output arg mult.args[2].add_attribute(llvm.core.ATTR_NO_CAPTURE) mult.does_not_throw = True # add nounwind attribute to function bb = mult.append_basic_block("entry") builder = Builder.new(bb) tmp = builder.fmul( mult.args[0], mult.args[1] ) builder.store( tmp, mult.args[2] ) builder.ret(llvm.core.Constant.int(ty_errcode, 0)) # print the created module logging.debug(my_module) # compile the function ee = ExecutionEngine.new(my_module) # let ctypes know about the function func_ptr_int = ee.get_pointer_to_function( mult ) FUNC_TYPE = ctypes.CFUNCTYPE(ct_errcode, *ct_argtypes) py_mult = FUNC_TYPE(func_ptr_int) # now run the function, calling via ctypes output_value = ct_float(123456.0) errcode = py_mult( 2.0, 3.0, ctypes.byref(output_value) ) self.assertEqual(errcode, 0, msg='unexpected error') self.assertEqual(output_value.value, 6.0)
def test_struct_extract_value_2d(self): ta = Type.struct([Type.int(32), Type.float()]) tb = Type.struct([ta, Type.float()]) m = Module.new('') f = m.add_function(Type.function(Type.void(), []), "foo") b = Builder.new(f.append_basic_block('')) v = Constant.undef(tb) ins = b.insert_value(v, Constant.real(Type.float(), 1.234), [0, 1]) ext = b.extract_value(ins, [0, 1]) b.ret_void() m.verify() self.assertEqual(str(ext), 'float 0x3FF3BE76C0000000')
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 is_scalar_neg(builder, value): """is _value_ negative?. Assumes _value_ is signed""" nullval = Constant.null(value.type) if value.type in (Type.float(), Type.double()): isneg = builder.fcmp(lc.FCMP_OLT, value, nullval) else: isneg = builder.icmp(lc.ICMP_SLT, value, nullval) return isneg
def test_sin_f32(self): if sys.platform == 'win32' and BITS == 32: # float32 support is known to fail on 32-bit Windows return float = Type.float() mod, func, b = self._build_module(float) intr = Function.intrinsic(mod, lc.INTR_SIN, [float]) b.ret(b.call(intr, func.args)) self._template(mod, func, math.sin)
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 testFAdd_float(self): ty = Type.float() a = Value.const_real(ty, 1.0) b = Value.const_real(ty, 1.0) bldr = Builder.create() c = bldr.fadd(a, b, "tmp1") x, l = c.get_double_value() self.assertTrue(x - 2.0 < 0.01 and 2.0 - x > -0.01) self.assertFalse(l)
def test_inline_rsqrt(self): mod = Module.new(__name__) fnty = Type.function(Type.void(), [Type.pointer(Type.float())]) fn = mod.add_function(fnty, "cu_rsqrt") bldr = Builder.new(fn.append_basic_block("entry")) rsqrt_approx_fnty = Type.function(Type.float(), [Type.float()]) inlineasm = InlineAsm.get(rsqrt_approx_fnty, "rsqrt.approx.f32 $0, $1;", "=f,f", side_effect=True) val = bldr.load(fn.args[0]) res = bldr.call(inlineasm, [val]) bldr.store(res, fn.args[0]) bldr.ret_void() # generate ptx nvvm.fix_data_layout(mod) nvvm.set_cuda_kernel(fn) nvvmir = str(mod) ptx = nvvm.llvm_to_ptx(nvvmir) self.assertTrue("rsqrt.approx.f32" in str(ptx))
def is_scalar_zero(builder, value): """ Return a predicate representing whether *value* is equal to zero. """ assert not is_pointer(value.type) assert not is_struct(value.type) 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_arg_attr(self): m = Module.new('oifjda') vptr = Type.pointer(Type.float()) fnty = Type.function(Type.void(), [vptr] * 5) func = m.add_function(fnty, 'foo') attrs = [lc.ATTR_STRUCT_RET, lc.ATTR_BY_VAL, lc.ATTR_NEST, lc.ATTR_NO_ALIAS, lc.ATTR_NO_CAPTURE] for i, attr in enumerate(attrs): arg = func.args[i] self.assertEqual(i, arg.arg_no) arg.add_attribute(attr) self.assertTrue(attr in func.args[i])
def add4impl(lfunc): '''For LLVMBackend, the implementation receives an empty llvm.core.Function to begin implementation. ''' bb = lfunc.append_basic_block('entry') builder = Builder.new(bb) arg0, arg1 = lfunc.args pvty = Type.pointer(Type.vector(Type.float(), 4)) v0 = builder.load(builder.bitcast(arg0, pvty)) v1 = builder.load(builder.bitcast(arg1, pvty)) vs = builder.fadd(v0, v1) builder.store(vs, builder.bitcast(arg0, pvty)) builder.ret_void()
def is_not_scalar_zero(builder, value): """ Return a predicate representin whether a *value* is not equal to zero. not exactly "not is_scalar_zero" because of nans """ assert not is_pointer(value.type) assert not is_struct(value.type) nullval = Constant.null(value.type) if value.type in (Type.float(), Type.double()): isnull = builder.fcmp(lc.FCMP_UNE, nullval, value) else: isnull = builder.icmp(lc.ICMP_NE, nullval, value) return isnull
def test_inline_rsqrt(self): mod = Module.new(__name__) fnty = Type.function(Type.void(), [Type.pointer(Type.float())]) fn = mod.add_function(fnty, 'cu_rsqrt') bldr = Builder.new(fn.append_basic_block('entry')) rsqrt_approx_fnty = Type.function(Type.float(), [Type.float()]) inlineasm = InlineAsm.get(rsqrt_approx_fnty, 'rsqrt.approx.f32 $0, $1;', '=f,f', side_effect=True) val = bldr.load(fn.args[0]) res = bldr.call(inlineasm, [val]) bldr.store(res, fn.args[0]) bldr.ret_void() # generate ptx nvvm.fix_data_layout(mod) nvvm.set_cuda_kernel(fn) nvvmir = str(mod) ptx = nvvm.llvm_to_ptx(nvvmir) self.assertTrue('rsqrt.approx.f32' in str(ptx))
def llvm_type(type): ty = type.__class__ if ty == Boolean: return Type.int(1) elif ty == Integral: return Type.int(type.bits) elif type == Float32: return Type.float() elif type == Float64: return Type.double() elif ty == Struct: return Type.struct([llvm_type(ftype) for ftype in type.types]) elif ty == Pointer: return Type.pointer(llvm_type(type.base)) elif ty == Function: return Type.function(llvm_type(type.restype), [llvm_type(argtype) for argtype in type.argtypes]) elif ty == Void: return Type.void() else: raise TypeError("Cannot convert type %s" % (type,))
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 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 test_struct_identical(self): ta = Type.struct([Type.int(32), Type.float()], name='ta') tb = Type.struct([Type.int(32), Type.float()]) self.assertTrue(ta.is_layout_identical(tb))
def test_powi_f32(self): float = Type.float() mod, func, b = self._build_module(float) intr = Function.intrinsic(mod, lc.INTR_POWI, [float]) b.ret(b.call(intr, [func.args[0], lc.Constant.int(Type.int(), 2)])) self._template(mod, func, lambda x: x**2)
def atan2_f32_impl(context, builder, sig, args): assert len(args) == 2 mod = cgutils.get_module(builder) fnty = Type.function(Type.float(), [Type.float(), Type.float()]) fn = mod.get_or_insert_function(fnty, name="atan2f") return builder.call(fn, args)
def test_sqrt_f32(self): float = Type.float() mod, func, b = self._build_module(float) intr = Function.intrinsic(mod, lc.INTR_SQRT, [float]) b.ret(b.call(intr, func.args)) self._template(mod, func, math.sqrt)
def f32impl(context, builder, sig, args): [val] = args mod = cgutils.get_module(builder) fnty = Type.function(Type.float(), [Type.float()]) fn = mod.get_or_insert_function(fnty, name=f32extern) return builder.call(fn, (val,))
def value(self, backend): '''Representation when used in a function and as a return value. ''' return Type.pointer(Type.vector(Type.float(), 4))
import ctypes import llvm.core as llcore from llvm.core import Type as lltype from ..ndtypes import ScalarT, PtrT, NoneT void_t = lltype.void() int1_t = lltype.int(1) int8_t = lltype.int(8) int16_t = lltype.int(16) int32_t = lltype.int(32) int64_t = lltype.int(64) float32_t = lltype.float() float64_t = lltype.double() ptr_int8_t = lltype.pointer(int8_t) ptr_int32_t = lltype.pointer(int32_t) ptr_int64_t = lltype.pointer(int64_t) def nbytes(t): if t.kind == llcore.TYPE_FLOAT: return 4 elif t.kind == llcore.TYPE_DOUBLE: return 8 else: return t.width / 8
return _transform(node) def pformat_ast(node, include_attrs=False, **kws): return pprint.pformat(ast2tree(node, include_attrs), **kws) def dump(node): return pformat_ast(node) ### == LLVM Codegen == pointer = Type.pointer int_type = Type.int() float_type = Type.float() double_type = Type.double() bool_type = Type.int(1) void_type = Type.void() void_ptr = pointer(Type.int(8)) def array_type(elt_type): return Type.struct( [ pointer(elt_type), # data int_type, # dimensions pointer(int_type), # shape ], name='ndarray_' + str(elt_type))
import numpy as np import llvm.core as llc from llvm.core import Type as lltype ty_void = lltype.void() ty_int8 = lltype.int(8) ty_int16 = lltype.int(16) ty_int32 = lltype.int(32) ty_int64 = lltype.int(64) ty_float32 = lltype.float() ty_float64 = lltype.double() ty_pyobj = lltype.opaque("PyObj") ty_ptr_pyobj = lltype.pointer(ty_pyobj) ty_ptr_int8 = lltype.pointer(ty_int8) ty_ptr_int16 = lltype.pointer(ty_int16) ty_ptr_int32 = lltype.pointer(ty_int32) ty_ptr_int64 = lltype.pointer(ty_int64) ty_ptr_float32 = lltype.pointer(ty_float32) ty_ptr_float64 = lltype.pointer(ty_float64) python_to_lltype_mappings = { np.int8 : ty_int8, np.int16 : ty_int16, np.int32 : ty_int32,
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
return builder.not_(builder.fcmp(lc.FCMP_OEQ, val, val)) @register @implement(math.isnan, types.int64) def isnan_s64_impl(context, builder, sig, args): return cgutils.false_bit @register @implement(math.isnan, types.uint64) def isnan_u64_impl(context, builder, sig, args): return cgutils.false_bit POS_INF_F32 = lc.Constant.real(Type.float(), float("+inf")) NEG_INF_F32 = lc.Constant.real(Type.float(), float("-inf")) POS_INF_F64 = lc.Constant.real(Type.double(), float("+inf")) NEG_INF_F64 = lc.Constant.real(Type.double(), float("-inf")) @register @implement(math.isinf, types.float32) def isinf_f32_impl(context, builder, sig, args): [val] = args isposinf = builder.fcmp(lc.FCMP_OEQ, val, POS_INF_F32) isneginf = builder.fcmp(lc.FCMP_OEQ, val, NEG_INF_F32) return builder.or_(isposinf, isneginf)
def test_struct_identical(self): m = Module.new("test_struct_identical") ta = Type.struct([Type.int(32), Type.float()], name="ta") tb = Type.struct([Type.int(32), Type.float()]) self.assertTrue(ta.is_layout_identical(tb))
def argument(self, backend): '''Representation when used as an argument. ''' return Type.pointer(Type.float())
# | } Nothing; | # | }; | # | }; | # +----------------------------+ # #------------------------------------------------------------------------ # Definitions #------------------------------------------------------------------------ void = Type.void() char = Type.int(8) short = Type.int(16) int = Type.int(32) int64 = Type.int(64) float = Type.float() double = Type.double() int8 = Type.int(8) int8p = Type.pointer(int8) # fountain of free variables free = lambda: iter(letters) def const(n): return Constant.int(int, n) spine = namedtuple('spine', 'name, params, values') value = namedtuple('value', 'name, params')
LTYPEMAP = { types.pyobject: Type.pointer(Type.int(8)), types.boolean: Type.int(8), types.uint8: Type.int(8), types.uint16: Type.int(16), types.uint32: Type.int(32), types.uint64: Type.int(64), types.int8: Type.int(8), types.int16: Type.int(16), types.int32: Type.int(32), types.int64: Type.int(64), types.float32: Type.float(), types.float64: Type.double(), } STRUCT_TYPES = { types.complex64: builtins.Complex64, types.complex128: builtins.Complex128, types.range_state32_type: builtins.RangeState32, types.range_iter32_type: builtins.RangeIter32, types.range_state64_type: builtins.RangeState64, types.range_iter64_type: builtins.RangeIter64, types.slice3_type: builtins.Slice, } Status = namedtuple("Status", ("code", "ok", "err", "exc", "none"))
def testCreateFloat(self): t1 = Type.float() t2 = Type.float(self.global_context) self.assertEqual(t1, t2) self.assertEqual('float', t1.name)