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 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, (ZeroDivisionError, "division by zero")) return builder.fdiv(fx, fy)
def atan2_f32_impl(context, builder, sig, args): assert len(args) == 2 mod = builder.module fnty = Type.function(Type.float(), [Type.float(), Type.float()]) fn = cgutils.insert_pure_function(builder.module, fnty, name="atan2f") res = builder.call(fn, args) return impl_ret_untracked(context, builder, sig.return_type, res)
def hypot_u64_impl(context, builder, sig, args): [x, y] = args y = builder.sitofp(y, Type.double()) x = builder.sitofp(x, Type.double()) fsig = signature(types.float64, types.float64, types.float64) res = hypot_float_impl(context, builder, fsig, (x, y)) return impl_ret_untracked(context, builder, sig.return_type, res)
def string_as_string_and_size(self, strobj): """ Returns a tuple of ``(ok, buffer, length)``. The ``ok`` is i1 value that is set if ok. The ``buffer`` is a i8* of the output buffer. The ``length`` is a i32/i64 (py_ssize_t) of the length of the buffer. """ p_length = cgutils.alloca_once(self.builder, self.py_ssize_t) if PYVERSION >= (3, 0): fnty = Type.function(self.cstring, [self.pyobj, self.py_ssize_t.as_pointer()]) fname = "PyUnicode_AsUTF8AndSize" fn = self._get_function(fnty, name=fname) buffer = self.builder.call(fn, [strobj, p_length]) ok = self.builder.icmp_unsigned('!=', ir.Constant(buffer.type, None), buffer) else: fnty = Type.function(lc.Type.int(), [self.pyobj, self.cstring.as_pointer(), self.py_ssize_t.as_pointer()]) fname = "PyString_AsStringAndSize" fn = self._get_function(fnty, name=fname) # Allocate space for the output parameters p_buffer = cgutils.alloca_once(self.builder, self.cstring) status = self.builder.call(fn, [strobj, p_buffer, p_length]) negone = ir.Constant(status.type, -1) ok = self.builder.icmp_signed("!=", status, negone) buffer = self.builder.load(p_buffer) return (ok, buffer, self.builder.load(p_length))
def wavebarrier_impl(context, builder, sig, args): assert not args fnty = Type.function(Type.void(), []) fn = builder.module.get_or_insert_function(fnty, name="__hsail_wavebarrier") fn.calling_convention = target.CC_SPIR_FUNC builder.call(fn, []) return _void_value
def call_function_pointer(self, builder, funcptr, signature, args, cconv=None): 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, cconv=cconv)
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 restore_thread(self, thread_state): """ Restore the given thread state by reacquiring the GIL. """ fnty = Type.function(Type.void(), [self.voidptr]) fn = self._get_function(fnty, name="PyEval_RestoreThread") self.builder.call(fn, [thread_state])
def ptx_warp_sync(context, builder, sig, args): fname = 'llvm.nvvm.bar.warp.sync' lmod = builder.module fnty = Type.function(Type.void(), (Type.int(32),)) sync = lmod.get_or_insert_function(fnty, name=fname) builder.call(sync, args) return context.get_dummy_value()
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="numba_adapt_ndarray") 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 numba_buffer_adaptor(self, buf, ptr): fnty = Type.function(Type.void(), [ir.PointerType(self.py_buffer_t), self.voidptr]) fn = self._get_function(fnty, name="numba_adapt_buffer") fn.args[0].add_attribute(lc.ATTR_NO_CAPTURE) fn.args[1].add_attribute(lc.ATTR_NO_CAPTURE) return self.builder.call(fn, (buf, ptr))
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 = builder.module 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 builder.if_else(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)) res = builder.load(pc) return impl_ret_untracked(context, builder, sig.return_type, res)
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 _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 self.builder.if_else(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 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 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: gv = lmod.add_global_variable(text.type, name=name, addrspace=nvvm.ADDRSPACE_CONSTANT) gv.linkage = LINKAGE_INTERNAL gv.global_constant = True gv.initializer = text constcharptrty = Type.pointer(charty, nvvm.ADDRSPACE_CONSTANT) charptr = builder.bitcast(gv, constcharptrty) conv = nvvmutils.insert_addrspace_conv(lmod, charty, nvvm.ADDRSPACE_CONSTANT) return builder.call(conv, [charptr])
def nrt_adapt_ndarray_from_python(self, ary, ptr): assert self.context.enable_nrt fnty = Type.function(Type.int(), [self.pyobj, self.voidptr]) fn = self._get_function(fnty, name="NRT_adapt_ndarray_from_python") 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 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 ptx_threadfence_device(context, builder, sig, args): assert not args fname = "llvm.nvvm.membar.gl" lmod = builder.module fnty = Type.function(Type.void(), ()) sync = lmod.get_or_insert_function(fnty, name=fname) builder.call(sync, ()) return context.get_dummy_value()
def err_set_string(self, exctype, msg): fnty = Type.function(Type.void(), [self.pyobj, self.cstring]) fn = self._get_function(fnty, name="PyErr_SetString") if isinstance(exctype, str): exctype = self.get_c_object(exctype) if isinstance(msg, str): msg = self.context.insert_const_string(self.module, msg) return self.builder.call(fn, (exctype, msg))
def list_setitem(self, seq, idx, val): """ Warning: Steals reference to ``val`` """ fnty = Type.function(Type.int(), [self.pyobj, self.py_ssize_t, self.pyobj]) fn = self._get_function(fnty, name="PyList_SetItem") return self.builder.call(fn, [seq, idx, val])
def core(context, builder, sig, args): assert sig.return_type == types.boolean, nvname fty = context.get_value_type(ty) lmod = builder.module fnty = Type.function(Type.int(), [fty]) fn = lmod.get_or_insert_function(fnty, name=nvname) result = builder.call(fn, args) return context.cast(builder, result, types.int32, types.boolean)
def nrt_adapt_buffer_from_python(self, buf, ptr): assert self.context.enable_nrt fnty = Type.function(Type.void(), [Type.pointer(self.py_buffer_t), self.voidptr]) fn = self._get_function(fnty, name="NRT_adapt_buffer_from_python") fn.args[0].add_attribute(lc.ATTR_NO_CAPTURE) fn.args[1].add_attribute(lc.ATTR_NO_CAPTURE) return self.builder.call(fn, (buf, ptr))
def ptx_syncthreads(context, builder, sig, args): assert not args fname = 'llvm.nvvm.barrier0' lmod = cgutils.get_module(builder) fnty = Type.function(Type.void(), ()) sync = lmod.get_or_insert_function(fnty, name=fname) builder.call(sync, ()) return context.get_dummy_value()
def atan2_f64_impl(context, builder, sig, args): assert len(args) == 2 mod = cgutils.get_module(builder) fnty = Type.function(Type.double(), [Type.double(), Type.double()]) # Workaround atan2() issues under Windows fname = "atan2_fixed" if sys.platform == "win32" else "atan2" fn = mod.get_or_insert_function(fnty, name=fname) return builder.call(fn, args)
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 implementer(context, builder, sig, args): [val] = args input_type = sig.args[0] if input_type.signed: fpval = builder.sitofp(val, Type.double()) else: fpval = builder.uitofp(val, Type.double()) sig = signature(types.float64, types.float64) return wrapped_impl(context, builder, sig, [fpval])
def printf(self, builder, format_string, *args): mod = builder.module if isinstance(format_string, str): cstr = self.insert_const_string(mod, format_string) else: cstr = format_string fnty = Type.function(Type.int(), (GENERIC_POINTER,), var_arg=True) fn = mod.get_or_insert_function(fnty, "printf") return builder.call(fn, (cstr,) + tuple(args))
def atan2_f64_impl(context, builder, sig, args): assert len(args) == 2 mod = builder.module fnty = Type.function(Type.double(), [Type.double(), Type.double()]) # Workaround atan2() issues under Windows fname = "atan2_fixed" if sys.platform == "win32" else "atan2" fn = cgutils.insert_pure_function(builder.module, fnty, name=fname) res = builder.call(fn, args) return impl_ret_untracked(context, builder, sig.return_type, res)
def set_add(self, set, value): fnty = Type.function(Type.int(), [self.pyobj, self.pyobj]) fn = self._get_function(fnty, name="PySet_Add") return self.builder.call(fn, [set, value])
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 print_string(self, builder, text): mod = builder.module cstring = GENERIC_POINTER fnty = Type.function(Type.int(), [cstring]) puts = cgutils.get_or_insert_function(mod, fnty, "puts") return builder.call(puts, [text])
def complex_imag_as_double(self, cobj): fnty = Type.function(Type.double(), [self.pyobj]) fn = self._get_function(fnty, name="PyComplex_ImagAsDouble") return self.builder.call(fn, [cobj])
def get_record_member(builder, record, offset, typ): pval = gep_inbounds(builder, record, 0, offset) assert not is_pointer(pval.type.pointee) return builder.bitcast(pval, Type.pointer(typ))
def tuple_size(self, tup): fnty = Type.function(self.py_ssize_t, [self.pyobj]) fn = self._get_function(fnty, name="PyTuple_Size") return self.builder.call(fn, [tup])
def sequence_tuple(self, obj): fnty = Type.function(self.pyobj, [self.pyobj]) fn = self._get_function(fnty, name="PySequence_Tuple") return self.builder.call(fn, [obj])
def object_getitem(self, obj, key): fnty = Type.function(self.pyobj, [self.pyobj, self.pyobj]) fn = self._get_function(fnty, name="PyObject_GetItem") return self.builder.call(fn, (obj, key))
def object_setattr(self, obj, attr, val): fnty = Type.function(Type.int(), [self.pyobj, self.pyobj, self.pyobj]) fn = self._get_function(fnty, name="PyObject_SetAttr") return self.builder.call(fn, [obj, attr, val])
def object_str(self, obj): fnty = Type.function(self.pyobj, [self.pyobj]) fn = self._get_function(fnty, name="PyObject_Str") return self.builder.call(fn, [obj])
def object_setitem(self, obj, key, val): fnty = Type.function(Type.int(), [self.pyobj, self.pyobj, self.pyobj]) fn = self._get_function(fnty, name="PyObject_SetItem") return self.builder.call(fn, (obj, key, val))
def sys_write_stdout(self, fmt, *args): fnty = Type.function(Type.void(), [self.cstring], var_arg=True) fn = self._get_function(fnty, name="PySys_WriteStdout") return self.builder.call(fn, (fmt, ) + args)
""" from __future__ import print_function, division, absolute_import import collections from contextlib import contextmanager import functools import re from llvmlite import ir from llvmlite.llvmpy.core import Constant, Type import llvmlite.llvmpy.core as lc from . import utils 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) intp_t = Type.int(utils.MACHINE_BITS) def as_bool_byte(builder, value): return builder.zext(value, Type.int(8)) def as_bool_bit(builder, value): return builder.icmp(lc.ICMP_NE, value, Constant.null(value.type))
def as_bool_byte(builder, value): return builder.zext(value, Type.int(8))
def set_new(self, iterable=None): if iterable is None: iterable = self.get_null_object() fnty = Type.function(self.pyobj, [self.pyobj]) fn = self._get_function(fnty, name="PySet_New") return self.builder.call(fn, [iterable])
def object_setattr_string(self, obj, attr, val): cstr = self.context.insert_const_string(self.module, attr) fnty = Type.function(Type.int(), [self.pyobj, self.cstring, self.pyobj]) fn = self._get_function(fnty, name="PyObject_SetAttrString") return self.builder.call(fn, [obj, cstr, val])
def tuple_new(self, count): fnty = Type.function(self.pyobj, [Type.int()]) fn = self._get_function(fnty, name='PyTuple_New') return self.builder.call( fn, [self.context.get_constant(types.int32, count)])
def object_getattr(self, obj, attr): fnty = Type.function(self.pyobj, [self.pyobj, self.pyobj]) fn = self._get_function(fnty, name="PyObject_GetAttr") return self.builder.call(fn, [obj, attr])
def list_new(self, szval): fnty = Type.function(self.pyobj, [self.py_ssize_t]) fn = self._get_function(fnty, name="PyList_New") return self.builder.call(fn, [szval])
def complex_from_doubles(self, realval, imagval): fnty = Type.function(self.pyobj, [Type.double(), Type.double()]) fn = self._get_function(fnty, name="PyComplex_FromDoubles") return self.builder.call(fn, [realval, imagval])
def sequence_getslice(self, obj, start, stop): fnty = Type.function(self.pyobj, [self.pyobj, self.py_ssize_t, self.py_ssize_t]) fn = self._get_function(fnty, name="PySequence_GetSlice") return self.builder.call(fn, (obj, start, stop))
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 iter_next(self, iterobj): fnty = Type.function(self.pyobj, [self.pyobj]) fn = self._get_function(fnty, name="PyIter_Next") return self.builder.call(fn, [iterobj])
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 object_not(self, obj): fnty = Type.function(Type.int(), [self.pyobj]) fn = self._get_function(fnty, name="PyObject_Not") return self.builder.call(fn, [obj])
def call_function_objargs(self, callee, objargs): fnty = Type.function(self.pyobj, [self.pyobj], var_arg=True) fn = self._get_function(fnty, name="PyObject_CallFunctionObjArgs") args = [callee] + list(objargs) args.append(self.context.get_constant_null(types.pyobject)) return self.builder.call(fn, args)
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 import_module_noblock(self, modname): fnty = Type.function(self.pyobj, [self.cstring]) fn = self._get_function(fnty, name="PyImport_ImportModuleNoBlock") return self.builder.call(fn, [modname])
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, ))
from llvmlite import ir as llvmir import llvmlite.llvmpy.core as lc from llvmlite.llvmpy.core import Type, Constant, LLVMException import llvmlite.binding as ll from numba.core import types, utils, typing, datamodel, debuginfo, funcdesc, config, cgutils, imputils from numba.core import event, errors, targetconfig from numba import _dynfunc, _helperlib from numba.core.compiler_lock import global_compiler_lock from numba.core.pythonapi import PythonAPI from numba.core.imputils import (user_function, user_generator, builtin_registry, impl_ret_borrowed, RegistryLoader) from numba.cpython import builtins GENERIC_POINTER = Type.pointer(Type.int(8)) PYOBJECT = GENERIC_POINTER void_ptr = GENERIC_POINTER class OverloadSelector(object): """ An object matching an actual signature against a registry of formal signatures and choosing the best candidate, if any. In the current implementation: - a "signature" is a tuple of type classes or type instances - the "best candidate" is the most specific match """ def __init__(self):