Skip to content

Commit

Permalink
[Mono][RISC-V] emit mul inst instead of emulated mul (#85445)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Xinlong-Wu authored Jul 8, 2023
1 parent 42742cd commit 045b526
Show file tree
Hide file tree
Showing 6 changed files with 347 additions and 109 deletions.
3 changes: 1 addition & 2 deletions src/mono/mono/arch/riscv/riscv-codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
38 changes: 21 additions & 17 deletions src/mono/mono/mini/cpu-riscv64.mdesc
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
175 changes: 161 additions & 14 deletions src/mono/mono/mini/exceptions-riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -67,18 +68,160 @@ 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)
{
*info = NULL;
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
Expand All @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -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
Expand All @@ -190,28 +329,32 @@ 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);

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) {
Expand All @@ -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));
Expand Down
Loading

0 comments on commit 045b526

Please sign in to comment.