From 2214be934e50cbd53192574568ced5b0130cf2a2 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 28 Nov 2022 20:47:53 +0000 Subject: [PATCH] Generate debug info in LLVM JIT backend --- src/jit/jit-core.c | 11 +--- src/jit/jit-exits.c | 3 +- src/jit/jit-llvm.c | 130 +++++++++++++++++++++++++++++++++++++------- src/jit/jit.h | 1 - src/rt/model.c | 9 +-- 5 files changed, 116 insertions(+), 38 deletions(-) diff --git a/src/jit/jit-core.c b/src/jit/jit-core.c index 1ba79eb8..9888dfcf 100644 --- a/src/jit/jit-core.c +++ b/src/jit/jit-core.c @@ -263,6 +263,7 @@ void jit_register(jit_t *j, ident_t name, jit_entry_fn_t fn, f->irbuf = xcalloc_array(bufsz, sizeof(jit_ir_t)); f->nirs = bufsz; f->object = obj; + f->spec = spec; for (int i = 0; i < bufsz; i++) { jit_ir_t *ir = &(f->irbuf[i]); @@ -571,7 +572,7 @@ bool jit_fastcall(jit_t *j, jit_handle_t handle, jit_scalar_t *result, jit_transition(j, f->symbol ? JIT_NATIVE : JIT_INTERP, JIT_IDLE); thread->jmp_buf_valid = 0; thread->anchor = NULL; - jit_set_exit_status(j, rc - 1); + atomic_cas(&(j->exit_status), 0, rc - 1); return false; } } @@ -602,7 +603,7 @@ static bool jit_try_vcall(jit_t *j, jit_func_t *f, jit_scalar_t *result, *result = args[0]; } else { - jit_set_exit_status(j, rc - 1); + atomic_cas(&(j->exit_status), 0, rc - 1); failed = true; } @@ -962,12 +963,6 @@ void jit_abort(int code) __builtin_unreachable(); } -void jit_set_exit_status(jit_t *j, int code) -{ - // Only allow one thread to set exit status - atomic_cas(&(j->exit_status), 0, code); -} - void jit_reset_exit_status(jit_t *j) { atomic_store(&(j->exit_status), 0); diff --git a/src/jit/jit-exits.c b/src/jit/jit-exits.c index 29c41979..a34d9831 100644 --- a/src/jit/jit-exits.c +++ b/src/jit/jit-exits.c @@ -1445,7 +1445,8 @@ jit_handle_t __nvc_get_handle(const char *func, ffi_spec_t spec) if (handle == JIT_HANDLE_INVALID) fatal_trace("missing function %s", func); - jit_get_func(j, handle)->spec = spec; // XXXX: delete me + if (spec != ~UINT64_C(0)) + jit_get_func(j, handle)->spec = spec; // XXXX: delete me return handle; } diff --git a/src/jit/jit-llvm.c b/src/jit/jit-llvm.c index 02cdc5f9..a82b054e 100644 --- a/src/jit/jit-llvm.c +++ b/src/jit/jit-llvm.c @@ -28,6 +28,7 @@ #include "thread.h" #include +#include #include #include #include @@ -122,18 +123,21 @@ typedef enum { typedef struct _cgen_func cgen_func_t; typedef struct _cgen_block cgen_block_t; -#define CTOR_MAX_ORDER 2 +#define DEBUG_METADATA_VERSION 3 +#define CTOR_MAX_ORDER 2 typedef struct _llvm_obj { LLVMModuleRef module; LLVMContextRef context; LLVMTargetMachineRef target; LLVMBuilderRef builder; + LLVMDIBuilderRef debuginfo; LLVMTargetDataRef data_ref; LLVMTypeRef types[LLVM_LAST_TYPE]; LLVMValueRef fns[LLVM_LAST_FN]; LLVMTypeRef fntypes[LLVM_LAST_FN]; LLVMValueRef ctor[CTOR_MAX_ORDER]; + LLVMMetadataRef debugcu; shash_t *string_pool; } llvm_obj_t; @@ -148,15 +152,17 @@ typedef struct _cgen_block { } cgen_block_t; typedef struct _cgen_func { - LLVMValueRef llvmfn; - LLVMValueRef args; - LLVMValueRef frame; - LLVMValueRef anchor; - LLVMValueRef cpool; - cgen_block_t *blocks; - jit_func_t *source; - jit_cfg_t *cfg; - char *name; + LLVMValueRef llvmfn; + LLVMValueRef args; + LLVMValueRef frame; + LLVMValueRef anchor; + LLVMValueRef cpool; + LLVMMetadataRef debugmd; + cgen_block_t *blocks; + jit_func_t *source; + jit_cfg_t *cfg; + char *name; + loc_t last_loc; } cgen_func_t; #define LLVM_CHECK(op, ...) do { \ @@ -334,6 +340,8 @@ static void llvm_optimise(LLVMModuleRef module) static void llvm_finalise(llvm_obj_t *obj) { + LLVMDIBuilderFinalize(obj->debuginfo); + llvm_dump_module(obj->module, "initial"); llvm_verify_module(obj->module); llvm_optimise(obj->module); @@ -727,6 +735,13 @@ static LLVMValueRef llvm_const_string(llvm_obj_t *obj, const char *str) #endif } +static void llvm_add_module_flag(llvm_obj_t *obj, const char *key, int value) +{ + LLVMAddModuleFlag(obj->module, LLVMModuleFlagBehaviorWarning, + key, strlen(key), + LLVMValueAsMetadata(llvm_int32(obj, value))); +} + //////////////////////////////////////////////////////////////////////////////// // JIT IR to LLVM lowering @@ -847,7 +862,7 @@ static LLVMValueRef cgen_rematerialise_handle(llvm_obj_t *obj, LLVMValueRef args[] = { llvm_const_string(obj, istr(name)), - llvm_int64(obj, jit_get_func(cgb->func->source->jit, handle)->spec), + llvm_int64(obj, ~UINT64_C(0)), }; LLVMValueRef init = llvm_call_fn(obj, LLVM_GET_HANDLE, args, ARRAY_LEN(args)); @@ -1041,6 +1056,23 @@ static void cgen_sync_irpos(llvm_obj_t *obj, cgen_block_t *cgb, jit_ir_t *ir) LLVMBuildStore(obj->builder, llvm_int32(obj, irpos), irpos_ptr); } +static void cgen_debug_loc(llvm_obj_t *obj, cgen_func_t *func, const loc_t *loc) +{ + if (loc_eq(loc, &(func->last_loc))) + return; + + LLVMMetadataRef dloc = LLVMDIBuilderCreateDebugLocation( + obj->context, loc->first_line, loc->first_column, + func->debugmd, NULL); + +#ifdef LLVM_HAVE_SET_CURRENT_DEBUG_LOCATION_2 + LLVMSetCurrentDebugLocation2(obj->builder, dloc); +#else + LLVMValueRef md = LLVMMetadataAsValue(obj->context, dloc); + LLVMSetCurrentDebugLocation(obj->builder, md); +#endif +} + static void cgen_op_recv(llvm_obj_t *obj, cgen_block_t *cgb, jit_ir_t *ir) { assert(ir->arg1.kind == JIT_VALUE_INT64); @@ -1714,8 +1746,6 @@ static void cgen_ir(llvm_obj_t *obj, cgen_block_t *cgb, jit_ir_t *ir) case J_CSEL: cgen_op_csel(obj, cgb, ir); break; - case J_DEBUG: - break; case J_CALL: cgen_op_call(obj, cgb, ir); break; @@ -1728,6 +1758,9 @@ static void cgen_ir(llvm_obj_t *obj, cgen_block_t *cgb, jit_ir_t *ir) case J_NEG: cgen_op_neg(obj, cgb, ir); break; + case J_DEBUG: + cgen_debug_loc(obj, cgb->func, &(ir->arg1.loc)); + break; case MACRO_EXP: cgen_macro_exp(obj, cgb, ir); break; @@ -1912,11 +1945,57 @@ static LLVMValueRef cgen_debug_irbuf(llvm_obj_t *obj, jit_func_t *f) return global; } +static LLVMMetadataRef cgen_debug_file(llvm_obj_t *obj, const loc_t *loc) +{ + const char *file_path = loc_file_str(loc); + + char *basec LOCAL = xstrdup(file_path); + char *dirc LOCAL = xstrdup(file_path); + + const char *file = basename(basec); + const size_t file_len = strlen(file); + + const char *dir = dirname(dirc); + const size_t dir_len = strlen(dir); + + return LLVMDIBuilderCreateFile(obj->debuginfo, file, file_len, dir, dir_len); +} + static void cgen_function(llvm_obj_t *obj, cgen_func_t *func) { func->llvmfn = LLVMAddFunction(obj->module, func->name, obj->types[LLVM_ENTRY_FN]); + LLVMMetadataRef file_ref = + cgen_debug_file(obj, &(func->source->object->loc)); + + if (obj->debugcu == NULL) { + obj->debugcu = LLVMDIBuilderCreateCompileUnit( + obj->debuginfo, LLVMDWARFSourceLanguageAda83, + file_ref, PACKAGE, sizeof(PACKAGE) - 1, + opt_get_int(OPT_OPTIMISE), "", 0, + 0, "", 0, + LLVMDWARFEmissionFull, 0, false, false +#if LLVM_CREATE_CU_HAS_SYSROOT + , "/", 1, "", 0 +#endif + ); + } + + LLVMMetadataRef dtype = LLVMDIBuilderCreateSubroutineType( + obj->debuginfo, file_ref, NULL, 0, 0); + const size_t namelen = strlen(func->name); + + func->debugmd = LLVMDIBuilderCreateFunction( + obj->debuginfo, obj->debugcu, func->name, namelen, + func->name, namelen, file_ref, + func->source->object->loc.first_line, dtype, true, true, + 1, 0, opt_get_int(OPT_OPTIMISE)); + + LLVMSetSubprogram(func->llvmfn, func->debugmd); + + cgen_debug_loc(obj, func, &(func->source->object->loc)); + if (obj->ctor[0] != NULL) { cgen_add_ctor(obj, 0); cgen_aot_cpool(obj, func); @@ -2107,9 +2186,10 @@ static void jit_llvm_cgen(jit_t *j, jit_handle_t handle, void *context) LOCAL_TEXT_BUF tb = tb_new(); tb_istr(tb, f->name); - obj.module = LLVMModuleCreateWithNameInContext(tb_get(tb), obj.context); - obj.builder = LLVMCreateBuilderInContext(obj.context); - obj.data_ref = LLVMCreateTargetDataLayout(obj.target); + obj.module = LLVMModuleCreateWithNameInContext(tb_get(tb), obj.context); + obj.builder = LLVMCreateBuilderInContext(obj.context); + obj.debuginfo = LLVMCreateDIBuilderDisallowUnresolved(obj.module); + obj.data_ref = LLVMCreateTargetDataLayout(obj.target); llvm_register_types(&obj); @@ -2177,11 +2257,12 @@ void jit_register_llvm_plugin(jit_t *j) llvm_obj_t *llvm_obj_new(const char *name) { llvm_obj_t *obj = xcalloc(sizeof(llvm_obj_t)); - obj->context = LLVMContextCreate(); - obj->module = LLVMModuleCreateWithNameInContext(name, obj->context); - obj->builder = LLVMCreateBuilderInContext(obj->context); - obj->target = llvm_target_machine(LLVMRelocPIC, LLVMCodeModelDefault); - obj->data_ref = LLVMCreateTargetDataLayout(obj->target); + obj->context = LLVMContextCreate(); + obj->module = LLVMModuleCreateWithNameInContext(name, obj->context); + obj->builder = LLVMCreateBuilderInContext(obj->context); + obj->target = llvm_target_machine(LLVMRelocPIC, LLVMCodeModelDefault); + obj->data_ref = LLVMCreateTargetDataLayout(obj->target); + obj->debuginfo = LLVMCreateDIBuilderDisallowUnresolved(obj->module); char *triple = LLVMGetTargetMachineTriple(obj->target); LLVMSetTarget(obj->module, triple); @@ -2191,6 +2272,13 @@ llvm_obj_t *llvm_obj_new(const char *name) llvm_register_types(obj); + llvm_add_module_flag(obj, "Debug Info Version", DEBUG_METADATA_VERSION); +#ifdef __APPLE__ + llvm_add_module_flag(obj, "Dwarf Version", 2); +#else + llvm_add_module_flag(obj, "Dwarf Version", 4); +#endif + LLVMValueRef ctors[CTOR_MAX_ORDER]; for (int i = 0; i < CTOR_MAX_ORDER; i++) { diff --git a/src/jit/jit.h b/src/jit/jit.h index 8a18a686..e0d8b84e 100644 --- a/src/jit/jit.h +++ b/src/jit/jit.h @@ -68,7 +68,6 @@ void jit_enable_runtime(jit_t *j, bool enable); mspace_t *jit_get_mspace(jit_t *j); void jit_load_dll(jit_t *j, ident_t name); int jit_exit_status(jit_t *j); -void jit_set_exit_status(jit_t *j, int code); void jit_reset_exit_status(jit_t *j); void jit_add_tier(jit_t *j, int threshold, const jit_plugin_t *plugin); ident_t jit_get_name(jit_t *j, jit_handle_t handle); diff --git a/src/rt/model.c b/src/rt/model.c index 5d92df22..1cdae8fe 100644 --- a/src/rt/model.c +++ b/src/rt/model.c @@ -2696,13 +2696,8 @@ void model_interrupt(rt_model_t *m) jit_msg(NULL, DIAG_FATAL, "interrupted in process %s at %s+%d", istr(active_proc->name), tmbuf, m->iteration); - else { - diag_t *d = diag_new(DIAG_FATAL, NULL); - diag_printf(d, "interrupted at %s+%d", tmbuf, m->iteration); - diag_emit(d); - - jit_set_exit_status(m->jit, EXIT_FAILURE); - } + else + jit_msg(NULL, DIAG_FATAL, "interrupted at %s+%d", tmbuf, m->iteration); } // TODO: this interface should be removed eventually -- 2.39.2