Exemple #1
0
    def codegen(context, builder, signature, args):
        vis_type, out_shape_type = signature.args
        return_type = signature.return_type
        vis, out_shape = args

        # Create the outer tuple
        llvm_outer_tuple_type = context.get_value_type(return_type)
        outer_tuple = cgutils.get_null_value(llvm_outer_tuple_type)

        def gen_array_factory(numba_dtype):
            """
            Create a funtion that creates an array.
            Bind the numpy dtype because I don't know how to create
            the numba version
            """
            np_dtype = numpy_support.as_dtype(numba_dtype)
            return lambda shape: np.zeros(shape, np_dtype)

        for i, inner_type in enumerate(return_type.types):
            # Generate an array and insert into return tuple
            if have_vis_array:
                array_factory = gen_array_factory(inner_type.dtype)
                factory_sig = inner_type(out_shape_type)
                factory_args = [out_shape]

                # Compile function and get handle to output array
                inner_value = context.compile_internal(builder, array_factory,
                                                       factory_sig,
                                                       factory_args)

            # Insert inner tuple into outer tuple
            elif have_vis_tuple:
                # Create the inner tuple
                llvm_inner_type = context.get_value_type(inner_type)
                inner_value = cgutils.get_null_value(llvm_inner_type)

                for j, array_type in enumerate(inner_type.types):
                    # Create function, it's signature and arguments
                    array_factory = gen_array_factory(array_type.dtype)
                    factory_sig = array_type(out_shape_type)
                    factory_args = [out_shape]

                    # Compile function and get handle to output
                    data = context.compile_internal(builder, array_factory,
                                                    factory_sig, factory_args)

                    # Insert data into inner_value
                    inner_value = builder.insert_value(inner_value, data, j)
            else:
                raise ValueError("Internal logic error")

            # Insert inner tuple into outer tuple
            outer_tuple = builder.insert_value(outer_tuple, inner_value, i)

        return outer_tuple
Exemple #2
0
def optional_to_optional(context, builder, fromty, toty, val):
    """
    The handling of optional->optional cast must be special cased for
    correct propagation of None value.  Given type T and U. casting of
    T? to U? (? denotes optional) should always succeed.   If the from-value
    is None, the None value the casted value (U?) should be None; otherwise,
    the from-value is casted to U. This is different from casting T? to U,
    which requires the from-value must not be None.
    """
    optval = context.make_helper(builder, fromty, value=val)
    validbit = cgutils.as_bool_bit(builder, optval.valid)
    # Create uninitialized optional value
    outoptval = context.make_helper(builder, toty)

    with builder.if_else(validbit) as (is_valid, is_not_valid):
        with is_valid:
            # Cast internal value
            outoptval.valid = cgutils.true_bit
            outoptval.data = context.cast(builder, optval.data, fromty.type,
                                          toty.type)

        with is_not_valid:
            # Store None to result
            outoptval.valid = cgutils.false_bit
            outoptval.data = cgutils.get_null_value(outoptval.data.type)

    return outoptval._getvalue()
Exemple #3
0
def _make_constant_bytes(context, builder, nbytes):
    bstr_ctor = cgutils.create_struct_proxy(bytes_type)
    bstr = bstr_ctor(context, builder)

    if isinstance(nbytes, int):
        nbytes = ir.Constant(bstr.nitems.type, nbytes)

    bstr.meminfo = context.nrt.meminfo_alloc(builder, nbytes)
    bstr.nitems = nbytes
    bstr.itemsize = ir.Constant(bstr.itemsize.type, 1)
    bstr.data = context.nrt.meminfo_data(builder, bstr.meminfo)
    bstr.parent = cgutils.get_null_value(bstr.parent.type)
    # bstr.shape and bstr.strides are not used
    bstr.shape = cgutils.get_null_value(bstr.shape.type)
    bstr.strides = cgutils.get_null_value(bstr.strides.type)
    return bstr
Exemple #4
0
def box_lsttype(typ, val, c):
    context = c.context
    builder = c.builder

    # XXX deduplicate
    ctor = cgutils.create_struct_proxy(typ)
    lstruct = ctor(context, builder, value=val)
    # Returns the plain MemInfo
    boxed_meminfo = c.box(
        types.MemInfoPointer(types.voidptr),
        lstruct.meminfo,
    )

    modname = c.context.insert_const_string(
        c.builder.module, 'numba.typed.typedlist',
    )
    typedlist_mod = c.pyapi.import_module_noblock(modname)
    fmp_fn = c.pyapi.object_getattr_string(typedlist_mod, '_from_meminfo_ptr')

    lsttype_obj = c.pyapi.unserialize(c.pyapi.serialize_object(typ))

    result_var = builder.alloca(c.pyapi.pyobj)
    builder.store(cgutils.get_null_value(c.pyapi.pyobj), result_var)

    with builder.if_then(cgutils.is_not_null(builder, lsttype_obj)):
        res = c.pyapi.call_function_objargs(
            fmp_fn, (boxed_meminfo, lsttype_obj),
        )
        c.pyapi.decref(fmp_fn)
        c.pyapi.decref(typedlist_mod)
        c.pyapi.decref(boxed_meminfo)
        builder.store(res, result_var)
    return builder.load(result_var)
Exemple #5
0
    def call_function(self, builder, callee, resty, argtys, args):
        """
        Call the Numba-compiled *callee*.
        """
        # XXX better fix for callees that are not function values
        #     (pointers to function; thus have no `.args` attribute)
        retty = self._get_return_argument(callee.function_type).pointee

        retvaltmp = cgutils.alloca_once(builder, retty)
        # initialize return value to zeros
        builder.store(cgutils.get_null_value(retty), retvaltmp)

        excinfoptr = cgutils.alloca_once(builder,
                                         ir.PointerType(excinfo_t),
                                         name="excinfo")

        arginfo = self._get_arg_packer(argtys)
        args = list(arginfo.as_arguments(builder, args))
        realargs = [retvaltmp, excinfoptr] + args
        code = builder.call(callee, realargs)
        status = self._get_return_status(builder, code,
                                         builder.load(excinfoptr))
        retval = builder.load(retvaltmp)
        out = self.context.get_returned_value(builder, resty, retval)
        return status, out
Exemple #6
0
    def unset_try_status(self, builder):
        try_state_ptr = self._get_try_state(builder)
        # Decrement try depth
        old = builder.load(try_state_ptr)
        new = builder.sub(old, old.type(1))
        builder.store(new, try_state_ptr)

        # Needs to reset the exception state so that the exception handler
        # will run normally.
        excinfoptr = self._get_excinfo_argument(builder.function)
        null = cgutils.get_null_value(excinfoptr.type.pointee)
        builder.store(null, excinfoptr)
Exemple #7
0
 def alloca(self, name, ltype=None):
     """
     Allocate a stack slot and initialize it to NULL.
     The default is to allocate a pyobject pointer.
     Use ``ltype`` to override.
     """
     if ltype is None:
         ltype = self.context.get_value_type(types.pyobject)
     with self.builder.goto_block(self.entry_block):
         ptr = self.builder.alloca(ltype, name=name)
         self.builder.store(cgutils.get_null_value(ltype), ptr)
     return ptr
Exemple #8
0
 def delvar(self, name):
     """
     Delete the variable slot with the given name. This will decref
     the corresponding Python object.
     """
     # If this raises then the live variables analysis is wrong
     self._live_vars.remove(name)
     ptr = self._getvar(name)  # initializes `name` if not already
     self.decref(self.builder.load(ptr))
     # This is a safety guard against double decref's, but really
     # the IR should be correct and have only one Del per variable
     # and code path.
     self.builder.store(cgutils.get_null_value(ptr.type.pointee), ptr)
Exemple #9
0
 def call_function(self, builder, callee, resty, argtys, args, env=None):
     """Call the Numba-compiled *callee*."""
     assert env is None
     retty = callee.args[0].type.pointee
     retvaltmp = cgutils.alloca_once(builder, retty)
     # initialize return value
     builder.store(cgutils.get_null_value(retty), retvaltmp)
     arginfo = self.context.get_arg_packer(argtys)
     args = arginfo.as_arguments(builder, args)
     realargs = [retvaltmp] + list(args)
     code = builder.call(callee, realargs)
     status = self._get_return_status(builder, code)
     retval = builder.load(retvaltmp)
     out = self.context.get_returned_value(builder, resty, retval)
     return status, out
Exemple #10
0
def _define_nrt_incref(module, atomic_incr):
    """
    Implement NRT_incref in the module
    """
    fn_incref = module.get_or_insert_function(incref_decref_ty, name="NRT_incref")
    # Cannot inline this for refcount pruning to work
    fn_incref.attributes.add("noinline")
    builder = ir.IRBuilder(fn_incref.append_basic_block())
    [ptr] = fn_incref.args
    is_null = builder.icmp_unsigned("==", ptr, cgutils.get_null_value(ptr.type))
    with cgutils.if_unlikely(builder, is_null):
        builder.ret_void()

    if _debug_print:
        cgutils.printf(builder, "*** NRT_Incref %zu [%p]\n", builder.load(ptr), ptr)
    builder.call(atomic_incr, [builder.bitcast(ptr, atomic_incr.args[0].type)])
    builder.ret_void()
Exemple #11
0
    def declare_env_global(self, module, envname):
        """Declare the Environment pointer as a global of the module.

        The pointer is initialized to NULL.  It must be filled by the runtime
        with the actual address of the Env before the associated function
        can be executed.

        Parameters
        ----------
        module :
            The LLVM Module
        envname : str
            The name of the global variable.
        """
        if envname not in module.globals:
            gv = llvmir.GlobalVariable(module, cgutils.voidptr_t, name=envname)
            gv.linkage = 'common'
            gv.initializer = cgutils.get_null_value(gv.type.pointee)

        return module.globals[envname]
Exemple #12
0
def ctor_impl(context, builder, sig, args):
    """
    Generic constructor (__new__) for jitclasses.
    """
    # Allocate the instance
    inst_typ = sig.return_type
    alloc_type = context.get_data_type(inst_typ.get_data_type())
    alloc_size = context.get_abi_sizeof(alloc_type)

    meminfo = context.nrt.meminfo_alloc_dtor(
        builder,
        context.get_constant(types.uintp, alloc_size),
        imp_dtor(context, builder.module, inst_typ),
    )
    data_pointer = context.nrt.meminfo_data(builder, meminfo)
    data_pointer = builder.bitcast(data_pointer,
                                   alloc_type.as_pointer())

    # Nullify all data
    builder.store(cgutils.get_null_value(alloc_type),
                  data_pointer)

    inst_struct = context.make_helper(builder, inst_typ)
    inst_struct.meminfo = meminfo
    inst_struct.data = data_pointer

    # Call the jitted __init__
    # TODO: extract the following into a common util
    init_sig = (sig.return_type,) + sig.args

    init = inst_typ.jit_methods['__init__']
    disp_type = types.Dispatcher(init)
    call = context.get_function(disp_type, types.void(*init_sig))
    _add_linking_libs(context, call)
    realargs = [inst_struct._getvalue()] + list(args)
    call(builder, realargs)

    # Prepare return value
    ret = inst_struct._getvalue()

    return imputils.impl_ret_new_ref(context, builder, inst_typ, ret)
    def codegen(context, builder, signature, args):
        # FIXME: mostly the same as jitclass ctor_impl()
        model = context.data_model_manager[inst_type.get_data_type()]
        alloc_type = model.get_value_type()
        alloc_size = context.get_abi_sizeof(alloc_type)

        meminfo = context.nrt.meminfo_alloc_dtor(
            builder,
            context.get_constant(types.uintp, alloc_size),
            imp_dtor(context, builder.module, inst_type),
        )
        data_pointer = context.nrt.meminfo_data(builder, meminfo)
        data_pointer = builder.bitcast(data_pointer, alloc_type.as_pointer())

        # Nullify all data
        builder.store(cgutils.get_null_value(alloc_type), data_pointer)

        inst_struct = context.make_helper(builder, inst_type)
        inst_struct.meminfo = meminfo

        return inst_struct._getvalue()
Exemple #14
0
def _define_nrt_decref(module, atomic_decr):
    """
    Implement NRT_decref in the module
    """
    fn_decref = cgutils.get_or_insert_function(module, incref_decref_ty,
                                               "NRT_decref")
    # Cannot inline this for refcount pruning to work
    fn_decref.attributes.add('noinline')
    calldtor = ir.Function(module,
                           ir.FunctionType(ir.VoidType(), [_pointer_type]),
                           name="NRT_MemInfo_call_dtor")

    builder = ir.IRBuilder(fn_decref.append_basic_block())
    [ptr] = fn_decref.args
    is_null = builder.icmp_unsigned("==", ptr,
                                    cgutils.get_null_value(ptr.type))
    with cgutils.if_unlikely(builder, is_null):
        builder.ret_void()

    # For memory fence usage, see https://llvm.org/docs/Atomics.html

    # A release fence is used before the relevant write operation.
    # No-op on x86.  On POWER, it lowers to lwsync.
    builder.fence("release")

    word_ptr = builder.bitcast(ptr, atomic_decr.args[0].type)

    if config.DEBUG_NRT:
        cgutils.printf(builder, "*** NRT_Decref %zu [%p]\n",
                       builder.load(word_ptr), ptr)
    newrefct = builder.call(atomic_decr, [word_ptr])

    refct_eq_0 = builder.icmp_unsigned("==", newrefct,
                                       ir.Constant(newrefct.type, 0))
    with cgutils.if_unlikely(builder, refct_eq_0):
        # An acquire fence is used after the relevant read operation.
        # No-op on x86.  On POWER, it lowers to lwsync.
        builder.fence("acquire")
        builder.call(calldtor, [ptr])
    builder.ret_void()
Exemple #15
0
    def call_function(self, builder, callee, resty, argtys, args,
                      attrs=None):
        """
        Call the Numba-compiled *callee*.
        Parameters:
        -----------
        attrs: LLVM style string or iterable of individual attributes, default
               is None which specifies no attributes. Examples:
               LLVM style string: "noinline fast"
               Equivalent iterable: ("noinline", "fast")
        """
        # XXX better fix for callees that are not function values
        #     (pointers to function; thus have no `.args` attribute)
        retty = self._get_return_argument(callee.function_type).pointee

        retvaltmp = cgutils.alloca_once(builder, retty)
        # initialize return value to zeros
        builder.store(cgutils.get_null_value(retty), retvaltmp)

        excinfoptr = cgutils.alloca_once(builder, ir.PointerType(excinfo_t),
                                         name="excinfo")

        arginfo = self._get_arg_packer(argtys)
        args = list(arginfo.as_arguments(builder, args))
        realargs = [retvaltmp, excinfoptr] + args
        # deal with attrs, it's fine to specify a load in a string like
        # "noinline fast" as per LLVM or equally as an iterable of individual
        # attributes.
        if attrs is None:
            _attrs = ()
        elif isinstance(attrs, Iterable) and not isinstance(attrs, str):
            _attrs = tuple(attrs)
        else:
            raise TypeError("attrs must be an iterable of strings or None")
        code = builder.call(callee, realargs, attrs=_attrs)
        status = self._get_return_status(builder, code,
                                         builder.load(excinfoptr))
        retval = builder.load(retvaltmp)
        out = self.context.get_returned_value(builder, resty, retval)
        return status, out
Exemple #16
0
    def lower_expr(self, expr):
        if expr.op == 'binop':
            return self.lower_binop(expr, expr.fn, inplace=False)
        elif expr.op == 'inplace_binop':
            return self.lower_binop(expr, expr.fn, inplace=True)
        elif expr.op == 'unary':
            value = self.loadvar(expr.value.name)
            if expr.fn == operator.neg:
                res = self.pyapi.number_negative(value)
            elif expr.fn == operator.pos:
                res = self.pyapi.number_positive(value)
            elif expr.fn == operator.not_:
                res = self.pyapi.object_not(value)
                self.check_int_status(res)
                res = self.pyapi.bool_from_bool(res)
            elif expr.fn == operator.invert:
                res = self.pyapi.number_invert(value)
            else:
                raise NotImplementedError(expr)
            self.check_error(res)
            return res
        elif expr.op == 'call':
            argvals = [self.loadvar(a.name) for a in expr.args]
            fn = self.loadvar(expr.func.name)
            args = self.pyapi.tuple_pack(argvals)
            if expr.vararg:
                # Expand *args
                new_args = self.pyapi.number_add(
                    args, self.loadvar(expr.vararg.name))
                self.decref(args)
                args = new_args
            if not expr.kws:
                # No named arguments
                ret = self.pyapi.call(fn, args, None)
            else:
                # Named arguments
                keyvalues = [(k, self.loadvar(v.name)) for k, v in expr.kws]
                kws = self.pyapi.dict_pack(keyvalues)
                ret = self.pyapi.call(fn, args, kws)
                self.decref(kws)
            self.decref(args)
            self.check_error(ret)
            return ret
        elif expr.op == 'getattr':
            obj = self.loadvar(expr.value.name)
            res = self.pyapi.object_getattr(obj,
                                            self._freeze_string(expr.attr))
            self.check_error(res)
            return res
        elif expr.op == 'build_tuple':
            items = [self.loadvar(it.name) for it in expr.items]
            res = self.pyapi.tuple_pack(items)
            self.check_error(res)
            return res
        elif expr.op == 'build_list':
            items = [self.loadvar(it.name) for it in expr.items]
            res = self.pyapi.list_pack(items)
            self.check_error(res)
            return res
        elif expr.op == 'build_map':
            res = self.pyapi.dict_new(expr.size)
            self.check_error(res)
            for k, v in expr.items:
                key = self.loadvar(k.name)
                value = self.loadvar(v.name)
                ok = self.pyapi.dict_setitem(res, key, value)
                self.check_int_status(ok)
            return res
        elif expr.op == 'build_set':
            items = [self.loadvar(it.name) for it in expr.items]
            res = self.pyapi.set_new()
            self.check_error(res)
            for it in items:
                ok = self.pyapi.set_add(res, it)
                self.check_int_status(ok)
            return res
        elif expr.op == 'getiter':
            obj = self.loadvar(expr.value.name)
            res = self.pyapi.object_getiter(obj)
            self.check_error(res)
            return res
        elif expr.op == 'iternext':
            iterobj = self.loadvar(expr.value.name)
            item = self.pyapi.iter_next(iterobj)
            is_valid = cgutils.is_not_null(self.builder, item)
            pair = self.pyapi.tuple_new(2)
            with self.builder.if_else(is_valid) as (then, otherwise):
                with then:
                    self.pyapi.tuple_setitem(pair, 0, item)
                with otherwise:
                    self.check_occurred()
                    # Make the tuple valid by inserting None as dummy
                    # iteration "result" (it will be ignored).
                    self.pyapi.tuple_setitem(pair, 0, self.pyapi.make_none())
            self.pyapi.tuple_setitem(pair, 1,
                                     self.pyapi.bool_from_bool(is_valid))
            return pair
        elif expr.op == 'pair_first':
            pair = self.loadvar(expr.value.name)
            first = self.pyapi.tuple_getitem(pair, 0)
            self.incref(first)
            return first
        elif expr.op == 'pair_second':
            pair = self.loadvar(expr.value.name)
            second = self.pyapi.tuple_getitem(pair, 1)
            self.incref(second)
            return second
        elif expr.op == 'exhaust_iter':
            iterobj = self.loadvar(expr.value.name)
            tup = self.pyapi.sequence_tuple(iterobj)
            self.check_error(tup)
            # Check tuple size is as expected
            tup_size = self.pyapi.tuple_size(tup)
            expected_size = self.context.get_constant(types.intp, expr.count)
            has_wrong_size = self.builder.icmp(lc.ICMP_NE, tup_size,
                                               expected_size)
            with cgutils.if_unlikely(self.builder, has_wrong_size):
                self.return_exception(ValueError)
            return tup
        elif expr.op == 'getitem':
            value = self.loadvar(expr.value.name)
            index = self.loadvar(expr.index.name)
            res = self.pyapi.object_getitem(value, index)
            self.check_error(res)
            return res
        elif expr.op == 'static_getitem':
            value = self.loadvar(expr.value.name)
            index = self.context.get_constant(types.intp, expr.index)
            indexobj = self.pyapi.long_from_ssize_t(index)
            self.check_error(indexobj)
            res = self.pyapi.object_getitem(value, indexobj)
            self.decref(indexobj)
            self.check_error(res)
            return res
        elif expr.op == 'getslice':
            target = self.loadvar(expr.target.name)
            start = self.loadvar(expr.start.name)
            stop = self.loadvar(expr.stop.name)

            slicefn = self.get_builtin_obj("slice")
            sliceobj = self.pyapi.call_function_objargs(slicefn, (start, stop))
            self.decref(slicefn)
            self.check_error(sliceobj)

            res = self.pyapi.object_getitem(target, sliceobj)
            self.check_error(res)

            return res

        elif expr.op == 'cast':
            val = self.loadvar(expr.value.name)
            self.incref(val)
            return val
        elif expr.op == 'phi':
            raise LoweringError("PHI not stripped")

        elif expr.op == 'null':
            # Make null value
            return cgutils.get_null_value(self.pyapi.pyobj)

        else:
            raise NotImplementedError(expr)
Exemple #17
0
def real_imag_impl(context, builder, typ, value):
    res = cgutils.get_null_value(value.type)
    return impl_ret_untracked(context, builder, typ, res)