def _unbox_native_field(typ, obj, field_name: str, c): ret_ptr = cgutils.alloca_once(c.builder, c.context.get_value_type(typ)) is_error_ptr = cgutils.alloca_once_value(c.builder, cgutils.false_bit) fail_obj = c.context.get_constant_null(typ) with local_return(c.builder) as ret: fail_blk = c.builder.append_basic_block("fail") with c.builder.goto_block(fail_blk): c.builder.store(cgutils.true_bit, is_error_ptr) c.builder.store(fail_obj, ret_ptr) ret() field_obj = c.pyapi.object_getattr_string(obj, field_name) with cgutils.if_unlikely(c.builder, cgutils.is_null(c.builder, field_obj)): c.builder.branch(fail_blk) field_native = c.unbox(typ, field_obj) c.pyapi.decref(field_obj) with cgutils.if_unlikely(c.builder, field_native.is_error): c.builder.branch(fail_blk) c.builder.store(cgutils.false_bit, is_error_ptr) c.builder.store(field_native.value, ret_ptr) return NativeValue(c.builder.load(ret_ptr), is_error=c.builder.load(is_error_ptr))
def _define_nrt_decref(module, atomic_decr): """ Implement NRT_decref in the module """ fn_decref = module.get_or_insert_function(incref_decref_ty, name="NRT_decref") calldtor = module.add_function(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() if _debug_print: cgutils.printf(builder, "*** NRT_Decref %zu [%p]\n", builder.load(ptr), ptr) newrefct = builder.call(atomic_decr, [builder.bitcast(ptr, atomic_decr.args[0].type)]) refct_eq_0 = builder.icmp_unsigned("==", newrefct, ir.Constant(newrefct.type, 0)) with cgutils.if_unlikely(builder, refct_eq_0): builder.call(calldtor, [ptr]) builder.ret_void()
def _define_decref(module, atomic_decr): """ Implement NRT_decref in the module """ if "NRT_decref" not in module.globals: return fn_decref = module.get_global_variable_named("NRT_decref") fn_decref.linkage = 'linkonce_odr' calldtor = module.add_function(ir.FunctionType( ir.VoidType(), [ir.IntType(8).as_pointer(), ir.IntType(32)]), 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() newrefct = builder.call(atomic_decr, [builder.bitcast(ptr, atomic_decr.args[0].type)]) refct_eq_0 = builder.icmp_unsigned("==", newrefct, ir.Constant(newrefct.type, 0)) with cgutils.if_unlikely(builder, refct_eq_0): do_defer = ir.Constant(ir.IntType(32), 0) builder.call(calldtor, [ptr, do_defer]) builder.ret_void()
def builtin_lookup(self, mod, name): """ Args ---- mod: The __builtins__ dictionary or module, as looked up in a module's globals. name: str The object to lookup """ fromdict = self.pyapi.dict_getitem_string(mod, name) self.incref(fromdict) # fromdict is borrowed bbifdict = self.builder.basic_block with cgutils.if_unlikely(self.builder, self.is_null(fromdict)): # This happen if we are using the __main__ module frommod = self.pyapi.object_getattr_string(mod, name) with cgutils.if_unlikely(self.builder, self.is_null(frommod)): self.pyapi.raise_missing_global_error(name) self.return_exception_raised() bbifmod = self.builder.basic_block builtin = self.builder.phi(self.pyapi.pyobj) builtin.add_incoming(fromdict, bbifdict) builtin.add_incoming(frommod, bbifmod) return builtin
def _define_decref(module, atomic_decr): """ Implement NRT_decref in the module """ if "NRT_decref" not in module.globals: return fn_decref = module.get_global_variable_named("NRT_decref") fn_decref.linkage = 'linkonce_odr' calldtor = module.add_function(ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer(), ir.IntType(32)]), 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() newrefct = builder.call(atomic_decr, [builder.bitcast(ptr, atomic_decr.args[0].type)]) refct_eq_0 = builder.icmp_unsigned("==", newrefct, ir.Constant(newrefct.type, 0)) with cgutils.if_unlikely(builder, refct_eq_0): do_defer = ir.Constant(ir.IntType(32), 0) builder.call(calldtor, [ptr, do_defer]) builder.ret_void()
def builtin_lookup(self, mod, name): """ Args ---- mod: The __builtins__ dictionary or module, as looked up in a module's globals. name: str The object to lookup """ fromdict = self.pyapi.dict_getitem(mod, self._freeze_string(name)) self.incref(fromdict) # fromdict is borrowed bbifdict = self.builder.basic_block with cgutils.if_unlikely(self.builder, self.is_null(fromdict)): # This happen if we are using the __main__ module frommod = self.pyapi.object_getattr(mod, self._freeze_string(name)) with cgutils.if_unlikely(self.builder, self.is_null(frommod)): self.pyapi.raise_missing_global_error(name) self.return_exception_raised() bbifmod = self.builder.basic_block builtin = self.builder.phi(self.pyapi.pyobj) builtin.add_incoming(fromdict, bbifdict) builtin.add_incoming(frommod, bbifmod) return builtin
def _define_nrt_decref(module, atomic_decr): """ Implement NRT_decref in the module """ fn_decref = module.get_or_insert_function(incref_decref_ty, name="NRT_decref") # Cannot inline this for refcount pruning to work fn_decref.attributes.add('noinline') calldtor = module.add_function(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() if _debug_print: cgutils.printf(builder, "*** NRT_Decref %zu [%p]\n", builder.load(ptr), ptr) newrefct = builder.call(atomic_decr, [builder.bitcast(ptr, atomic_decr.args[0].type)]) refct_eq_0 = builder.icmp_unsigned("==", newrefct, ir.Constant(newrefct.type, 0)) with cgutils.if_unlikely(builder, refct_eq_0): builder.call(calldtor, [ptr]) builder.ret_void()
def iternext_zip(context, builder, sig, args, result): genty, = sig.args gen, = args # XXX We should link with the generator's library. # Currently, this doesn't make a difference as the library has already # been linked for the generator init function. impl = context.get_generator_impl(genty) status, retval = impl(context, builder, sig, args) with cgutils.if_likely(builder, status.is_ok): result.set_valid(True) result.yield_(retval) with cgutils.if_unlikely(builder, status.is_stop_iteration): result.set_exhausted() with cgutils.if_unlikely(builder, builder.and_(status.is_error, builder.not_(status.is_stop_iteration))): context.call_conv.return_status_propagate(builder, status)
def lower_global(self, name, value): """ 1) Check global scope dictionary. 2) Check __builtins__. 2a) is it a dictionary (for non __main__ module) 2b) is it a module (for __main__ module) """ moddict = self.pyapi.get_module_dict() obj = self.pyapi.dict_getitem_string(moddict, name) self.incref(obj) # obj is borrowed if hasattr(builtins, name): obj_is_null = self.is_null(obj) bbelse = self.builder.basic_block with cgutils.ifthen(self.builder, obj_is_null): mod = self.pyapi.dict_getitem_string(moddict, "__builtins__") builtin = self.builtin_lookup(mod, name) bbif = self.builder.basic_block retval = self.builder.phi(self.pyapi.pyobj) retval.add_incoming(obj, bbelse) retval.add_incoming(builtin, bbif) else: retval = obj with cgutils.if_unlikely(self.builder, self.is_null(retval)): self.pyapi.raise_missing_global_error(name) self.return_exception_raised() self.incref(retval) return retval
def check_occurred(self): err_occurred = cgutils.is_not_null(self.builder, self.pyapi.err_occurred()) with cgutils.if_unlikely(self.builder, err_occurred): # FIXME: this should decref all live variables before returning self.return_exception_raised()
def set_iter_valid(self, state, item): iterstate = PyIterState(self.context, self.builder, ref=state) iterstate.valid = cgutils.as_bool_byte( self.builder, cgutils.is_not_null(self.builder, item)) with cgutils.if_unlikely(self.builder, self.is_null(item)): self.check_occurred()
def to_native_arg(self, obj, typ): if isinstance(typ, types.Record): # Generate a dummy integer type that has the size of Py_buffer dummy_py_buffer_type = Type.int(_helperlib.py_buffer_size * 8) # Allocate the Py_buffer py_buffer = cgutils.alloca_once(self.builder, dummy_py_buffer_type) # Zero-fill the py_buffer. where the obj field in Py_buffer is NULL # PyBuffer_Release has no effect. zeroed_buffer = lc.Constant.null(dummy_py_buffer_type) self.builder.store(zeroed_buffer, py_buffer) buf_as_voidptr = self.builder.bitcast(py_buffer, self.voidptr) ptr = self.extract_record_data(obj, buf_as_voidptr) with cgutils.if_unlikely(self.builder, cgutils.is_null(self.builder, ptr)): self.builder.ret(ptr) ltyp = self.context.get_value_type(typ) val = cgutils.init_record_by_ptr(self.builder, ltyp, ptr) def dtor(): self.release_record_buffer(buf_as_voidptr) else: val = self.to_native_value(obj, typ) def dtor(): pass return val, dtor
def iternext_zip(context, builder, sig, args, result): genty, = sig.args gen, = args impl = context.get_generator_impl(genty) status, retval = impl(context, builder, sig, args) context.add_linking_libs(getattr(impl, 'libs', ())) with cgutils.if_likely(builder, status.is_ok): result.set_valid(True) result.yield_(retval) with cgutils.if_unlikely(builder, status.is_stop_iteration): result.set_exhausted() with cgutils.if_unlikely(builder, builder.and_(status.is_error, builder.not_(status.is_stop_iteration))): context.call_conv.return_status_propagate(builder, status)
def add_arg(self, obj, ty): """ Unbox argument and emit code that handles any error during unboxing. Args are cleaned up in reverse order of the parameter list, and cleanup begins as soon as unboxing of any argument fails. E.g. failure on arg2 will result in control flow going through: arg2.err -> arg1.err -> arg0.err -> arg.end (returns) """ # Unbox argument val, dtor = self.api.to_native_arg(self.builder.load(obj), ty) # check for Python C-API Error error_check = self.api.err_occurred() err_happened = self.builder.icmp(lc.ICMP_NE, error_check, self.api.get_null_object()) # Write the cleanup block cleanupblk = cgutils.append_basic_block(self.builder, "arg%d.err" % self.arg_count) with cgutils.goto_block(self.builder, cleanupblk): dtor() # Go to next cleanup block self.builder.branch(self.nextblk) # If an error occurred, go to the cleanup block with cgutils.if_unlikely(self.builder, err_happened): self.builder.branch(cleanupblk) self.cleanups.append(dtor) self.nextblk = cleanupblk self.arg_count += 1 return val
def imp(context, builder, sig, args): func = context.declare_function(cgutils.get_module(builder), fndesc) status, retval = context.call_function(builder, func, fndesc.restype, fndesc.argtypes, args) with cgutils.if_unlikely(builder, status.err): context.return_errcode_propagate(builder, status.code) return retval
def get_next_int32(context, builder, state_ptr): """ Get the next int32 generated by the PRNG at *state_ptr*. """ idxptr = get_index_ptr(builder, state_ptr) idx = builder.load(idxptr) need_reshuffle = builder.icmp_unsigned('>=', idx, N_const) with cgutils.if_unlikely(builder, need_reshuffle): fnty = ir.FunctionType(ir.VoidType(), (rnd_state_ptr_t,)) fn = builder.function.module.get_or_insert_function(fnty, "numba_rnd_shuffle") builder.call(fn, (state_ptr,)) builder.store(const_int(0), idxptr) idx = builder.load(idxptr) array_ptr = get_array_ptr(builder, state_ptr) y = builder.load(cgutils.gep(builder, array_ptr, 0, idx)) idx = builder.add(idx, const_int(1)) builder.store(idx, idxptr) # Tempering y = builder.xor(y, builder.lshr(y, const_int(11))) y = builder.xor(y, builder.and_(builder.shl(y, const_int(7)), const_int(0x9d2c5680))) y = builder.xor(y, builder.and_(builder.shl(y, const_int(15)), const_int(0xefc60000))) y = builder.xor(y, builder.lshr(y, const_int(18))) return y
def init_specific(self, context, builder, arrty, arr): zero = context.get_constant(types.intp, 0) data = arr.data ndim = arrty.ndim shapes = cgutils.unpack_tuple(builder, arr.shape, ndim) indices = cgutils.alloca_once(builder, zero.type, size=context.get_constant(types.intp, arrty.ndim)) pointers = cgutils.alloca_once(builder, data.type, size=context.get_constant(types.intp, arrty.ndim)) strides = cgutils.unpack_tuple(builder, arr.strides, ndim) exhausted = cgutils.alloca_once_value(builder, cgutils.false_byte) # Initialize indices and pointers with their start values. for dim in range(ndim): idxptr = cgutils.gep(builder, indices, dim) ptrptr = cgutils.gep(builder, pointers, dim) builder.store(data, ptrptr) builder.store(zero, idxptr) # 0-sized dimensions really indicate an empty array, # but we have to catch that condition early to avoid # a bug inside the iteration logic (see issue #846). dim_size = shapes[dim] dim_is_empty = builder.icmp(lc.ICMP_EQ, dim_size, zero) with cgutils.if_unlikely(builder, dim_is_empty): builder.store(cgutils.true_byte, exhausted) self.indices = indices self.pointers = pointers self.exhausted = exhausted
def init_specific(self, context, builder, arrty, arr): zero = context.get_constant(types.intp, 0) data = arr.data ndim = arrty.ndim shapes = cgutils.unpack_tuple(builder, arr.shape, ndim) indices = cgutils.alloca_once(builder, zero.type, size=context.get_constant( types.intp, arrty.ndim)) pointers = cgutils.alloca_once(builder, data.type, size=context.get_constant( types.intp, arrty.ndim)) strides = cgutils.unpack_tuple(builder, arr.strides, ndim) exhausted = cgutils.alloca_once_value(builder, cgutils.false_byte) # Initialize indices and pointers with their start values. for dim in range(ndim): idxptr = cgutils.gep(builder, indices, dim) ptrptr = cgutils.gep(builder, pointers, dim) builder.store(data, ptrptr) builder.store(zero, idxptr) # 0-sized dimensions really indicate an empty array, # but we have to catch that condition early to avoid # a bug inside the iteration logic (see issue #846). dim_size = shapes[dim] dim_is_empty = builder.icmp(lc.ICMP_EQ, dim_size, zero) with cgutils.if_unlikely(builder, dim_is_empty): builder.store(cgutils.true_byte, exhausted) self.indices = indices self.pointers = pointers self.exhausted = exhausted
def add_arg(self, obj, ty): """ Unbox argument and emit code that handles any error during unboxing. Args are cleaned up in reverse order of the parameter list, and cleanup begins as soon as unboxing of any argument fails. E.g. failure on arg2 will result in control flow going through: arg2.err -> arg1.err -> arg0.err -> arg.end (returns) """ # Unbox argument native = self.api.to_native_value(self.builder.load(obj), ty) # If an error occurred, go to the cleanup block for the previous argument. with cgutils.if_unlikely(self.builder, native.is_error): self.builder.branch(self.nextblk) # Write the cleanup block for this argument cleanupblk = cgutils.append_basic_block(self.builder, "arg%d.err" % self.arg_count) with cgutils.goto_block(self.builder, cleanupblk): if native.cleanup is not None: native.cleanup() self.cleanups.append(native.cleanup) # Go to next cleanup block self.builder.branch(self.nextblk) self.nextblk = cleanupblk self.arg_count += 1 return native.value
def build_wrapper(self, api, builder, closure, args, kws): nargs = len(self.fndesc.argtypes) objs = [api.alloca_obj() for _ in range(nargs)] parseok = api.unpack_tuple(args, self.fndesc.qualname, nargs, nargs, *objs) pred = builder.icmp(lc.ICMP_EQ, parseok, Constant.null(parseok.type)) with cgutils.if_unlikely(builder, pred): builder.ret(api.get_null_object()) # Block that returns after erroneous argument unboxing/cleanup endblk = builder.append_basic_block("arg.end") with builder.goto_block(endblk): builder.ret(api.get_null_object()) # Extract the Environment object from the Closure envptr, env_manager = self.get_env(api, builder, closure) cleanup_manager = _ArgManager(self.context, builder, api, env_manager, endblk, nargs) # Compute the arguments to the compiled Numba function. innerargs = [] for obj, ty in zip(objs, self.fndesc.argtypes): if isinstance(ty, types.Omitted): # It's an omitted value => ignore dummy Python object innerargs.append(None) else: val = cleanup_manager.add_arg(builder.load(obj), ty) innerargs.append(val) if self.release_gil: cleanup_manager = _GilManager(builder, api, cleanup_manager) status, retval = self.context.call_conv.call_function( builder, self.func, self.fndesc.restype, self.fndesc.argtypes, innerargs, env=envptr) # Do clean up self.debug_print(builder, "# callwrapper: emit_cleanup") cleanup_manager.emit_cleanup() self.debug_print(builder, "# callwrapper: emit_cleanup end") # Determine return status with builder.if_then(status.is_ok, likely=True): # Ok => return boxed Python value with builder.if_then(status.is_none): api.return_none() retty = self._simplified_return_type() obj = api.from_native_return(retty, retval, env_manager) builder.ret(obj) # Error out self.context.call_conv.raise_error(builder, api, status) builder.ret(api.get_null_object())
def getiter_range_generic(context, builder, iterobj, start, stop, step): diff = builder.sub(stop, start) intty = start.type zero = Constant.int(intty, 0) one = Constant.int(intty, 1) pos_diff = builder.icmp(lc.ICMP_SGT, diff, zero) pos_step = builder.icmp(lc.ICMP_SGT, step, zero) sign_differs = builder.xor(pos_diff, pos_step) zero_step = builder.icmp(lc.ICMP_EQ, step, zero) with cgutils.if_unlikely(builder, zero_step): # step shouldn't be zero context.return_errcode(builder, 1) with cgutils.ifelse(builder, sign_differs) as (then, orelse): with then: builder.store(zero, iterobj.count) with orelse: rem = builder.srem(diff, step) uneven = builder.icmp(lc.ICMP_SGT, rem, zero) newcount = builder.add(builder.sdiv(diff, step), builder.select(uneven, one, zero)) builder.store(newcount, iterobj.count) return iterobj._getvalue()
def getitem_array1d(context, builder, sig, args): aryty, _ = sig.args if aryty.ndim != 1: # TODO raise NotImplementedError("1D indexing into %dD array" % aryty.ndim) ary, idx = args arystty = make_array(aryty) ary = arystty(context, builder, ary) dataptr = ary.data if True or WARPAROUND: # TODO target flag ZERO = context.get_constant(types.intp, 0) negative = builder.icmp(lc.ICMP_SLT, idx, ZERO) bbnormal = builder.basic_block with cgutils.if_unlikely(builder, negative): # Index is negative, wraparound [nelem] = cgutils.unpack_tuple(builder, ary.shape, 1) wrapped = builder.add(nelem, idx) bbwrapped = builder.basic_block where = builder.phi(idx.type) where.add_incoming(idx, bbnormal) where.add_incoming(wrapped, bbwrapped) ptr = builder.gep(dataptr, [where]) else: # No wraparound ptr = builder.gep(dataptr, [idx]) if context.is_struct_type(aryty.dtype): return ptr else: return builder.load(ptr)
def iternext_specific(self, context, builder, result): zero = context.get_constant(types.intp, 0) one = context.get_constant(types.intp, 1) bbend = cgutils.append_basic_block(builder, 'end') exhausted = cgutils.as_bool_bit(builder, builder.load(self.exhausted)) with cgutils.if_unlikely(builder, exhausted): result.set_valid(False) builder.branch(bbend) indices = [ builder.load(cgutils.gep(builder, self.indices, dim)) for dim in range(ndim) ] result.yield_(cgutils.pack_array(builder, indices)) result.set_valid(True) shape = cgutils.unpack_tuple(builder, self.shape, ndim) _increment_indices(context, builder, ndim, shape, self.indices, self.exhausted) builder.branch(bbend) builder.position_at_end(bbend)
def check_int_status(self, num, ok_value=0): """ Raise an exception if *num* is smaller than *ok_value*. """ ok = lc.Constant.int(num.type, ok_value) pred = self.builder.icmp(lc.ICMP_SLT, num, ok) with cgutils.if_unlikely(self.builder, pred): self.return_exception_raised()
def set_iter_valid(self, state, item): iterstate = PyIterState(self.context, self.builder, ref=state) iterstate.valid = cgutils.as_bool_byte(self.builder, cgutils.is_not_null(self.builder, item)) with cgutils.if_unlikely(self.builder, self.is_null(item)): self.check_occurred()
def getrandbits_impl(context, builder, sig, args): nbits, = args too_large = builder.icmp_unsigned(">=", nbits, const_int(65)) too_small = builder.icmp_unsigned("==", nbits, const_int(0)) with cgutils.if_unlikely(builder, builder.or_(too_large, too_small)): msg = "getrandbits() limited to 64 bits" context.call_conv.return_user_exc(builder, OverflowError, (msg,)) state_ptr = get_state_ptr(context, builder, "py") return get_next_int(context, builder, state_ptr, nbits)
def iternext_numpy_flatiter(context, builder, sig, args, result): [flatiterty] = sig.args [flatiter] = args flatitercls = make_array_flat_cls(flatiterty) flatiter = flatitercls(context, builder, value=flatiter) arrty = flatiterty.array_type arrcls = context.make_array(arrty) arr = arrcls(context, builder, value=builder.load(flatiter.array)) ndim = arrty.ndim shapes = cgutils.unpack_tuple(builder, arr.shape, ndim) indptr = flatiter.iters # Load indices and check if they are valid indices = [] is_valid = cgutils.true_bit zero = context.get_constant(types.intp, 0) one = context.get_constant(types.intp, 1) for ax in range(ndim): axsize = shapes[ax] idxptr = builder.gep(indptr, [context.get_constant(types.intp, ax)]) idx = builder.load(idxptr) ax_valid = builder.icmp(lc.ICMP_SLT, idx, axsize) indices.append(idx) is_valid = builder.and_(is_valid, ax_valid) result.set_valid(is_valid) with cgutils.if_likely(builder, is_valid): # Get yielded value valptr = cgutils.get_item_pointer(builder, arrty, arr, indices) yield_value = builder.load(valptr) result.yield_(yield_value) # Increment iterator indices carry_flags = [cgutils.true_bit] for ax, (idx, axsize) in reversed(list(enumerate(zip(indices, shapes)))): idxptr = builder.gep(indptr, [context.get_constant(types.intp, ax)]) lastcarry = carry_flags[-1] idxp1 = builder.add(idx, one) carry = builder.icmp(lc.ICMP_SGE, idxp1, axsize) idxfinal = builder.select(lastcarry, builder.select(carry, zero, idxp1), idx) builder.store(idxfinal, idxptr) carry_flags.append(builder.and_(carry, lastcarry)) with cgutils.if_unlikely(builder, carry_flags[-1]): # If we have iterated all elements, # Set first index to out-of-bound idxptr = builder.gep(indptr, [context.get_constant(types.intp, 0)]) builder.store(shapes[0], idxptr)
def pre_lower(self): # Store environment argument for later use self.envarg = self.context.get_env_argument(self.function) with cgutils.if_unlikely(self.builder, self.is_null(self.envarg)): self.pyapi.err_set_string( "PyExc_SystemError", "Numba internal error: object mode function called " "without an environment") self.return_exception_raised() self.env_body = self.context.get_env_body(self.builder, self.envarg)
def loadvar(self, name): """ Load the llvm value of the variable named *name*. """ ptr = self.varmap[name] val = self.builder.load(ptr) with cgutils.if_unlikely(self.builder, self.is_null(val)): self.pyapi.raise_missing_name_error(name) self.return_error_occurred() return val
def build_wrapper(self, api, builder, closure, args, kws): nargs = len(self.fndesc.args) objs = [api.alloca_obj() for _ in range(nargs)] parseok = api.unpack_tuple(args, self.fndesc.qualname, nargs, nargs, *objs) pred = builder.icmp(lc.ICMP_EQ, parseok, Constant.null(parseok.type)) with cgutils.if_unlikely(builder, pred): builder.ret(api.get_null_object()) # Block that returns after erroneous argument unboxing/cleanup endblk = builder.append_basic_block("arg.end") with builder.goto_block(endblk): builder.ret(api.get_null_object()) cleanup_manager = _ArgManager(self.context, builder, api, endblk, nargs) innerargs = [] for obj, ty in zip(objs, self.fndesc.argtypes): val = cleanup_manager.add_arg(obj, ty) innerargs.append(val) if self.release_gil: cleanup_manager = _GilManager(builder, api, cleanup_manager) # Extract the Environment object from the Closure envptr, env_manager = self.get_env(api, builder, closure) status, res = self.context.call_conv.call_function( builder, self.func, self.fndesc.restype, self.fndesc.argtypes, innerargs, envptr) # Do clean up self.debug_print(builder, "# callwrapper: emit_cleanup") cleanup_manager.emit_cleanup() self.debug_print(builder, "# callwrapper: emit_cleanup end") # Determine return status with cgutils.if_likely(builder, status.is_ok): # Ok => return boxed Python value with builder.if_then(status.is_none): api.return_none() retval = api.from_native_return(res, self._simplified_return_type(), env_manager) builder.ret(retval) with builder.if_then(builder.not_(status.is_python_exc)): # User exception raised self.make_exception_switch(api, builder, status) # Error out builder.ret(api.get_null_object())
def build_wrapper(self, api, builder, closure, args, kws): nargs = len(self.fndesc.args) keywords = self.make_keywords(self.fndesc.args) fmt = self.make_const_string("O" * nargs) objs = [api.alloca_obj() for _ in range(nargs)] parseok = api.parse_tuple_and_keywords(args, kws, fmt, keywords, *objs) pred = builder.icmp(lc.ICMP_EQ, parseok, Constant.null(parseok.type)) with cgutils.if_unlikely(builder, pred): builder.ret(api.get_null_object()) # Block that returns after erroneous argument unboxing/cleanup endblk = cgutils.append_basic_block(builder, "arg.end") with cgutils.goto_block(builder, endblk): builder.ret(api.get_null_object()) cleanup_manager = _ArgManager(builder, api, endblk, nargs) innerargs = [] for obj, ty in zip(objs, self.fndesc.argtypes): val = cleanup_manager.add_arg(obj, ty) innerargs.append(val) if self.release_gil: cleanup_manager = _GilManager(builder, api, cleanup_manager) # The wrapped function doesn't take a full closure, only # the Environment object. env = self.context.get_env_from_closure(builder, closure) status, res = self.context.call_function(builder, self.func, self.fndesc.restype, self.fndesc.argtypes, innerargs, env) # Do clean up cleanup_manager.emit_cleanup() # Determine return status with cgutils.if_likely(builder, status.ok): with cgutils.ifthen(builder, status.none): api.return_none() retval = api.from_native_return(res, self.fndesc.restype) builder.ret(retval) with cgutils.ifthen(builder, builder.not_(status.exc)): # !ok && !exc # User exception raised self.make_exception_switch(api, builder, status.code) # !ok && exc builder.ret(api.get_null_object())
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") 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() builder.call(atomic_incr, [builder.bitcast(ptr, atomic_incr.args[0].type)]) builder.ret_void()
def call_internal(self, builder, fndesc, sig, args): """Given the function descriptor of an internally compiled function, emit a call to that function with the given arguments. """ # Add call to the generated function llvm_mod = builder.module fn = self.declare_function(llvm_mod, fndesc) status, res = self.call_conv.call_function(builder, fn, sig.return_type, sig.args, args) with cgutils.if_unlikely(builder, status.is_error): self.call_conv.return_status_propagate(builder, status) return res
def build_wrapper(self, api, builder, closure, args, kws): nargs = len(self.fndesc.args) objs = [api.alloca_obj() for _ in range(nargs)] parseok = api.unpack_tuple(args, self.fndesc.qualname, nargs, nargs, *objs) pred = builder.icmp(lc.ICMP_EQ, parseok, Constant.null(parseok.type)) with cgutils.if_unlikely(builder, pred): builder.ret(api.get_null_object()) # Block that returns after erroneous argument unboxing/cleanup endblk = builder.append_basic_block("arg.end") with builder.goto_block(endblk): builder.ret(api.get_null_object()) cleanup_manager = _ArgManager(self.context, builder, api, endblk, nargs) innerargs = [] for obj, ty in zip(objs, self.fndesc.argtypes): val = cleanup_manager.add_arg(obj, ty) innerargs.append(val) if self.release_gil: cleanup_manager = _GilManager(builder, api, cleanup_manager) # Extract the Environment object from the Closure envptr, env_manager = self.get_env(api, builder, closure) status, retval = self.context.call_conv.call_function( builder, self.func, self.fndesc.restype, self.fndesc.argtypes, innerargs, envptr) # Do clean up self.debug_print(builder, "# callwrapper: emit_cleanup") cleanup_manager.emit_cleanup() self.debug_print(builder, "# callwrapper: emit_cleanup end") # Determine return status with cgutils.if_likely(builder, status.is_ok): # Ok => return boxed Python value with builder.if_then(status.is_none): api.return_none() retty = self._simplified_return_type() obj = api.from_native_return(retval, retty, env_manager) builder.ret(obj) with builder.if_then(builder.not_(status.is_python_exc)): # User exception raised self.make_exception_switch(api, builder, status) # Error out builder.ret(api.get_null_object())
def unbox_COO(typ: COOType, obj: COO, c) -> NativeValue: ret_ptr = cgutils.alloca_once(c.builder, c.context.get_value_type(typ)) is_error_ptr = cgutils.alloca_once_value(c.builder, cgutils.false_bit) fail_obj = c.context.get_constant_null(typ) with local_return(c.builder) as ret: fail_blk = c.builder.append_basic_block("fail") with c.builder.goto_block(fail_blk): c.builder.store(cgutils.true_bit, is_error_ptr) c.builder.store(fail_obj, ret_ptr) ret() data = _unbox_native_field(typ.data_type, obj, "data", c) with cgutils.if_unlikely(c.builder, data.is_error): c.builder.branch(fail_blk) coords = _unbox_native_field(typ.coords_type, obj, "coords", c) with cgutils.if_unlikely(c.builder, coords.is_error): c.builder.branch(fail_blk) shape = _unbox_native_field(typ.shape_type, obj, "shape", c) with cgutils.if_unlikely(c.builder, shape.is_error): c.builder.branch(fail_blk) fill_value = _unbox_native_field(typ.fill_value_type, obj, "fill_value", c) with cgutils.if_unlikely(c.builder, fill_value.is_error): c.builder.branch(fail_blk) coo = cgutils.create_struct_proxy(typ)(c.context, c.builder) coo.coords = coords.value coo.data = data.value coo.shape = shape.value coo.fill_value = fill_value.value c.builder.store(cgutils.false_bit, is_error_ptr) c.builder.store(coo._getvalue(), ret_ptr) return NativeValue(c.builder.load(ret_ptr), is_error=c.builder.load(is_error_ptr))
def get_env_from_closure(self, builder, clo): """ From the pointer *clo* to a _dynfunc.Closure, get a pointer to the enclosed _dynfunc.Environment. """ with cgutils.if_unlikely(builder, cgutils.is_null(builder, clo)): self.debug_print(builder, "Fatal error: missing _dynfunc.Closure") builder.unreachable() clo_body_ptr = cgutils.pointer_add( builder, clo, _dynfunc._impl_info['offsetof_closure_body']) clo_body = ClosureBody(self, builder, ref=clo_body_ptr, cast_ref=True) return clo_body.env
def _define_nrt_decref(module, atomic_decr): """ Implement NRT_decref in the module """ fn_decref = module.get_or_insert_function(incref_decref_ty, name="NRT_decref") # Cannot inline this for refcount pruning to work fn_decref.attributes.add('noinline') calldtor = module.add_function(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() if _debug_print: cgutils.printf(builder, "*** NRT_Decref %zu [%p]\n", builder.load(ptr), ptr) # 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") newrefct = builder.call(atomic_decr, [builder.bitcast(ptr, atomic_decr.args[0].type)]) 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()
def emit_environment_sentry(self, envptr, return_pyobject=False): """Emits LLVM code to ensure the `envptr` is not NULL """ is_null = cgutils.is_null(self.builder, envptr) with cgutils.if_unlikely(self.builder, is_null): if return_pyobject: fnty = self.builder.function.type.pointee assert fnty.return_type == self.pyobj self.err_set_string("PyExc_RuntimeError", "missing Environment") self.builder.ret(self.get_null_object()) else: self.context.call_conv.return_user_exc( self.builder, RuntimeError, ("missing Environment", ))
def build_wrapper(self, api, builder, closure, args, kws): nargs = len(self.fndesc.args) keywords = self.make_keywords(self.fndesc.args) fmt = self.make_const_string("O" * nargs) objs = [api.alloca_obj() for _ in range(nargs)] parseok = api.parse_tuple_and_keywords(args, kws, fmt, keywords, *objs) pred = builder.icmp(lc.ICMP_EQ, parseok, Constant.null(parseok.type)) with cgutils.if_unlikely(builder, pred): builder.ret(api.get_null_object()) innerargs = [] cleanups = [] for obj, ty in zip(objs, self.fndesc.argtypes): #api.context.debug_print(builder, "%s -> %s" % (obj, ty)) #api.print_object(builder.load(obj)) val, dtor = api.to_native_arg(builder.load(obj), ty) innerargs.append(val) cleanups.append(dtor) # The wrapped function doesn't take a full closure, only # the Environment object. env = self.context.get_env_from_closure(builder, closure) status, res = self.context.call_function(builder, self.func, self.fndesc.restype, self.fndesc.argtypes, innerargs, env) # Do clean up for dtor in cleanups: dtor() # Determine return status with cgutils.if_likely(builder, status.ok): with cgutils.ifthen(builder, status.none): api.return_none() retval = api.from_native_return(res, self.fndesc.restype) builder.ret(retval) with cgutils.ifthen(builder, builder.not_(status.exc)): # !ok && !exc # User exception raised self.make_exception_switch(api, builder, status.code) # !ok && exc builder.ret(api.get_null_object())
def _define_nrt_decref(module, atomic_decr): """ Implement NRT_decref in the module """ fn_decref = module.get_or_insert_function(incref_decref_ty, name="NRT_decref") calldtor = module.add_function(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() newrefct = builder.call(atomic_decr, [builder.bitcast(ptr, atomic_decr.args[0].type)]) refct_eq_0 = builder.icmp_unsigned("==", newrefct, ir.Constant(newrefct.type, 0)) with cgutils.if_unlikely(builder, refct_eq_0): builder.call(calldtor, [ptr]) builder.ret_void()
def emit_environment_sentry(self, envptr, return_pyobject=False): """Emits LLVM code to ensure the `envptr` is not NULL """ is_null = cgutils.is_null(self.builder, envptr) with cgutils.if_unlikely(self.builder, is_null): if return_pyobject: fnty = self.builder.function.type.pointee assert fnty.return_type == self.pyobj self.err_set_string("PyExc_RuntimeError", "missing Environment") self.builder.ret(self.get_null_object()) else: self.context.call_conv.return_user_exc(self.builder, RuntimeError, ("missing Environment",))
def to_native_array(self, typ, ary): # TODO check matching dtype. # currently, mismatching dtype will still work and causes # potential memory corruption voidptr = Type.pointer(Type.int(8)) nativearycls = self.context.make_array(typ) nativeary = nativearycls(self.context, self.builder) aryptr = nativeary._getpointer() ptr = self.builder.bitcast(aryptr, voidptr) errcode = self.numba_array_adaptor(ary, ptr) failed = cgutils.is_not_null(self.builder, errcode) with cgutils.if_unlikely(self.builder, failed): # TODO self.builder.unreachable() return self.builder.load(aryptr)