def cprint_lower(context, builder, sig, args): from sdc.str_ext import string_type, char_type for i, val in enumerate(args): typ = sig.args[i] if typ == string_type: fnty = lir.FunctionType(lir.VoidType(), [lir.IntType(8).as_pointer()]) fn = builder.module.get_or_insert_function(fnty, name="print_str") builder.call(fn, [val]) cgutils.printf(builder, " ") continue if typ == char_type: fnty = lir.FunctionType(lir.VoidType(), [lir.IntType(8)]) fn = builder.module.get_or_insert_function(fnty, name="print_char") builder.call(fn, [val]) cgutils.printf(builder, " ") continue if isinstance(typ, types.ArrayCTypes): cgutils.printf(builder, "%p ", val) continue format_str = typ_to_format[typ] cgutils.printf(builder, "%{} ".format(format_str), val) cgutils.printf(builder, "\n") return context.get_dummy_value()
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 _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()
def init_gdb_codegen(cgctx, builder, signature, args, const_args, do_break=False): int8_t = ir.IntType(8) int32_t = ir.IntType(32) intp_t = ir.IntType(utils.MACHINE_BITS) char_ptr = ir.PointerType(ir.IntType(8)) zero_i32t = int32_t(0) mod = builder.module pid = cgutils.alloca_once(builder, int32_t, size=1) # 32bit pid, 11 char max + terminator pidstr = cgutils.alloca_once(builder, int8_t, size=12) # str consts intfmt = cgctx.insert_const_string(mod, '%d') gdb_str = cgctx.insert_const_string(mod, config.GDB_BINARY) attach_str = cgctx.insert_const_string(mod, 'attach') new_args = [] # add break point command to known location # this command file thing is due to commands attached to a breakpoint # requiring an interactive prompt # https://sourceware.org/bugzilla/show_bug.cgi?id=10079 new_args.extend(['-x', os.path.join(_path, 'cmdlang.gdb')]) # issue command to continue execution from sleep function new_args.extend(['-ex', 'c']) # then run the user defined args if any new_args.extend([x.literal_value for x in const_args]) cmdlang = [cgctx.insert_const_string(mod, x) for x in new_args] # insert getpid, getpid is always successful, call without concern! fnty = ir.FunctionType(int32_t, tuple()) getpid = mod.get_or_insert_function(fnty, "getpid") # insert snprintf # int snprintf(char *str, size_t size, const char *format, ...); fnty = ir.FunctionType(int32_t, (char_ptr, intp_t, char_ptr), var_arg=True) snprintf = mod.get_or_insert_function(fnty, "snprintf") # insert fork fnty = ir.FunctionType(int32_t, tuple()) fork = mod.get_or_insert_function(fnty, "fork") # insert execl fnty = ir.FunctionType(int32_t, (char_ptr, char_ptr), var_arg=True) execl = mod.get_or_insert_function(fnty, "execl") # insert sleep fnty = ir.FunctionType(int32_t, (int32_t, )) sleep = mod.get_or_insert_function(fnty, "sleep") # insert break point fnty = ir.FunctionType(ir.VoidType(), tuple()) breakpoint = mod.get_or_insert_function(fnty, "numba_gdb_breakpoint") # do the work parent_pid = builder.call(getpid, tuple()) builder.store(parent_pid, pid) pidstr_ptr = builder.gep(pidstr, [zero_i32t], inbounds=True) pid_val = builder.load(pid) # call snprintf to write the pid into a char * stat = builder.call(snprintf, (pidstr_ptr, intp_t(12), intfmt, pid_val)) invalid_write = builder.icmp_signed('>', stat, int32_t(12)) with builder.if_then(invalid_write, likely=False): msg = "Internal error: `snprintf` buffer would have overflowed." cgctx.call_conv.return_user_exc(builder, RuntimeError, (msg, )) # fork, check pids etc child_pid = builder.call(fork, tuple()) fork_failed = builder.icmp_signed('==', child_pid, int32_t(-1)) with builder.if_then(fork_failed, likely=False): msg = "Internal error: `fork` failed." cgctx.call_conv.return_user_exc(builder, RuntimeError, (msg, )) is_child = builder.icmp_signed('==', child_pid, zero_i32t) with builder.if_else(is_child) as (then, orelse): with then: # is child nullptr = ir.Constant(char_ptr, None) gdb_str_ptr = builder.gep(gdb_str, [zero_i32t], inbounds=True) attach_str_ptr = builder.gep(attach_str, [zero_i32t], inbounds=True) cgutils.printf(builder, "Attaching to PID: %s\n", pidstr) buf = (gdb_str_ptr, gdb_str_ptr, attach_str_ptr, pidstr_ptr) buf = buf + tuple(cmdlang) + (nullptr, ) builder.call(execl, buf) with orelse: # is parent builder.call(sleep, (int32_t(10), )) # if breaking is desired, break now if do_break is True: builder.call(breakpoint, tuple())
def make_wrapper(fname, atypes, rtype, cres, target: TargetInfo, verbose=False): """Make wrapper function to numba compile result. The compilation result contains a function with prototype:: <status> <function name>(<rtype>** result, <arguments>) The make_wrapper adds a wrapper function to compilation result library with the following prototype:: <rtype> <fname>(<arguments>) or, if <rtype>.return_as_first_argument == True, then void <fname>(<rtype>* <arguments>) Parameters ---------- fname : str Function name. atypes : tuple A tuple of argument Numba types. rtype : numba.Type The return Numba type cres : CompileResult Numba compilation result. verbose: bool When True, insert printf statements for debugging errors. For CUDA target this feature is disabled. """ fndesc = cres.fndesc module = cres.library.create_ir_module(fndesc.unique_name) context = cres.target_context ll_argtypes = [context.get_value_type(ty) for ty in atypes] ll_return_type = context.get_value_type(rtype) return_as_first_argument = getattr(rtype, 'return_as_first_argument', False) assert isinstance(return_as_first_argument, bool) if return_as_first_argument: wrapty = ir.FunctionType(ir.VoidType(), [ll_return_type] + ll_argtypes) wrapfn = ir.Function(module, wrapty, fname) builder = ir.IRBuilder(wrapfn.append_basic_block('entry')) fnty = context.call_conv.get_function_type(rtype, atypes) fn = ir.Function(builder.module, fnty, cres.fndesc.llvm_func_name) status, out = context.call_conv.call_function(builder, fn, rtype, atypes, wrapfn.args[1:]) with cgutils.if_unlikely(builder, status.is_error): if verbose and target.is_cpu: cgutils.printf(builder, f"rbc: {fname} failed with status code %i\n", status.code) externals.stdio._cg_fflush(builder) builder.ret_void() builder.store(builder.load(out), wrapfn.args[0]) builder.ret_void() else: wrapty = ir.FunctionType(ll_return_type, ll_argtypes) wrapfn = ir.Function(module, wrapty, fname) builder = ir.IRBuilder(wrapfn.append_basic_block('entry')) fnty = context.call_conv.get_function_type(rtype, atypes) fn = ir.Function(builder.module, fnty, cres.fndesc.llvm_func_name) status, out = context.call_conv.call_function(builder, fn, rtype, atypes, wrapfn.args) if verbose and target.is_cpu: with cgutils.if_unlikely(builder, status.is_error): cgutils.printf(builder, f"rbc: {fname} failed with status code %i\n", status.code) externals.stdio._cg_fflush(builder) builder.ret(out) cres.library.add_ir_module(module)
def codegen(context, builder, signature, args): target_info = TargetInfo() if target_info.is_cpu: cgutils.printf(builder, format_type.literal_value, *args[1:]) _cg_fflush(builder)
def codegen(context, builder, signature, args): cgutils.printf(builder, format_type.literal_value, *args[1:])
def make_wrapper(fname, atypes, rtype, cres): """Make wrapper function to numba compile result. The compilation result contains a function with prototype:: <status> <function name>(<rtype>** result, <arguments>) The make_wrapper adds a wrapper function to compilation result library with the following prototype:: <rtype> <fname>(<arguments>) or, if <rtype> is Omnisci Array, then void <fname>(<rtype>* <arguments>) Parameters ---------- fname : str Function name. atypes : tuple A tuple of argument Numba types. rtype : numba.Type The return Numba type cres : CompileResult Numba compilation result. """ fndesc = cres.fndesc module = cres.library.create_ir_module(fndesc.unique_name) context = cres.target_context ll_argtypes = [context.get_value_type(ty) for ty in atypes] ll_return_type = context.get_value_type(rtype) # TODO: design a API for custom wrapping if type(rtype).__name__ == 'ArrayPointer': wrapty = ir.FunctionType(ir.VoidType(), [ll_return_type] + ll_argtypes) wrapfn = module.add_function(wrapty, fname) builder = ir.IRBuilder(wrapfn.append_basic_block('entry')) fnty = context.call_conv.get_function_type(rtype, atypes) fn = builder.module.add_function(fnty, cres.fndesc.llvm_func_name) status, out = context.call_conv.call_function(builder, fn, rtype, atypes, wrapfn.args[1:]) with cgutils.if_unlikely(builder, status.is_error): cgutils.printf(builder, f"rbc: {fname} failed with status code %i\n", status.code) builder.ret_void() builder.store(builder.load(out), wrapfn.args[0]) builder.ret_void() else: wrapty = ir.FunctionType(ll_return_type, ll_argtypes) wrapfn = module.add_function(wrapty, fname) builder = ir.IRBuilder(wrapfn.append_basic_block('entry')) fnty = context.call_conv.get_function_type(rtype, atypes) fn = builder.module.add_function(fnty, cres.fndesc.llvm_func_name) status, out = context.call_conv.call_function(builder, fn, rtype, atypes, wrapfn.args) with cgutils.if_unlikely(builder, status.is_error): cgutils.printf(builder, f"rbc: {fname} failed with status code %i\n", status.code) builder.ret(out) cres.library.add_ir_module(module)