def call_function(self, builder, callee, resty, argtys, args, env=None): """ Call the Numba-compiled *callee*. """ if env is None: # This only works with functions that don't use the environment # (nopython functions). env = cgutils.get_null_value(PYOBJECT) is_generator_function = isinstance(resty, types.Generator) retty = self._get_return_argument(callee).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.context.get_arg_packer(argtys) args = list(arginfo.as_arguments(builder, args)) realargs = [retvaltmp, excinfoptr, env] + args code = builder.call(callee, realargs) status = self._get_return_status(builder, code, builder.load(excinfoptr)) if is_generator_function: retval = retvaltmp else: retval = builder.load(retvaltmp) out = self.context.get_returned_value(builder, resty, retval) return status, out
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()
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 codegen(cgctx, builder, signature, args): lltupty = cgctx.get_value_type(tupty) # Create an empty indexing tuple. tup = cgutils.get_null_value(lltupty) # We only need value of the axis dimension here. # The rest are constants defined above. [_, value_arg, _] = args def create_full_slice(): return slice(None, None) # loop to fill the tuple with slice(None,None) before # the axis dimension. # compile and call create_full_slice slice_data = cgctx.compile_internal(builder, create_full_slice, types.slice2_type(), []) for i in range(0, axis_value): tup = builder.insert_value(tup, slice_data, i) # Add the axis dimension 'value'. tup = builder.insert_value(tup, value_arg, axis_value) # loop to fill the tuple with slice(None,None) after # the axis dimension. for i in range(axis_value + 1, nd): tup = builder.insert_value(tup, slice_data, i) return tup
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 _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 codegen(cgctx, builder, signature, args): # This is the implementation defined using LLVM builder. lltupty = cgctx.get_value_type(typed_tuple) tup = cgutils.get_null_value(lltupty) [_, idxaryval] = args def array_checker(a): if a.size != tuple_size: raise IndexError("index array size mismatch") # Compile and call array_checker. cgctx.compile_internal(builder, array_checker, types.none(indexer_array), [idxaryval]) def array_indexer(a, i): return a[i] # loop to fill the tuple for i in range(tuple_size): dataidx = cgctx.get_constant(types.intp, i) # compile and call array_indexer data = cgctx.compile_internal( builder, array_indexer, indexer_array.dtype(indexer_array, types.intp), [idxaryval, dataidx], ) tup = builder.insert_value(tup, data, i) return tup
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
def codegen(context, builder, sig, args): src, start, length = args in_str = cgutils.create_struct_proxy(types.unicode_type)(context, builder, value=src) view_str = cgutils.create_struct_proxy(types.unicode_type)(context, builder) view_str.meminfo = in_str.meminfo view_str.kind = in_str.kind view_str.length = length # hash value -1 to indicate "need to compute hash" view_str.hash = context.get_constant(_Py_hash_t, -1) # get a pointer to start of slice data bw_typ = context.typing_context.resolve_value_type(_kind_to_byte_width) bw_sig = bw_typ.get_call_type(context.typing_context, (types.int32, ), {}) bw_impl = context.get_function(bw_typ, bw_sig) byte_width = bw_impl(builder, (in_str.kind, )) offset = builder.mul(start, byte_width) view_str.data = builder.gep(in_str.data, [offset]) # Set parent pyobject to NULL view_str.parent = cgutils.get_null_value(view_str.parent.type) # incref original string if context.enable_nrt: context.nrt.incref(builder, sig.args[0], src) return view_str._getvalue()
def codegen(context, builder, sig, args): src, start, length = args in_str = cgutils.create_struct_proxy( types.unicode_type)(context, builder, value=src) view_str = cgutils.create_struct_proxy( types.unicode_type)(context, builder) view_str.meminfo = in_str.meminfo view_str.kind = in_str.kind view_str.is_ascii = in_str.is_ascii view_str.length = length # hash value -1 to indicate "need to compute hash" view_str.hash = context.get_constant(_Py_hash_t, -1) # get a pointer to start of slice data bw_typ = context.typing_context.resolve_value_type(_kind_to_byte_width) bw_sig = bw_typ.get_call_type( context.typing_context, (types.int32,), {}) bw_impl = context.get_function(bw_typ, bw_sig) byte_width = bw_impl(builder, (in_str.kind,)) offset = builder.mul(start, byte_width) view_str.data = builder.gep(in_str.data, [offset]) # Set parent pyobject to NULL view_str.parent = cgutils.get_null_value(view_str.parent.type) # incref original string if context.enable_nrt: context.nrt.incref(builder, sig.args[0], src) return view_str._getvalue()
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
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) if binding.get_process_triple().startswith("powerpc"): 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): if binding.get_process_triple().startswith("powerpc"): builder.fence("acquire") builder.call(calldtor, [ptr]) builder.ret_void()
def delvar(self, name): """ Delete the variable slot with the given name. This will decref the corresponding Python object. """ 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)
def codegen(context, builder, signature, args): ptr, _ = args alloc_type = context.get_data_type(inst_typ.get_data_type()) inst_struct = context.make_helper(builder, inst_typ) # Set meminfo to NULL inst_struct.meminfo = cgutils.get_null_value(inst_struct.meminfo.type) # Set data from the given pointer inst_struct.data = builder.bitcast(ptr, alloc_type.as_pointer()) return inst_struct._getvalue()
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 cgutils.goto_block(self.builder, self.entry_block): ptr = self.builder.alloca(ltype, name=name) self.builder.store(cgutils.get_null_value(ltype), ptr) return ptr
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 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)
def _define_incref(module, atomic_incr): """ Implement NRT_incref in the module """ if "NRT_incref" not in module.globals: return fn_incref = module.get_global_variable_named("NRT_incref") fn_incref.linkage = 'linkonce_odr' 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_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) args = [self.context.get_value_as_argument(builder, ty, arg) for ty, arg in zip(argtys, 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
def details(context, builder, signature, args): [kind_val, char_bytes_val, length_val] = args # fill the struct uni_str_ctor = cgutils.create_struct_proxy(types.unicode_type) uni_str = uni_str_ctor(context, builder) # add null padding character nbytes_val = builder.mul(char_bytes_val, builder.add(length_val, Constant(length_val.type, 1))) uni_str.meminfo = context.nrt.meminfo_alloc(builder, nbytes_val) uni_str.kind = kind_val uni_str.length = length_val uni_str.data = context.nrt.meminfo_data(builder, uni_str.meminfo) # Set parent to NULL uni_str.parent = cgutils.get_null_value(uni_str.parent.type) return uni_str._getvalue()
def call_function(self, builder, callee, resty, argtys, args): """ Call the Numba-compiled *callee*. """ 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._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
def ctor_impl(context, builder, sig, args): # 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_typ = cgutils.create_struct_proxy(inst_typ) inst_struct = inst_struct_typ(context, builder) inst_struct.meminfo = meminfo inst_struct.data = data_pointer # Call the __init__ # TODO: extract the following into a common util init_sig = (sig.return_type,) + sig.args init = inst_typ.jitmethods['__init__'] init.compile(init_sig) cres = init._compileinfos[init_sig] realargs = [inst_struct._getvalue()] + list(args) context.call_internal(builder, cres.fndesc, types.void(*init_sig), realargs) # Prepare reutrn value ret = inst_struct._getvalue() # Add function to link codegen = context.codegen() codegen.add_linking_library(cres.library) return imputils.impl_ret_new_ref(context, builder, inst_typ, ret)
def details(context, builder, signature, args): [kind_val, char_bytes_val, length_val] = args # fill the struct uni_str_ctor = cgutils.create_struct_proxy(types.unicode_type) uni_str = uni_str_ctor(context, builder) # add null padding character nbytes_val = builder.mul(char_bytes_val, builder.add(length_val, Constant(length_val.type, 1))) uni_str.meminfo = context.nrt.meminfo_alloc(builder, nbytes_val) uni_str.kind = kind_val uni_str.length = length_val # empty string has hash value -1 to indicate "need to compute hash" uni_str.hash = context.get_constant(_Py_hash_t, -1) uni_str.data = context.nrt.meminfo_data(builder, uni_str.meminfo) # Set parent to NULL uni_str.parent = cgutils.get_null_value(uni_str.parent.type) return uni_str._getvalue()
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()
def codegen(cgctx, builder, signature, args): lltupty = cgctx.get_value_type(tupty) # Create an empty int tuple. tup = cgutils.get_null_value(lltupty) # Get the shape list from the args and we don't need shape tuple. [in_shape, _] = args def array_indexer(a, i): return a[i] # loop to fill the tuple for i in range(nd): dataidx = cgctx.get_constant(types.intp, i) # compile and call array_indexer data = cgctx.compile_internal(builder, array_indexer, types.intp(shape_list, types.intp), [in_shape, dataidx]) tup = builder.insert_value(tup, data, i) return tup
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]
def details(context, builder, signature, args): [kind_val, char_bytes_val, length_val, is_ascii_val] = args # fill the struct uni_str_ctor = cgutils.create_struct_proxy(types.unicode_type) uni_str = uni_str_ctor(context, builder) # add null padding character nbytes_val = builder.mul(char_bytes_val, builder.add(length_val, Constant(length_val.type, 1))) uni_str.meminfo = context.nrt.meminfo_alloc(builder, nbytes_val) uni_str.kind = kind_val uni_str.is_ascii = is_ascii_val uni_str.length = length_val # empty string has hash value -1 to indicate "need to compute hash" uni_str.hash = context.get_constant(_Py_hash_t, -1) uni_str.data = context.nrt.meminfo_data(builder, uni_str.meminfo) # Set parent to NULL uni_str.parent = cgutils.get_null_value(uni_str.parent.type) return uni_str._getvalue()
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.jitmethods['__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 ctor_impl(context, builder, sig, args): # 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_typ = cgutils.create_struct_proxy(inst_typ) inst_struct = inst_struct_typ(context, builder) inst_struct.meminfo = meminfo inst_struct.data = data_pointer # Call the __init__ # TODO: extract the following into a common util init_sig = (sig.return_type, ) + sig.args init = inst_typ.jitmethods['__init__'] init.compile(init_sig) cres = init._compileinfos[init_sig] realargs = [inst_struct._getvalue()] + list(args) context.call_internal(builder, cres.fndesc, types.void(*init_sig), realargs) # Prepare reutrn value ret = inst_struct._getvalue() # Add function to link codegen = context.codegen() codegen.add_linking_library(cres.library) return imputils.impl_ret_new_ref(context, builder, inst_typ, ret)
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()