From 447f78ea4af3da5486d506006d3689c79d4b9306 Mon Sep 17 00:00:00 2001 From: VincentWu <43398706+Xinlong-Wu@users.noreply.github.com> Date: Sun, 17 Dec 2023 23:46:51 +0800 Subject: [PATCH] [RISC-V] Fix the order of parameters stored on the stack (#96106) * tmp * fix ArgVtypeByRef * update * OP_VCALL2_REG * update * update * fix OP_ZEXT_ * OP_RCLT_UN & OP_ICONV_TO_OVF_U1 * fix save lmf * fix type of imm param in load/store * mono_arch_get_rethrow_exception & mono_arch_get_rethrow_preserve_exception * skip non callee saved regs when unwind frame * fix cfa * update porting ststus * lowering & output fcall_reg decompose F/RCONV_TO_OVF_I8, OP_LCONV_TO_OVF_U* * update * update * update * fix mono_arch_emit_outarg_vt for type ArgVtypeInMixed * update * unsolved roslyn-sdk * call_filter OP_ICONV_TO_OVF_U8 & OP_LSUB_OVF & OP_LMUL_OVF OP_SUBCC & OP_LSUBCC * fix OP_ADDCC * update * voidcall_membase, mono_arch_get_call_filter * fix stack usage of Call param with OnStack type * fix stack alloc for freg * tmp * tmp * update * fix call_filter * fix MAX_ARCH_DELEGATE_PARAMS mono_arch_get_delegate_invoke_impl for ( sig->param_count > MAX_ARCH_DELEGATE_PARAMS) process param type ArgVtypeByRefOnStack * fix call_membase & vcall2_membase * rcall_membase * update * softbreak * realoc stack * fix OP_ENDFILTER * decompose OP_ICONV_TO_OVF_U* * tmp * clang format * fmt * clean * revert --- src/mono/mono/mini/cpu-riscv64.mdesc | 13 +- src/mono/mono/mini/exceptions-riscv.c | 118 ++++++++++++++++-- src/mono/mono/mini/mini-riscv.c | 173 ++++++++++++++++---------- src/mono/mono/mini/mini-riscv.h | 17 +-- src/mono/mono/utils/mono-context.h | 2 +- 5 files changed, 234 insertions(+), 89 deletions(-) diff --git a/src/mono/mono/mini/cpu-riscv64.mdesc b/src/mono/mono/mini/cpu-riscv64.mdesc index f1d4470a42b7b..8eb340ea1fd2e 100644 --- a/src/mono/mono/mini/cpu-riscv64.mdesc +++ b/src/mono/mono/mini/cpu-riscv64.mdesc @@ -38,13 +38,14 @@ seq_point: len:0 check_this: src1:b len:4 get_ex_obj: dest:i len:4 gc_safe_point: src1:i len:12 clob:c -start_handler: len:8 clob:c +start_handler: len:16 clob:c call_handler: len:4 clob:c endfinally: len:32 endfilter: src1:i len:32 localloc: dest:i src1:i len:52 localloc_imm: dest:i len:28 generic_class_init: src1:a len:12 clob:c +break: len:4 throw: src1:i len:4 rethrow: src1:i len:4 @@ -54,14 +55,17 @@ br_reg: src1:i len:4 jump_table: dest:i len:16 call: dest:a len:4 clob:c call_reg: dest:a src1:i len:4 clob:c -call_membase: dest:a src1:b len:8 clob:c +call_membase: dest:a src1:b len:20 clob:c voidcall: len:4 clob:c voidcall_reg: src1:i len:4 clob:c -voidcall_membase: src1:b len:8 clob:c +voidcall_membase: src1:b len:20 clob:c vcall2: len:16 clob:c -vcall2_membase: src1:b len:20 clob:c +vcall2_reg: src1:i len:16 clob:c +vcall2_membase: src1:b len:28 clob:c fcall: dest:f len:8 clob:c rcall: dest:f len:8 clob:c +rcall_membase: dest:f src1:b len:12 clob:c +fcall_reg: dest:f src1:i len:8 clob:c fcall_membase: dest:f src1:b len:12 clob:c # Note: in RV32, it shoule be @@ -148,6 +152,7 @@ float_cle: dest:i src1:f src2:f len:4 float_clt: dest:i src1:f src2:f len:4 float_clt_un: dest:i src1:f src2:f len:4 r4_clt: dest:i src1:f src2:f len:4 +r4_clt_un: dest:i src1:f src2:f len:4 r4_cle: dest:i src1:f src2:f len:4 add_imm: 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 b8cba29238727..fec9d18fafb60 100644 --- a/src/mono/mono/mini/exceptions-riscv.c +++ b/src/mono/mono/mini/exceptions-riscv.c @@ -112,8 +112,104 @@ mono_riscv_throw_exception (gpointer arg, host_mgreg_t pc, host_mgreg_t *int_reg gpointer mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) { - *info = NULL; - return nop_stub (0x37); + guint8 *code; + guint8 *start; + int i, size, offset, gregs_offset, fregs_offset, ctx_offset, num_fregs, frame_size; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; + + size = 632; + start = code = mono_global_codeman_reserve (size); + + /* 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 */ + offset += RISCV_N_FREGS * sizeof (host_mgreg_t); + fregs_offset = offset; + + /* ctx */ + offset += sizeof (host_mgreg_t); + ctx_offset = offset; + frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT); + + /* + * We are being called from C code, ctx is in a0, the address to call is in a1. + * We need to save state, restore ctx, make the call, then restore the previous state, + * returning the value returned by the call. + */ + + MINI_BEGIN_CODEGEN (); + + // riscv_ebreak (code); + + /* 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 ctx */ + code = mono_riscv_emit_store (code, RISCV_A0, RISCV_FP, -ctx_offset, 0); + /* Save gregs */ + code = mono_riscv_emit_store_stack (code, MONO_ARCH_CALLEE_SAVED_REGS, RISCV_FP, -gregs_offset, FALSE); + /* Save fregs */ + if (riscv_stdext_f || riscv_stdext_d) + code = mono_riscv_emit_store_stack (code, 0xffffffff, RISCV_FP, -fregs_offset, TRUE); + + /* Load regs from ctx */ + code = mono_riscv_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, RISCV_A0, + MONO_STRUCT_OFFSET (MonoContext, gregs), FALSE); + + /* Load fregs */ + if (riscv_stdext_f || riscv_stdext_d) + code = + mono_riscv_emit_load_regarray (code, 0xffffffff, RISCV_A0, MONO_STRUCT_OFFSET (MonoContext, fregs), TRUE); + + /* Load fp */ + // code = mono_riscv_emit_load (code, RISCV_FP, RISCV_A0, MONO_STRUCT_OFFSET (MonoContext, gregs) + (RISCV_FP * + // sizeof (host_mgreg_t)), 0); + + /* Make the call */ + riscv_jalr (code, RISCV_RA, RISCV_A1, 0); + /* For filters, the result is in R0 */ + + /* Restore fp */ + riscv_addi (code, RISCV_FP, RISCV_SP, frame_size); + + /* Load ctx */ + code = mono_riscv_emit_load (code, RISCV_T0, RISCV_FP, -ctx_offset, 0); + /* Save registers back to ctx, except FP*/ + /* This isn't strictly necessary since we don't allocate variables used in eh clauses to registers */ + code = mono_riscv_emit_store_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS ^ (1 << RISCV_FP), RISCV_T0, + MONO_STRUCT_OFFSET (MonoContext, gregs), FALSE); + + /* Restore regs */ + code = mono_riscv_emit_load_stack (code, MONO_ARCH_CALLEE_SAVED_REGS, RISCV_FP, -gregs_offset, FALSE); + /* Restore fregs */ + if (riscv_stdext_f || riscv_stdext_d) + code = mono_riscv_emit_load_stack (code, 0xffffffff, RISCV_FP, -fregs_offset, TRUE); + + /* Destroy frame */ + code = mono_riscv_emit_destroy_frame (code); + + riscv_jalr (code, RISCV_X0, RISCV_RA, 0); + + 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 ("call_filter", start, code - start, ji, unwind_ops); + + return MINI_ADDR_TO_FTNPTR (start); } static gpointer @@ -227,15 +323,13 @@ mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) gpointer mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) { - *info = NULL; - return nop_stub (0x88); + return get_throw_trampoline (384, FALSE, TRUE, FALSE, FALSE, "rethrow_exception", info, aot, FALSE); } gpointer mono_arch_get_rethrow_preserve_exception (MonoTrampInfo **info, gboolean aot) { - *info = NULL; - return nop_stub (0x99); + return get_throw_trampoline (384, FALSE, TRUE, FALSE, FALSE, "rethrow_preserve_exception", info, aot, TRUE); } gpointer @@ -331,6 +425,9 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, MonoJitInfo *ji, gpointer ip = MINI_FTNPTR_TO_ADDR (MONO_CONTEXT_GET_IP (ctx)); + // printf ("%s %p %p\n", ji->d.method->name, ji->code_start, ip); + // mono_print_unwind_info (unwind_info, unwind_info_len); + 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); @@ -350,7 +447,7 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, MonoJitInfo *ji, 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)); + *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~3); } /* we subtract 1, so that the PC points into the call instruction */ @@ -369,6 +466,11 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, MonoJitInfo *ji, 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); + for (int i = 0; i < RISCV_N_GREGS; i++) { + if (!(MONO_ARCH_LMF_REGS & (1 << i))) { + new_ctx->gregs [i] = ctx->gregs [i]; + } + } // 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 @@ -376,7 +478,7 @@ mono_arch_unwind_frame (MonoJitTlsData *jit_tls, MonoJitInfo *ji, /* 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)); + *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~3); return TRUE; } diff --git a/src/mono/mono/mini/mini-riscv.c b/src/mono/mono/mini/mini-riscv.c index fe169c316e7ca..4ef94ee41cd21 100644 --- a/src/mono/mono/mini/mini-riscv.c +++ b/src/mono/mono/mini/mini-riscv.c @@ -146,7 +146,7 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask) } // Reference to mini-arm64, should be the namber of Parameter Regs -#define MAX_ARCH_DELEGATE_PARAMS 7 +#define MAX_ARCH_DELEGATE_PARAMS 8 static gpointer get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size) @@ -282,7 +282,7 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe static guint8 *cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL}; if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS) - NOT_IMPLEMENTED; + return NULL; for (int i = 0; i < sig->param_count; ++i) if (!mono_is_regsize_var (sig->params [i])) return NULL; @@ -773,11 +773,11 @@ add_arg (CallInfo *cinfo, ArgInfo *ainfo, int size, gboolean sign) } // If no argument registers are available, the scalar is passed on the stack by value else { - // cinfo->stack_usage & ainfo->offset - // will be calculated in get_call_info() ainfo->storage = ArgOnStack; - ainfo->slot_size = size; + ainfo->slot_size = sizeof (host_mgreg_t); ainfo->is_signed = sign; + ainfo->offset = cinfo->stack_usage; + cinfo->stack_usage += sizeof (host_mgreg_t); } } @@ -798,6 +798,8 @@ add_farg (CallInfo *cinfo, ArgInfo *ainfo, gboolean single) } else { ainfo->storage = single ? ArgOnStackR4 : ArgOnStackR8; ainfo->slot_size = size; + ainfo->offset = cinfo->stack_usage; + cinfo->stack_usage += size; } } @@ -831,8 +833,8 @@ add_valuetype (CallInfo *cinfo, ArgInfo *ainfo, MonoType *t) 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; + cinfo->stack_usage += aligned_size; + ainfo->slot_size = aligned_size; } // 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 @@ -865,8 +867,8 @@ add_valuetype (CallInfo *cinfo, ArgInfo *ainfo, MonoType *t) if (cinfo->next_arg > RISCV_A7) { ainfo->offset = cinfo->stack_usage; ainfo->storage = ArgVtypeOnStack; - cinfo->stack_usage += sizeof (host_mgreg_t); - ainfo->slot_size = sizeof (host_mgreg_t); + cinfo->stack_usage += aligned_size; + ainfo->slot_size = aligned_size; } else { ainfo->storage = ArgVtypeInIReg; ainfo->reg = cinfo->next_arg; @@ -1021,7 +1023,6 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } // other general Arguments - guint32 argStack = 0; for (pindex = paramStart; pindex < sig->param_count; ++pindex) { ArgInfo *ainfo = cinfo->args + sig->hasthis + pindex; @@ -1030,12 +1031,6 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) NOT_IMPLEMENTED; add_param (cinfo, ainfo, sig->params [pindex]); - - if (ainfo->storage == ArgOnStack || ainfo->storage == ArgOnStackR4 || ainfo->storage == ArgOnStackR8) { - ainfo->offset = argStack; - cinfo->stack_usage += ainfo->slot_size; - argStack += ainfo->slot_size; - } } /* Handle the case where there are no implicit arguments */ @@ -1614,7 +1609,8 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) case ArgVtypeInIReg: case ArgVtypeByRef: case ArgVtypeOnStack: - case ArgVtypeInMixed: { + case ArgVtypeInMixed: + case ArgVtypeByRefOnStack: { MonoInst *ins; guint32 align; guint32 size; @@ -1691,6 +1687,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) load->inst_basereg = src->dreg; load->inst_offset = 0; MONO_ADD_INS (cfg->cbb, load); + add_outarg_reg (cfg, call, ArgInIReg, ainfo->reg, load); MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE); load->dreg = mono_alloc_ireg (cfg); @@ -1700,7 +1697,8 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, RISCV_SP, ainfo->offset, load->dreg); break; } - case ArgVtypeByRef: { + case ArgVtypeByRef: + case ArgVtypeByRefOnStack: { MonoInst *vtaddr, *arg; /* Pass the vtype address in a reg/on the stack */ // if (ainfo->gsharedvt) { @@ -1820,7 +1818,9 @@ mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) case OP_FCONV_TO_R4: case OP_FCONV_TO_R8: case OP_FCONV_TO_I8: + case OP_FCONV_TO_OVF_I8: case OP_RCONV_TO_I8: + case OP_RCONV_TO_OVF_I8: #endif case OP_FNEG: case OP_IAND: @@ -1865,16 +1865,32 @@ mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) case OP_LREM_UN: case OP_IREM_UN_IMM: + case OP_ICONV_TO_OVF_U1: + case OP_ICONV_TO_OVF_U1_UN: case OP_ICONV_TO_OVF_U2: + case OP_ICONV_TO_OVF_U2_UN: + case OP_ICONV_TO_OVF_U4: + case OP_ICONV_TO_OVF_U4_UN: + case OP_ICONV_TO_OVF_U8: + case OP_ICONV_TO_OVF_U8_UN: case OP_LCONV_TO_OVF_I: case OP_LCONV_TO_OVF_U: + case OP_LCONV_TO_OVF_U1: + case OP_LCONV_TO_OVF_U1_UN: + case OP_LCONV_TO_OVF_U2: + case OP_LCONV_TO_OVF_U2_UN: case OP_LCONV_TO_OVF_I4: case OP_LCONV_TO_OVF_I4_UN: + case OP_LCONV_TO_OVF_U4: case OP_LCONV_TO_OVF_U4_UN: + case OP_LCONV_TO_OVF_U8: + case OP_LCONV_TO_OVF_U8_UN: case OP_LADD_OVF: case OP_LADD_OVF_UN: + case OP_LSUB_OVF: case OP_IMUL_OVF: + case OP_LMUL_OVF: case OP_LMUL_OVF_UN: case OP_LMUL_OVF_UN_OOM: @@ -2015,6 +2031,21 @@ mono_arch_allocate_vars (MonoCompile *cfg) offset += sizeof (host_mgreg_t) * 2; ins->inst_offset = -offset; break; + case ArgVtypeByRefOnStack: { + MonoInst *vtaddr; + + /* The vtype address is in the parent frame */ + g_assert (ainfo->offset >= 0); + MONO_INST_NEW (cfg, vtaddr, 0); + vtaddr->opcode = OP_REGOFFSET; + vtaddr->inst_basereg = RISCV_FP; + vtaddr->inst_offset = ainfo->offset; + + /* Need an indirection */ + ins->opcode = OP_VTARG_ADDR; + ins->inst_left = vtaddr; + break; + } case ArgVtypeByRef: { MonoInst *vtaddr; @@ -2030,8 +2061,8 @@ mono_arch_allocate_vars (MonoCompile *cfg) MONO_INST_NEW (cfg, vtaddr, 0); vtaddr->opcode = OP_REGOFFSET; vtaddr->inst_basereg = cfg->frame_reg; - vtaddr->inst_offset = offset; offset += sizeof (host_mgreg_t); + vtaddr->inst_offset = -offset; /* Need an indirection */ ins->opcode = OP_VTARG_ADDR; @@ -2141,6 +2172,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) { loop_start: switch (ins->opcode) { + case OP_BREAK: case OP_IL_SEQ_POINT: case OP_SEQ_POINT: case OP_GC_SAFE_POINT: @@ -2264,6 +2296,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FCEQ: case OP_FCLT: case OP_RCLT: + case OP_RCLT_UN: case OP_FCLT_UN: case OP_RISCV_SETFREG_R4: case OP_R4CONST: @@ -2434,6 +2467,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_CALL_MEMBASE: + case OP_RCALL_MEMBASE: case OP_LCALL_MEMBASE: case OP_FCALL_MEMBASE: case OP_VCALL2_MEMBASE: @@ -2458,7 +2492,9 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_CALL_REG: + case OP_FCALL_REG: case OP_VOIDCALL_REG: + case OP_VCALL2_REG: break; /* Throw */ @@ -2580,38 +2616,6 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) ins->sreg1 = temp->dreg; ins->inst_imm = 0; } - // TODO: Move This to Optimisation - if ((ins->next) && (ins->next->opcode >= OP_ZEXT_I1 && ins->next->opcode <= OP_ZEXT_I4)) { - switch (ins->opcode) { - case OP_LOADI1_MEMBASE: - ins->opcode = OP_LOADU1_MEMBASE; - ins->dreg = ins->next->dreg; - NULLIFY_INS (ins->next); - break; - case OP_LOADI2_MEMBASE: - ins->opcode = OP_LOADU2_MEMBASE; - ins->dreg = ins->next->dreg; - NULLIFY_INS (ins->next); - break; - case OP_LOADI4_MEMBASE: - ins->opcode = OP_LOADU4_MEMBASE; - ins->dreg = ins->next->dreg; - NULLIFY_INS (ins->next); - break; - case OP_LOADU1_MEMBASE: - case OP_LOADU2_MEMBASE: - case OP_LOADU4_MEMBASE: - ins->dreg = ins->next->dreg; - NULLIFY_INS (ins->next); - break; - case OP_LOAD_MEMBASE: - case OP_LOADI8_MEMBASE: - break; - default: - g_print (mono_inst_name (ins->opcode)); - g_assert_not_reached (); - } - } break; case OP_COMPARE_IMM: @@ -2703,12 +2707,12 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) ins->next->sreg1 = ins->sreg1; ins->next->sreg2 = ins->sreg2; NULLIFY_INS (ins); - } else if (ins->next->opcode == OP_COND_EXC_LT) { + } else if (ins->next->opcode == OP_COND_EXC_LT || ins->next->opcode == OP_COND_EXC_ILT) { ins->next->opcode = OP_RISCV_EXC_BLT; ins->next->sreg1 = ins->sreg1; ins->next->sreg2 = ins->sreg2; NULLIFY_INS (ins); - } else if (ins->next->opcode == OP_COND_EXC_LT_UN) { + } else if (ins->next->opcode == OP_COND_EXC_LT_UN || ins->next->opcode == OP_COND_EXC_ILT_UN) { ins->next->opcode = OP_RISCV_EXC_BLTU; ins->next->sreg1 = ins->sreg1; ins->next->sreg2 = ins->sreg2; @@ -2819,7 +2823,8 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) } 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_BR || - ins->next->opcode == OP_LOADI8_MEMBASE || ins->next->opcode == OP_ICONST) { + ins->next->opcode == OP_LOADI8_MEMBASE || ins->next->opcode == OP_ICONST || + ins->next->opcode == OP_I8CONST || ins->next->opcode == OP_ADD_IMM) { /** * there is compare without branch OP followed * @@ -2854,17 +2859,22 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) // convert OP_{I|L}SUB_IMM to their corresponding ADD_IMM ins->opcode -= 1; goto loop_start; + case OP_SUBCC: case OP_ISUBCC: + case OP_LSUBCC: /** * sub rd, rs1, rs2 * slti t1, x0, rs2 * slt t2, rd, rs1 * bne t1, t2, overflow */ - ins->opcode = OP_ISUB; + if (ins->opcode == OP_LSUBCC) + ins->opcode = OP_LSUB; + else + ins->opcode = OP_ISUB; MonoInst *branch_ins = ins->next; if (branch_ins) { - if (ins->next->opcode == OP_COND_EXC_IOV){ + if (branch_ins->opcode == OP_COND_EXC_OV || ins->next->opcode == OP_COND_EXC_IOV) { // bne t1, t2, overflow branch_ins->opcode = OP_RISCV_EXC_BNE; branch_ins->sreg1 = mono_alloc_ireg (cfg); @@ -2881,8 +2891,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) temp->dreg = branch_ins->sreg2; temp->sreg1 = ins->dreg; temp->sreg2 = ins->sreg1; - } - else{ + } else { mono_print_ins (branch_ins); g_assert_not_reached (); } @@ -2904,7 +2913,14 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) * slt t4,t0,t1 * bne t3, t4, overflow */ - ins->opcode = OP_IADD; + +#ifdef TARGET_RISCV64 + if (ins->opcode == OP_ADDCC) + ins->opcode = OP_LADD; + else +#endif + ins->opcode = OP_IADD; + MonoInst *branch_ins = ins->next; if (branch_ins) { if (branch_ins->opcode == OP_COND_EXC_C || branch_ins->opcode == OP_COND_EXC_OV || branch_ins->opcode == OP_COND_EXC_IOV) { @@ -3204,7 +3220,7 @@ mono_riscv_emit_nop (guint8 *code) // Uses at most 16 bytes on RV32I and 24 bytes on RV64I. // length == 0 means the data size follows the XLEN guint8 * -mono_riscv_emit_load (guint8 *code, int rd, int rs1, gint32 imm, int length) +mono_riscv_emit_load (guint8 *code, int rd, int rs1, target_mgreg_t imm, int length) { if (!RISCV_VALID_I_IMM (imm)) { code = mono_riscv_emit_imm (code, RISCV_T0, imm); @@ -3244,7 +3260,7 @@ mono_riscv_emit_load (guint8 *code, int rd, int rs1, gint32 imm, int length) // Uses at most 16 bytes on RV32I and 24 bytes on RV64I. guint8 * -mono_riscv_emit_loadu (guint8 *code, int rd, int rs1, gint32 imm, int length) +mono_riscv_emit_loadu (guint8 *code, int rd, int rs1, target_mgreg_t imm, int length) { if (!RISCV_VALID_I_IMM (imm)) { code = mono_riscv_emit_imm (code, RISCV_T0, imm); @@ -3274,7 +3290,7 @@ mono_riscv_emit_loadu (guint8 *code, int rd, int rs1, gint32 imm, int length) // Uses at most 16 bytes on RV32D and 24 bytes on RV64D. guint8 * -mono_riscv_emit_fload (guint8 *code, int rd, int rs1, gint32 imm, gboolean isSingle) +mono_riscv_emit_fload (guint8 *code, int rd, int rs1, target_mgreg_t imm, gboolean isSingle) { g_assert (riscv_stdext_d || (isSingle && riscv_stdext_f)); if (!RISCV_VALID_I_IMM (imm)) { @@ -3295,7 +3311,7 @@ mono_riscv_emit_fload (guint8 *code, int rd, int rs1, gint32 imm, gboolean isSin // May clobber t0. Uses at most 16 bytes on RV32I and 24 bytes on RV64I. // length == 0 means the data size follows the XLEN guint8 * -mono_riscv_emit_store (guint8 *code, int rs2, int rs1, gint32 imm, int length) +mono_riscv_emit_store (guint8 *code, int rs2, int rs1, target_mgreg_t imm, int length) { if (!RISCV_VALID_S_IMM (imm)) { code = mono_riscv_emit_imm (code, RISCV_T0, imm); @@ -3335,7 +3351,7 @@ mono_riscv_emit_store (guint8 *code, int rs2, int rs1, gint32 imm, int length) // May clobber t0. Uses at most 16 bytes on RV32I and 24 bytes on RV64I. guint8 * -mono_riscv_emit_fstore (guint8 *code, int rs2, int rs1, gint32 imm, gboolean isSingle) +mono_riscv_emit_fstore (guint8 *code, int rs2, int rs1, target_mgreg_t imm, gboolean isSingle) { g_assert (riscv_stdext_d || (isSingle && riscv_stdext_f)); if (!RISCV_VALID_I_IMM (imm)) { @@ -3534,11 +3550,10 @@ emit_setup_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset) */ g_assert (lmf_offset <= 0); /* pc */ - code = mono_riscv_emit_imm (code, RISCV_T6, (gsize)code); - code = mono_riscv_emit_store (code, RISCV_T6, RISCV_FP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, pc), 0); + code = mono_riscv_emit_store (code, RISCV_RA, RISCV_FP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, pc), 0); /* callee saved gregs + sp */ code = emit_store_regarray_cfa (cfg, code, MONO_ARCH_LMF_REGS, RISCV_FP, - lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, gregs), (1 << RISCV_SP)); + lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, gregs), (1 << RISCV_SP | 1 << RISCV_FP)); return code; } @@ -3619,6 +3634,7 @@ emit_move_args (MonoCompile *cfg, guint8 *code) break; case ArgOnStack: case ArgVtypeOnStack: + case ArgVtypeByRefOnStack: break; default: g_print ("can't process Storage type %d\n", ainfo->storage); @@ -3653,7 +3669,13 @@ emit_move_return_value (MonoCompile *cfg, guint8 *code, MonoInst *ins) if (riscv_stdext_d) riscv_fsgnj_d (code, call->inst.dreg, cinfo->ret.reg, cinfo->ret.reg); else - riscv_fsgnj_s (code, ins->dreg, cinfo->ret.reg, cinfo->ret.reg); + riscv_fsgnj_s (code, call->inst.dreg, cinfo->ret.reg, cinfo->ret.reg); + } + break; + case ArgInFRegR4: + g_assert (riscv_stdext_d || riscv_stdext_f); + if (call->inst.dreg != cinfo->ret.reg) { + riscv_fsgnj_s (code, call->inst.dreg, cinfo->ret.reg, cinfo->ret.reg); } break; case ArgVtypeInIReg: { @@ -4075,6 +4097,15 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_riscv_patch (branch_label, code, MONO_R_RISCV_BNE); break; } + case OP_BREAK: + /* + * gdb does not like encountering the hw breakpoint ins in the debugged code. + * So instead of emitting a trap, we emit a call a C function and place a + * breakpoint there. + */ + code = mono_riscv_emit_call (cfg, code, MONO_PATCH_INFO_JIT_ICALL_ID, + GUINT_TO_POINTER (MONO_JIT_ICALL_mono_break)); + break; case OP_NOP: case OP_RELAXED_NOP: @@ -4641,13 +4672,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; } case OP_CALL_REG: + case OP_RCALL_REG: + case OP_FCALL_REG: case OP_VOIDCALL_REG: + case OP_VCALL2_REG: // JALR x1, 0(src1) riscv_jalr (code, RISCV_RA, ins->sreg1, 0); code = emit_move_return_value (cfg, code, ins); break; case OP_CALL_MEMBASE: case OP_LCALL_MEMBASE: + case OP_RCALL_MEMBASE: case OP_FCALL_MEMBASE: case OP_VCALL2_MEMBASE: case OP_VOIDCALL_MEMBASE: @@ -4764,7 +4799,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_ENDFILTER: { MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); if (cfg->param_area) - riscv_addi (code, RISCV_SP, RISCV_SP, -cfg->param_area); + riscv_addi (code, RISCV_SP, RISCV_SP, cfg->param_area); if (ins->opcode == OP_ENDFILTER && ins->sreg1 != RISCV_A0) riscv_addi (code, RISCV_A0, ins->sreg1, 0); diff --git a/src/mono/mono/mini/mini-riscv.h b/src/mono/mono/mini/mini-riscv.h index d9a34c5f8d5b8..c03905f038d37 100644 --- a/src/mono/mono/mini/mini-riscv.h +++ b/src/mono/mono/mini/mini-riscv.h @@ -202,6 +202,11 @@ typedef struct { } while (0) struct MonoLMF { + /* + * The rsp field points to the stack location where the caller ip is saved. + * If the second lowest bit is set, then this is a MonoLMFExt structure, and + * the other fields are not valid. + */ gpointer previous_lmf; gpointer lmf_addr; host_mgreg_t pc; @@ -235,8 +240,6 @@ typedef enum { #endif ArgOnStackR4, ArgOnStackR8, - ArgStructByVal, - ArgStructByAddr, /* * Vtype passed in consecutive int registers. */ @@ -300,19 +303,19 @@ __attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_float_imm (guint8 * __attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_nop (guint8 *code); __attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_load ( - guint8 *code, int rd, int rs1, gint32 imm, int length); + guint8 *code, int rd, int rs1, target_mgreg_t imm, int length); __attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_loadu ( - guint8 *code, int rd, int rs1, gint32 imm, int length); + guint8 *code, int rd, int rs1, target_mgreg_t imm, int length); __attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_fload ( - guint8 *code, int rd, int rs1, gint32 imm, gboolean isSingle); + guint8 *code, int rd, int rs1, target_mgreg_t imm, gboolean isSingle); __attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_store ( - guint8 *code, int rs2, int rs1, gint32 imm, int length); + guint8 *code, int rs2, int rs1, target_mgreg_t imm, int length); __attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_fstore ( - guint8 *code, int rs2, int rs1, gint32 imm, gboolean isSingle); + guint8 *code, int rs2, int rs1, target_mgreg_t imm, gboolean isSingle); __attribute__ ((__warn_unused_result__)) guint8 *mono_riscv_emit_destroy_frame (guint8 *code); diff --git a/src/mono/mono/utils/mono-context.h b/src/mono/mono/utils/mono-context.h index 686ec7c038ff4..e8416d076cb66 100644 --- a/src/mono/mono/utils/mono-context.h +++ b/src/mono/mono/utils/mono-context.h @@ -865,7 +865,7 @@ typedef struct ucontext MonoContext; typedef struct { host_mgreg_t gregs [RISCV_N_GREGS]; // [0] contains pc since x0 is hard-wired to zero anyway. - double fregs [RISCV_N_FREGS * 2 + 2]; // [32] contains fcsr (32 bits), the rest is for quad-precision values (currently unused). + double fregs [RISCV_N_FREGS + 2]; // [32] contains fcsr (32 bits), the rest is for quad-precision values (currently unused). } MonoContext; #define MONO_CONTEXT_SET_IP(ctx, ip) do { (ctx)->gregs [RISCV_ZERO] = (host_mgreg_t) (ip); } while (0)