From 7172cf064d99ccaace47a1497d9677f750122b5d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 27 Oct 2022 09:46:14 +0100 Subject: [PATCH] Various fixes for LLVM JIT --- src/jit/jit-core.c | 4 +- src/jit/jit-interp.c | 1 + src/jit/jit-llvm.c | 151 +++++++++++++++++++++++++++++++------------ src/lib.c | 6 +- src/nvc.c | 39 +---------- src/opt.c | 38 +++++++++++ src/opt.h | 3 + test/jitperf.c | 29 +-------- 8 files changed, 162 insertions(+), 109 deletions(-) diff --git a/src/jit/jit-core.c b/src/jit/jit-core.c index a63e7621..94c31811 100644 --- a/src/jit/jit-core.c +++ b/src/jit/jit-core.c @@ -487,7 +487,7 @@ bool jit_fastcall(jit_t *j, jit_handle_t handle, jit_scalar_t *result, else { jit_transition(j, JIT_IDLE, JIT_INTERP); jit_scalar_t args[JIT_MAX_ARGS] = { p1, p2 }; - jit_interp(f, NULL, args); + (*f->entry)(f, NULL, args); *result = args[0]; jit_transition(j, JIT_INTERP, JIT_IDLE); } @@ -526,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 - jit_interp(f, NULL, args); + (*f->entry)(f, NULL, args); *result = args[0]; } diff --git a/src/jit/jit-interp.c b/src/jit/jit-interp.c index 4475ce61..48f30710 100644 --- a/src/jit/jit-interp.c +++ b/src/jit/jit-interp.c @@ -876,6 +876,7 @@ void jit_interp(jit_func_t *f, jit_anchor_t *caller, jit_scalar_t *args) // Came from stale compiled code // TODO: should we patch the call site? (*f->entry)(f, caller, args); + return; } if (f->irbuf == NULL) diff --git a/src/jit/jit-llvm.c b/src/jit/jit-llvm.c index a5bb6131..339bdd7d 100644 --- a/src/jit/jit-llvm.c +++ b/src/jit/jit-llvm.c @@ -17,6 +17,7 @@ #include "util.h" #include "ident.h" +#include "lib.h" #include "jit/jit-priv.h" #include "opt.h" #include "thread.h" @@ -25,6 +26,7 @@ #include #include +#include #include #include @@ -335,7 +337,11 @@ static LLVMValueRef cgen_get_fn(cgen_req_t *req, llvm_fn_t which) case LLVM_DO_EXIT: { - LLVMTypeRef args[] = { req->types[LLVM_INT32], req->types[LLVM_PTR] }; + LLVMTypeRef args[] = { + req->types[LLVM_INT32], + req->types[LLVM_PTR], + req->types[LLVM_PTR] + }; req->fntypes[which] = LLVMFunctionType(req->types[LLVM_VOID], args, ARRAY_LEN(args), false); @@ -410,6 +416,18 @@ static const char *cgen_reg_name(jit_reg_t reg) #endif } +static const char *cgen_arg_name(int nth) +{ +#ifdef DEBUG + static volatile int uniq = 0; + static __thread char buf[32]; + checked_sprintf(buf, sizeof(buf), "A%d.%d", nth, relaxed_add(&uniq, 1)); + return buf; +#else + return ""; +#endif +} + static const char *cgen_istr(cgen_req_t *req, ident_t id) { tb_rewind(req->textbuf); @@ -502,7 +520,8 @@ static void cgen_op_recv(cgen_req_t *req, cgen_block_t *cgb, jit_ir_t *ir) LLVMTypeRef result_type = req->types[req->regtypes[ir->result]]; LLVMValueRef ptr = LLVMBuildInBoundsGEP2(req->builder, int64_type, req->args, indexes, - ARRAY_LEN(indexes), ""); + ARRAY_LEN(indexes), + cgen_arg_name(nth)); LLVMValueRef value = LLVMBuildLoad2(req->builder, result_type, ptr, cgen_reg_name(ir->result)); @@ -521,7 +540,22 @@ static void cgen_op_send(cgen_req_t *req, cgen_block_t *cgb, jit_ir_t *ir) LLVMTypeRef int64_type = req->types[LLVM_INT64]; LLVMValueRef ptr = LLVMBuildInBoundsGEP2(req->builder, int64_type, req->args, indexes, - ARRAY_LEN(indexes), ""); + ARRAY_LEN(indexes), + cgen_arg_name(nth)); + + // Must always store a 64-bit quantity + switch (LLVMGetTypeKind(LLVMTypeOf(value))) { + case LLVMIntegerTypeKind: + value = LLVMBuildSExt(req->builder, value, req->types[LLVM_INT64], ""); + break; + case LLVMPointerTypeKind: + assert(sizeof(void *) == sizeof(int64_t)); + break; + default: + LLVMDumpValue(value); + fatal_trace("cannot extend LLVM type to 64 bits"); + } + LLVMBuildStore(req->builder, value, ptr); } @@ -725,6 +759,9 @@ static void cgen_op_cmp(cgen_req_t *req, cgen_block_t *cgb, jit_ir_t *ir) case JIT_CC_LT: cgb->outflags = LLVMBuildICmp(req->builder, LLVMIntSLT, arg1, arg2, ""); break; + case JIT_CC_LE: + cgb->outflags = LLVMBuildICmp(req->builder, LLVMIntSLE, arg1, arg2, ""); + break; default: jit_dump_with_mark(req->func, ir - req->func->irbuf, false); fatal_trace("unhandled cmp condition code"); @@ -815,6 +852,7 @@ static void cgen_macro_exit(cgen_req_t *req, cgen_block_t *cgb, jit_ir_t *ir) LLVMValueRef args[] = { which, + req->anchor, req->args }; LLVMBuildCall2(req->builder, req->fntypes[LLVM_DO_EXIT], fn, @@ -848,7 +886,8 @@ static void cgen_macro_getpriv(cgen_req_t *req, cgen_block_t *cgb, jit_ir_t *ir) }; cgb->outregs[ir->result] = LLVMBuildCall2(req->builder, req->fntypes[LLVM_GETPRIV], - fn, args, ARRAY_LEN(args), ""); + fn, args, ARRAY_LEN(args), + cgen_reg_name(ir->result)); } static void cgen_macro_putpriv(cgen_req_t *req, cgen_block_t *cgb, jit_ir_t *ir) @@ -973,8 +1012,8 @@ static void cgen_dump_reg_types(cgen_req_t *req) } } -static void cgen_force_reg_type(cgen_req_t *req, jit_reg_t reg, - llvm_type_t type) +static void cgen_set_reg_type(cgen_req_t *req, jit_reg_t reg, + llvm_type_t type) { if (req->regtypes[reg] == LLVM_VOID || req->regtypes[reg] == LLVM_INTPTR) req->regtypes[reg] = type; @@ -988,12 +1027,23 @@ static void cgen_force_reg_type(cgen_req_t *req, jit_reg_t reg, } } -static void cgen_force_reg_size(cgen_req_t *req, jit_reg_t reg, jit_size_t sz, - llvm_type_t deftype) +static void cgen_hint_value_type(cgen_req_t *req, jit_value_t value, + llvm_type_t type) { - assert(deftype == LLVM_INTPTR); + switch (value.kind) { + case JIT_VALUE_REG: + case JIT_ADDR_REG: + cgen_set_reg_type(req, value.reg, type); + break; + + default: + break; + } +} - llvm_type_t type = deftype; +static void cgen_hint_reg_size(cgen_req_t *req, jit_reg_t reg, jit_size_t sz) +{ + llvm_type_t type = LLVM_INTPTR; switch (sz) { case JIT_SZ_8: type = LLVM_INT8; break; case JIT_SZ_16: type = LLVM_INT16; break; @@ -1002,15 +1052,16 @@ static void cgen_force_reg_size(cgen_req_t *req, jit_reg_t reg, jit_size_t sz, case JIT_SZ_UNSPEC: break; } - cgen_force_reg_type(req, reg, type); + cgen_set_reg_type(req, reg, type); } static void cgen_hint_value_size(cgen_req_t *req, jit_value_t value, - jit_size_t sz, llvm_type_t deftype) + jit_size_t sz) { switch (value.kind) { case JIT_VALUE_REG: - cgen_force_reg_size(req, value.reg, sz, deftype); + case JIT_ADDR_REG: + cgen_hint_reg_size(req, value.reg, sz); break; default: @@ -1018,16 +1069,16 @@ static void cgen_hint_value_size(cgen_req_t *req, jit_value_t value, } } -static void cgen_constrain_type(cgen_req_t *req, jit_reg_t reg, - jit_value_t value) +static void cgen_hint_reg_type(cgen_req_t *req, jit_reg_t reg, + jit_value_t value) { switch (value.kind) { case JIT_VALUE_REG: - req->regtypes[reg] = req->regtypes[value.reg]; + cgen_set_reg_type(req, reg, req->regtypes[value.reg]); break; case JIT_VALUE_INT64: - req->regtypes[reg] = LLVM_INTPTR; + cgen_set_reg_type(req, reg, LLVM_INTPTR); break; default: @@ -1043,49 +1094,45 @@ static void cgen_reg_types(cgen_req_t *req) jit_ir_t *ir = &(req->func->irbuf[i]); switch (ir->op) { case J_RECV: - cgen_force_reg_type(req, ir->result, LLVM_INTPTR); + cgen_set_reg_type(req, ir->result, LLVM_INTPTR); break; case J_LOAD: case J_ULOAD: + cgen_hint_reg_size(req, ir->result, ir->size); + break; + case J_MUL: case J_ADD: case J_SUB: - cgen_force_reg_size(req, ir->result, ir->size, LLVM_INTPTR); - cgen_hint_value_size(req, ir->arg1, ir->size, LLVM_INTPTR); - cgen_hint_value_size(req, ir->arg2, ir->size, LLVM_INTPTR); - break; - - case J_NOT: - cgen_force_reg_type(req, ir->result, req->regtypes[ir->arg1.reg]); + cgen_hint_reg_size(req, ir->result, ir->size); + cgen_hint_reg_type(req, ir->result, ir->arg1); break; case J_CSET: - cgen_force_reg_type(req, ir->result, LLVM_INT1); + cgen_set_reg_type(req, ir->result, LLVM_INT1); break; case J_STORE: - cgen_hint_value_size(req, ir->arg1, ir->size, LLVM_INTPTR); - break; - - case J_CSEL: - if (ir->arg1.kind == JIT_VALUE_REG) - cgen_force_reg_type(req, ir->result, req->regtypes[ir->arg1.reg]); - else if (ir->arg2.kind == JIT_VALUE_REG) - cgen_force_reg_type(req, ir->result, req->regtypes[ir->arg2.reg]); - else - cgen_force_reg_type(req, ir->result, LLVM_INTPTR); + cgen_hint_value_type(req, ir->arg2, LLVM_PTR); + cgen_hint_value_size(req, ir->arg1, ir->size); break; case J_LEA: case MACRO_GETPRIV: case MACRO_GALLOC: - cgen_force_reg_type(req, ir->result, LLVM_PTR); + cgen_set_reg_type(req, ir->result, LLVM_PTR); + break; + + case J_CSEL: + cgen_hint_reg_type(req, ir->result, ir->arg1); + cgen_hint_reg_type(req, ir->result, ir->arg2); break; case J_MOV: case J_NEG: - cgen_constrain_type(req, ir->result, ir->arg1); + case J_NOT: + cgen_hint_reg_type(req, ir->result, ir->arg1); break; case J_JUMP: @@ -1110,6 +1157,26 @@ static void cgen_reg_types(cgen_req_t *req) cgen_dump_reg_types(req); } +static void cgen_dump_module(cgen_req_t *req, const char *tag) +{ + size_t length; + const char *module_name = LLVMGetModuleIdentifier(req->module, &length); + + if (!opt_get_verbose(OPT_LLVM_VERBOSE, module_name)) + return; + + char *file_name LOCAL = xasprintf("_%s.%s.ll", module_name, tag); + + char file_path[PATH_MAX]; + lib_realpath(lib_work(), file_name, file_path, sizeof(file_path)); + + char *error; + if (LLVMPrintModuleToFile(req->module, file_path, &error)) + fatal("Failed to write LLVM IR file: %s", error); + + debugf("wrote LLVM IR for %s to %s", module_name, file_path); +} + static void cgen_frame_anchor(cgen_req_t *req) { LLVMTypeRef type = req->types[LLVM_ANCHOR]; @@ -1296,7 +1363,7 @@ static void cgen_module(cgen_req_t *req) LLVMDisposeTargetData(data_ref); - LLVMDumpModule(req->module); + cgen_dump_module(req, "initial"); #ifdef DEBUG if (LLVMVerifyModule(req->module, LLVMPrintMessageAction, NULL)) @@ -1323,7 +1390,7 @@ static void cgen_optimise(cgen_req_t *req) LLVMFinalizeFunctionPassManager(fpm); LLVMDisposePassManager(fpm); - LLVMDumpModule(req->module); + cgen_dump_module(req, "final"); } static void *jit_llvm_init(void) @@ -1358,6 +1425,10 @@ static void jit_llvm_cgen(jit_t *j, jit_handle_t handle, void *context) jit_func_t *f = jit_get_func(j, handle); + const char *only = getenv("NVC_JIT_ONLY"); + if (only != NULL && !icmp(f->name, only)) + return; + printf("LLVM compile %s\n", istr(f->name)); static __thread LLVMTargetMachineRef tm_ref = NULL; diff --git a/src/lib.c b/src/lib.c index dc9b8cf2..6fed1df3 100644 --- a/src/lib.c +++ b/src/lib.c @@ -1048,10 +1048,12 @@ void lib_realpath(lib_t lib, const char *name, char *buf, size_t buflen) { assert(lib != NULL); - if (name) + if (lib->path == NULL) + checked_sprintf(buf, buflen, "." DIR_SEP "%s", name); + else if (name) checked_sprintf(buf, buflen, "%s" DIR_SEP "%s", lib->path, name); else - strncpy(buf, lib->path, buflen); + checked_sprintf(buf, buflen, "%s", lib->path); } void lib_mkdir(lib_t lib, const char *name) diff --git a/src/nvc.c b/src/nvc.c index 0a6e0d76..d174d32f 100644 --- a/src/nvc.c +++ b/src/nvc.c @@ -866,43 +866,6 @@ static int dump_cmd(int argc, char **argv) return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; } -static void set_default_opts(void) -{ - opt_set_int(OPT_RT_STATS, 0); - opt_set_int(OPT_RT_TRACE, 0); - opt_set_str(OPT_VHPI_TRACE, getenv("NVC_VHPI_VERBOSE")); - opt_set_int(OPT_DUMP_LLVM, 0); - opt_set_int(OPT_OPTIMISE, 2); - opt_set_int(OPT_BOOTSTRAP, 0); - opt_set_int(OPT_COVER, 0); - opt_set_int(OPT_STOP_DELTA, 10000); - opt_set_int(OPT_UNIT_TEST, 0); - opt_set_int(OPT_MAKE_DEPS_ONLY, 0); - opt_set_int(OPT_MAKE_POSIX, 0); - opt_set_str(OPT_DUMP_VCODE, getenv("NVC_LOWER_VERBOSE")); - opt_set_int(OPT_IGNORE_TIME, 0); - opt_set_int(OPT_VERBOSE, 0); - opt_set_int(OPT_RT_PROFILE, 0); - opt_set_int(OPT_SYNTHESIS, 0); - opt_set_int(OPT_MISSING_BODY, 1); - opt_set_int(OPT_ERROR_LIMIT, -1); - opt_set_int(OPT_IEEE_WARNINGS, 1); - opt_set_int(OPT_ARENA_SIZE, 1 << 24); - opt_set_int(OPT_DUMP_ARRAYS, 0); - opt_set_str(OPT_OBJECT_VERBOSE, getenv("NVC_OBJECT_VERBOSE")); - opt_set_str(OPT_GC_VERBOSE, getenv("NVC_GC_VERBOSE") DEBUG_ONLY(?: "1")); - opt_set_str(OPT_EVAL_VERBOSE, getenv("NVC_EVAL_VERBOSE")); - opt_set_str(OPT_ELAB_VERBOSE, getenv("NVC_ELAB_VERBOSE")); - opt_set_int(OPT_HEAP_SIZE, 16 * 1024 * 1024); - opt_set_int(OPT_ERROR_LIMIT, 20); - opt_set_int(OPT_GC_STRESS, 0 DEBUG_ONLY(|| getenv("NVC_GC_STRESS") != 0)); - opt_set_int(OPT_RELAXED, 0); - opt_set_str(OPT_JIT_VERBOSE, getenv("NVC_JIT_VERBOSE")); - opt_set_int(OPT_JIT_LOG, getenv("NVC_JIT_LOG") != NULL); - opt_set_int(OPT_WARN_HIDDEN, 0); - opt_set_int(OPT_NO_SAVE, 0); -} - static void usage(void) { printf("Usage: %s [OPTION]... COMMAND [OPTION]...\n" @@ -1132,7 +1095,7 @@ int main(int argc, char **argv) { term_init(); thread_init(); - set_default_opts(); + set_default_options(); intern_strings(); register_signal_handlers(); mspace_stack_limit(MSPACE_CURRENT_FRAME); diff --git a/src/opt.c b/src/opt.c index 0dd0f812..145c9407 100644 --- a/src/opt.c +++ b/src/opt.c @@ -98,3 +98,41 @@ bool opt_get_verbose(opt_name_t name, const char *filter) else return strstr(filter, value) != NULL; } + +void set_default_options(void) +{ + opt_set_int(OPT_RT_STATS, 0); + opt_set_int(OPT_RT_TRACE, 0); + opt_set_str(OPT_VHPI_TRACE, getenv("NVC_VHPI_VERBOSE")); + opt_set_int(OPT_DUMP_LLVM, 0); + opt_set_int(OPT_OPTIMISE, 2); + opt_set_int(OPT_BOOTSTRAP, 0); + opt_set_int(OPT_COVER, 0); + opt_set_int(OPT_STOP_DELTA, 10000); + opt_set_int(OPT_UNIT_TEST, 0); + opt_set_int(OPT_MAKE_DEPS_ONLY, 0); + opt_set_int(OPT_MAKE_POSIX, 0); + opt_set_str(OPT_DUMP_VCODE, getenv("NVC_LOWER_VERBOSE")); + opt_set_int(OPT_IGNORE_TIME, 0); + opt_set_int(OPT_VERBOSE, 0); + opt_set_int(OPT_RT_PROFILE, 0); + opt_set_int(OPT_SYNTHESIS, 0); + opt_set_int(OPT_MISSING_BODY, 1); + opt_set_int(OPT_ERROR_LIMIT, -1); + opt_set_int(OPT_IEEE_WARNINGS, 1); + opt_set_int(OPT_ARENA_SIZE, 1 << 24); + opt_set_int(OPT_DUMP_ARRAYS, 0); + opt_set_str(OPT_OBJECT_VERBOSE, getenv("NVC_OBJECT_VERBOSE")); + opt_set_str(OPT_GC_VERBOSE, getenv("NVC_GC_VERBOSE") DEBUG_ONLY(?: "1")); + opt_set_str(OPT_EVAL_VERBOSE, getenv("NVC_EVAL_VERBOSE")); + opt_set_str(OPT_ELAB_VERBOSE, getenv("NVC_ELAB_VERBOSE")); + opt_set_int(OPT_HEAP_SIZE, 16 * 1024 * 1024); + opt_set_int(OPT_ERROR_LIMIT, 20); + opt_set_int(OPT_GC_STRESS, 0 DEBUG_ONLY(|| getenv("NVC_GC_STRESS") != 0)); + opt_set_int(OPT_RELAXED, 0); + opt_set_str(OPT_JIT_VERBOSE, getenv("NVC_JIT_VERBOSE")); + opt_set_int(OPT_JIT_LOG, getenv("NVC_JIT_LOG") != NULL); + opt_set_int(OPT_WARN_HIDDEN, 0); + opt_set_int(OPT_NO_SAVE, 0); + opt_set_str(OPT_LLVM_VERBOSE, getenv("NVC_LLVM_VERBOSE")); +} diff --git a/src/opt.h b/src/opt.h index 4ae830ef..e8d4964d 100644 --- a/src/opt.h +++ b/src/opt.h @@ -55,6 +55,7 @@ typedef enum { OPT_JIT_LOG, OPT_WARN_HIDDEN, OPT_NO_SAVE, + OPT_LLVM_VERBOSE, OPT_LAST_NAME } opt_name_t; @@ -65,4 +66,6 @@ int opt_get_int(opt_name_t name); const char *opt_get_str(opt_name_t name); bool opt_get_verbose(opt_name_t name, const char *filter); +void set_default_options(void); + #endif // _OPT_H diff --git a/test/jitperf.c b/test/jitperf.c index 9cc1c4d3..d48ab2c9 100644 --- a/test/jitperf.c +++ b/test/jitperf.c @@ -122,33 +122,6 @@ static void find_benchmarks(tree_t pack, const char *filter, bool interpret) } } -static void set_default_options(void) -{ - opt_set_int(OPT_BOOTSTRAP, 0); - opt_set_int(OPT_COVER, 0); - opt_set_int(OPT_UNIT_TEST, 1); - opt_set_str(OPT_DUMP_VCODE, getenv("NVC_LOWER_VERBOSE")); - opt_set_int(OPT_IGNORE_TIME, 0); - opt_set_int(OPT_VERBOSE, 0); - opt_set_int(OPT_SYNTHESIS, 0); - opt_set_int(OPT_ERROR_LIMIT, -1); - opt_set_int(OPT_ARENA_SIZE, 1 << 20); - opt_set_str(OPT_GC_VERBOSE, getenv("NVC_GC_VERBOSE")); - opt_set_str(OPT_OBJECT_VERBOSE, getenv("NVC_OBJECT_VERBOSE")); - opt_set_str(OPT_ELAB_VERBOSE, getenv("NVC_ELAB_VERBOSE")); - opt_set_str(OPT_EVAL_VERBOSE, getenv("NVC_EVAL_VERBOSE")); - opt_set_str(OPT_JIT_VERBOSE, getenv("NVC_JIT_VERBOSE")); - opt_set_int(OPT_HEAP_SIZE, 128 * 1024); - opt_set_int(OPT_GC_STRESS, getenv("NVC_GC_STRESS") != 0); - opt_set_int(OPT_RELAXED, 0); - opt_set_int(OPT_JIT_LOG, getenv("NVC_JIT_LOG") != NULL); - opt_set_int(OPT_WARN_HIDDEN, 0); - opt_set_int(OPT_RT_TRACE, 0); - opt_set_int(OPT_STOP_DELTA, 1000); - opt_set_int(OPT_RT_STATS, 0); - opt_set_int(OPT_IEEE_WARNINGS, 1); -} - static void usage(void) { printf("Usage: jitperf [OPTION]... [FILE]...\n" @@ -173,6 +146,8 @@ int main(int argc, char **argv) mspace_stack_limit(MSPACE_CURRENT_FRAME); intern_strings(); + opt_set_str(OPT_GC_VERBOSE, NULL); + _std_standard_init(); _std_env_init(); _nvc_sim_pkg_init(); -- 2.39.2