From 045b526b7185d78ae20e9868e8857ce85a88d493 Mon Sep 17 00:00:00 2001 From: VincentWu <43398706+Xinlong-Wu@users.noreply.github.com> Date: Sun, 9 Jul 2023 01:47:00 +0800 Subject: [PATCH] [Mono][RISC-V] emit mul inst instead of emulated mul (#85445) * update makefile * add format file * use mul inst instead of emulate mul process stack size larger than imm32 * emit get_throw_trampoline * mono_riscv_throw_exception * fix error of stack trace * test case * output inst idiv fix mono_riscv_emit_branch_exc * implement mono_arch_get_throw_corlib_exception * fix rdiv * move ArgOnStack arg at prologue lowering OP_XOR_IMM&OP_IXOR_IMM * fix emit_imm * test imm * update test case * use swich to process return value * fix offset of params in a call * lowering OP_IDIV_IMM * fmt * remove test file * address comment --- src/mono/mono/arch/riscv/riscv-codegen.h | 3 +- src/mono/mono/mini/cpu-riscv64.mdesc | 38 +++--- src/mono/mono/mini/exceptions-riscv.c | 175 ++++++++++++++++++++++-- src/mono/mono/mini/mini-riscv.c | 222 +++++++++++++++++++++---------- src/mono/mono/mini/mini-riscv.h | 7 +- src/mono/mono/mini/tramp-riscv.c | 11 +- 6 files changed, 347 insertions(+), 109 deletions(-) diff --git a/src/mono/mono/arch/riscv/riscv-codegen.h b/src/mono/mono/arch/riscv/riscv-codegen.h index 4abff40..054c0b0 100644 --- a/src/mono/mono/arch/riscv/riscv-codegen.h +++ b/src/mono/mono/arch/riscv/riscv-codegen.h @@ -293,8 +293,7 @@ enum { (RISCV_BITS ((ins), 12, 8) << 12) | (RISCV_SIGN ((ins)) << 20)) // Check a value for validity as an immediate. -#define RISCV_VALID_IMM(value) \ - (((gint32)value) == (value)) +#define RISCV_VALID_IMM32(value) (((gint32)value) == (value)) #define RISCV_VALID_I_IMM(value) \ (RISCV_DECODE_I_IMM (RISCV_ENCODE_I_IMM ((value))) == (value)) #define RISCV_VALID_S_IMM(value) \ diff --git a/src/mono/mono/mini/cpu-riscv64.mdesc b/src/mono/mono/mini/cpu-riscv64.mdesc index 7a7a261..7ba7da1 100644 --- a/src/mono/mono/mini/cpu-riscv64.mdesc +++ b/src/mono/mono/mini/cpu-riscv64.mdesc @@ -65,22 +65,22 @@ fcall: dest:f len:8 clob:c lcall: dest:a len:16 clob:c lcall_membase: dest:a src1:b len:8 clob:c -store_membase_reg: dest:b src1:i len:4 -storei1_membase_reg: dest:b src1:i len:4 -storei2_membase_reg: dest:b src1:i len:4 -storei4_membase_reg: dest:b src1:i len:4 -storei8_membase_reg: dest:b src1:i len:4 +store_membase_reg: dest:b src1:i len:24 +storei1_membase_reg: dest:b src1:i len:24 +storei2_membase_reg: dest:b src1:i len:24 +storei4_membase_reg: dest:b src1:i len:24 +storei8_membase_reg: dest:b src1:i len:24 storer4_membase_reg: dest:b src1:f len:4 storer8_membase_reg: dest:b src1:f len:4 load_membase: dest:i src1:b len:24 -loadu1_membase: dest:i src1:b len:16 -loadi1_membase: dest:i src1:b len:16 -loadu2_membase: dest:i src1:b len:16 -loadi2_membase: dest:i src1:b len:16 -loadu4_membase: dest:i src1:b len:16 -loadi4_membase: dest:i src1:b len:16 -loadi8_membase: dest:i src1:b len:16 +loadu1_membase: dest:i src1:b len:24 +loadi1_membase: dest:i src1:b len:24 +loadu2_membase: dest:i src1:b len:24 +loadi2_membase: dest:i src1:b len:24 +loadu4_membase: dest:i src1:b len:24 +loadi4_membase: dest:i src1:b len:24 +loadi8_membase: dest:i src1:b len:24 loadr4_membase: dest:f src1:b len:16 loadr8_membase: dest:f src1:b len:16 @@ -110,10 +110,14 @@ int_sub: dest:i src1:i src2:i len:4 long_sub: dest:i src1:i src2:i len:4 int_mul: dest:i src1:i src2:i len:4 r4_mul: dest:f src1:f src2:f len:4 +long_mul: dest:i src1:i src2:i len:4 float_mul: dest:f src1:f src2:f len:4 +int_div: dest:i src1:i src2:i len:32 long_div: dest:i src1:i src2:i len:32 +int_div_un: dest:i src1:i src2:i len:32 long_div_un: dest:i src1:i src2:i len:32 r4_div: dest:f src1:f src2:f len:36 +float_div: dest:f src1:f src2:f len:4 int_rem: dest:i src1:i src2:i len:32 long_rem: dest:i src1:i src2:i len:32 int_rem_un: dest:i src1:i src2:i len:32 @@ -173,11 +177,11 @@ riscv_bge: src1:i src2:i len:8 riscv_bgeu: src1:i src2:i len:8 riscv_blt: src1:i src2:i len:8 riscv_bltu: src1:i src2:i len:8 -riscv_exc_beq: src1:i src2:i len:32 -riscv_exc_bne: src1:i src2:i len:32 -riscv_exc_bgeu: src1:i src2:i len:32 -riscv_exc_blt: src1:i src2:i len:32 -riscv_exc_bltu: src1:i src2:i len:32 +riscv_exc_beq: src1:i src2:i len:12 +riscv_exc_bne: src1:i src2:i len:12 +riscv_exc_bgeu: src1:i src2:i len:12 +riscv_exc_blt: src1:i src2:i len:12 +riscv_exc_bltu: src1:i src2:i len:12 riscv_slt: dest:i src1:i src2:i len:4 riscv_sltu: dest:i src1:i src2:i len:4 riscv_slti: dest:i src1:i len:4 diff --git a/src/mono/mono/mini/exceptions-riscv.c b/src/mono/mono/mini/exceptions-riscv.c index 18b3f08..8ae90e7 100644 --- a/src/mono/mono/mini/exceptions-riscv.c +++ b/src/mono/mono/mini/exceptions-riscv.c @@ -6,6 +6,7 @@ #include "mini-runtime.h" #include +#include #include #include "mono/utils/mono-tls-inline.h" @@ -67,6 +68,47 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) return start; } +void +mono_riscv_throw_exception (gpointer arg, host_mgreg_t pc, host_mgreg_t *int_regs, gdouble *fp_regs, gboolean corlib, gboolean rethrow, gboolean preserve_ips){ + ERROR_DECL (error); + MonoContext ctx; + MonoObject *exc = NULL; + guint32 ex_token_index, ex_token; + if (!corlib) + exc = (MonoObject *)arg; + else { + ex_token_index = (guint64)arg; + ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index; + exc = (MonoObject *)mono_exception_from_token (mono_defaults.corlib, ex_token); + } + + /* Adjust pc so it points into the call instruction */ + pc -= 4; + + /* Initialize a ctx based on the arguments */ + memset (&ctx, 0, sizeof (MonoContext)); + memcpy (&(ctx.gregs [0]), int_regs, sizeof (host_mgreg_t) * RISCV_N_GREGS); + memcpy (&(ctx.fregs [0]), fp_regs, sizeof (host_mgreg_t) * RISCV_N_FREGS); + + ctx.gregs [0] = pc; + + if (mono_object_isinst_checked (exc, mono_defaults.exception_class, error)) { + MonoException *mono_ex = (MonoException *)exc; + if (!rethrow && !mono_ex->caught_in_unmanaged) { + mono_ex->stack_trace = NULL; + mono_ex->trace_ips = NULL; + } else if (preserve_ips) { + mono_ex->caught_in_unmanaged = TRUE; + } + } + + mono_error_assert_ok (error); + + mono_handle_exception (&ctx, exc); + + mono_restore_context (&ctx); +} + gpointer mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) { @@ -74,11 +116,112 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) return nop_stub (0x37); } +static gpointer +get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm, gboolean resume_unwind, const char *tramp_name, MonoTrampInfo **info, gboolean aot, gboolean preserve_ips){ + guint8 *start, *code; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; + int i, offset, gregs_offset, fregs_offset, frame_size, num_fregs; + + code = start = mono_global_codeman_reserve (size); + + /* This will being called by JITted code, the exception object/type token is in A0 */ + + /* Compute stack frame size and offsets */ + offset = 0; + /* ra & fp */ + offset += 2 * sizeof (host_mgreg_t); + + /* gregs */ + offset += RISCV_N_GREGS * sizeof (host_mgreg_t); + gregs_offset = offset; + + /* fregs */ + num_fregs = RISCV_N_FREGS; + offset += num_fregs * sizeof (host_mgreg_t); + fregs_offset = offset; + frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT); + + MINI_BEGIN_CODEGEN (); + + /* Setup a frame */ + g_assert (RISCV_VALID_I_IMM (-frame_size)); + riscv_addi (code, RISCV_SP, RISCV_SP, -frame_size); + code = mono_riscv_emit_store (code, RISCV_RA, RISCV_SP, frame_size - sizeof (host_mgreg_t), 0); + code = mono_riscv_emit_store (code, RISCV_FP, RISCV_SP, frame_size - 2 * sizeof (host_mgreg_t), 0); + riscv_addi (code, RISCV_FP, RISCV_SP, frame_size); + + /* Save gregs */ + code = mono_riscv_emit_store_stack (code, 0xffffffff, RISCV_FP, -gregs_offset, FALSE); + if (corlib && !llvm) + /* The real ra is in A1 */ + code = mono_riscv_emit_store (code, RISCV_A1, RISCV_FP, -gregs_offset + (RISCV_RA * sizeof (host_mgreg_t)), 0); + + /* Save previous fp/sp */ + code = mono_riscv_emit_load (code, RISCV_T0, RISCV_FP, -2 * sizeof (host_mgreg_t), 0); + code = mono_riscv_emit_store (code, RISCV_T0, RISCV_FP, -gregs_offset + (RISCV_FP * sizeof (host_mgreg_t)), 0); + // current fp is previous sp + code = mono_riscv_emit_store (code, RISCV_FP, RISCV_FP, -gregs_offset + (RISCV_SP * sizeof (host_mgreg_t)), 0); + + /* Save fregs */ + if (riscv_stdext_f || riscv_stdext_d) + code = mono_riscv_emit_store_stack (code, 0xffffffff, RISCV_FP, -fregs_offset, TRUE); + + /* Call the C trampoline function */ + /* Arg1 = exception object/type token */ + // riscv_addi (code, RISCV_A0, RISCV_A0, 0); + /* Arg2 = caller ip, should be return address in this case */ + if (corlib) { + // caller ip are set to A1 already + if (llvm) + NOT_IMPLEMENTED; + } else + code = mono_riscv_emit_load (code, RISCV_A1, RISCV_FP, -sizeof (host_mgreg_t), 0); + /* Arg 3 = gregs */ + riscv_addi (code, RISCV_A2, RISCV_FP, -gregs_offset); + /* Arg 4 = fregs */ + riscv_addi (code, RISCV_A3, RISCV_FP, -fregs_offset); + /* Arg 5 = corlib */ + riscv_addi (code, RISCV_A4, RISCV_ZERO, corlib ? 1 : 0); + /* Arg 6 = rethrow */ + riscv_addi (code, RISCV_A5, RISCV_ZERO, rethrow ? 1 : 0); + if (!resume_unwind) { + /* Arg 7 = preserve_ips */ + riscv_addi (code, RISCV_A6, RISCV_ZERO, preserve_ips ? 1 : 0); + } + + /* Call the function */ + if (aot) { + NOT_IMPLEMENTED; + } else { + gpointer icall_func; + + if (resume_unwind) + // icall_func = (gpointer)mono_riscv_resume_unwind; + NOT_IMPLEMENTED; + else + icall_func = (gpointer)mono_riscv_throw_exception; + + code = mono_riscv_emit_imm (code, RISCV_RA, (guint64)icall_func); + } + riscv_jalr (code, RISCV_ZERO, RISCV_RA, 0); + /* This shouldn't return */ + /* hang in debugger */ + riscv_ebreak (code); + + g_assert ((code - start) < size); + MINI_END_CODEGEN (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + + if (info) + *info = mono_tramp_info_create (tramp_name, start, code - start, ji, unwind_ops); + + return MINI_ADDR_TO_FTNPTR (start); +} + gpointer mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) { - *info = NULL; - return nop_stub (0x77); + return get_throw_trampoline (384, FALSE, FALSE, FALSE, FALSE, "throw_exception", info, aot, FALSE); } gpointer @@ -98,8 +241,7 @@ mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) gpointer mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { - *info = NULL; - return nop_stub (0xaa); + return get_throw_trampoline (384, TRUE, FALSE, FALSE, FALSE, "throw_corlib_exception", info, aot, FALSE); } #else @@ -160,8 +302,6 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, host_mgreg_t **save_locations, StackFrameInfo *frame) { - gpointer ip = MONO_CONTEXT_GET_IP (ctx); - memset (frame, 0, sizeof (StackFrameInfo)); frame->ji = ji; @@ -174,7 +314,6 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, MonoJitInfo *ji, guint32 unwind_info_len; guint8 *unwind_info; - if (ji->is_trampoline) frame->type = FRAME_TYPE_TRAMPOLINE; else @@ -190,6 +329,8 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, MonoJitInfo *ji, for (int i = 0; i < 10; i++) (regs + MONO_MAX_IREGS) [i] = *((host_mgreg_t*)&new_ctx->fregs [RISCV_F18 + i]); + gpointer ip = MINI_FTNPTR_TO_ADDR (MONO_CONTEXT_GET_IP (ctx)); + gboolean success = mono_unwind_frame (unwind_info, unwind_info_len, (guint8 *)ji->code_start, (guint8 *)ji->code_start + ji->code_size, (guint8 *)ip, NULL, regs, MONO_MAX_IREGS + 12 + 1, save_locations, MONO_MAX_IREGS, (guint8 **)&cfa); @@ -197,21 +338,23 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, MonoJitInfo *ji, if (!success) return FALSE; - memcpy (&new_ctx->gregs, regs, sizeof (host_mgreg_t) * 32); + memcpy (new_ctx->gregs, regs, sizeof (host_mgreg_t) * MONO_MAX_IREGS); for (int i = 0; i < 2; i++) *((host_mgreg_t*)&new_ctx->fregs [RISCV_F8 + i]) = (regs + MONO_MAX_IREGS) [i]; for (int i = 0; i < 10; i++) - *((host_mgreg_t*)&new_ctx->fregs [RISCV_F18 + i]) = (regs + MONO_MAX_IREGS) [i]; + *((host_mgreg_t *)&new_ctx->fregs [RISCV_F18 + i]) = (regs + MONO_MAX_IREGS) [2 + i]; + new_ctx->gregs [0] = regs [RISCV_RA]; new_ctx->gregs [RISCV_SP] = (host_mgreg_t)(gsize)cfa; - if (*lmf && (*lmf)->gregs [RISCV_FP] && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->gregs [RISCV_SP])) { + if (*lmf && (*lmf)->gregs [MONO_ARCH_LMF_REG_SP] && + (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->gregs [MONO_ARCH_LMF_REG_SP])) { /* remove any unused lmf */ *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P - 1)); } - /* we substract 1, so that the pc points into the call instruction */ - new_ctx->gregs [RISCV_ZERO]--; + /* we subtract 1, so that the PC points into the call instruction */ + new_ctx->gregs [0]--; return TRUE; } else if (*lmf) { @@ -223,10 +366,14 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, MonoJitInfo *ji, if (!ji) return FALSE; - memcpy (&new_ctx->gregs, (*lmf)->gregs, sizeof (host_mgreg_t) * RISCV_N_GREGS); + g_assert (MONO_ARCH_LMF_REGS == ((MONO_ARCH_CALLEE_SAVED_REGS) | (1 << RISCV_SP))); + + memcpy (&new_ctx->gregs [0], &(*lmf)->gregs [0], sizeof (host_mgreg_t) * RISCV_N_GREGS); + // new_ctx->gregs [RISCV_FP] = (*lmf)->gregs [MONO_ARCH_LMF_REG_FP]; + // new_ctx->gregs [RISCV_SP] = (*lmf)->gregs [MONO_ARCH_LMF_REG_SP]; new_ctx->gregs [0] = (*lmf)->pc; // use [0] as pc reg since x0 is hard-wired zero - /* we substract 1, so that the IP points into the call instruction */ + /* we subtract 1, so that the PC points into the call instruction */ new_ctx->gregs [0]--; *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(TARGET_SIZEOF_VOID_P - 1)); diff --git a/src/mono/mono/mini/mini-riscv.c b/src/mono/mono/mini/mini-riscv.c index 2b4dcaa..0d9a779 100644 --- a/src/mono/mono/mini/mini-riscv.c +++ b/src/mono/mono/mini/mini-riscv.c @@ -622,9 +622,6 @@ riscv_patch_full (MonoCompile *cfg, guint8 *code, guint8 *target, int relocation g_assert_not_reached (); break; } - case MONO_R_RISCV_JALR: - *(guint64 *)code = (guint64)target; - break; default: NOT_IMPLEMENTED; } @@ -761,10 +758,10 @@ add_valuetype (CallInfo *cinfo, ArgInfo *ainfo, MonoType *t) // Scalars wider than 2×XLEN bits are passed by reference if (aligned_size > sizeof (host_mgreg_t) * 2) { if (cinfo->next_arg > RISCV_A7) { + ainfo->offset = cinfo->stack_usage; ainfo->storage = ArgVtypeByRefOnStack; cinfo->stack_usage += aligned_size; ainfo->slot_size = aligned_size; - ainfo->offset = cinfo->stack_usage; } else { ainfo->storage = ArgVtypeByRef; ainfo->reg = cinfo->next_arg; @@ -777,18 +774,18 @@ add_valuetype (CallInfo *cinfo, ArgInfo *ainfo, MonoType *t) else if (aligned_size == sizeof (host_mgreg_t) * 2) { // If no argument registers are available, the scalar is passed on the stack by value if (cinfo->next_arg > RISCV_A7) { + ainfo->offset = cinfo->stack_usage; ainfo->storage = ArgVtypeOnStack; cinfo->stack_usage += sizeof (host_mgreg_t) * 2; ainfo->slot_size = sizeof (host_mgreg_t) * 2; - ainfo->offset = cinfo->stack_usage; } // If exactly one register is available, the low-order XLEN bits are // passed in the register and the high-order XLEN bits are passed on the stack else if (cinfo->next_arg == RISCV_A7) { + ainfo->offset = cinfo->stack_usage; ainfo->storage = ArgVtypeInMixed; cinfo->stack_usage += sizeof (host_mgreg_t); ainfo->slot_size = sizeof (host_mgreg_t); - ainfo->offset = cinfo->stack_usage; ainfo->reg = cinfo->next_arg; ainfo->size = sizeof (host_mgreg_t); @@ -927,11 +924,25 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) // If the reture value would have been passed by reference, // the caller allocates memory for the return value, and // passes the address as an implicit first parameter. - if (cinfo->ret.storage == ArgVtypeByRef) { + + switch (cinfo->ret.storage) { + case ArgVtypeByRef: g_assert (cinfo->ret.reg == RISCV_A0); cinfo->next_arg = RISCV_A1; - } else + break; + + case ArgVtypeInIReg: + case ArgInIReg: + case ArgInFReg: + case ArgNone: cinfo->next_arg = RISCV_A0; + break; + + default: + g_print ("Unhandled retyrn type %d\n", cinfo->ret.storage); + NOT_IMPLEMENTED; + break; + } cinfo->next_farg = RISCV_FA0; // reset status @@ -1377,7 +1388,7 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) /** * mono_arch_emit_call: - * we process all Args of a function call + * move all Args to corresponding reg/stack in Caller * (return, parameters) */ void @@ -1494,7 +1505,8 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) break; } case ArgVtypeInIReg: - case ArgVtypeByRef: { + case ArgVtypeByRef: + case ArgVtypeOnStack: { MonoInst *ins; guint32 align; guint32 size; @@ -1568,7 +1580,9 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) load->inst_basereg = src->dreg; load->inst_offset = i; MONO_ADD_INS (cfg->cbb, load); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, op_load, RISCV_FP, -ainfo->offset + i, load->dreg); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, + op_load == OP_LOADI8_MEMBASE ? OP_STOREI8_MEMBASE_REG : OP_STOREI4_MEMBASE_REG, + RISCV_SP, ainfo->offset + i, load->dreg); } break; case ArgVtypeByRef: { @@ -1704,14 +1718,18 @@ mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) case OP_LMUL: case OP_RMUL: case OP_FMUL: + case OP_IMUL_IMM: case OP_LMUL_IMM: case OP_IDIV: case OP_LDIV: case OP_LDIV_UN: case OP_IDIV_UN: + case OP_IDIV_IMM: + case OP_IDIV_UN_IMM: case OP_RDIV: case OP_IREM: case OP_LREM: + case OP_IREM_IMM: case OP_IREM_UN: case OP_LREM_UN: @@ -1722,6 +1740,7 @@ mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) case OP_LADD_OVF_UN: case OP_IMUL_OVF: + case OP_LMUL_OVF_UN: case OP_LMUL_OVF_UN_OOM: case OP_FDIV: @@ -1983,9 +2002,14 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) case OP_LSUB: case OP_IADD: case OP_LADD: + case OP_IMUL: + case OP_LMUL: case OP_RMUL: case OP_FMUL: + case OP_FDIV: + case OP_IDIV: case OP_LDIV: + case OP_IDIV_UN: case OP_LDIV_UN: case OP_RDIV: case OP_IREM: @@ -1995,8 +2019,6 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) case OP_CHECK_THIS: case OP_IAND: case OP_LAND: - case OP_XOR_IMM: - case OP_IXOR_IMM: case OP_IXOR: case OP_LXOR: case OP_IOR: @@ -2240,11 +2262,38 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) case OP_STOREI8_MEMBASE_REG: #endif case OP_STORER8_MEMBASE_REG: - case OP_STORE_MEMBASE_REG: + case OP_STORE_MEMBASE_REG: { + if (ins->opcode == OP_STORER4_MEMBASE_REG && !cfg->r4fp) { + NEW_INS_BEFORE (cfg, ins, temp, OP_FCONV_TO_R4); + temp->dreg = mono_alloc_freg (cfg); + temp->sreg1 = ins->sreg1; + + ins->sreg1 = temp->dreg; + } // check if offset is valid I-type Imm - if (!RISCV_VALID_I_IMM ((gint32)(gssize)(ins->inst_offset))) - NOT_IMPLEMENTED; + if (!RISCV_VALID_I_IMM ((gint32)(gssize)(ins->inst_offset))) { + g_assert (ins->opcode != OP_STORER4_MEMBASE_REG); + + /** + * iconst t0, offset + * add t0, rd, t0 + * store rs1, 0(t0) + */ + int offset_reg = mono_alloc_ireg (cfg); + NEW_INS_BEFORE (cfg, ins, temp, OP_ICONST); + temp->dreg = offset_reg; + temp->inst_c0 = ins->inst_offset; + + NEW_INS_BEFORE (cfg, ins, temp, OP_IADD); + temp->dreg = offset_reg; + temp->sreg1 = ins->inst_destbasereg; + temp->sreg2 = offset_reg; + + ins->inst_offset = 0; + ins->inst_destbasereg = offset_reg; + } break; + } // Inst L{B|H|W|D} use I-type Imm case OP_LOADI1_MEMBASE: @@ -2467,7 +2516,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) NULLIFY_INS (ins); } else if (ins->next->opcode == OP_IL_SEQ_POINT || ins->next->opcode == OP_MOVE || ins->next->opcode == OP_LOAD_MEMBASE || ins->next->opcode == OP_NOP || - ins->next->opcode == OP_LOADI4_MEMBASE) { + ins->next->opcode == OP_LOADI4_MEMBASE || ins->next->opcode == OP_BR) { /** * there is compare without branch OP followed * @@ -2505,8 +2554,9 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) case OP_ADD_IMM: case OP_IADD_IMM: case OP_LADD_IMM: - if (!RISCV_VALID_I_IMM ((gint32)(gssize)(ins->inst_imm))) + if (!RISCV_VALID_I_IMM ((gint32)(gssize)(ins->inst_imm))) { mono_decompose_op_imm (cfg, bb, ins); + } break; case OP_ADDCC: case OP_IADDCC: { @@ -2544,6 +2594,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) break; } case OP_MUL_IMM: + case OP_IMUL_IMM: { g_assert (riscv_stdext_m); NEW_INS_BEFORE (cfg, ins, temp, OP_ICONST); temp->inst_c0 = ins->inst_imm; @@ -2552,8 +2603,10 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_imm = 0; ins->opcode = OP_IMUL; break; + } case OP_IREM_IMM: case OP_LREM_UN_IMM: + case OP_IDIV_IMM: mono_decompose_op_imm (cfg, bb, ins); break; @@ -2563,6 +2616,8 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) case OP_LAND_IMM: case OP_IOR_IMM: case OP_LOR_IMM: + case OP_XOR_IMM: + case OP_IXOR_IMM: if (!RISCV_VALID_I_IMM ((gint32)(gssize)(ins->inst_imm))) mono_decompose_op_imm (cfg, bb, ins); break; @@ -2571,6 +2626,21 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) ins->opcode = OP_XOR_IMM; ins->inst_imm = -1; break; + case OP_ICONV_TO_I1: + case OP_LCONV_TO_I1: + // slli a0, a0, 56 + // srai a0, a0, 56 + NEW_INS_BEFORE (cfg, ins, temp, OP_ICONST); + temp->opcode = OP_SHL_IMM; + temp->dreg = ins->dreg; + temp->sreg1 = ins->sreg1; + temp->inst_imm = 56; + + ins->opcode = OP_SHR_IMM; + ins->dreg = ins->dreg; + ins->sreg1 = temp->dreg; + ins->inst_imm = 56; + break; case OP_ICONV_TO_U1: case OP_LCONV_TO_U1: // andi rd, rs1, 255 @@ -2634,7 +2704,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) } #endif default: - printf ("unable to lowering following IR:"); + printf ("unable to lower the following IR:"); mono_print_ins (ins); NOT_IMPLEMENTED; break; @@ -2679,22 +2749,21 @@ mono_riscv_emit_imm (guint8 *code, int rd, gsize imm) * LUI: High 20 bit of imm * ADDIW: Low 12 bit of imm */ - if (RISCV_VALID_IMM (imm)) { + if (RISCV_VALID_IMM32 (imm)) { gint32 Hi = RISCV_BITS (imm, 12, 20); gint32 Lo = RISCV_BITS (imm, 0, 12); // Lo is in signed num - // if Lo > 0x800 + // if Lo >= 0x800 // convert into ((Hi + 1) << 20) - (0x1000 - Lo) if (Lo >= 0x800) { - Hi += 1; + if (imm > 0) + Hi += 1; Lo = Lo - 0x1000; } - // if Hi is 0 or overflow, skip - if (Hi < 0xfffff) { - riscv_lui (code, rd, Hi); - } + g_assert (Hi <= 0xfffff); + riscv_lui (code, rd, Hi); riscv_addiw (code, rd, rd, Lo); return code; } @@ -2938,8 +3007,6 @@ mono_riscv_emit_store_regarray (guint8 *code, guint64 regs, int basereg, int off for (int i = 0; i < 32; ++i) { if (regs & (1 << i)) { - if (!isFloat && i == RISCV_SP) - g_assert_not_reached (); if (isFloat) code = mono_riscv_emit_fstore (code, i, basereg, offset + (i * sizeof (host_mgreg_t)), FALSE); else @@ -2971,6 +3038,8 @@ mono_riscv_emit_load_stack (guint8 *code, guint64 regs, int basereg, int offset, for (int i = 0; i < 32; ++i) { if (regs & (1 << i)) { + if (!isFloat && i == RISCV_SP) + g_assert_not_reached (); if (isFloat) code = mono_riscv_emit_fload (code, i, basereg, (offset + (pos * sizeof (host_mgreg_t))), FALSE); else @@ -3072,14 +3141,18 @@ emit_move_args (MonoCompile *cfg, guint8 *code) if (ins->opcode == OP_REGVAR) { switch (ainfo->storage) { case ArgInIReg: - riscv_addi (code, ins->dreg, ainfo->reg, 0); + if (ins->dreg != ainfo->reg) + riscv_addi (code, ins->dreg, ainfo->reg, 0); if (i == 0 && sig->hasthis) { mono_add_var_location (cfg, ins, TRUE, ainfo->reg, 0, 0, code - cfg->native_code); mono_add_var_location (cfg, ins, TRUE, ins->dreg, 0, code - cfg->native_code, 0); } break; - + case ArgOnStack: + code = mono_riscv_emit_load (code, ins->dreg, RISCV_FP, ainfo->offset, ainfo->slot_size); + break; default: + g_print ("Can't handle arg type %d\n", ainfo->storage); NOT_IMPLEMENTED; } } else { @@ -3181,46 +3254,29 @@ mono_riscv_emit_call (MonoCompile *cfg, guint8 *code, MonoJumpInfoType patch_typ static guint8 * mono_riscv_emit_branch_exc (MonoCompile *cfg, guint8 *code, int opcode, int sreg1, int sreg2, const char *exc_name) { - // guint8 *p; - - // riscv_auipc(code, RISCV_T0, 0); - // // load imm - // riscv_jal (code, RISCV_T1, sizeof (guint64) + 4); - // p = code; - // code += sizeof (guint64); - // riscv_ld (code, RISCV_T1, RISCV_T1, 0); - // // pc + imm - // riscv_add(code, RISCV_T0, RISCV_T0, RISCV_T1); - - // *(guint64 *)p = (gsize)code; - + riscv_auipc (code, RISCV_T0, 0); switch (opcode) { case OP_RISCV_EXC_BEQ: - riscv_bne (code, sreg1, sreg2, 16 + sizeof (guint64)); + riscv_bne (code, sreg1, sreg2, 8); break; case OP_RISCV_EXC_BNE: - riscv_beq (code, sreg1, sreg2, 16 + sizeof (guint64)); + riscv_beq (code, sreg1, sreg2, 8); break; case OP_RISCV_EXC_BLT: - riscv_bge (code, sreg1, sreg2, 16 + sizeof (guint64)); + riscv_bge (code, sreg1, sreg2, 8); break; case OP_RISCV_EXC_BLTU: - riscv_bgeu (code, sreg1, sreg2, 16 + sizeof (guint64)); + riscv_bgeu (code, sreg1, sreg2, 8); break; case OP_RISCV_EXC_BGEU: - riscv_bltu (code, sreg1, sreg2, 16 + sizeof (guint64)); + riscv_bltu (code, sreg1, sreg2, 8); break; default: g_print ("can't emit exc branch %d\n", opcode); NOT_IMPLEMENTED; } - riscv_jal (code, RISCV_T6, sizeof (guint64) + 4); - - mono_add_patch_info_rel (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, exc_name, MONO_R_RISCV_JALR); - code += sizeof (guint64); - - code = mono_riscv_emit_load (code, RISCV_T6, RISCV_T6, 0, 0); - riscv_jalr (code, RISCV_ZERO, RISCV_T6, 0); + mono_add_patch_info_rel (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, exc_name, MONO_R_RISCV_JAL); + riscv_jal (code, RISCV_ZERO, 0); return code; } @@ -3268,17 +3324,35 @@ mono_arch_emit_prolog (MonoCompile *cfg) // save s0(fp) value stack_size += sizeof (target_mgreg_t); code = mono_riscv_emit_store (code, RISCV_FP, RISCV_SP, cfg->stack_offset - stack_size, 0); - } else - NOT_IMPLEMENTED; + + // set s0(fp) value + riscv_addi (code, RISCV_FP, RISCV_SP, cfg->stack_offset); + } else { + // save current FP into T0 + riscv_addi (code, RISCV_T0, RISCV_FP, 0); + + // FP = SP + riscv_addi (code, RISCV_FP, RISCV_SP, 0); + + // save return value + stack_size += sizeof (target_mgreg_t); + code = mono_riscv_emit_store (code, RISCV_RA, RISCV_FP, -stack_size, 0); + + // save fp value, here is T0 + stack_size += sizeof (target_mgreg_t); + code = mono_riscv_emit_store (code, RISCV_T0, RISCV_FP, -stack_size, 0); + + // save stack size into T0 + code = mono_riscv_emit_imm (code, RISCV_T0, cfg->stack_offset); + // calculate SP + riscv_sub (code, RISCV_SP, RISCV_SP, RISCV_T0); + } cfa_offset += cfg->stack_offset; mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset); mono_emit_unwind_op_offset (cfg, code, RISCV_RA, cfa_offset - sizeof (target_mgreg_t)); mono_emit_unwind_op_offset (cfg, code, RISCV_FP, cfa_offset - (sizeof (target_mgreg_t) * 2)); - // set s0(fp) value - riscv_addi (code, RISCV_FP, RISCV_SP, cfg->stack_offset); - // save other registers if (cfg->param_area) /* The param area is below the stack pointer */ @@ -3616,19 +3690,19 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; #endif case OP_STORE_MEMBASE_REG: - code = mono_riscv_emit_store (code, ins->sreg1, ins->dreg, ins->inst_offset, 0); + code = mono_riscv_emit_store (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset, 0); break; case OP_STOREI1_MEMBASE_REG: - code = mono_riscv_emit_store (code, ins->sreg1, ins->dreg, ins->inst_offset, 1); + code = mono_riscv_emit_store (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset, 1); break; case OP_STOREI2_MEMBASE_REG: - code = mono_riscv_emit_store (code, ins->sreg1, ins->dreg, ins->inst_offset, 2); + code = mono_riscv_emit_store (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset, 2); break; case OP_STOREI4_MEMBASE_REG: - code = mono_riscv_emit_store (code, ins->sreg1, ins->dreg, ins->inst_offset, 4); + code = mono_riscv_emit_store (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset, 4); break; case OP_STOREI8_MEMBASE_REG: - code = mono_riscv_emit_store (code, ins->sreg1, ins->dreg, ins->inst_offset, 8); + code = mono_riscv_emit_store (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset, 8); break; case OP_ICONST: case OP_I8CONST: @@ -3648,6 +3722,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) riscv_sub (code, ins->dreg, ins->sreg1, ins->sreg2); break; case OP_IMUL: + case OP_LMUL: g_assert (riscv_stdext_m); riscv_mul (code, ins->dreg, ins->sreg1, ins->sreg2); break; @@ -3662,12 +3737,21 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) else NOT_IMPLEMENTED; break; + case OP_FDIV: + g_assert (riscv_stdext_f || riscv_stdext_d); + if (riscv_stdext_d) + riscv_fdiv_d (code, RISCV_ROUND_DY, ins->dreg, ins->sreg1, ins->sreg2); + else + riscv_fdiv_d (code, RISCV_ROUND_DY, ins->dreg, ins->sreg1, ins->sreg2); + break; + case OP_IDIV: case OP_LDIV: g_assert (riscv_stdext_m); code = mono_riscv_emit_branch_exc (cfg, code, OP_RISCV_EXC_BEQ, ins->sreg2, RISCV_ZERO, "DivideByZeroException"); riscv_div (code, ins->dreg, ins->sreg1, ins->sreg2); break; + case OP_IDIV_UN: case OP_LDIV_UN: g_assert (riscv_stdext_m); code = mono_riscv_emit_branch_exc (cfg, code, OP_RISCV_EXC_BEQ, ins->sreg2, RISCV_ZERO, @@ -3930,7 +4014,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) riscv_fmv_w_x (code, RISCV_FT0, RISCV_ZERO); riscv_feq_s (code, RISCV_T0, ins->sreg2, RISCV_FT0); - code = mono_riscv_emit_branch_exc (cfg, code, OP_RISCV_EXC_BNE, RISCV_T0, RISCV_ZERO, + code = mono_riscv_emit_branch_exc (cfg, code, OP_RISCV_EXC_BEQ, RISCV_T0, RISCV_ZERO, "DivideByZeroException"); riscv_fdiv_s (code, RISCV_ROUND_DY, ins->dreg, ins->sreg1, ins->sreg2); break; @@ -4153,20 +4237,20 @@ mono_arch_emit_exceptions (MonoCompile *cfg) guint8 *code, *ip; guint8 *exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL}; guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0}; - int exc_id, max_epilog_size = 0; + int exc_id, size = 0; for (ji = cfg->patch_info; ji; ji = ji->next) { if (ji->type == MONO_PATCH_INFO_EXC) { exc_id = mini_exception_id_by_name ((const char *)ji->data.target); g_assert (exc_id < MONO_EXC_INTRINS_NUM); if (!exc_throw_found [exc_id]) { - max_epilog_size += 40; // 8 Inst for exception + size += 40; // 8 Inst for exception exc_throw_found [exc_id] = TRUE; } } } - code = realloc_code (cfg, max_epilog_size); + code = realloc_code (cfg, size); /* Emit code to raise corlib exceptions */ for (ji = cfg->patch_info; ji; ji = ji->next) { diff --git a/src/mono/mono/mini/mini-riscv.h b/src/mono/mono/mini/mini-riscv.h index d01227d..349764e 100644 --- a/src/mono/mono/mini/mini-riscv.h +++ b/src/mono/mono/mini/mini-riscv.h @@ -121,7 +121,9 @@ extern gboolean riscv_stdext_a, riscv_stdext_b, riscv_stdext_c, riscv_stdext_d, #define MONO_ARCH_CODE_ALIGNMENT (32) // TODO: remove following def -#define MONO_ARCH_EMULATE_MUL_DIV (1) +#define MONO_ARCH_EMULATE_MUL_OVF (1) +#define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS (1) +#define MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS (1) #define MONO_ARCH_EMULATE_FREM (1) #ifdef TARGET_RISCV64 @@ -284,6 +286,9 @@ enum { MONO_R_RISCV_JALR = 10, }; +void +mono_riscv_throw_exception (gpointer arg, host_mgreg_t pc, host_mgreg_t *int_regs, gdouble *fp_regs, gboolean corlib, gboolean rethrow, gboolean preserve_ips); + __attribute__ ((warn_unused_result)) guint8 * mono_riscv_emit_imm (guint8 *code, int rd, gsize imm); diff --git a/src/mono/mono/mini/tramp-riscv.c b/src/mono/mono/mini/tramp-riscv.c index 87ae678..414c3a4 100644 --- a/src/mono/mono/mini/tramp-riscv.c +++ b/src/mono/mono/mini/tramp-riscv.c @@ -166,17 +166,16 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf } riscv_jalr (code, RISCV_RA, RISCV_T1, 0); - /* a0 contains the address of the tls slot holding the current lmf */ + /* a0 contains the address of the tls slot holding the current (MonoLMF **)lmf */ /* T0 = lmf */ riscv_addi (code, RISCV_T0, RISCV_FP, -lmf_offset); /* lmf->lmf_addr = lmf_addr */ - code = mono_riscv_emit_store (code, RISCV_A0, RISCV_FP, -lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, lmf_addr), 0); + code = mono_riscv_emit_store (code, RISCV_A0, RISCV_T0, MONO_STRUCT_OFFSET (MonoLMF, lmf_addr), 0); /* lmf->previous_lmf = *lmf_addr */ code = mono_riscv_emit_load (code, RISCV_T1, RISCV_A0, 0, 0); - code = - mono_riscv_emit_store (code, RISCV_T1, RISCV_FP, -lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), 0); + code = mono_riscv_emit_store (code, RISCV_T1, RISCV_T0, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), 0); /* *lmf_addr = lmf */ code = mono_riscv_emit_store (code, RISCV_T0, RISCV_A0, 0, 0); @@ -216,9 +215,9 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* T0 = lmf */ riscv_addi (code, RISCV_T0, RISCV_FP, -lmf_offset); /* T1 = lmf->previous_lmf */ - code = mono_riscv_emit_load (code, RISCV_T1, RISCV_FP, -lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), 0); + code = mono_riscv_emit_load (code, RISCV_T1, RISCV_T0, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), 0); /* T0 = lmf->lmf_addr */ - code = mono_riscv_emit_load (code, RISCV_T0, RISCV_FP, -lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, lmf_addr), 0); + code = mono_riscv_emit_load (code, RISCV_T0, RISCV_T0, MONO_STRUCT_OFFSET (MonoLMF, lmf_addr), 0); /* *lmf_addr = previous_lmf */ code = mono_riscv_emit_store (code, RISCV_T1, RISCV_T0, 0, 0); -- 2.7.4