From 4fef4bc6d5d6f6885b50320a41b1065649a5394b Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 23 Oct 2022 10:56:43 +0100 Subject: [PATCH] Improve accuracy of interpreter stack traces --- src/jit/jit-core.c | 237 ++++++++++++++++++++++-------------------- src/jit/jit-exits.c | 87 ++++++++++++++-- src/jit/jit-interp.c | 157 ++++------------------------ src/jit/jit-llvm.c | 4 +- src/jit/jit-priv.h | 36 +++++-- src/jit/jit.h | 3 + test/lower/array1.vhd | 5 +- test/test_jit.c | 20 ++-- 8 files changed, 277 insertions(+), 272 deletions(-) diff --git a/src/jit/jit-core.c b/src/jit/jit-core.c index ec68881a..0b61f0c5 100644 --- a/src/jit/jit-core.c +++ b/src/jit/jit-core.c @@ -22,6 +22,7 @@ #include "diag.h" #include "hash.h" #include "lib.h" +#include "jit/jit.h" #include "jit/jit-priv.h" #include "opt.h" #include "rt/model.h" @@ -34,8 +35,6 @@ #include #include #include -#include -#include #include #include #include @@ -73,19 +72,6 @@ typedef struct _jit { jit_dll_t *aotlib; } jit_t; -typedef enum { - JIT_IDLE, - JIT_NATIVE, - JIT_INTERP -} jit_state_t; - -typedef struct { - jit_t *jit; - jit_state_t state; - jmp_buf abort_env; - volatile sig_atomic_t jmp_buf_valid; -} jit_thread_local_t; - static void jit_oom_cb(mspace_t *m, size_t size) { diag_t *d = diag_new(DIAG_FATAL, NULL); @@ -100,7 +86,7 @@ static void jit_oom_cb(mspace_t *m, size_t size) jit_abort(EXIT_FAILURE); } -static jit_thread_local_t *jit_thread_local(void) +jit_thread_local_t *jit_thread_local(void) { static __thread jit_thread_local_t *local = NULL; @@ -236,6 +222,7 @@ jit_handle_t jit_lazy_compile(jit_t *j, ident_t name) jit_func_t *jit_get_func(jit_t *j, jit_handle_t handle) { + assert(handle != JIT_HANDLE_INVALID); return AGET(j->funcs, handle); } @@ -273,20 +260,20 @@ void *jit_link(jit_t *j, jit_handle_t handle) const loc_t *loc = vcode_unit_loc(); - jit_scalar_t args[JIT_MAX_ARGS] = { { .pointer = NULL } }; - if (!jit_interp(f, args)) { + jit_scalar_t p1 = { .pointer = NULL }, p2 = p1, result; + if (!jit_fastcall(j, f->handle, &result, p1, p2)) { error_at(loc, "failed to initialise %s", istr(f->name)); - args[0].pointer = NULL; + result.pointer = NULL; } - else if (args[0].pointer == NULL) + else if (result.pointer == NULL) fatal_trace("link %s returned NULL", istr(f->name)); vcode_state_restore(&state); // Initialisation should save the context pointer - assert(args[0].pointer == mptr_get(j->mspace, f->privdata)); + assert(result.pointer == mptr_get(j->mspace, f->privdata)); - return args[0].pointer; + return result.pointer; } void *jit_get_privdata(jit_t *j, jit_func_t *f) @@ -313,6 +300,41 @@ void *jit_get_frame_var(jit_t *j, jit_handle_t handle, uint32_t var) return (char *)mptr_get(j->mspace, f->privdata) + f->varoff[var]; } +static void jit_emit_trace(diag_t *d, const loc_t *loc, tree_t enclosing, + const char *symbol) +{ + switch (tree_kind(enclosing)) { + case T_PROCESS: + { + rt_proc_t *proc = get_active_proc(); + const char *name = istr(proc ? proc->name : tree_ident(enclosing)); + diag_trace(d, loc, "Process$$ %s", name); + } + break; + case T_FUNC_BODY: + case T_FUNC_DECL: + diag_trace(d, loc, "Function$$ %s", type_pp(tree_type(enclosing))); + break; + case T_PROC_BODY: + case T_PROC_DECL: + diag_trace(d, loc, "Procedure$$ %s", type_pp(tree_type(enclosing))); + break; + case T_TYPE_DECL: + if (strstr(symbol, "$value")) + diag_trace(d, loc, "Attribute$$ %s'VALUE", + istr(tree_ident(enclosing))); + else + diag_trace(d, loc, "Type$$ %s", istr(tree_ident(enclosing))); + break; + case T_BLOCK: + diag_trace(d, loc, "Process$$ (init)"); + break; + default: + diag_trace(d, loc, "$$%s", istr(tree_ident(enclosing))); + break; + } +} + static void jit_native_trace(diag_t *d) { assert(jit_thread_local()->state == JIT_NATIVE); @@ -360,6 +382,42 @@ static void jit_native_trace(diag_t *d) debug_free(di); } +static void jit_interp_trace(diag_t *d) +{ + for (jit_anchor_t *a = jit_thread_local()->anchor; a; a = a->caller) { + vcode_state_t state; + vcode_state_save(&state); + + vcode_select_unit(a->func->unit); + while (vcode_unit_context() != NULL) + vcode_select_unit(vcode_unit_context()); + + ident_t unit_name = vcode_unit_name(); + if (vcode_unit_kind() == VCODE_UNIT_INSTANCE) + unit_name = ident_prefix(unit_name, well_known(W_ELAB), '.'); + + vcode_state_restore(&state); + + const char *symbol = istr(a->func->name); + tree_t enclosing = find_enclosing_decl(unit_name, symbol); + if (enclosing == NULL) + return; + + // Scan backwards to find the last debug info + assert(a->irpos < a->func->nirs); + const loc_t *loc = NULL; + for (jit_ir_t *ir = &(a->func->irbuf[a->irpos]); + ir >= a->func->irbuf && !ir->target; ir--) { + if (ir->op == J_DEBUG) { + loc = &ir->arg1.loc; + break; + } + } + + jit_emit_trace(d, loc ?: tree_loc(enclosing), enclosing, symbol); + } +} + static void jit_diag_cb(diag_t *d, void *arg) { jit_t *j = arg; @@ -409,64 +467,41 @@ static void jit_transition(jit_t *j, jit_state_t from, jit_state_t to) } } -bool jit_call_thunk(jit_t *j, vcode_unit_t unit, jit_scalar_t *result) -{ - vcode_select_unit(unit); - assert(vcode_unit_kind() == VCODE_UNIT_THUNK); - - jit_func_t *f = xcalloc(sizeof(jit_func_t)); - f->unit = unit; - f->jit = j; - f->handle = JIT_HANDLE_INVALID; - f->entry = jit_interp; - - jit_irgen(f); - - jit_transition(j, JIT_IDLE, JIT_INTERP); - - jit_scalar_t args[JIT_MAX_ARGS]; - bool ok = jit_interp(f, args); - - jit_transition(j, JIT_INTERP, JIT_IDLE); - - jit_free_func(f); - - *result = args[0]; - return ok; -} - bool jit_fastcall(jit_t *j, jit_handle_t handle, jit_scalar_t *result, jit_scalar_t p1, jit_scalar_t p2) { jit_func_t *f = jit_get_func(j, handle); jit_thread_local_t *thread = jit_thread_local(); - if (f->symbol) { - assert(!thread->jmp_buf_valid); - const int rc = setjmp(thread->abort_env); - if (rc == 0) { - thread->jmp_buf_valid = 1; + assert(!thread->jmp_buf_valid); + const int rc = setjmp(thread->abort_env); + if (rc == 0) { + thread->jmp_buf_valid = 1; + + if (f->symbol) { jit_transition(j, JIT_IDLE, JIT_NATIVE); void *(*fn)(void *, void *) = f->symbol; result->pointer = (*fn)(p1.pointer, p2.pointer); jit_transition(j, JIT_NATIVE, JIT_IDLE); - thread->jmp_buf_valid = 0; - return true; } else { - jit_transition(j, JIT_NATIVE, JIT_IDLE); - thread->jmp_buf_valid = 0; - jit_set_exit_status(j, rc - 1); - return false; + jit_transition(j, JIT_IDLE, JIT_INTERP); + jit_scalar_t args[JIT_MAX_ARGS] = { p1, p2 }; + jit_interp(f, NULL, args); + *result = args[0]; + jit_transition(j, JIT_INTERP, JIT_IDLE); } + + thread->jmp_buf_valid = 0; + thread->anchor = NULL; + return true; } else { - jit_transition(j, JIT_IDLE, JIT_INTERP); - jit_scalar_t args[JIT_MAX_ARGS] = { p1, p2 }; - bool ok = jit_interp(f, args); - *result = args[0]; - jit_transition(j, JIT_INTERP, JIT_IDLE); - return ok; + 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); + return false; } } @@ -491,7 +526,7 @@ static bool jit_try_vcall(jit_t *j, jit_func_t *f, jit_scalar_t *result, jit_ffi_call(ff, args); } else - failed = !jit_interp(f, args); + jit_interp(f, NULL, args); *result = args[0]; } @@ -502,6 +537,7 @@ static bool jit_try_vcall(jit_t *j, jit_func_t *f, jit_scalar_t *result, jit_transition(j, newstate, oldstate); thread->jmp_buf_valid = 0; + thread->anchor = NULL; return !failed; } @@ -616,6 +652,26 @@ bool jit_try_call_packed(jit_t *j, jit_handle_t handle, jit_scalar_t context, return true; } +bool jit_call_thunk(jit_t *j, vcode_unit_t unit, jit_scalar_t *result) +{ + vcode_select_unit(unit); + assert(vcode_unit_kind() == VCODE_UNIT_THUNK); + + jit_func_t *f = xcalloc(sizeof(jit_func_t)); + f->unit = unit; + f->jit = j; + f->handle = JIT_HANDLE_INVALID; + f->entry = jit_interp; + + jit_irgen(f); + + jit_scalar_t args[JIT_MAX_ARGS]; + bool ok = jit_try_vcall(j, f, result, args); + + jit_free_func(f); + return ok; +} + void jit_set_lower_fn(jit_t *j, jit_lower_fn_t fn, void *ctx) { j->lower_fn = fn; @@ -796,42 +852,6 @@ void jit_load_dll(jit_t *j, ident_t name) so_path, abi_version, RT_ABI_VERSION); } -void jit_emit_trace(diag_t *d, const loc_t *loc, tree_t enclosing, - const char *symbol) -{ - switch (tree_kind(enclosing)) { - case T_PROCESS: - { - rt_proc_t *proc = get_active_proc(); - const char *name = istr(proc ? proc->name : tree_ident(enclosing)); - diag_trace(d, loc, "Process$$ %s", name); - } - break; - case T_FUNC_BODY: - case T_FUNC_DECL: - diag_trace(d, loc, "Function$$ %s", type_pp(tree_type(enclosing))); - break; - case T_PROC_BODY: - case T_PROC_DECL: - diag_trace(d, loc, "Procedure$$ %s", type_pp(tree_type(enclosing))); - break; - case T_TYPE_DECL: - if (strstr(symbol, "$value")) - diag_trace(d, loc, "Attribute$$ %s'VALUE", - istr(tree_ident(enclosing))); - else - diag_trace(d, loc, "Type$$ %s", istr(tree_ident(enclosing))); - break; - case T_BLOCK: - diag_trace(d, loc, "Process$$ (init)"); - break; - default: - diag_trace(d, loc, "$$%s", istr(tree_ident(enclosing))); - break; - } -} - -__attribute__((format(printf, 3, 4))) void jit_msg(const loc_t *where, diag_level_t level, const char *fmt, ...) { diag_t *d = diag_new(level, where); @@ -856,16 +876,16 @@ void jit_abort(int code) fatal_exit(code); break; case JIT_NATIVE: + case JIT_INTERP: assert(code >= 0); if (thread->jmp_buf_valid) longjmp(thread->abort_env, code + 1); else fatal_exit(code); break; - case JIT_INTERP: - jit_interp_abort(code); - break; } + + __builtin_unreachable(); } void jit_set_exit_status(jit_t *j, int code) @@ -906,13 +926,6 @@ void jit_add_tier(jit_t *j, int threshold, const jit_plugin_t *plugin) j->tiers = t; } -jit_t *jit_for_thread(void) -{ - jit_thread_local_t *thread = jit_thread_local(); - assert(thread->jit != NULL); - return thread->jit; -} - ident_t jit_get_name(jit_t *j, jit_handle_t handle) { return jit_get_func(j, handle)->name; diff --git a/src/jit/jit-exits.c b/src/jit/jit-exits.c index 2e1ce37b..6266b8e9 100644 --- a/src/jit/jit-exits.c +++ b/src/jit/jit-exits.c @@ -493,7 +493,7 @@ void *x_mspace_alloc(uint32_t size, uint32_t nelems) __builtin_unreachable(); } else - return mspace_alloc(jit_get_mspace(jit_for_thread()), total); + return mspace_alloc(jit_get_mspace(jit_thread_local()->jit), total); } void x_elab_order_fail(tree_t where) @@ -513,13 +513,36 @@ void x_unreachable(tree_t where) jit_msg(NULL, DIAG_FATAL, "executed unreachable instruction"); } +void x_func_wait(void) +{ + jit_msg(NULL, DIAG_FATAL, "cannot wait inside function call"); +} + //////////////////////////////////////////////////////////////////////////////// // Entry point from interpreter or JIT compiled code DLLEXPORT -void __nvc_do_exit(jit_exit_t which, jit_scalar_t *args) +void __nvc_do_exit(jit_exit_t which, jit_anchor_t *anchor, jit_scalar_t *args) { + jit_thread_local_t *thread = jit_thread_local(); + thread->anchor = anchor; + switch (which) { + case JIT_EXIT_ASSERT_FAIL: + { + uint8_t *msg = args[0].pointer; + int32_t len = args[1].integer; + int32_t severity = args[2].integer; + int64_t hint_left = args[3].integer; + int64_t hint_right = args[4].integer; + int8_t hint_valid = args[5].integer; + tree_t where = args[6].pointer; + + x_assert_fail(msg, len, severity, hint_left, hint_right, + hint_valid, where); + } + break; + case JIT_EXIT_MAP_SIGNAL: { sig_shared_t *src_ss = args[0].pointer; @@ -546,7 +569,7 @@ void __nvc_do_exit(jit_exit_t which, jit_scalar_t *args) { int64_t value = args[0].integer; - mspace_t *m = jit_get_mspace(jit_for_thread()); + mspace_t *m = jit_get_mspace(jit_thread_local()->jit); char *buf = mspace_alloc(m, 20); if (buf == NULL) return; @@ -604,7 +627,7 @@ void __nvc_do_exit(jit_exit_t which, jit_scalar_t *args) case JIT_EXIT_PUSH_SCOPE: { - if (!jit_has_runtime(jit_for_thread())) + if (!jit_has_runtime(jit_thread_local()->jit)) return; // Called during constant folding tree_t where = args[0].pointer; @@ -616,15 +639,67 @@ void __nvc_do_exit(jit_exit_t which, jit_scalar_t *args) case JIT_EXIT_POP_SCOPE: { - if (!jit_has_runtime(jit_for_thread())) + if (!jit_has_runtime(jit_thread_local()->jit)) return; // Called during constant folding x_pop_scope(); } break; + + case JIT_EXIT_FUNC_WAIT: + { + x_func_wait(); + } + break; + + case JIT_EXIT_CANON_VALUE: + { + uint8_t *ptr = args[0].pointer; + int32_t len = args[1].integer; + + char *buf = mspace_alloc(jit_get_mspace(jit_thread_local()->jit), len); + if (buf == NULL) + return; + + ffi_uarray_t u = x_canon_value(ptr, len, buf); + args[0].pointer = u.ptr; + args[1].integer = u.dims[0].left; + args[2].integer = u.dims[0].length; + } + break; + + case JIT_EXIT_STRING_TO_INT: + { + uint8_t *ptr = args[0].pointer; + int32_t len = args[1].integer; + int32_t *used = args[2].pointer; + + args[0].integer = x_string_to_int(ptr, len, used); + } + break; + + case JIT_EXIT_STRING_TO_REAL: + { + uint8_t *ptr = args[0].pointer; + int32_t len = args[1].integer; + + args[0].real = x_string_to_real(ptr, len); + } + break; + + case JIT_EXIT_DIV_ZERO: + { + tree_t where = args[0].pointer; + + x_div_zero(where); + } + break; + default: fatal_trace("unhandled exit %s", jit_exit_name(which)); } + + thread->anchor = NULL; } //////////////////////////////////////////////////////////////////////////////// @@ -995,7 +1070,7 @@ void *__nvc_mspace_alloc(uint32_t size, uint32_t nelems) DLLEXPORT jit_handle_t __nvc_get_handle(const char *func, ffi_spec_t spec) { - jit_t *j = jit_for_thread(); + jit_t *j = jit_thread_local()->jit; jit_handle_t handle = jit_lazy_compile(j, ident_new(func)); if (handle == JIT_HANDLE_INVALID) diff --git a/src/jit/jit-interp.c b/src/jit/jit-interp.c index 6c79b603..a4091b1a 100644 --- a/src/jit/jit-interp.c +++ b/src/jit/jit-interp.c @@ -45,7 +45,7 @@ typedef struct _jit_interp { bool abort; mspace_t *mspace; unsigned backedge; - jit_interp_t *caller; + jit_anchor_t *anchor; } jit_interp_t; #ifdef DEBUG @@ -72,8 +72,6 @@ typedef struct _jit_interp { #define BOUNDED_LIMIT 10000 // Max backedges in bounded mode -static __thread jit_interp_t *call_stack = NULL; - static void interp_dump_reg(jit_interp_t *state, int64_t ival) { printf("%"PRIx64, ival); @@ -176,34 +174,6 @@ static jit_scalar_t interp_get_value(jit_interp_t *state, jit_value_t value) } } -void jit_interp_trace(diag_t *d) -{ - for (jit_interp_t *p = call_stack; p != NULL; p = p->caller) { - vcode_state_t state; - vcode_state_save(&state); - - vcode_select_unit(p->func->unit); - while (vcode_unit_context() != NULL) - vcode_select_unit(vcode_unit_context()); - - ident_t unit_name = vcode_unit_name(); - if (vcode_unit_kind() == VCODE_UNIT_INSTANCE) - unit_name = ident_prefix(unit_name, well_known(W_ELAB), '.'); - - vcode_state_restore(&state); - - const char *symbol = istr(p->func->name); - tree_t enclosing = find_enclosing_decl(unit_name, symbol); - if (enclosing == NULL) - return; - - // TODO: this is much less accurate than the DWARF info - const loc_t *loc = tree_loc(enclosing); - - jit_emit_trace(d, loc, enclosing, symbol); - } -} - __attribute__((format(printf, 3, 4))) static void interp_error(jit_interp_t *state, const loc_t *loc, const char *fmt, ...) @@ -625,12 +595,13 @@ static void interp_call(jit_interp_t *state, jit_ir_t *ir) { JIT_ASSERT(ir->arg1.kind == JIT_VALUE_HANDLE); + state->anchor->irpos = ir - state->func->irbuf; + if (ir->arg1.handle == JIT_HANDLE_INVALID) - state->abort = true; + jit_msg(NULL, DIAG_FATAL, "missing definition for subprogram"); else { jit_func_t *f = jit_get_func(state->func->jit, ir->arg1.handle); - if (!(*f->entry)(f, state->args)) - state->abort = true; + (*f->entry)(f, state->anchor, state->args); } } @@ -716,11 +687,16 @@ static void interp_bzero(jit_interp_t *state, jit_ir_t *ir) static void interp_galloc(jit_interp_t *state, jit_ir_t *ir) { + jit_thread_local_t *thread = jit_thread_local(); + thread->anchor = state->anchor; + const size_t bytes = interp_get_value(state, ir->arg1).integer; state->regs[ir->result].pointer = mspace_alloc(state->mspace, bytes); if (state->regs[ir->result].pointer == NULL && bytes > 0) state->abort = true; // Out of memory + + thread->anchor = NULL; } static void interp_range_fail(jit_interp_t *state) @@ -773,13 +749,6 @@ static void interp_length_fail(jit_interp_t *state) x_length_fail(left, right, dim, where); } -static void interp_div_zero(jit_interp_t *state) -{ - tree_t where = state->args[0].pointer; - - x_div_zero(where); -} - static void interp_exponent_fail(jit_interp_t *state) { int32_t value = state->args[0].integer; @@ -795,11 +764,6 @@ static void interp_unreachable(jit_interp_t *state) x_unreachable(where); } -static void interp_func_wait(jit_interp_t *state) -{ - interp_error(state, NULL, "cannot wait inside function call"); -} - static void interp_report(jit_interp_t *state) { uint8_t *msg = state->args[0].pointer; @@ -810,19 +774,6 @@ static void interp_report(jit_interp_t *state) x_report(msg, len, severity, where); } -static void interp_assert_fail(jit_interp_t *state) -{ - uint8_t *msg = state->args[0].pointer; - int32_t len = state->args[1].integer; - int32_t severity = state->args[2].integer; - int64_t hint_left = state->args[3].integer; - int64_t hint_right = state->args[4].integer; - int8_t hint_valid = state->args[5].integer; - tree_t where = state->args[6].pointer; - - x_assert_fail(msg, len, severity, hint_left, hint_right, hint_valid, where); -} - static void interp_scalar_init_signal(jit_interp_t *state) { int32_t count = state->args[0].integer; @@ -961,25 +912,6 @@ static void interp_endfile(jit_interp_t *state) state->nargs = 1; } -static void interp_string_to_int(jit_interp_t *state) -{ - uint8_t *ptr = state->args[0].pointer; - int32_t len = state->args[1].integer; - int32_t *used = state->args[2].pointer; - - state->args[0].integer = x_string_to_int(ptr, len, used); - state->nargs = 1; -} - -static void interp_string_to_real(jit_interp_t *state) -{ - uint8_t *ptr = state->args[0].pointer; - int32_t len = state->args[1].integer; - - state->args[0].real = x_string_to_real(ptr, len); - state->nargs = 1; -} - static void interp_real_to_string(jit_interp_t *state) { double value = state->args[0].real; @@ -995,22 +927,6 @@ static void interp_real_to_string(jit_interp_t *state) state->nargs = 3; } -static void interp_canon_value(jit_interp_t *state) -{ - uint8_t *ptr = state->args[0].pointer; - int32_t len = state->args[1].integer; - - char *buf = mspace_alloc(state->mspace, len); - if (buf == NULL) - return; - - ffi_uarray_t u = x_canon_value(ptr, len, buf); - state->args[0].pointer = u.ptr; - state->args[1].integer = u.dims[0].left; - state->args[2].integer = u.dims[0].length; - state->nargs = 3; -} - static void interp_debug_out(jit_interp_t *state) { int64_t value = state->args[0].integer; @@ -1075,6 +991,8 @@ static void interp_last_active(jit_interp_t *state) static void interp_exit(jit_interp_t *state, jit_ir_t *ir) { + state->anchor->irpos = ir - state->func->irbuf; + switch (ir->arg1.exit) { case JIT_EXIT_INDEX_FAIL: interp_index_fail(state); @@ -1096,10 +1014,6 @@ static void interp_exit(jit_interp_t *state, jit_ir_t *ir) interp_unreachable(state); break; - case JIT_EXIT_DIV_ZERO: - interp_div_zero(state); - break; - case JIT_EXIT_EXPONENT_FAIL: interp_exponent_fail(state); break; @@ -1108,10 +1022,6 @@ static void interp_exit(jit_interp_t *state, jit_ir_t *ir) interp_report(state); break; - case JIT_EXIT_ASSERT_FAIL: - interp_assert_fail(state); - break; - case JIT_EXIT_REAL_TO_STRING: interp_real_to_string(state); break; @@ -1120,10 +1030,6 @@ static void interp_exit(jit_interp_t *state, jit_ir_t *ir) interp_range_fail(state); break; - case JIT_EXIT_FUNC_WAIT: - interp_func_wait(state); - break; - case JIT_EXIT_INIT_SIGNAL: interp_scalar_init_signal(state); break; @@ -1172,18 +1078,6 @@ static void interp_exit(jit_interp_t *state, jit_ir_t *ir) interp_endfile(state); break; - case JIT_EXIT_STRING_TO_INT: - interp_string_to_int(state); - break; - - case JIT_EXIT_STRING_TO_REAL: - interp_string_to_real(state); - break; - - case JIT_EXIT_CANON_VALUE: - interp_canon_value(state); - break; - case JIT_EXIT_DEBUG_OUT: interp_debug_out(state); break; @@ -1209,7 +1103,7 @@ static void interp_exit(jit_interp_t *state, jit_ir_t *ir) break; default: - __nvc_do_exit(ir->arg1.exit, state->args); + __nvc_do_exit(ir->arg1.exit, state->anchor, state->args); } } @@ -1372,12 +1266,12 @@ static void interp_loop(jit_interp_t *state) } while (!state->abort); } -bool jit_interp(jit_func_t *f, jit_scalar_t *args) +void jit_interp(jit_func_t *f, jit_anchor_t *caller, jit_scalar_t *args) { if (f->entry != jit_interp) { // Came from stale compiled code // TODO: should we patch the call site? - return (*f->entry)(f, args); + (*f->entry)(f, caller, args); } if (f->irbuf == NULL) @@ -1386,6 +1280,11 @@ bool jit_interp(jit_func_t *f, jit_scalar_t *args) if (f->next_tier && --(f->hotness) <= 0) jit_tier_up(f); + jit_anchor_t anchor = { + .caller = caller, + .func = f, + }; + // Using VLAs here as we need these allocated on the stack so the // mspace GC can scan them jit_scalar_t regs[f->nregs]; @@ -1405,22 +1304,8 @@ bool jit_interp(jit_func_t *f, jit_scalar_t *args) .frame = frame, .mspace = jit_get_mspace(f->jit), .backedge = jit_backedge_limit(f->jit), - .caller = call_stack, + .anchor = &anchor, }; - call_stack = &state; - interp_loop(&state); - - assert(call_stack == &state); - call_stack = state.caller; - - return !state.abort; -} - -void jit_interp_abort(int code) -{ - assert(call_stack != NULL); - call_stack->abort = true; - jit_set_exit_status(call_stack->func->jit, code); } diff --git a/src/jit/jit-llvm.c b/src/jit/jit-llvm.c index a5c9eaf0..d0c16a36 100644 --- a/src/jit/jit-llvm.c +++ b/src/jit/jit-llvm.c @@ -621,7 +621,7 @@ static void cgen_op_mul(cgen_req_t *req, cgen_block_t *cgb, jit_ir_t *ir) static void cgen_op_ret(cgen_req_t *req, jit_ir_t *ir) { - LLVMBuildRet(req->builder, llvm_int1(req, true)); + LLVMBuildRetVoid(req->builder); } static void cgen_op_jump(cgen_req_t *req, cgen_block_t *cgb, jit_ir_t *ir) @@ -1008,7 +1008,7 @@ static void cgen_module(cgen_req_t *req) req->types[LLVM_INTPTR] = LLVMIntPtrTypeInContext(req->context, data_ref); LLVMTypeRef atypes[] = { req->types[LLVM_PTR], req->types[LLVM_PTR] }; - req->types[LLVM_ENTRY_FN] = LLVMFunctionType(req->types[LLVM_INT1], atypes, + req->types[LLVM_ENTRY_FN] = LLVMFunctionType(req->types[LLVM_VOID], atypes, ARRAY_LEN(atypes), false); req->llvmfn = LLVMAddFunction(req->module, req->name, diff --git a/src/jit/jit-priv.h b/src/jit/jit-priv.h index 5d445440..7d7d33fa 100644 --- a/src/jit/jit-priv.h +++ b/src/jit/jit-priv.h @@ -24,6 +24,9 @@ #include "mask.h" #include "rt/mspace.h" +#include +#include + typedef enum { J_SEND, J_RECV, @@ -192,8 +195,9 @@ STATIC_ASSERT(sizeof(jit_ir_t) == 40); typedef struct _jit_tier jit_tier_t; typedef struct _jit_func jit_func_t; typedef struct _jit_block jit_block_t; +typedef struct _jit_anchor jit_anchor_t; -typedef bool (*jit_entry_fn_t)(jit_func_t *, jit_scalar_t *); +typedef void (*jit_entry_fn_t)(jit_func_t *, jit_anchor_t *, jit_scalar_t *); typedef struct { unsigned count; @@ -240,6 +244,26 @@ typedef struct _jit_func { ffi_spec_t spec; } jit_func_t; +typedef struct _jit_anchor { + jit_anchor_t *caller; + jit_func_t *func; + unsigned irpos; +} jit_anchor_t; + +typedef enum { + JIT_IDLE, + JIT_NATIVE, + JIT_INTERP +} jit_state_t; + +typedef struct { + jit_t *jit; + jit_state_t state; + jmp_buf abort_env; + volatile sig_atomic_t jmp_buf_valid; + jit_anchor_t *anchor; +} jit_thread_local_t; + #define JIT_MAX_ARGS 64 typedef struct _jit_interp jit_interp_t; @@ -250,11 +274,7 @@ void jit_dump_with_mark(jit_func_t *f, jit_label_t label, bool cpool); void jit_dump_interleaved(jit_func_t *f); const char *jit_op_name(jit_op_t op); const char *jit_exit_name(jit_exit_t exit); -bool jit_interp(jit_func_t *f, jit_scalar_t *args); -void jit_interp_abort(int code); -void jit_interp_trace(diag_t *d); -void jit_emit_trace(diag_t *d, const loc_t *loc, tree_t enclosing, - const char *symbol); +void jit_interp(jit_func_t *f, jit_anchor_t *caller, jit_scalar_t *args); jit_func_t *jit_get_func(jit_t *j, jit_handle_t handle); void jit_hexdump(const unsigned char *data, size_t sz, int blocksz, const void *highlight, const char *prefix); @@ -263,13 +283,13 @@ void jit_put_privdata(jit_t *j, jit_func_t *f, void *ptr); bool jit_has_runtime(jit_t *j); int jit_backedge_limit(jit_t *j); void jit_tier_up(jit_func_t *f); -jit_t *jit_for_thread(void); +jit_thread_local_t *jit_thread_local(void); jit_cfg_t *jit_get_cfg(jit_func_t *f); void jit_free_cfg(jit_func_t *f); jit_block_t *jit_block_for(jit_cfg_t *cfg, int pos); int jit_get_edge(jit_edge_list_t *list, int nth); -void __nvc_do_exit(jit_exit_t which, jit_scalar_t *args); +void __nvc_do_exit(jit_exit_t which, jit_anchor_t *anchor, jit_scalar_t *args); #endif // _JIT_PRIV_H diff --git a/src/jit/jit.h b/src/jit/jit.h index 9bc201d3..8e243dc0 100644 --- a/src/jit/jit.h +++ b/src/jit/jit.h @@ -80,7 +80,10 @@ bool jit_call_thunk(jit_t *j, vcode_unit_t unit, jit_scalar_t *result); bool jit_fastcall(jit_t *j, jit_handle_t handle, jit_scalar_t *result, jit_scalar_t p1, jit_scalar_t p2); +__attribute__((format(printf, 3, 4))) void jit_msg(const loc_t *where, diag_level_t level, const char *fmt, ...); + +__attribute__((noreturn)) void jit_abort(int code); #endif // _JIT_H diff --git a/test/lower/array1.vhd b/test/lower/array1.vhd index 8b8bcd71..182decc7 100644 --- a/test/lower/array1.vhd +++ b/test/lower/array1.vhd @@ -3,7 +3,10 @@ end entity; architecture test of array1 is - function func return bit_vector; + impure function func return bit_vector is + begin + return "101"; + end function; begin diff --git a/test/test_jit.c b/test/test_jit.c index 7be1256d..b2c3c1c0 100644 --- a/test/test_jit.c +++ b/test/test_jit.c @@ -498,7 +498,7 @@ START_TEST(test_proc1) input_from_file(TESTDIR "/jit/proc1.vhd"); const error_t expect[] = { - { 45, "cannot wait inside function call" }, + { 48, "cannot wait inside function call" }, { -1, NULL }, }; expect_errors(expect); @@ -1090,12 +1090,14 @@ START_TEST(test_ffi1) { jit_scalar_t args[] = { { .integer = 5 }, { .integer = 3 } }; - ck_assert_int_eq(jit_ffi_call(add_ff, args).integer, 8); + jit_ffi_call(add_ff, args); + ck_assert_int_eq(args[0].integer, 8); } { jit_scalar_t args[] = { { .integer = 5 }, { .integer = -7 } }; - ck_assert_int_eq(jit_ffi_call(add_ff, args).integer, -2); + jit_ffi_call(add_ff, args); + ck_assert_int_eq(args[0].integer, -2); } ident_t fma_i = ident_new("test_ffi_fma"); @@ -1112,14 +1114,16 @@ START_TEST(test_ffi1) jit_scalar_t args[] = { { .real = 2.0 }, { .real = 3.0 }, { .real = 1.0 } }; - ck_assert_double_eq(jit_ffi_call(fma_ff, args).real, 7.0); + jit_ffi_call(fma_ff, args); + ck_assert_double_eq(args[0].real, 7.0); } { jit_scalar_t args[] = { { .real = -2.0 }, { .real = 3.0 }, { .real = 1.0 } }; - ck_assert_double_eq(jit_ffi_call(fma_ff, args).real, -5.0); + jit_ffi_call(fma_ff, args); + ck_assert_double_eq(args[0].real, -5.0); } ident_t len_i = ident_new("len"); @@ -1134,7 +1138,8 @@ START_TEST(test_ffi1) jit_scalar_t args[] = { { .pointer = NULL }, { .integer = 1 }, { .integer = 4 } }; - ck_assert_int_eq(jit_ffi_call(len_ff, args).integer, 4); + jit_ffi_call(len_ff, args); + ck_assert_int_eq(args[0].integer, 4); } ident_t sum_i = ident_new("sum"); @@ -1150,7 +1155,8 @@ START_TEST(test_ffi1) jit_scalar_t args[] = { { .pointer = data }, { .integer = 1 }, { .integer = 4 } }; - ck_assert_int_eq(jit_ffi_call(sum_ff, args).integer, 10); + jit_ffi_call(sum_ff, args); + ck_assert_int_eq(args[0].integer, 10); } } END_TEST -- 2.39.2