[Mono][RISC-V] emit mul inst instead of emulated mul (#85445)
authorVincentWu <43398706+Xinlong-Wu@users.noreply.github.com>
Sat, 8 Jul 2023 17:47:00 +0000 (01:47 +0800)
committerGitHub <noreply@github.com>
Sat, 8 Jul 2023 17:47:00 +0000 (13:47 -0400)
* 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
src/mono/mono/mini/cpu-riscv64.mdesc
src/mono/mono/mini/exceptions-riscv.c
src/mono/mono/mini/mini-riscv.c
src/mono/mono/mini/mini-riscv.h
src/mono/mono/mini/tramp-riscv.c

index 4abff40..054c0b0 100644 (file)
@@ -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) \
index 7a7a261..7ba7da1 100644 (file)
@@ -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
index 18b3f08..8ae90e7 100644 (file)
@@ -6,6 +6,7 @@
 #include "mini-runtime.h"
 
 #include <mono/metadata/abi-details.h>
+#include <mono/metadata/tokentype.h>
 #include <mono/utils/mono-sigcontext.h>
 #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));
index 2b4dcaa..0d9a779 100644 (file)
@@ -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) {
index d01227d..349764e 100644 (file)
@@ -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);
 
index 87ae678..414c3a4 100644 (file)
@@ -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);