[RISC-V] Port Mono for RISC-V 64 Arch (1/3) lp64d ABI (#83714)
authorVincentWu <43398706+Xinlong-Wu@users.noreply.github.com>
Mon, 3 Apr 2023 19:11:42 +0000 (03:11 +0800)
committerGitHub <noreply@github.com>
Mon, 3 Apr 2023 19:11:42 +0000 (15:11 -0400)
* support abi lp64d for RISC-V 64

* format

src/mono/mono.proj
src/mono/mono/arch/riscv/riscv-codegen.h
src/mono/mono/metadata/object-offsets.h
src/mono/mono/mini/helpers.c
src/mono/mono/mini/mini-riscv.c
src/mono/mono/mini/mini-riscv.h

index 695064c..8e6d21c 100644 (file)
       <_Objcopy Condition="'$(TargetsAndroid)' == 'true' or '$(TargetsLinuxBionic)' == 'true'">$(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/$(MonoToolchainPrebuiltOS)/bin/llvm-objcopy</_Objcopy>
       <_Objcopy Condition="'$(TargetsLinuxMusl)' == 'true' and '$(CrossBuild)' != 'true'">objcopy</_Objcopy>
 
-      <_ObjcopyPrefix Condition="'$(MonoCrossDir)' != '' and '$(Platform)' == 'riscv64'">llvm-objcopy-</_ObjcopyPrefix>
+      <_ObjcopyPrefix Condition="'$(MonoCrossDir)' != '' and '$(Platform)' == 'riscv64' and $(_Objcopy) == ''">llvm-objcopy-</_ObjcopyPrefix>
     </PropertyGroup>
     <!-- test viability of objcopy command -->
     <Exec Condition="'$(BuildMonoAOTCrossCompilerOnly)' != 'true' and ('$(TargetsLinux)' == 'true' or '$(TargetsAndroid)' == 'true' or '$(TargetsLinuxBionic)' == 'true')" Command="$(_Objcopy) -V" IgnoreStandardErrorWarningFormat="true" ContinueOnError="WarnAndContinue" IgnoreExitCode="true" EchoOff="true" ConsoleToMsBuild="true">
index 7ba438a..95e18a0 100644 (file)
@@ -293,7 +293,8 @@ 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_I_IMM(value) \
        (RISCV_DECODE_I_IMM (RISCV_ENCODE_I_IMM ((value))) == (value))
 #define RISCV_VALID_S_IMM(value) \
index 9290970..a1ab49f 100644 (file)
@@ -255,6 +255,9 @@ DECL_OFFSET(MonoLMF, eip)
 DECL_OFFSET(MonoLMF, gregs)
 DECL_OFFSET(MonoLMF, fregs)
 #elif defined(TARGET_RISCV)
+DECL_OFFSET(MonoLMF, lmf_addr)
+DECL_OFFSET(MonoLMF, pc)
+DECL_OFFSET(MonoLMF, gregs)
 DECL_OFFSET(MonoContext, gregs)
 DECL_OFFSET(MonoContext, fregs)
 #endif
@@ -314,6 +317,13 @@ DECL_OFFSET(CallContext, stack_size)
 DECL_OFFSET(CallContext, stack)
 #endif
 
+#if defined(TARGET_RISCV)
+DECL_OFFSET(CallContext, gregs)
+DECL_OFFSET(CallContext, fregs)
+DECL_OFFSET(CallContext, stack_size)
+DECL_OFFSET(CallContext, stack)
+#endif
+
 #if defined(TARGET_X86)
 DECL_OFFSET(GSharedVtCallInfo, stack_usage)
 DECL_OFFSET(GSharedVtCallInfo, vret_slot)
index ca7df28..130210c 100644 (file)
@@ -69,7 +69,11 @@ static const gint16 opidx [] = {
 
 #endif
 
+#ifdef TARGET_RISCV64
+#define ARCH_PREFIX "riscv64-linux-gnu-"
+#else
 #define ARCH_PREFIX ""
+#endif
 //#define ARCH_PREFIX "powerpc64-linux-gnu-"
 
 const char*
index c2e1b64..8367970 100644 (file)
@@ -6,6 +6,9 @@
 #include <mono/utils/mono-hwcap.h>
 
 #include "mini-runtime.h"
+#include "ir-emit.h"
+
+#include <mono/metadata/tokentype.h>
 
 #ifdef TARGET_RISCV64
 #include "cpu-riscv64.h"
 #include "cpu-riscv32.h"
 #endif
 
-static gboolean riscv_stdext_a, riscv_stdext_b, riscv_stdext_c,
-                riscv_stdext_d, riscv_stdext_f, riscv_stdext_j,
-                riscv_stdext_l, riscv_stdext_m, riscv_stdext_n,
-                riscv_stdext_p, riscv_stdext_q, riscv_stdext_t,
-                riscv_stdext_v;
+/* The single step trampoline */
+static gpointer ss_trampoline;
+
+/* The breakpoint trampoline */
+static gpointer bp_trampoline;
+
+gboolean riscv_stdext_a, riscv_stdext_b, riscv_stdext_c, riscv_stdext_d, riscv_stdext_f, riscv_stdext_j, riscv_stdext_l,
+    riscv_stdext_m, riscv_stdext_n, riscv_stdext_p, riscv_stdext_q, riscv_stdext_t, riscv_stdext_v;
 
 void
 mono_arch_cpu_init (void)
@@ -28,10 +34,14 @@ void
 mono_arch_init (void)
 {
        riscv_stdext_a = mono_hwcap_riscv_has_stdext_a;
-       riscv_stdext_c = mono_hwcap_riscv_has_stdext_c;
+       // TODO: skip compress inst for now
+       riscv_stdext_c = FALSE;
        riscv_stdext_d = mono_hwcap_riscv_has_stdext_d;
        riscv_stdext_f = mono_hwcap_riscv_has_stdext_f;
        riscv_stdext_m = mono_hwcap_riscv_has_stdext_m;
+
+       if (!mono_aot_only)
+               bp_trampoline = mini_get_breakpoint_trampoline ();
 }
 
 void
@@ -172,10 +182,9 @@ mono_arch_opcode_supported (int opcode)
                return riscv_stdext_a;
        case OP_ATOMIC_LOAD_R4:
        case OP_ATOMIC_STORE_R4:
-#ifdef TARGET_RISCV64
+               return riscv_stdext_a && riscv_stdext_f;
        case OP_ATOMIC_LOAD_R8:
        case OP_ATOMIC_STORE_R8:
-#endif
                return riscv_stdext_a && riscv_stdext_d;
        default:
                return FALSE;
@@ -229,7 +238,7 @@ mono_arch_find_imt_method (host_mgreg_t *regs, guint8 *code)
 MonoVTable *
 mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code)
 {
-       return (MonoVTable *) regs [MONO_ARCH_VTABLE_REG];
+       return (MonoVTable *)regs [MONO_ARCH_RGCTX_REG];
 }
 
 GSList*
@@ -314,6 +323,26 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count,
     return 0;
 }
 
+/**
+ * [NFC] Because there is OP_LOCALLOC stuff,
+ * the stack size will increase dynamicly,
+ * so the stack size stored in cfg->stack_offset
+ * can't guide us to destroy the frame.
+ *
+ * Emits:
+ *      addi sp,fp, 0
+ *   ld ra, -8(fp) # 8-byte Folded Reload
+ *   ld s0, -16(fp) # 8-byte Folded Reload
+ */
+guint8 *
+mono_riscv_emit_destroy_frame (guint8 *code)
+{
+       riscv_addi (code, RISCV_SP, RISCV_FP, 0);
+       code = mono_riscv_emit_load (code, RISCV_RA, RISCV_FP, -(gint32)sizeof (host_mgreg_t), 0);
+       code = mono_riscv_emit_load (code, RISCV_S0, RISCV_FP, -(gint32)sizeof (host_mgreg_t) * 2, 0);
+
+       return code;
+}
 void
 mono_arch_patch_code_new (MonoCompile *cfg, guint8 *code,
                           MonoJumpInfo *ji, gpointer target)
@@ -321,11 +350,392 @@ mono_arch_patch_code_new (MonoCompile *cfg, guint8 *code,
        NOT_IMPLEMENTED;
 }
 
+/**
+ * add_arg:
+ *     Add Arguments into a0-a7 reg.
+ *     if there is no available regs, store it into stack.
+ */
+static void
+add_arg (CallInfo *cinfo, ArgInfo *ainfo, int size, gboolean sign)
+{
+       g_assert (size <= 8);
+       g_assert (cinfo->next_arg >= RISCV_A0);
+
+       if (cinfo->vararg) {
+               NOT_IMPLEMENTED;
+       }
+
+       // for RV64, length of all arg here will not wider then XLEN
+       // store it normally.
+       if (cinfo->next_arg <= RISCV_A7) {
+               // there is at least 1 avaliable reg
+#ifdef TARGET_RISCV32
+               // Scalars that are 2×XLEN bits wide are passed in a pair of argument registers
+               if (size == 8) {
+                       NOT_IMPLEMENTED;
+                       // 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
+                       if (cinfo->next_arg == RISCV_A7) {
+                               NOT_IMPLEMENTED;
+                       }
+                       return;
+               }
+#endif
+               ainfo->storage = ArgInIReg;
+               ainfo->reg = cinfo->next_arg;
+               cinfo->next_arg++;
+       }
+       // 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->is_signed = sign;
+       }
+}
+
+static void
+add_farg (CallInfo *cinfo, ArgInfo *ainfo, gboolean single)
+{
+       int size = single ? 4 : 8;
+
+       g_assert (mono_arch_is_soft_float () == FALSE);
+       if (cinfo->next_farg <= RISCV_FA7) {
+#ifdef TARGET_RISCV64
+               ainfo->storage = single ? ArgInFRegR4 : ArgInFReg;
+               ainfo->reg = cinfo->next_farg;
+               cinfo->next_farg++;
+#else
+               NOT_IMPLEMENTED;
+#endif
+       } else {
+               ainfo->storage = single ? ArgOnStackR4 : ArgOnStackR8;
+               ainfo->slot_size = size;
+       }
+}
+
+static void
+add_valuetype (CallInfo *cinfo, ArgInfo *ainfo, MonoType *t)
+{
+       int size, aligned_size;
+       guint32 align;
+
+       size = mini_type_stack_size_full (t, &align, cinfo->pinvoke);
+       aligned_size = ALIGN_TO (size, align);
+
+       // 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->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;
+                       ainfo->size = sizeof (host_mgreg_t);
+                       ainfo->is_regpair = FALSE;
+                       cinfo->next_arg += 1;
+               }
+       }
+       // Scalars that are 2×XLEN bits wide are passed in a pair of argument registers
+       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->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->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);
+                       ainfo->is_regpair = FALSE;
+
+                       cinfo->next_arg += 1;
+               }
+               // Scalars that are 2×XLEN bits wide are passed in a pair of argument
+               // registers, with the low-order XLEN bits in the lower-numbered register
+               // and the high-order XLEN bits in the higher-numbered register
+               else {
+                       ainfo->storage = ArgVtypeInIReg;
+                       ainfo->reg = cinfo->next_arg;
+                       ainfo->size = sizeof (host_mgreg_t) * 2;
+                       ainfo->is_regpair = TRUE;
+
+                       cinfo->next_arg += 2;
+               }
+       }
+       // Scalars that are at most XLEN bits wide are passed in a single argument register
+       else {
+               ainfo->storage = ArgVtypeInIReg;
+               ainfo->reg = cinfo->next_arg;
+               ainfo->size = sizeof (host_mgreg_t);
+               ainfo->is_regpair = FALSE;
+
+               cinfo->next_arg += 1;
+       }
+}
+
+static void
+add_param (CallInfo *cinfo, ArgInfo *ainfo, MonoType *t)
+{
+       MonoType *ptype;
+
+       ptype = mini_get_underlying_type (t);
+       // FIXME: May break some ABI rules
+       switch (ptype->type) {
+       case MONO_TYPE_VOID:
+               ainfo->storage = ArgNone;
+               break;
+       case MONO_TYPE_I1:
+               add_arg (cinfo, ainfo, 1, TRUE);
+               break;
+       case MONO_TYPE_U1:
+               add_arg (cinfo, ainfo, 1, FALSE);
+               break;
+       case MONO_TYPE_I2:
+               add_arg (cinfo, ainfo, 2, TRUE);
+               break;
+       case MONO_TYPE_U2:
+               add_arg (cinfo, ainfo, 2, FALSE);
+               break;
+       case MONO_TYPE_I:
+       case MONO_TYPE_I4:
+               add_arg (cinfo, ainfo, 4, TRUE);
+               break;
+       case MONO_TYPE_U:
+       case MONO_TYPE_U4:
+#ifdef TARGET_RISCV32
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_FNPTR:
+       case MONO_TYPE_OBJECT:
+#endif
+               add_arg (cinfo, ainfo, 4, FALSE);
+               break;
+       case MONO_TYPE_I8:
+               add_arg (cinfo, ainfo, 8, TRUE);
+               break;
+       case MONO_TYPE_U8:
+#ifdef TARGET_RISCV64
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_FNPTR:
+       case MONO_TYPE_OBJECT:
+#endif
+               add_arg (cinfo, ainfo, 8, FALSE);
+               break;
+       case MONO_TYPE_R4:
+               if (mono_arch_is_soft_float ())
+                       add_arg (cinfo, ainfo, 4, TRUE);
+               else
+                       add_farg (cinfo, ainfo, TRUE);
+               break;
+       case MONO_TYPE_R8:
+               if (mono_arch_is_soft_float ())
+                       add_arg (cinfo, ainfo, 8, FALSE);
+               else
+                       add_farg (cinfo, ainfo, FALSE);
+               break;
+
+       case MONO_TYPE_GENERICINST:
+               if (!mono_type_generic_inst_is_valuetype (ptype))
+                       add_arg (cinfo, ainfo, sizeof (host_mgreg_t), FALSE);
+               else if (mini_is_gsharedvt_variable_type (ptype))
+                       NOT_IMPLEMENTED;
+               else
+                       add_valuetype (cinfo, ainfo, ptype);
+               break;
+       case MONO_TYPE_VALUETYPE:
+               add_valuetype (cinfo, ainfo, ptype);
+               break;
+
+       default:
+               g_print ("Can't handle as return value 0x%x\n", ptype->type);
+               g_assert_not_reached ();
+               break;
+       }
+}
+
+/**
+ * get_call_info:
+ *     create call info here.
+ *  allocate memory for *cinfo, and assign Regs for Arguments.
+ *  if thsere is no available regs, store it into stack top of caller
+ *  in increase order.
+ *  eg. 8th arg is stored at sp+8, 9th arg is stored at sp+0, etc.
+ */
+static CallInfo *
+get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
+{
+       CallInfo *cinfo;
+       int paramNum = sig->hasthis + sig->param_count;
+       int pindex;
+       if (mp)
+               cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * paramNum));
+       else
+               cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * paramNum));
+
+       cinfo->nargs = paramNum;
+
+       // return value
+       cinfo->next_arg = RISCV_A0;
+       cinfo->next_farg = RISCV_FA0;
+       add_param (cinfo, &cinfo->ret, sig->ret);
+
+       //  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) {
+               g_assert (cinfo->ret.reg == RISCV_A0);
+               cinfo->next_arg = RISCV_A1;
+       } else
+               cinfo->next_arg = RISCV_A0;
+
+       cinfo->next_farg = RISCV_FA0;
+       // reset status
+       cinfo->stack_usage = 0;
+
+       // add this pointer as first argument if hasthis == true
+       if (sig->hasthis)
+               add_arg (cinfo, cinfo->args + 0, 8, FALSE);
+
+       // other general Arguments
+       guint32 paramStart = 0;
+       guint32 argStack = 0;
+       for (pindex = paramStart; pindex < sig->param_count; ++pindex) {
+               ArgInfo *ainfo = cinfo->args + sig->hasthis + pindex;
+
+               // process the variable parameter sig->sentinelpos mark the first VARARG
+               if ((sig->call_convention == MONO_CALL_VARARG) && (pindex == sig->sentinelpos))
+                       NOT_IMPLEMENTED;
+
+               add_param (cinfo, ainfo, sig->params [pindex]);
+
+               if (ainfo->storage == ArgOnStack || ainfo->storage == ArgOnStackR4 || ainfo->storage == ArgOnStackR8)
+                       argStack += ainfo->slot_size;
+       }
+
+       // reserve the regs stored at the srack
+       if (argStack > 0) {
+               cinfo->stack_usage += argStack;
+
+               for (pindex = paramStart; pindex < sig->param_count; ++pindex) {
+                       ArgInfo *ainfo = cinfo->args + sig->hasthis + pindex;
+                       if (ainfo->storage == ArgOnStack || ainfo->storage == ArgOnStackR4 || ainfo->storage == ArgOnStackR8) {
+                               g_assert (argStack >= ainfo->slot_size);
+                               argStack -= ainfo->slot_size;
+                               ainfo->offset = argStack;
+                       }
+               }
+       }
+
+       /* Handle the case where there are no implicit arguments */
+       if ((sig->call_convention == MONO_CALL_VARARG) && (pindex == sig->sentinelpos))
+               NOT_IMPLEMENTED;
+
+       cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
+
+       return cinfo;
+}
+
+static int
+arg_need_temp (ArgInfo *ainfo)
+{
+       if (ainfo->storage == ArgVtypeInMixed)
+               return sizeof (host_mgreg_t) * 2;
+       return 0;
+}
+
+static gpointer
+arg_get_storage (CallContext *ccontext, ArgInfo *ainfo)
+{
+       switch (ainfo->storage) {
+       case ArgInIReg:
+       case ArgVtypeInIReg:
+               return &ccontext->gregs [ainfo->reg];
+       case ArgInFReg:
+               return &ccontext->fregs [ainfo->reg];
+       case ArgOnStack:
+       case ArgVtypeOnStack:
+               return ccontext->stack + ainfo->offset;
+       case ArgVtypeByRef:
+               return (gpointer)ccontext->gregs [ainfo->reg];
+       default:
+               g_print ("Can't process storage type %d\n", ainfo->storage);
+               NOT_IMPLEMENTED;
+       }
+}
+
+static void
+arg_set_val (CallContext *ccontext, ArgInfo *ainfo, gpointer src)
+{
+       g_assert (arg_need_temp (ainfo));
+       NOT_IMPLEMENTED;
+}
+
+static void
+arg_get_val (CallContext *ccontext, ArgInfo *ainfo, gpointer dest)
+{
+       g_assert (arg_need_temp (ainfo));
+       NOT_IMPLEMENTED;
+}
+
 /* Set arguments in the ccontext (for i2n entry) */
 void
 mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig)
 {
-       NOT_IMPLEMENTED;
+       const MonoEECallbacks *interp_cb = mini_get_interp_callbacks ();
+       CallInfo *cinfo = get_call_info (NULL, sig);
+       gpointer storage;
+       ArgInfo *ainfo;
+
+       memset (ccontext, 0, sizeof (CallContext));
+
+       ccontext->stack_size = ALIGN_TO (cinfo->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
+       if (ccontext->stack_size)
+               ccontext->stack = (guint8 *)g_calloc (1, ccontext->stack_size);
+
+       if (sig->ret->type != MONO_TYPE_VOID) {
+               ainfo = &cinfo->ret;
+               if (ainfo->storage == ArgVtypeByRef) {
+                       g_assert (cinfo->ret.reg == RISCV_A0);
+                       storage = interp_cb->frame_arg_to_storage ((MonoInterpFrameHandle)frame, sig, -1);
+                       ccontext->gregs [cinfo->ret.reg] = (gsize)storage;
+               }
+       }
+
+       g_assert (!sig->hasthis);
+
+       for (int i = 0; i < sig->param_count; i++) {
+               ainfo = &cinfo->args [i];
+
+               if (ainfo->storage == ArgVtypeByRef) {
+                       ccontext->gregs [ainfo->reg] =
+                           (host_mgreg_t)interp_cb->frame_arg_to_storage ((MonoInterpFrameHandle)frame, sig, i);
+                       continue;
+               }
+
+               int temp_size = arg_need_temp (ainfo);
+
+               if (temp_size)
+                       storage = alloca (temp_size); // FIXME? alloca in a loop
+               else
+                       storage = arg_get_storage (ccontext, ainfo);
+
+               interp_cb->frame_arg_to_data ((MonoInterpFrameHandle)frame, sig, i, storage);
+               if (temp_size)
+                       arg_set_val (ccontext, ainfo, storage);
+       }
+
+       g_free (cinfo);
 }
 
 /* Set return value in the ccontext (for n2i return) */
@@ -346,7 +756,30 @@ mono_arch_get_native_call_context_args (CallContext *ccontext, gpointer frame, M
 void
 mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig)
 {
-       NOT_IMPLEMENTED;
+       const MonoEECallbacks *interp_cb;
+       CallInfo *cinfo;
+       ArgInfo *ainfo;
+       gpointer storage;
+
+       if (sig->ret->type == MONO_TYPE_VOID)
+               return;
+
+       interp_cb = mini_get_interp_callbacks ();
+       cinfo = get_call_info (NULL, sig);
+       ainfo = &cinfo->ret;
+
+       if (ainfo->storage != ArgVtypeByRef) {
+               int temp_size = arg_need_temp (ainfo);
+
+               if (temp_size) {
+                       storage = alloca (temp_size);
+                       arg_get_val (ccontext, ainfo, storage);
+               } else
+                       storage = arg_get_storage (ccontext, ainfo);
+               interp_cb->data_to_frame_arg ((MonoInterpFrameHandle)frame, sig, -1, storage);
+       }
+
+       g_free (cinfo);
 }
 
 #ifndef DISABLE_JIT
@@ -426,7 +859,9 @@ mono_arch_get_global_int_regs (MonoCompile *cfg)
 {
        GList *regs = NULL;
 
-       for (int i = RISCV_S0; i <= RISCV_S11; i++)
+       // RISCV_FP aka RISCV_S0 is reserved
+       regs = g_list_prepend (regs, GUINT_TO_POINTER (RISCV_S1));
+       for (int i = RISCV_S2; i <= RISCV_S11; i++)
                regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
 
        return regs;
@@ -448,10 +883,51 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
 
 #endif
 
+/**
+ * mono_arch_create_vars:
+ *     before this function, mono_compile_create_vars() in mini.c
+ *     has process vars in a genetic ways. So just do some Arch
+ *     related process specified in ABI.
+ */
+
 void
 mono_arch_create_vars (MonoCompile *cfg)
 {
-       NOT_IMPLEMENTED;
+       MonoMethodSignature *sig;
+       CallInfo *cinfo;
+
+       sig = mono_method_signature_internal (cfg->method);
+       if (!cfg->arch.cinfo)
+               cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
+       cinfo = cfg->arch.cinfo;
+
+       if (cinfo->ret.storage == ArgVtypeByRef) {
+               cfg->vret_addr = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL);
+               cfg->vret_addr->flags |= MONO_INST_VOLATILE;
+       }
+
+       if (cfg->gen_sdb_seq_points) {
+               MonoInst *ins;
+
+               if (cfg->compile_aot) {
+                       ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL);
+                       ins->flags |= MONO_INST_VOLATILE;
+                       cfg->arch.seq_point_info_var = ins;
+               }
+
+               ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL);
+               ins->flags |= MONO_INST_VOLATILE;
+               cfg->arch.ss_tramp_var = ins;
+
+               ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL);
+               ins->flags |= MONO_INST_VOLATILE;
+               cfg->arch.bp_tramp_var = ins;
+       }
+
+       if (cfg->method->save_lmf) {
+               cfg->create_lmf_var = TRUE;
+               cfg->lmf_ir = TRUE;
+       }
 }
 
 MonoInst *
@@ -461,22 +937,335 @@ mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod,
        return NULL;
 }
 
+static void
+add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *arg)
+{
+       MonoInst *ins;
+
+       switch (storage) {
+       default:
+               g_print ("unable process storage type %d\n", storage);
+               NOT_IMPLEMENTED;
+               break;
+       case ArgInIReg:
+               MONO_INST_NEW (cfg, ins, OP_MOVE);
+               ins->dreg = mono_alloc_ireg_copy (cfg, arg->dreg);
+               ins->sreg1 = arg->dreg;
+               MONO_ADD_INS (cfg->cbb, ins);
+               mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, FALSE);
+               break;
+       case ArgInFReg:
+               MONO_INST_NEW (cfg, ins, OP_FMOVE);
+               ins->dreg = mono_alloc_freg (cfg);
+               ins->sreg1 = arg->dreg;
+               MONO_ADD_INS (cfg->cbb, ins);
+               mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, TRUE);
+               break;
+       case ArgInFRegR4:
+               if (cfg->r4fp)
+                       MONO_INST_NEW (cfg, ins, OP_RMOVE);
+               else
+                       MONO_INST_NEW (cfg, ins, OP_RISCV_SETFREG_R4);
+               ins->dreg = mono_alloc_freg (cfg);
+               ins->sreg1 = arg->dreg;
+               MONO_ADD_INS (cfg->cbb, ins);
+               mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, TRUE);
+               break;
+       }
+}
+
+/*
+ * take the arguments and generate the arch-specific
+ * instructions to properly call the function in call.
+ * This includes pushing, moving arguments to the right register
+ * etc.
+ */
+static void
+emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
+{
+       NOT_IMPLEMENTED;
+       MonoMethodSignature *tmp_sig;
+       MonoInst *sig_arg;
+
+       if (MONO_IS_TAILCALL_OPCODE (call))
+               NOT_IMPLEMENTED;
+
+       /*
+        * mono_ArgIterator_Setup assumes the signature cookie is
+        * passed first and all the arguments which were before it are
+        * passed on the stack after the signature. So compensate by
+        * passing a different signature.
+        */
+       tmp_sig = mono_metadata_signature_dup (call->signature);
+       tmp_sig->param_count -= call->signature->sentinelpos;
+       tmp_sig->sentinelpos = 0;
+       memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos,
+               tmp_sig->param_count * sizeof (MonoType *));
+
+       MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
+       sig_arg->dreg = mono_alloc_ireg (cfg);
+       sig_arg->inst_p0 = tmp_sig;
+       MONO_ADD_INS (cfg->cbb, sig_arg);
+
+       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, RISCV_SP, cinfo->sig_cookie.offset, sig_arg->dreg);
+}
+
+/**
+ * mono_arch_emit_call:
+ *     we process all Args of a function call
+ *  (return, parameters)
+ */
 void
 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
 {
-       NOT_IMPLEMENTED;
+       MonoInst *arg, *vtarg;
+       MonoMethodSignature *sig;
+       ArgInfo *ainfo;
+       CallInfo *cinfo;
+
+       sig = call->signature;
+       int paramNum = sig->param_count + sig->hasthis;
+
+       cinfo = get_call_info (cfg->mempool, sig);
+
+       /* Emit the inst of return at mono_arch_emit_setret() */
+       switch (cinfo->ret.storage) {
+       case ArgVtypeInIReg:
+               if (MONO_IS_TAILCALL_OPCODE (call))
+                       break;
+               /*
+                * The vtype is returned in registers, save the return area address in a local, and save the vtype into
+                * the location pointed to by it after call in mono_riscv_emitmove_return_value ().
+                */
+               if (!cfg->arch.vret_addr_loc) {
+                       cfg->arch.vret_addr_loc = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL);
+                       /* Prevent it from being register allocated or optimized away */
+                       cfg->arch.vret_addr_loc->flags |= MONO_INST_VOLATILE;
+               }
+               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->arch.vret_addr_loc->dreg, call->vret_var->dreg);
+               break;
+       case ArgVtypeByRef:
+               /* Pass the vtype return address in A0 */
+               g_assert (cinfo->ret.reg == RISCV_A0);
+               g_assert (!MONO_IS_TAILCALL_OPCODE (call) || call->vret_var == cfg->vret_addr);
+               MONO_INST_NEW (cfg, vtarg, OP_MOVE);
+               vtarg->sreg1 = call->vret_var->dreg;
+               vtarg->dreg = mono_alloc_preg (cfg);
+               MONO_ADD_INS (cfg->cbb, vtarg);
+               mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
+               break;
+       case ArgVtypeByRefOnStack:
+               NOT_IMPLEMENTED;
+               break;
+       case ArgVtypeOnStack:
+               NOT_IMPLEMENTED;
+               break;
+       case ArgVtypeInMixed:
+               NOT_IMPLEMENTED;
+               break;
+       default:
+               break;
+       }
+
+       // if (cinfo->struct_ret)
+       //      // call->used_iregs |= 1 << cinfo->struct_ret;
+       //      NOT_IMPLEMENTED;
+
+       if (COMPILE_LLVM (cfg)) {
+               /* We shouldn't be called in the llvm case */
+               cfg->disable_llvm = TRUE;
+               return;
+       }
+
+       for (int i = 0; i < paramNum; i++) {
+               ainfo = cinfo->args + i;
+               MonoType *t;
+
+               if (sig->hasthis && i == 0)
+                       t = mono_get_object_type ();
+               else
+                       t = sig->params [i - sig->hasthis];
+               t = mini_get_underlying_type (t);
+
+               /* Emit the signature cookie just before the implicit arguments */
+               if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
+                       emit_sig_cookie (cfg, call, cinfo);
+
+               arg = call->args [i];
+               switch (ainfo->storage) {
+               case ArgInIReg:
+               case ArgInFReg:
+               case ArgInFRegR4:
+                       add_outarg_reg (cfg, call, ainfo->storage, ainfo->reg, arg);
+                       break;
+               case ArgOnStack: {
+                       switch (ainfo->slot_size) {
+                       case 1:
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, RISCV_SP, ainfo->offset, arg->dreg);
+                               break;
+                       case 2:
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, RISCV_SP, ainfo->offset, arg->dreg);
+                               break;
+                       case 4:
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, RISCV_SP, ainfo->offset, arg->dreg);
+                               break;
+                       case 8:
+#ifdef TARGET_RISCV32
+                               NOT_IMPLEMENTED;
+                               break;
+#else // TARGET_RISCV64
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, RISCV_SP, ainfo->offset, arg->dreg);
+                               break;
+                       // RV64 Only, XLEN*2 == 16
+                       case 16:
+                               NOT_IMPLEMENTED;
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, RISCV_SP, ainfo->offset, arg->dreg);
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, RISCV_SP, ainfo->offset + 8, arg->dreg + 1);
+                               break;
+#endif
+                       default:
+                               g_assert_not_reached ();
+                       }
+                       break;
+               }
+               case ArgVtypeInIReg:
+               case ArgVtypeByRef: {
+                       MonoInst *ins;
+                       guint32 align;
+                       guint32 size;
+                       size = mono_class_value_size (arg->klass, &align);
+
+                       MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
+                       ins->sreg1 = arg->dreg;
+                       ins->klass = arg->klass;
+                       ins->backend.size = size;
+                       ins->inst_p0 = call;
+                       ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
+                       memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
+                       MONO_ADD_INS (cfg->cbb, ins);
+
+                       break;
+               }
+               default:
+                       g_print ("can't process Storage type %d\n", ainfo->storage);
+                       NOT_IMPLEMENTED;
+               }
+       }
+
+       /* Handle the case where there are no implicit arguments */
+       if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (paramNum == sig->sentinelpos))
+               emit_sig_cookie (cfg, call, cinfo);
+
+       call->call_info = cinfo;
+       call->stack_usage = cinfo->stack_usage;
 }
 
 void
 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
 {
-       NOT_IMPLEMENTED;
+       MonoCallInst *call = (MonoCallInst *)ins->inst_p0;
+       ArgInfo *ainfo = (ArgInfo *)ins->inst_p1;
+       MonoInst *load;
+       int op_load = 0;
+
+#ifdef TARGET_RISCV64
+       op_load = OP_LOADI8_MEMBASE;
+#else // TARGET_RISCV32
+       op_load = OP_LOADI4_MEMBASE;
+#endif
+
+       if (ins->backend.size == 0)
+               return;
+
+       switch (ainfo->storage) {
+       case ArgVtypeInIReg:
+               MONO_INST_NEW (cfg, load, op_load);
+               load->dreg = mono_alloc_ireg (cfg);
+               load->inst_basereg = src->dreg;
+               load->inst_offset = 0;
+               MONO_ADD_INS (cfg->cbb, load);
+               add_outarg_reg (cfg, call, ArgInIReg, ainfo->reg, load);
+
+               if (ainfo->size > sizeof (host_mgreg_t)) {
+                       MONO_INST_NEW (cfg, load, op_load);
+                       load->dreg = mono_alloc_ireg (cfg);
+                       load->inst_basereg = src->dreg;
+                       load->inst_offset = sizeof (target_mgreg_t);
+                       MONO_ADD_INS (cfg->cbb, load);
+                       add_outarg_reg (cfg, call, ArgInIReg, ainfo->reg + 1, load);
+               }
+               break;
+       case ArgVtypeOnStack:
+               g_assert (ainfo->offset >= 0);
+               for (int i = 0; i < ainfo->slot_size; i += sizeof (target_mgreg_t)) {
+                       MONO_INST_NEW (cfg, load, op_load);
+                       load->dreg = mono_alloc_ireg (cfg);
+                       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);
+               }
+               break;
+       case ArgVtypeByRef: {
+               MonoInst *vtaddr, *arg;
+               /* Pass the vtype address in a reg/on the stack */
+               // if (ainfo->gsharedvt) {
+               //      load = src;
+               // } else {
+               /* Make a copy of the argument */
+               vtaddr = mono_compile_create_var (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL);
+
+               MONO_INST_NEW (cfg, load, OP_LDADDR);
+               load->inst_p0 = vtaddr;
+               vtaddr->flags |= MONO_INST_INDIRECT;
+               load->type = STACK_MP;
+               load->klass = vtaddr->klass;
+               load->dreg = mono_alloc_ireg (cfg);
+               MONO_ADD_INS (cfg->cbb, load);
+               mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, ainfo->size, 8);
+               // }
+
+               if (ainfo->storage == ArgVtypeByRef) {
+                       MONO_INST_NEW (cfg, arg, OP_MOVE);
+                       arg->dreg = mono_alloc_preg (cfg);
+                       arg->sreg1 = load->dreg;
+                       MONO_ADD_INS (cfg->cbb, arg);
+                       add_outarg_reg (cfg, call, ArgInIReg, ainfo->reg, arg);
+               } else {
+                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, RISCV_SP, ainfo->offset, load->dreg);
+               }
+               break;
+       }
+       default:
+               NOT_IMPLEMENTED;
+               break;
+       }
 }
 
 void
 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
 {
-       NOT_IMPLEMENTED;
+       MonoMethodSignature *sig;
+       CallInfo *cinfo;
+
+       sig = mono_method_signature_internal (cfg->method);
+       if (!cfg->arch.cinfo)
+               cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
+       cinfo = cfg->arch.cinfo;
+
+       switch (cinfo->ret.storage) {
+       case ArgNone:
+               break;
+       case ArgInIReg:
+               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
+               break;
+       case ArgInFReg:
+               MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
+               break;
+       default:
+               g_print ("can't process Storage type %d\n", cinfo->ret.storage);
+               NOT_IMPLEMENTED;
+       }
 }
 
 void
@@ -493,10 +1282,185 @@ mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
 #endif
 }
 
+/*
+ * Set var information according to the calling convention. RISCV version.
+ */
 void
 mono_arch_allocate_vars (MonoCompile *cfg)
 {
-       NOT_IMPLEMENTED;
+       MonoMethodSignature *sig;
+       MonoInst *ins;
+       CallInfo *cinfo;
+       ArgInfo *ainfo;
+       int offset, size, align;
+       guint32 locals_stack_size, locals_stack_align;
+       gint32 *local_stack;
+
+       /*
+        * Allocate arguments and locals to either register (OP_REGVAR) or to a stack slot (OP_REGOFFSET).
+        * Compute cfg->stack_offset and update cfg->used_int_regs.
+        */
+       sig = mono_method_signature_internal (cfg->method);
+
+       if (!cfg->arch.cinfo)
+               cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
+       cinfo = cfg->arch.cinfo;
+
+       offset = 0;
+       // save RA & FP reg to stack
+       cfg->frame_reg = RISCV_FP;
+       offset += sizeof (host_mgreg_t) * 2;
+
+       if (cfg->method->save_lmf) {
+               /* The LMF var is allocated normally */
+       } else {
+               /* Callee saved regs */
+               // saved_gregs_offset store the addr of firs reg
+               for (guint i = 0; i < 32; ++i)
+                       if ((MONO_ARCH_CALLEE_SAVED_REGS & (1 << i)) && (cfg->used_int_regs & (1 << i))) {
+                               offset += sizeof (host_mgreg_t);
+                       }
+               cfg->arch.saved_gregs_offset = offset;
+       }
+
+       /* Return value */
+       if (sig->ret->type != MONO_TYPE_VOID) {
+               switch (cinfo->ret.storage) {
+               case ArgNone:
+                       break;
+               case ArgInIReg:
+               case ArgInFReg:
+                       cfg->ret->opcode = OP_REGVAR;
+                       cfg->ret->inst_c0 = cinfo->ret.reg;
+                       cfg->ret->dreg = cinfo->ret.reg;
+                       break;
+               case ArgVtypeInIReg:
+                       /* Allocate a local to hold the result, the epilog will copy it to the correct place */
+                       cfg->ret->opcode = OP_REGOFFSET;
+                       cfg->ret->inst_basereg = cfg->frame_reg;
+                       if (cinfo->ret.is_regpair)
+                               offset += sizeof (host_mgreg_t);
+                       offset += sizeof (host_mgreg_t);
+                       cfg->ret->inst_offset = -offset;
+                       break;
+               case ArgVtypeByRef:
+                       /**
+                        * Caller pass the address of return value by A0 as an implicit param.
+                        * It will be saved in the prolog
+                        */
+                       cfg->vret_addr->opcode = OP_REGOFFSET;
+                       cfg->vret_addr->inst_basereg = cfg->frame_reg;
+                       offset += sizeof (host_mgreg_t);
+                       cfg->vret_addr->inst_offset = -offset;
+                       if (G_UNLIKELY (cfg->verbose_level > 1)) {
+                               printf ("vret_addr =");
+                               mono_print_ins (cfg->vret_addr);
+                       }
+                       break;
+               default:
+                       g_print ("Can't handle storage type %d\n", cinfo->ret.storage);
+                       NOT_IMPLEMENTED;
+                       break;
+               }
+       }
+
+       /* Arguments */
+       for (guint i = 0; i < sig->param_count + sig->hasthis; ++i) {
+               ainfo = cinfo->args + i;
+               ins = cfg->args [i];
+
+               if (ins->opcode == OP_REGVAR)
+                       continue;
+               ins->opcode = OP_REGOFFSET;
+               ins->inst_basereg = cfg->frame_reg;
+
+               switch (ainfo->storage) {
+               case ArgInIReg:
+               case ArgInFReg:
+               case ArgInFRegR4:
+                       offset += sizeof (host_mgreg_t);
+                       ins->inst_offset = -offset;
+                       break;
+               case ArgOnStack:
+               case ArgVtypeOnStack:
+                       /* These are in the parent frame */
+                       g_assert (ainfo->offset >= 0);
+                       ins->inst_basereg = RISCV_FP;
+                       ins->inst_offset = ainfo->offset;
+                       break;
+               case ArgVtypeInIReg:
+                       ins->opcode = OP_REGOFFSET;
+                       ins->inst_basereg = cfg->frame_reg;
+                       /* These arguments are saved to the stack in the prolog */
+                       if (ainfo->is_regpair)
+                               offset += sizeof (host_mgreg_t);
+                       offset += sizeof (host_mgreg_t);
+                       ins->inst_offset = -offset;
+                       break;
+               default:
+                       NOT_IMPLEMENTED;
+                       break;
+               }
+               if (cfg->verbose_level >= 2)
+                       g_print ("arg %d allocated to %ld(%s).\n", i, ins->inst_offset, mono_arch_regname (ins->inst_basereg));
+       }
+
+       /* OP_SEQ_POINT depends on these */
+       // FIXME: Allocate these to registers
+       ins = cfg->arch.seq_point_info_var;
+       if (ins) {
+               size = sizeof (host_mgreg_t);
+               align = sizeof (host_mgreg_t);
+               offset += align - 1;
+               offset &= ~(align - 1);
+               ins->opcode = OP_REGOFFSET;
+               ins->inst_basereg = cfg->frame_reg;
+               offset += size;
+               ins->inst_offset = -offset;
+               g_print ("alloc seq_point_info_var to %ld(%s).\n", ins->inst_offset, mono_arch_regname (ins->inst_basereg));
+       }
+       ins = cfg->arch.ss_tramp_var;
+       if (ins) {
+               size = sizeof (host_mgreg_t);
+               align = sizeof (host_mgreg_t);
+               offset += align - 1;
+               offset &= ~(align - 1);
+               ins->opcode = OP_REGOFFSET;
+               ins->inst_basereg = cfg->frame_reg;
+               offset += size;
+               ins->inst_offset = -offset;
+               g_print ("alloc ss_tramp_var to %ld(%s).\n", ins->inst_offset, mono_arch_regname (ins->inst_basereg));
+       }
+       ins = cfg->arch.bp_tramp_var;
+       if (ins) {
+               size = sizeof (host_mgreg_t);
+               align = sizeof (host_mgreg_t);
+               offset += align - 1;
+               offset &= ~(align - 1);
+               ins->opcode = OP_REGOFFSET;
+               ins->inst_basereg = cfg->frame_reg;
+               offset += size;
+               ins->inst_offset = -offset;
+               g_print ("alloc bp_tramp_var to %ld(%s).\n", ins->inst_offset, mono_arch_regname (ins->inst_basereg));
+       }
+
+       /* Allocate locals */
+       local_stack = mono_allocate_stack_slots (cfg, FALSE, &locals_stack_size, &locals_stack_align);
+       if (locals_stack_align)
+               offset = ALIGN_TO (offset, locals_stack_align);
+
+       offset += locals_stack_size;
+       for (guint i = cfg->locals_start; i < cfg->num_varinfo; i++) {
+               if (local_stack [i] != -1) {
+                       ins = cfg->varinfo [i];
+                       ins->opcode = OP_REGOFFSET;
+                       ins->inst_basereg = cfg->frame_reg;
+                       ins->inst_offset = -offset + local_stack [i];
+               }
+       }
+       offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
+
+       cfg->stack_offset = offset;
 }
 
 void
@@ -525,11 +1489,36 @@ mono_riscv_emit_imm (guint8 *code, int rd, gsize imm)
                return code;
        }
 
+       /**
+        * use LUI & ADDIW load 32 bit Imm
+        * LUI: High 20 bit of imm
+        * ADDIW: Low 12 bit of imm
+        */
+       if (RISCV_VALID_IMM (imm)) {
+               gint32 Hi = RISCV_BITS (imm, 12, 20);
+               gint32 Lo = RISCV_BITS (imm, 0, 12);
+
+               // Lo is in signed num
+               // if Lo > 0x800
+               // convert into ((Hi + 1) << 20) -  (0x1000 - Lo)
+               if (Lo >= 0x800) {
+                       Hi += 1;
+                       Lo = Lo - 0x1000;
+               }
+
+               // if Hi is 0 or overflow, skip
+               if (Hi < 0xfffff) {
+                       riscv_lui (code, rd, Hi);
+               }
+               riscv_addiw (code, rd, rd, Lo);
+               return code;
+       }
+
        /*
         * This is not pretty, but RV64I doesn't make it easy to load constants.
         * Need to figure out something better.
         */
-       riscv_jal (code, rd, sizeof (guint64));
+       riscv_jal (code, rd, sizeof (guint64) + 4);
        *(guint64 *) code = imm;
        code += sizeof (guint64);
        riscv_ld (code, rd, rd, 0);
@@ -548,49 +1537,448 @@ mono_riscv_emit_imm (guint8 *code, int rd, gsize imm)
        return code;
 }
 
+guint8 *
+mono_riscv_emit_float_imm (guint8 *code, int rd, gsize f_imm, gboolean isSingle)
+{
+       if (f_imm == 0) {
+               if (mono_arch_is_soft_float ())
+                       riscv_addi (code, rd, RISCV_ZERO, 0);
+               else if (isSingle)
+                       riscv_fmv_w_x (code, rd, RISCV_ZERO);
+               else
+                       riscv_fmv_d_x (code, rd, RISCV_ZERO);
+               return code;
+       }
+
+       riscv_jal (code, RISCV_T0, sizeof (guint64) + 4);
+       *(guint64 *)code = f_imm;
+       code += sizeof (guint64);
+
+       if (mono_arch_is_soft_float ())
+#ifdef TARGET_RISCV64
+               riscv_ld (code, rd, RISCV_T0, 0);
+#else
+               riscv_lw (code, rd, RISCV_T0, 0);
+#endif
+       else if (isSingle)
+               riscv_flw (code, rd, RISCV_T0, 0);
+       else
+               riscv_fld (code, rd, RISCV_T0, 0);
+
+       return code;
+}
+
+guint8 *
+mono_riscv_emit_nop (guint8 *code)
+{
+       // if(riscv_stdext_c){
+       // }
+       riscv_addi (code, RISCV_ZERO, RISCV_ZERO, 0);
+       return 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)
+mono_riscv_emit_load (guint8 *code, int rd, int rs1, gint32 imm, int length)
 {
-       if (RISCV_VALID_I_IMM (imm)) {
+       if (!RISCV_VALID_I_IMM (imm)) {
+               code = mono_riscv_emit_imm (code, RISCV_T0, imm);
+               riscv_add (code, RISCV_T0, rs1, RISCV_T0);
+               rs1 = RISCV_T0;
+               imm = 0;
+       }
+
+       switch (length) {
+       case 0:
 #ifdef TARGET_RISCV64
                riscv_ld (code, rd, rs1, imm);
 #else
                riscv_lw (code, rd, rs1, imm);
 #endif
-       } else {
-               code = mono_riscv_emit_imm (code, rd, imm);
-               riscv_add (code, rd, rs1, rd);
+               break;
+       case 1:
+               riscv_lb (code, rd, rs1, imm);
+               break;
+       case 2:
+               riscv_lh (code, rd, rs1, imm);
+               break;
+       case 4:
+               riscv_lw (code, rd, rs1, imm);
+               break;
 #ifdef TARGET_RISCV64
-               riscv_ld (code, rd, rd, 0);
-#else
-               riscv_lw (code, rd, rd, 0);
+       case 8:
+               riscv_ld (code, rd, rs1, imm);
+               break;
 #endif
+       default:
+               g_assert_not_reached ();
+               break;
+       }
+       return code;
+}
+
+// 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)
+{
+       g_assert (riscv_stdext_d || (isSingle && riscv_stdext_f));
+       if (!RISCV_VALID_I_IMM (imm)) {
+               code = mono_riscv_emit_imm (code, RISCV_T0, imm);
+               riscv_add (code, RISCV_T0, rs1, RISCV_T0);
+               rs1 = RISCV_T0;
+               imm = 0;
        }
 
+       if (isSingle)
+               riscv_flw (code, rd, rs1, imm);
+       else
+               riscv_fld (code, rd, rs1, imm);
+
        return code;
 }
 
-// May clobber t1. Uses at most 16 bytes on RV32I and 24 bytes on RV64I.
+// 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 rs1, int rs2, gint32 imm)
+mono_riscv_emit_store (guint8 *code, int rs2, int rs1, gint32 imm, int length)
 {
-       if (RISCV_VALID_S_IMM (imm)) {
+       if (!RISCV_VALID_S_IMM (imm)) {
+               code = mono_riscv_emit_imm (code, RISCV_T0, imm);
+               riscv_add (code, RISCV_T0, rs1, RISCV_T0);
+               rs1 = RISCV_T0;
+               imm = 0;
+       }
+
+       switch (length) {
+       case 0:
 #ifdef TARGET_RISCV64
-               riscv_sd (code, rs1, rs2, imm);
+               riscv_sd (code, rs2, rs1, imm);
 #else
-               riscv_sw (code, rs1, rs2, imm);
+               riscv_sd (code, rs2, rs1, imm);
 #endif
-       } else {
-               code = mono_riscv_emit_imm (code, RISCV_T1, imm);
-               riscv_add (code, RISCV_T1, rs2, RISCV_T1);
+               break;
+       case 1:
+               riscv_sb (code, rs2, rs1, imm);
+               break;
+       case 2:
+               riscv_sh (code, rs2, rs1, imm);
+               break;
+       case 4:
+               riscv_sw (code, rs2, rs1, imm);
+               break;
 #ifdef TARGET_RISCV64
-               riscv_sd (code, rs1, RISCV_T1, 0);
-#else
-               riscv_sw (code, rs1, RISCV_T1, 0);
+       case 8:
+               riscv_sd (code, rs2, rs1, imm);
+               break;
 #endif
+       default:
+               g_assert_not_reached ();
+               break;
+       }
+       return code;
+}
+
+// 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)
+{
+       g_assert (riscv_stdext_d || (isSingle && riscv_stdext_f));
+       if (!RISCV_VALID_I_IMM (imm)) {
+               code = mono_riscv_emit_imm (code, RISCV_T0, imm);
+               riscv_add (code, RISCV_T0, rs1, RISCV_T0);
+               rs1 = RISCV_T0;
+               imm = 0;
        }
 
+       if (isSingle)
+               riscv_fsw (code, rs2, rs1, imm);
+       else
+               riscv_fsd (code, rs2, rs1, imm);
+
+       return code;
+
+       return code;
+}
+
+/*
+ * mono_riscv_emit_load_regarray:
+ *
+ *   Emit code to load the registers in REGS from the appropriate elements of
+ * a register array at BASEREG+OFFSET.
+ */
+guint8 *
+mono_riscv_emit_load_regarray (guint8 *code, guint64 regs, int basereg, int offset, gboolean isFloat)
+{
+       g_assert (basereg != RISCV_SP);
+
+       if (!RISCV_VALID_S_IMM (offset)) {
+               code = mono_riscv_emit_imm (code, RISCV_T6, offset);
+               riscv_add (code, RISCV_T6, basereg, RISCV_T6);
+               basereg = RISCV_T6;
+               offset = 0;
+       }
+
+       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 + (i * sizeof (host_mgreg_t)), FALSE);
+                       else
+                               code = mono_riscv_emit_load (code, i, basereg, offset + (i * sizeof (host_mgreg_t)), 0);
+               }
+       }
+
+       return code;
+}
+
+/*
+ * mono_riscv_emit_store_regarray:
+ *
+ *   Emit code to store the registers in REGS from the appropriate elements of
+ * a register array at BASEREG+OFFSET.
+ */
+guint8 *
+mono_riscv_emit_store_regarray (guint8 *code, guint64 regs, int basereg, int offset, gboolean isFloat)
+{
+       g_assert (basereg != RISCV_SP);
+
+       if (!RISCV_VALID_S_IMM (offset)) {
+               code = mono_riscv_emit_imm (code, RISCV_T6, offset);
+               riscv_add (code, RISCV_T6, basereg, RISCV_T6);
+               basereg = RISCV_T6;
+               offset = 0;
+       }
+
+       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
+                               code = mono_riscv_emit_store (code, i, basereg, offset + (i * sizeof (host_mgreg_t)), 0);
+               }
+       }
+
+       return code;
+}
+
+/*
+ * mono_riscv_emit_load_stack:
+ *
+ *   Emit code to load the registers in REGS from stack or consecutive memory locations starting
+ * at BASEREG+OFFSET.
+ */
+guint8 *
+mono_riscv_emit_load_stack (guint8 *code, guint64 regs, int basereg, int offset, gboolean isFloat)
+{
+       int pos = 0;
+       g_assert (basereg != RISCV_SP);
+
+       if (!RISCV_VALID_S_IMM (offset)) {
+               code = mono_riscv_emit_imm (code, RISCV_T6, offset);
+               riscv_add (code, RISCV_T6, basereg, RISCV_T6);
+               basereg = RISCV_T6;
+               offset = 0;
+       }
+
+       for (int i = 0; i < 32; ++i) {
+               if (regs & (1 << i)) {
+                       if (isFloat)
+                               code = mono_riscv_emit_fload (code, i, basereg, (offset + (pos * sizeof (host_mgreg_t))), FALSE);
+                       else
+                               code = mono_riscv_emit_load (code, i, basereg, (offset + (pos * sizeof (host_mgreg_t))), 0);
+                       pos++;
+               }
+       }
+
+       return code;
+}
+
+/*
+ * mono_riscv_emit_store_stack:
+ *
+ *   Emit code to store the registers in REGS into consecutive memory locations starting
+ * at BASEREG+OFFSET.
+ */
+guint8 *
+mono_riscv_emit_store_stack (guint8 *code, guint64 regs, int basereg, int offset, gboolean isFloat)
+{
+       int pos = 0;
+       g_assert (basereg != RISCV_SP);
+
+       for (int i = 0; i < 32; ++i) {
+               if (regs & (1 << i)) {
+                       if (isFloat)
+                               code = mono_riscv_emit_fstore (code, i, basereg, (offset + (pos * sizeof (host_mgreg_t))), FALSE);
+                       else
+                               code = mono_riscv_emit_store (code, i, basereg, (offset + (pos * sizeof (host_mgreg_t))), 0);
+                       pos++;
+               }
+       }
+       return code;
+}
+
+/* Same as mono_riscv_emitstore_regarray, but emit unwind info */
+/* CFA_OFFSET is the offset between the CFA and basereg */
+static __attribute__ ((__warn_unused_result__)) guint8 *
+emit_store_regarray_cfa (
+    MonoCompile *cfg, guint8 *code, guint64 regs, int basereg, int offset, int cfa_offset, guint64 no_cfa_regset)
+{
+       guint32 cfa_regset = regs & ~no_cfa_regset;
+
+       for (int i = 0; i < 32; ++i) {
+               if (regs & (1 << i)) {
+                       code = mono_riscv_emit_store (code, i, basereg, offset + (i * sizeof (host_mgreg_t)), 0);
+
+                       if (cfa_regset & (1 << i)) {
+                               g_assert (cfa_offset >= 0);
+                               mono_emit_unwind_op_offset (cfg, code, i, (-cfa_offset) + offset + (i * sizeof (host_mgreg_t)));
+                       }
+               }
+       }
+       return code;
+}
+
+/*
+ * emit_setup_lmf:
+ *
+ *   Emit code to initialize an LMF structure at LMF_OFFSET.
+ * Clobbers T6.
+ */
+static guint8 *
+emit_setup_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, int cfa_offset)
+{
+       /*
+        * The LMF should contain all the state required to be able to reconstruct the machine state
+        * at the current point of execution. Since the LMF is only read during EH, only callee
+        * saved etc. registers need to be saved.
+        * FIXME: Save callee saved fp regs, JITted code doesn't use them, but native code does, and they
+        * need to be restored during EH.
+        */
+       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);
+       /* callee saved gregs + sp */
+       code = emit_store_regarray_cfa (cfg, code, MONO_ARCH_LMF_REGS, RISCV_FP,
+                                       lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, gregs), cfa_offset, (1 << RISCV_SP));
+
+       return code;
+}
+
+static guint8 *
+emit_move_args (MonoCompile *cfg, guint8 *code)
+{
+       MonoInst *ins;
+       CallInfo *cinfo;
+       ArgInfo *ainfo;
+       MonoMethodSignature *sig = mono_method_signature_internal (cfg->method);
+
+       cinfo = cfg->arch.cinfo;
+       g_assert (cinfo);
+
+       for (int i = 0; i < cinfo->nargs; ++i) {
+               ainfo = cinfo->args + i;
+               ins = cfg->args [i];
+
+               if (ins->opcode == OP_REGVAR) {
+                       switch (ainfo->storage) {
+                       case ArgInIReg:
+                               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;
+
+                       default:
+                               NOT_IMPLEMENTED;
+                       }
+               } else {
+                       if (ainfo->storage != ArgVtypeByRef && ainfo->storage != ArgVtypeByRefOnStack)
+                               g_assert (ins->opcode == OP_REGOFFSET);
+
+                       switch (ainfo->storage) {
+                       case ArgInIReg:
+                               g_assert (ainfo->is_regpair == FALSE);
+                               code = mono_riscv_emit_store (code, ainfo->reg, ins->inst_basereg, ins->inst_offset, 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, FALSE, ins->inst_basereg, ins->inst_offset,
+                                                              code - cfg->native_code, 0);
+                               }
+                               break;
+                       case ArgInFReg:
+                       case ArgInFRegR4:
+                               code = mono_riscv_emit_fstore (code, ainfo->reg, ins->inst_basereg, ins->inst_offset,
+                                                              ainfo->storage == ArgInFRegR4);
+                               break;
+                       case ArgVtypeInIReg:
+                               if (ainfo->is_regpair)
+                                       code = mono_riscv_emit_store (code, ainfo->reg + 1, ins->inst_basereg,
+                                                                     ins->inst_offset + sizeof (host_mgreg_t), 0);
+                               code = mono_riscv_emit_store (code, ainfo->reg, ins->inst_basereg, ins->inst_offset, 0);
+                               break;
+                       case ArgOnStack:
+                               break;
+                       default:
+                               g_print ("can't process Storage type %d\n", ainfo->storage);
+                               NOT_IMPLEMENTED;
+                       }
+               }
+       }
+
+       return code;
+}
+
+static guint8 *
+emit_move_return_value (MonoCompile *cfg, guint8 *code, MonoInst *ins)
+{
+       CallInfo *cinfo;
+       MonoCallInst *call;
+
+       call = (MonoCallInst *)ins;
+       cinfo = call->call_info;
+       g_assert (cinfo);
+       switch (cinfo->ret.storage) {
+       case ArgNone:
+               break;
+       case ArgInIReg:
+               if (call->inst.dreg != cinfo->ret.reg) {
+                       riscv_addi (code, call->inst.dreg, cinfo->ret.reg, 0);
+               }
+               break;
+       case ArgInFReg:
+               g_assert (riscv_stdext_d || riscv_stdext_f);
+               if (call->inst.dreg != cinfo->ret.reg) {
+                       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);
+               }
+               break;
+       case ArgVtypeInIReg: {
+               MonoInst *loc = cfg->arch.vret_addr_loc;
+
+               /* Load the destination address */
+               g_assert (loc && loc->opcode == OP_REGOFFSET);
+               code = mono_riscv_emit_load (code, RISCV_T0, loc->inst_basereg, loc->inst_offset, 0);
+               code = mono_riscv_emit_store (code, cinfo->ret.reg, RISCV_T0, 0, 0);
+               if (cinfo->ret.is_regpair) {
+                       code = mono_riscv_emit_store (code, cinfo->ret.reg + 1, RISCV_T0, sizeof (host_mgreg_t), 0);
+               }
+               break;
+       }
+       case ArgVtypeByRef:
+               break;
+       default:
+               g_print ("Unable process returned storage %d(0x%x)\n", cinfo->ret.storage, cinfo->ret.storage);
+               NOT_IMPLEMENTED;
+               break;
+       }
        return code;
 }
 
@@ -650,26 +2038,28 @@ mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
 void
 mono_arch_start_single_stepping (void)
 {
-       NOT_IMPLEMENTED;
+       ss_trampoline = mini_get_single_step_trampoline ();
 }
 
 void
 mono_arch_stop_single_stepping (void)
 {
-       NOT_IMPLEMENTED;
+       ss_trampoline = NULL;
 }
 
 gboolean
 mono_arch_is_single_step_event (void *info, void *sigctx)
 {
-       NOT_IMPLEMENTED;
+       // NOT_IMPLEMENTED;
+       /* No reference Information, Don't know how to implement */
        return FALSE;
 }
 
 gboolean
 mono_arch_is_breakpoint_event (void *info, void *sigctx)
 {
-       NOT_IMPLEMENTED;
+       // NOT_IMPLEMENTED;
+       /* No reference Information, Don't know how to implement */
        return FALSE;
 }
 
@@ -688,8 +2078,32 @@ mono_arch_skip_single_step (MonoContext *ctx)
 SeqPointInfo*
 mono_arch_get_seq_point_info (guint8 *code)
 {
-       NOT_IMPLEMENTED;
-       return NULL;
+       SeqPointInfo *info;
+       MonoJitInfo *ji;
+       MonoJitMemoryManager *jit_mm;
+
+       jit_mm = get_default_jit_mm ();
+
+       // FIXME: Add a free function
+
+       jit_mm_lock (jit_mm);
+       info = (SeqPointInfo *)g_hash_table_lookup (jit_mm->arch_seq_points, code);
+       jit_mm_unlock (jit_mm);
+
+       if (!info) {
+               ji = mini_jit_info_table_find (code);
+               g_assert (ji);
+
+               info = g_malloc0 (sizeof (SeqPointInfo) + (ji->code_size / 4) * sizeof (guint8 *));
+
+               info->ss_tramp_addr = &ss_trampoline;
+
+               jit_mm_lock (jit_mm);
+               g_hash_table_insert (jit_mm->arch_seq_points, code, info);
+               jit_mm_unlock (jit_mm);
+       }
+
+       return info;
 }
 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
 
index 663ee46..61841cb 100644 (file)
@@ -14,6 +14,9 @@
 #define MONO_RISCV_ARCHITECTURE "riscv32"
 #endif
 
+extern gboolean riscv_stdext_a, riscv_stdext_b, riscv_stdext_c, riscv_stdext_d, riscv_stdext_f, riscv_stdext_j,
+    riscv_stdext_l, riscv_stdext_m, riscv_stdext_n, riscv_stdext_p, riscv_stdext_q, riscv_stdext_t, riscv_stdext_v;
+
 #if defined (RISCV_FPABI_SOFT)
 #define MONO_ARCH_SOFT_FLOAT_FALLBACK
 #define RISCV_FP_MODEL "soft-fp"
  * - x0 is hard-wired to zero and can't be allocated by the register allocator.
  */
 
+#define MONO_ARCH_ARGUMENT_REGS            (0b00000000000000111111110000000000)
+#define MONO_ARCH_IS_ARGUMENT_REGS(reg)    (MONO_ARCH_ARGUMENT_REGS & (1 << (reg)))
 #define MONO_ARCH_CALLEE_REGS        (0b11110000000000111111110000000000)
 #define MONO_ARCH_CALLEE_SAVED_REGS  (0b00001111111111000000001100000000)
+#define MONO_ARCH_IS_CALLEE_SAVED_REG(reg) (MONO_ARCH_CALLEE_SAVED_REGS & (1 << (reg)))
+
+/**
+ * callee saved regs + sp
+ * fp aka s0 is firse reg in LMF_REGS
+ */
+#define MONO_ARCH_LMF_REGS      ((MONO_ARCH_CALLEE_SAVED_REGS) | (1 << RISCV_SP))
+#define MONO_ARCH_FIRST_LMF_REG RISCV_S0
+#define MONO_ARCH_LMF_REG_FP    RISCV_S0
+#define MONO_ARCH_LMF_REG_SP    RISCV_SP
 
 #ifdef RISCV_FPABI_SOFT
 
@@ -64,6 +79,8 @@
 
 #else
 
+#define MONO_ARCH_ARGUMENT_FREGS         (0b00000000000000111111110000000000)
+#define MONO_ARCH_IS_ARGUMENT_FREGS(reg) (MONO_ARCH_ARGUMENT_FREGS & (1 << (reg)))
 #define MONO_ARCH_CALLEE_FREGS       (0b11110000000000111111110011111000)
 #define MONO_ARCH_CALLEE_SAVED_FREGS (0b00001111111111000000001100000000)
 
 
 #endif
 
-#define MONO_ARCH_RGCTX_REG  (RISCV_T2)
-#define MONO_ARCH_IMT_REG    (RISCV_T2)
+#define MONO_ARCH_RGCTX_REG  (RISCV_T6)
+#define MONO_ARCH_IMT_REG    MONO_ARCH_RGCTX_REG
 #define MONO_ARCH_VTABLE_REG (RISCV_A0)
 
 #define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 0
 #define MONO_ARCH_FRAME_ALIGNMENT (16)
 #define MONO_ARCH_CODE_ALIGNMENT  (32)
 
+// TODO: remove following def
 #define MONO_ARCH_EMULATE_MUL_DIV           (1)
 #define MONO_ARCH_EMULATE_FREM              (1)
 
 #define MONO_ARCH_EMULATE_LCONV_TO_R8       (1)
 #define MONO_ARCH_EMULATE_LCONV_TO_R4       (1)
 #define MONO_ARCH_EMULATE_LCONV_TO_R8_UN    (1)
+#define MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS (1)
 
 #define MONO_ARCH_NEED_DIV_CHECK (1)
 
 #define MONO_ARCH_HAVE_OP_TAIL_CALL          (1)
 #define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT (1)
-#define MONO_ARCH_HAVE_CARD_TABLE_WBARRIER   (1)
 
 #define MONO_ARCH_HAVE_GENERALIZED_IMT_TRAMPOLINE          (1)
 #define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE (1)
 
 // #define MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE (1)
 // #define MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP (1)
-// #define MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED (1)
+#define MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED (1)
+
+#define THUNK_SIZE (4 * 4 + 8)
 
 typedef struct {
+       CallInfo *cinfo;
+       int saved_gregs_offset;
+       guint32 saved_iregs;
+       MonoInst *vret_addr_loc;
+       MonoInst *seq_point_info_var;
+       MonoInst *ss_tramp_var;
+       MonoInst *bp_tramp_var;
+       guint8 *thunks;
+       int thunks_size;
 } MonoCompileArch;
 
 #define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) \
@@ -170,40 +199,126 @@ typedef struct {
        } while (0)
 
 struct MonoLMF {
-       // If the second-lowest bit of this field is set, this is a MonoLMFExt.
        gpointer previous_lmf;
        gpointer lmf_addr;
        host_mgreg_t pc;
-       host_mgreg_t sp;
-       host_mgreg_t ra;
-       host_mgreg_t gregs [RISCV_N_GSREGS]; // s0..s11
-       double fregs [RISCV_N_FSREGS]; // fs0..fs11
+       host_mgreg_t gregs [RISCV_N_GREGS];
+};
+
+/* Structure used by the sequence points in AOTed code */
+struct SeqPointInfo {
+       gpointer ss_tramp_addr;
+       guint8 *bp_addrs [MONO_ZERO_LEN_ARRAY];
 };
 
 #define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf)
 
 typedef struct {
+       /* General registers */
+       target_mgreg_t gregs [RISCV_N_GREGS];
+       /* Floating registers */
+       double fregs [RISCV_N_FREGS];
+       /* Stack usage, used for passing params on stack */
+       guint32 stack_size;
        guint8 *stack;
 } CallContext;
 
+typedef enum {
+       ArgInIReg = 0x01,
+       ArgOnStack,
+       ArgInFReg,
+#ifdef TARGET_RISCV64
+       ArgInFRegR4,
+#endif
+       ArgOnStackR4,
+       ArgOnStackR8,
+       ArgStructByVal,
+       ArgStructByAddr,
+       /*
+        * Vtype passed in consecutive int registers.
+        */
+       ArgVtypeByRef,
+       ArgVtypeByRefOnStack,
+       ArgVtypeOnStack,
+       ArgVtypeInIReg,
+       ArgVtypeInMixed,
+       ArgNone // only in void return type
+} ArgStorage;
+
+typedef struct {
+       ArgStorage storage;
+       /* ArgVtypeInIRegs */
+       guint8 reg;
+       int size;
+       guint8 is_regpair;
+       /* ArgOnStack */
+       int slot_size;
+       gint32 offset;
+       guint8 is_signed : 1;
+} ArgInfo;
+
+struct CallInfo {
+       int nargs;
+       guint32 next_arg, next_farg;
+       gboolean pinvoke, vararg;
+       guint32 stack_usage;
+       guint32 struct_ret;
+       ArgInfo ret;
+       ArgInfo sig_cookie;
+       ArgInfo args [1];
+};
+
+/* Relocations */
 enum {
-       MONO_R_RISCV_IMM  = 1,
-       MONO_R_RISCV_B    = 2,
-       MONO_R_RISCV_BEQ  = 3,
-       MONO_R_RISCV_BNE  = 4,
-       MONO_R_RISCV_BLT  = 5,
-       MONO_R_RISCV_BGE  = 6,
+       MONO_R_RISCV_IMM = 1,
+       MONO_R_RISCV_B = 2,
+       MONO_R_RISCV_BEQ = 3,
+       MONO_R_RISCV_BNE = 4,
+       MONO_R_RISCV_BLT = 5,
+       MONO_R_RISCV_BGE = 6,
        MONO_R_RISCV_BLTU = 7,
        MONO_R_RISCV_BGEU = 8,
+
+       MONO_R_RISCV_JAL = 9,
+       MONO_R_RISCV_JALR = 10,
 };
 
 __attribute__ ((warn_unused_result)) guint8 *
 mono_riscv_emit_imm (guint8 *code, int rd, gsize imm);
 
-__attribute__ ((warn_unused_result)) guint8 *
-mono_riscv_emit_load (guint8 *code, int rd, int rs1, gint32 imm);
+__attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_float_imm (guint8 *code,
+                                                                        int rd,
+                                                                        gsize f_imm,
+                                                                        gboolean isSingle);
 
-__attribute__ ((warn_unused_result)) guint8 *
-mono_riscv_emit_store (guint8 *code, int rs1, int rs2, gint32 imm);
+__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);
+
+__attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_fload (
+    guint8 *code, int rd, int rs1, gint32 imm, gboolean isSingle);
+
+__attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_store (
+    guint8 *code, int rs2, int rs1, gint32 imm, int length);
+
+__attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_fstore (
+    guint8 *code, int rs2, int rs1, gint32 imm, gboolean isSingle);
+
+__attribute__ ((__warn_unused_result__)) guint8 *mono_riscv_emit_destroy_frame (guint8 *code);
+
+__attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_store_stack (
+    guint8 *code, guint64 regs, int basereg, int offset, gboolean isFloat);
+
+__attribute__ ((warn_unused_result)) guint8 *mono_riscv_emit_load_stack (
+    guint8 *code, guint64 used_regs, int basereg, int offset, gboolean isFloat);
+
+__attribute__ ((__warn_unused_result__)) guint8 *mono_riscv_emit_store_regarray (
+    guint8 *code, guint64 regs, int basereg, int offset, gboolean isFloat);
+
+__attribute__ ((__warn_unused_result__)) guint8 *mono_riscv_emit_load_regarray (
+    guint8 *code, guint64 regs, int basereg, int offset, gboolean isFloat);
+
+__attribute__ ((__warn_unused_result__)) void mono_riscv_patch (guint8 *code, guint8 *target, int relocation);
 
 #endif