From 89c8244d6106d9c16334d019b636c077aadaaa89 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 13 Nov 2022 15:01:15 +0000 Subject: [PATCH] Serialise JIT IRs for debugging --- src/array.h | 10 ++++-- src/jit/jit-core.c | 59 +++++++++++++++++++++++++++++- src/jit/jit-exits.c | 7 ++-- src/jit/jit-llvm.c | 88 +++++++++++++++++++++++++++++++++++++++++++-- src/jit/jit-priv.h | 13 ++++++- 5 files changed, 167 insertions(+), 10 deletions(-) diff --git a/src/array.h b/src/array.h index 9ef145c8..f3f07b89 100644 --- a/src/array.h +++ b/src/array.h @@ -119,10 +119,14 @@ void __array_resize_slow(void **ptr, uint32_t *limit, uint32_t count, (a).items[(a).count++] = (item); \ } while (0) -#define ARESIZE(a, newsize) do { \ - if ((unsigned)(newsize) > (a).limit) \ +#define ARESERVE(a, newmax) do { \ + if ((unsigned)(newmax) > (a).limit) \ __array_resize_slow((void **)&((a).items), &((a).limit), \ - (newsize), sizeof((a).items[0])); \ + (newmax), sizeof((a).items[0])); \ + } while (0) + +#define ARESIZE(a, newsize) do { \ + ARESERVE((a), (newsize)); \ (a).count = (newsize); \ } while (0) diff --git a/src/jit/jit-core.c b/src/jit/jit-core.c index 6d173fa3..bc0435f0 100644 --- a/src/jit/jit-core.c +++ b/src/jit/jit-core.c @@ -240,7 +240,8 @@ jit_handle_t jit_compile(jit_t *j, ident_t name) return handle; } -void jit_register(jit_t *j, const char *name, jit_entry_fn_t fn) +void jit_register(jit_t *j, const char *name, jit_entry_fn_t fn, + const uint8_t *debug, size_t bufsz) { jit_func_t *f = hash_get(j->index, name); if (f != NULL) @@ -255,6 +256,62 @@ void jit_register(jit_t *j, const char *name, jit_entry_fn_t fn) f->next_tier = j->tiers; f->hotness = f->next_tier ? f->next_tier->threshold : 0; f->entry = fn; + f->irbuf = xcalloc_array(bufsz, sizeof(jit_ir_t)); + f->nirs = bufsz; + + for (int i = 0; i < bufsz; i++) { + jit_ir_t *ir = &(f->irbuf[i]); + ir->op = J_TRAP; + ir->size = JIT_SZ_UNSPEC; + ir->result = JIT_REG_INVALID; + ir->arg1.kind = JIT_VALUE_INVALID; + ir->arg2.kind = JIT_VALUE_INVALID; + } + + char *file LOCAL = NULL; + loc_file_ref_t file_ref = FILE_INVALID; + int pos = 0, lineno; + for (const uint8_t *cmd = debug; *cmd >> 4 != DC_STOP; cmd++) { + jit_ir_t *ir = &(f->irbuf[pos]); + + switch (*cmd >> 4) { + case DC_TRAP: + pos += *cmd & 0xf; + break; + case DC_LONG_TRAP: + pos += *(cmd + 1) | *(cmd + 2) << 8; + cmd += 2; + break; + case DC_TARGET: + ir->target = 1; + break; + case DC_LOCINFO: + lineno = *cmd & 0xf; + ir->op = J_DEBUG; + ir->arg1.kind = JIT_VALUE_LOC; + ir->arg1.loc = get_loc(lineno, 0, lineno, 0, file_ref); + pos++; + break; + case DC_LONG_LOCINFO: + lineno = *(cmd + 1) | *(cmd + 2) << 8; + ir->op = J_DEBUG; + ir->arg1.kind = JIT_VALUE_LOC; + ir->arg1.loc = get_loc(lineno, 0, lineno, 0, file_ref); + pos++; + cmd += 2; + break; + case DC_FILE: + { + char *p = file = xmalloc(1 << (*cmd & 0xf)); + do { *p++ = *++cmd; } while (*cmd); + file_ref = loc_file_ref(file, NULL); + } + break; + default: + fatal_trace("unhandled debug command %x", *cmd); + } + } + assert(pos == bufsz); if (f->unit) hash_put(j->index, f->unit, f); hash_put(j->index, f->name, f); diff --git a/src/jit/jit-exits.c b/src/jit/jit-exits.c index ede575a1..de0fc05a 100644 --- a/src/jit/jit-exits.c +++ b/src/jit/jit-exits.c @@ -1474,12 +1474,13 @@ void __nvc_setup_toggle_cb(sig_shared_t *ss, int32_t* toggle_mask) } DLLEXPORT -void __nvc_register(const char *name, jit_entry_fn_t fn) +void __nvc_register(const char *name, jit_entry_fn_t fn, const uint8_t *debug, + int32_t bufsz) { - printf("register! name=%s fn=%p\n", name, fn); + printf("register! name=%s fn=%p bufsz=%d\n", name, fn, bufsz); jit_t *j = jit_thread_local()->jit; - jit_register(j, name, fn); + jit_register(j, name, fn, debug, bufsz); } DLLEXPORT diff --git a/src/jit/jit-llvm.c b/src/jit/jit-llvm.c index 22d3ff5d..e51da831 100644 --- a/src/jit/jit-llvm.c +++ b/src/jit/jit-llvm.c @@ -16,6 +16,7 @@ // #include "util.h" +#include "array.h" #include "hash.h" #include "ident.h" #include "jit/jit-llvm.h" @@ -602,7 +603,9 @@ static LLVMValueRef llvm_get_fn(llvm_obj_t *obj, llvm_fn_t which) { LLVMTypeRef args[] = { obj->types[LLVM_PTR], - obj->types[LLVM_PTR] + obj->types[LLVM_PTR], + obj->types[LLVM_PTR], + obj->types[LLVM_INT32], }; obj->fntypes[which] = LLVMFunctionType(obj->types[LLVM_VOID], args, ARRAY_LEN(args), false); @@ -1688,6 +1691,85 @@ static void cgen_frame_anchor(llvm_obj_t *obj, cgen_func_t *func) LLVMBuildStore(obj->builder, llvm_int32(obj, 0), irpos_ptr); } +static LLVMValueRef cgen_debug_irbuf(llvm_obj_t *obj, jit_func_t *f) +{ + LOCAL_TEXT_BUF tb = tb_new(); + tb_istr(tb, f->name); + tb_cat(tb, ".debug"); + + int run = 0, lineno = 0; + const char *file = NULL; + + SCOPED_A(LLVMValueRef) enc = AINIT; + ARESERVE(enc, MIN(f->nirs + 100, 1024)); + + for (int i = 0; i < f->nirs; i++) { + jit_ir_t *ir = &(f->irbuf[i]); + if ((ir->target || ir->op == J_DEBUG) && run > 0) { + if (run < 16) + APUSH(enc, llvm_int8(obj, (DC_TRAP << 4) | run)); + else { + APUSH(enc, llvm_int8(obj, DC_LONG_TRAP << 4)); + APUSH(enc, llvm_int8(obj, run & 0xff)); + APUSH(enc, llvm_int8(obj, (run >> 8) & 0xff)); + } + run = 0; + } + + if (ir->target) + APUSH(enc, llvm_int8(obj, DC_TARGET << 4)); + + if (ir->op == J_DEBUG) { + if (file == NULL) { + file = loc_file_str(&ir->arg1.loc); + lineno = 0; + const int len2 = ilog2(strlen(file) + 1); + assert(len2 < 16); + APUSH(enc, llvm_int8(obj, (DC_FILE << 4) | len2)); + + const char *p = file; + do { + APUSH(enc, llvm_int8(obj, *p)); + } while (*p++); + } + + const int delta = ir->arg1.loc.first_line - lineno; + if (delta >= 0 && delta < 16) + APUSH(enc, llvm_int8(obj, (DC_LOCINFO << 4) | delta)); + else { + APUSH(enc, llvm_int8(obj, DC_LONG_LOCINFO << 4)); + APUSH(enc, llvm_int8(obj, ir->arg1.loc.first_line & 0xff)); + APUSH(enc, llvm_int8(obj, (ir->arg1.loc.first_line >> 8) & 0xff)); + } + } + else + run++; + } + + if (run > 0 && run < 16) + APUSH(enc, llvm_int8(obj, (DC_TRAP << 4) | run)); + else if (run > 0) { + APUSH(enc, llvm_int8(obj, DC_LONG_TRAP << 4)); + APUSH(enc, llvm_int8(obj, run & 0xff)); + APUSH(enc, llvm_int8(obj, (run >> 8) & 0xff)); + } + + APUSH(enc, llvm_int8(obj, DC_STOP << 4)); + + LLVMTypeRef array_type = LLVMArrayType(obj->types[LLVM_INT8], enc.count); + + LLVMValueRef global = LLVMAddGlobal(obj->module, array_type, tb_get(tb)); + LLVMSetLinkage(global, LLVMPrivateLinkage); + LLVMSetGlobalConstant(global, true); + LLVMSetUnnamedAddr(global, true); + + LLVMValueRef init = + LLVMConstArray(obj->types[LLVM_INT8], enc.items, enc.count); + LLVMSetInitializer(global, init); + + return global; +} + static void cgen_function(llvm_obj_t *obj, cgen_func_t *func) { func->llvmfn = LLVMAddFunction(obj->module, func->name, @@ -1698,7 +1780,9 @@ static void cgen_function(llvm_obj_t *obj, cgen_func_t *func) LLVMValueRef args[] = { llvm_const_string(obj, func->name), - PTR(func->llvmfn) + PTR(func->llvmfn), + PTR(cgen_debug_irbuf(obj, func->source)), + llvm_int32(obj, func->source->nirs), }; llvm_call_fn(obj, LLVM_REGISTER, args, ARRAY_LEN(args)); diff --git a/src/jit/jit-priv.h b/src/jit/jit-priv.h index 43fdcc84..33acb7cb 100644 --- a/src/jit/jit-priv.h +++ b/src/jit/jit-priv.h @@ -278,6 +278,16 @@ typedef struct { typedef struct _jit_interp jit_interp_t; +typedef enum { + DC_TRAP, + DC_LONG_TRAP, + DC_STOP, + DC_LOCINFO, + DC_TARGET, + DC_FILE, + DC_LONG_LOCINFO, +} debug_cmd_t; + void jit_irgen(jit_func_t *f); void jit_dump(jit_func_t *f); void jit_dump_with_mark(jit_func_t *f, jit_label_t label, bool cpool); @@ -294,7 +304,8 @@ bool jit_has_runtime(jit_t *j); int jit_backedge_limit(jit_t *j); void jit_tier_up(jit_func_t *f); jit_thread_local_t *jit_thread_local(void); -void jit_register(jit_t *j, const char *name, jit_entry_fn_t fn); +void jit_register(jit_t *j, const char *name, jit_entry_fn_t fn, + const uint8_t *debug, size_t bufsz); jit_cfg_t *jit_get_cfg(jit_func_t *f); void jit_free_cfg(jit_func_t *f); -- 2.39.2