Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mono][RISC-V] emit mul inst instead of emulated mul #85445

Merged
merged 23 commits into from
Jul 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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