def _list_codegen_set_method_table(context, builder, lp, itemty): vtablety = ir.LiteralStructType([ ll_voidptr_type, # item incref ll_voidptr_type, # item decref ]) setmethod_fnty = ir.FunctionType( ir.VoidType(), [ll_list_type, vtablety.as_pointer()]) setmethod_fn = builder.module.get_or_insert_function( setmethod_fnty, name='numba_list_set_method_table') vtable = cgutils.alloca_once(builder, vtablety, zfill=True) # install item incref/decref item_incref_ptr = cgutils.gep_inbounds(builder, vtable, 0, 0) item_decref_ptr = cgutils.gep_inbounds(builder, vtable, 0, 1) dm_item = context.data_model_manager[itemty] if dm_item.contains_nrt_meminfo(): item_incref, item_decref = _get_incref_decref(context, builder.module, dm_item, "list") builder.store( builder.bitcast(item_incref, item_incref_ptr.type.pointee), item_incref_ptr, ) builder.store( builder.bitcast(item_decref, item_decref_ptr.type.pointee), item_decref_ptr, ) builder.call(setmethod_fn, [lp, vtable])
def codegen(context, builder, sig, args): vtablety = ir.LiteralStructType([ ll_voidptr_type, # equal ll_voidptr_type, # key incref ll_voidptr_type, # key decref ll_voidptr_type, # val incref ll_voidptr_type, # val decref ]) setmethod_fnty = ir.FunctionType( ir.VoidType(), [ll_dict_type, vtablety.as_pointer()]) setmethod_fn = ir.Function( builder.module, setmethod_fnty, name='numba_dict_set_method_table', ) dp = args[0] vtable = cgutils.alloca_once(builder, vtablety, zfill=True) # install key incref/decref key_equal_ptr = cgutils.gep_inbounds(builder, vtable, 0, 0) key_incref_ptr = cgutils.gep_inbounds(builder, vtable, 0, 1) key_decref_ptr = cgutils.gep_inbounds(builder, vtable, 0, 2) val_incref_ptr = cgutils.gep_inbounds(builder, vtable, 0, 3) val_decref_ptr = cgutils.gep_inbounds(builder, vtable, 0, 4) dm_key = context.data_model_manager[keyty.instance_type] if dm_key.contains_nrt_meminfo(): equal = _get_equal(context, builder.module, dm_key, 'dict') key_incref, key_decref = _get_incref_decref( context, builder.module, dm_key, 'dict') builder.store( builder.bitcast(equal, key_equal_ptr.type.pointee), key_equal_ptr, ) builder.store( builder.bitcast(key_incref, key_incref_ptr.type.pointee), key_incref_ptr, ) builder.store( builder.bitcast(key_decref, key_decref_ptr.type.pointee), key_decref_ptr, ) dm_val = context.data_model_manager[valty.instance_type] if dm_val.contains_nrt_meminfo(): val_incref, val_decref = _get_incref_decref( context, builder.module, dm_val, 'dict') builder.store( builder.bitcast(val_incref, val_incref_ptr.type.pointee), val_incref_ptr, ) builder.store( builder.bitcast(val_decref, val_decref_ptr.type.pointee), val_decref_ptr, ) builder.call(setmethod_fn, [dp, vtable])
def lower_finalize_func_body(self, builder, genptr): """ Lower the body of the generator's finalizer: decref all live state variables. """ pyapi = self.context.get_python_api(builder) resume_index_ptr = self.get_resume_index_ptr(builder, genptr) resume_index = builder.load(resume_index_ptr) # If resume_index is 0, next() was never called # If resume_index is -1, generator terminated cleanly # (note function arguments are saved in state variables, # so they don't need a separate cleanup step) need_cleanup = builder.icmp_signed('>', resume_index, Constant.int(resume_index.type, 0)) with cgutils.if_unlikely(builder, need_cleanup): # Decref all live vars (some may be NULL) gen_state_ptr = self.get_state_ptr(builder, genptr) for state_index in range(len(self.gentype.state_types)): state_slot = cgutils.gep_inbounds(builder, gen_state_ptr, 0, state_index) ty = self.gentype.state_types[state_index] val = self.context.unpack_value(builder, ty, state_slot) pyapi.decref(val) builder.ret_void()
def iternext_zip(context, builder, sig, args, result): [zip_type] = sig.args [zipobj] = args zipobj = context.make_helper(builder, zip_type, value=zipobj) if len(zipobj) == 0: # zip() is an empty iterator result.set_exhausted() return p_ret_tup = cgutils.alloca_once( builder, context.get_value_type(zip_type.yield_type)) p_is_valid = cgutils.alloca_once_value(builder, value=cgutils.true_bit) for i, (iterobj, srcty) in enumerate(zip(zipobj, zip_type.source_types)): is_valid = builder.load(p_is_valid) # Avoid calling the remaining iternext if a iterator has been exhausted with builder.if_then(is_valid): srcres = call_iternext(context, builder, srcty, iterobj) is_valid = builder.and_(is_valid, srcres.is_valid()) builder.store(is_valid, p_is_valid) val = srcres.yielded_value() ptr = cgutils.gep_inbounds(builder, p_ret_tup, 0, i) builder.store(val, ptr) is_valid = builder.load(p_is_valid) result.set_valid(is_valid) with builder.if_then(is_valid): result.yield_(builder.load(p_ret_tup))
def codegen(context, builder, signature, args): [obj] = args [ty] = signature.args # A sequence of (type, meminfo) meminfos = [] if context.enable_nrt: tmp_mis = context.nrt.get_meminfos(builder, ty, obj) meminfos.extend(tmp_mis) if meminfos: pyapi = context.get_python_api(builder) gil_state = pyapi.gil_ensure() pyapi.print_string("dump refct of {}".format(ty)) for ty, mi in meminfos: miptr = builder.bitcast(mi, _meminfo_struct_type.as_pointer()) refctptr = cgutils.gep_inbounds(builder, miptr, 0, 0) refct = builder.load(refctptr) pyapi.print_string(" | {} refct=".format(ty)) # "%zu" is not portable. just truncate refcount to 32-bit. # that's good enough for a debugging util. refct_32bit = builder.trunc(refct, ir.IntType(32)) printed = cgutils.snprintf_stackbuffer( builder, 30, "%d".format(ty), refct_32bit, ) pyapi.sys_write_stdout(printed) pyapi.print_string(";\n") pyapi.gil_release(gil_state) return cgutils.true_bit else: return cgutils.false_bit
def _do_load(self, builder, ptr, formal_list=None): res = [] for i, i_formal in enumerate(self._pack_map): elem_ptr = cgutils.gep_inbounds(builder, ptr, 0, i) val = self._models[i_formal].load_from_data_pointer(builder, elem_ptr) if formal_list is None: res.append((self._fe_types[i_formal], val)) else: formal_list[i_formal] = val return res
def load_from_data_pointer(self, builder, ptr, align=None): values = [] for i, model in enumerate(self._models): elem_ptr = cgutils.gep_inbounds(builder, ptr, 0, i) val = model.load_from_data_pointer(builder, elem_ptr, align) values.append(val) struct = ir.Constant(self.get_value_type(), ir.Undefined) for i, val in enumerate(values): struct = self.set(builder, struct, val, i) return struct
def lower_yield_resume(self): # Emit resumption point self.genlower.create_resumption_block(self.lower, self.inst.index) self.lower.debug_print("# generator resume") # Reload live vars from state for state_index, name in zip(self.live_var_indices, self.live_vars): state_slot = cgutils.gep_inbounds(self.builder, self.gen_state_ptr, 0, state_index) ty = self.gentype.state_types[state_index] val = self.context.unpack_value(self.builder, ty, state_slot) self.lower.storevar(val, name) # Previous storevar is making an extra incref if self.context.enable_nrt: self.context.nrt.decref(self.builder, ty, val) self.lower.debug_print("# generator resume end")
def codegen(context, builder, signature, args): [obj] = args [ty] = signature.args # A sequence of (type, meminfo) meminfos = [] if context.enable_nrt: tmp_mis = context.nrt.get_meminfos(builder, ty, obj) meminfos.extend(tmp_mis) refcounts = [] if meminfos: for ty, mi in meminfos: miptr = builder.bitcast(mi, _meminfo_struct_type.as_pointer()) refctptr = cgutils.gep_inbounds(builder, miptr, 0, 0) refct = builder.load(refctptr) refct_32bit = builder.trunc(refct, ir.IntType(32)) refcounts.append(refct_32bit) return refcounts[0]
def lower_yield_suspend(self): self.lower.debug_print("# generator suspend") # Save live vars in state for state_index, name in zip(self.live_var_indices, self.live_vars): state_slot = cgutils.gep_inbounds(self.builder, self.gen_state_ptr, 0, state_index) ty = self.gentype.state_types[state_index] val = self.lower.loadvar(name) # IncRef newly stored value if self.context.enable_nrt: self.context.nrt.incref(self.builder, ty, val) self.context.pack_value(self.builder, ty, val, state_slot) # Save resume index indexval = Constant.int(self.resume_index_ptr.type.pointee, self.inst.index) self.builder.store(indexval, self.resume_index_ptr) self.lower.debug_print("# generator suspend end")
def string_split_impl(context, builder, sig, args): nitems = cgutils.alloca_once(builder, lir.IntType(64)) # input str, sep, size pointer fnty = lir.FunctionType(lir.IntType(8).as_pointer().as_pointer(), [lir.IntType(8).as_pointer(), lir.IntType(8).as_pointer(), lir.IntType(64).as_pointer()]) fn = cgutils.get_or_insert_function(builder.module, fnty, name="str_split") ptr = builder.call(fn, args + [nitems]) size = builder.load(nitems) # TODO: use ptr instead of allocating and copying, use NRT_MemInfo_new # TODO: deallocate ptr _list = numba.cpython.listobj.ListInstance.allocate(context, builder, sig.return_type, size) _list.size = size with cgutils.for_range(builder, size) as loop: value = builder.load(cgutils.gep_inbounds(builder, ptr, loop.index)) # TODO: refcounted str _list.setitem(loop.index, value, incref=False) return impl_ret_new_ref(context, builder, sig.return_type, _list.value)
def lower_yield_suspend(self): self.lower.debug_print("# generator suspend") # Save live vars in state for state_index, name in zip(self.live_var_indices, self.live_vars): state_slot = cgutils.gep_inbounds(self.builder, self.gen_state_ptr, 0, state_index) ty = self.gentype.state_types[state_index] # The yield might be in a loop, in which case the state might # contain a predicate var that branches back to the loop head, in # this case the var is live but in sequential lowering won't have # been alloca'd yet, so do this here. fetype = self.lower.typeof(name) self.lower._alloca_var(name, fetype) val = self.lower.loadvar(name) # IncRef newly stored value if self.context.enable_nrt: self.context.nrt.incref(self.builder, ty, val) self.context.pack_value(self.builder, ty, val, state_slot) # Save resume index indexval = Constant.int(self.resume_index_ptr.type.pointee, self.inst.index) self.builder.store(indexval, self.resume_index_ptr) self.lower.debug_print("# generator suspend end")
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): fn = get_rnd_shuffle(builder) 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_inbounds(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 get_args_ptr(self, builder, genptr): return cgutils.gep_inbounds(builder, genptr, 0, 1)
def get_array_ptr(builder, state_ptr): return cgutils.gep_inbounds(builder, state_ptr, 0, 1)
def get_gauss_ptr(builder, state_ptr): return cgutils.gep_inbounds(builder, state_ptr, 0, 3)
def get_resume_index_ptr(self, builder, genptr): return cgutils.gep_inbounds(builder, genptr, 0, 0, name='gen.resume_index')
def get_index_ptr(builder, state_ptr): return cgutils.gep_inbounds(builder, state_ptr, 0, 0)
def as_data(self, builder, value): values = [ builder.load(cgutils.gep_inbounds(builder, value, i)) for i in range(self._fe_type.count) ] return cgutils.pack_array(builder, values)
def get_state_ptr(self, builder, genptr): return cgutils.gep_inbounds(builder, genptr, 0, 2, name='gen.state')
def _build_array(context, builder, array_ty, input_types, inputs): """Utility function to handle allocation of an implicit output array given the target context, builder, output array type, and a list of _ArrayHelper instances. """ # First, strip optional types, ufunc loops are typed on concrete types input_types = [ x.type if isinstance(x, types.Optional) else x for x in input_types ] intp_ty = context.get_value_type(types.intp) def make_intp_const(val): return context.get_constant(types.intp, val) ZERO = make_intp_const(0) ONE = make_intp_const(1) src_shape = cgutils.alloca_once(builder, intp_ty, array_ty.ndim, "src_shape") dest_ndim = make_intp_const(array_ty.ndim) dest_shape = cgutils.alloca_once(builder, intp_ty, array_ty.ndim, "dest_shape") dest_shape_addrs = tuple( cgutils.gep_inbounds(builder, dest_shape, index) for index in range(array_ty.ndim)) # Initialize the destination shape with all ones. for dest_shape_addr in dest_shape_addrs: builder.store(ONE, dest_shape_addr) # For each argument, try to broadcast onto the destination shape, # mutating along any axis where the argument shape is not one and # the destination shape is one. for arg_number, arg in enumerate(inputs): if not hasattr(arg, "ndim"): # Skip scalar arguments continue arg_ndim = make_intp_const(arg.ndim) for index in range(arg.ndim): builder.store(arg.shape[index], cgutils.gep_inbounds(builder, src_shape, index)) arg_result = context.compile_internal( builder, _broadcast_onto, _broadcast_onto_sig, [arg_ndim, src_shape, dest_ndim, dest_shape]) with cgutils.if_unlikely(builder, builder.icmp(lc.ICMP_SLT, arg_result, ONE)): msg = "unable to broadcast argument %d to output array" % ( arg_number, ) loc = errors.loc_info.get('loc', None) if loc is not None: msg += '\nFile "%s", line %d, ' % (loc.filename, loc.line) context.call_conv.return_user_exc(builder, ValueError, (msg, )) real_array_ty = array_ty.as_array dest_shape_tup = tuple( builder.load(dest_shape_addr) for dest_shape_addr in dest_shape_addrs) array_val = arrayobj._empty_nd_impl(context, builder, real_array_ty, dest_shape_tup) # Get the best argument to call __array_wrap__ on array_wrapper_index = select_array_wrapper(input_types) array_wrapper_ty = input_types[array_wrapper_index] try: # __array_wrap__(source wrapped array, out array) -> out wrapped array array_wrap = context.get_function( '__array_wrap__', array_ty(array_wrapper_ty, real_array_ty)) except NotImplementedError: # If it's the same priority as a regular array, assume we # should use the allocated array unchanged. if array_wrapper_ty.array_priority != types.Array.array_priority: raise out_val = array_val._getvalue() else: wrap_args = (inputs[array_wrapper_index].return_val, array_val._getvalue()) out_val = array_wrap(builder, wrap_args) ndim = array_ty.ndim shape = cgutils.unpack_tuple(builder, array_val.shape, ndim) strides = cgutils.unpack_tuple(builder, array_val.strides, ndim) return _ArrayHelper(context, builder, shape, strides, array_val.data, array_ty.layout, array_ty.dtype, ndim, out_val)