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_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 _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_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() 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 = 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 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 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())