2 * Licensed to the .NET Foundation under one or more agreements.
3 * The .NET Foundation licenses this file to you under the MIT license.
4 * See the LICENSE file in the project root for more information.
7 #include <mono/utils/mono-hwcap.h>
9 #include "mini-runtime.h"
12 #include "cpu-riscv64.h"
14 #include "cpu-riscv32.h"
17 static gboolean riscv_stdext_a
, riscv_stdext_b
, riscv_stdext_c
,
18 riscv_stdext_d
, riscv_stdext_f
, riscv_stdext_j
,
19 riscv_stdext_l
, riscv_stdext_m
, riscv_stdext_n
,
20 riscv_stdext_p
, riscv_stdext_q
, riscv_stdext_t
,
24 mono_arch_cpu_init (void)
31 riscv_stdext_a
= mono_hwcap_riscv_has_stdext_a
;
32 riscv_stdext_c
= mono_hwcap_riscv_has_stdext_c
;
33 riscv_stdext_d
= mono_hwcap_riscv_has_stdext_d
;
34 riscv_stdext_f
= mono_hwcap_riscv_has_stdext_f
;
35 riscv_stdext_m
= mono_hwcap_riscv_has_stdext_m
;
39 mono_arch_finish_init (void)
44 mono_arch_register_lowlevel_calls (void)
49 mono_arch_cleanup (void)
54 mono_arch_set_target (char *mtriple
)
56 // riscv{32,64}[extensions]-[<vendor>-]<system>-<abi>
58 size_t len
= strlen (MONO_RISCV_ARCHITECTURE
);
60 if (!strncmp (mtriple
, MONO_RISCV_ARCHITECTURE
, len
)) {
69 // ISA manual says upper and lower case are both OK.
73 riscv_stdext_a
= TRUE
;
77 riscv_stdext_b
= TRUE
;
81 riscv_stdext_c
= TRUE
;
85 riscv_stdext_d
= TRUE
;
89 riscv_stdext_f
= TRUE
;
93 riscv_stdext_j
= TRUE
;
97 riscv_stdext_l
= TRUE
;
101 riscv_stdext_m
= TRUE
;
105 riscv_stdext_n
= TRUE
;
109 riscv_stdext_p
= TRUE
;
113 riscv_stdext_q
= TRUE
;
117 riscv_stdext_t
= TRUE
;
121 riscv_stdext_v
= TRUE
;
133 mono_arch_cpu_optimizations (guint32
*exclude_mask
)
140 mono_arch_cpu_enumerate_simd_versions (void)
146 mono_arch_have_fast_tls (void)
152 mono_arch_opcode_supported (int opcode
)
155 case OP_ATOMIC_ADD_I4
:
156 case OP_ATOMIC_EXCHANGE_I4
:
157 case OP_ATOMIC_CAS_I4
:
158 case OP_ATOMIC_LOAD_I1
:
159 case OP_ATOMIC_LOAD_I2
:
160 case OP_ATOMIC_LOAD_I4
:
161 case OP_ATOMIC_LOAD_U1
:
162 case OP_ATOMIC_LOAD_U2
:
163 case OP_ATOMIC_LOAD_U4
:
164 case OP_ATOMIC_STORE_I1
:
165 case OP_ATOMIC_STORE_I2
:
166 case OP_ATOMIC_STORE_I4
:
167 case OP_ATOMIC_STORE_U1
:
168 case OP_ATOMIC_STORE_U2
:
169 case OP_ATOMIC_STORE_U4
:
170 #ifdef TARGET_RISCV64
171 case OP_ATOMIC_ADD_I8
:
172 case OP_ATOMIC_EXCHANGE_I8
:
173 case OP_ATOMIC_CAS_I8
:
174 case OP_ATOMIC_LOAD_I8
:
175 case OP_ATOMIC_LOAD_U8
:
176 case OP_ATOMIC_STORE_I8
:
177 case OP_ATOMIC_STORE_U8
:
179 return riscv_stdext_a
;
180 case OP_ATOMIC_LOAD_R4
:
181 case OP_ATOMIC_STORE_R4
:
182 #ifdef TARGET_RISCV64
183 case OP_ATOMIC_LOAD_R8
:
184 case OP_ATOMIC_STORE_R8
:
186 return riscv_stdext_a
&& riscv_stdext_d
;
193 mono_arch_regname (int reg
)
195 static const char *names
[RISCV_N_GREGS
] = {
196 "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
197 "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
198 "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
199 "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
202 if (reg
>= 0 && reg
< G_N_ELEMENTS (names
))
209 mono_arch_fregname (int reg
)
211 static const char *names
[RISCV_N_FREGS
] = {
212 "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
213 "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
214 "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
215 "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11",
218 if (reg
>= 0 && reg
< G_N_ELEMENTS (names
))
225 mono_arch_get_this_arg_from_call (host_mgreg_t
*regs
, guint8
*code
)
227 return (gpointer
) regs
[RISCV_A0
];
231 mono_arch_find_imt_method (host_mgreg_t
*regs
, guint8
*code
)
233 return (MonoMethod
*) regs
[MONO_ARCH_IMT_REG
];
237 mono_arch_find_static_call_vtable (host_mgreg_t
*regs
, guint8
*code
)
239 return (MonoVTable
*) regs
[MONO_ARCH_VTABLE_REG
];
243 mono_arch_context_get_int_reg (MonoContext
*ctx
, int reg
)
245 return ctx
->gregs
[reg
];
249 mono_arch_context_set_int_reg (MonoContext
*ctx
, int reg
, host_mgreg_t val
)
251 ctx
->gregs
[reg
] = val
;
255 mono_arch_flush_register_windows (void)
260 mono_arch_flush_icache (guint8
*code
, gint size
)
262 #ifndef MONO_CROSS_COMPILE
263 __builtin___clear_cache (code
, code
+ size
);
268 mono_arch_dyn_call_prepare (MonoMethodSignature
*sig
)
275 mono_arch_dyn_call_free (MonoDynCallInfo
*info
)
281 mono_arch_dyn_call_get_buf_size (MonoDynCallInfo
*info
)
288 mono_arch_start_dyn_call (MonoDynCallInfo
*info
, gpointer
**args
, guint8
*ret
,
295 mono_arch_finish_dyn_call (MonoDynCallInfo
*info
, guint8
*buf
)
301 mono_arch_get_argument_info (MonoMethodSignature
*csig
, int param_count
,
302 MonoJitArgumentInfo
*arg_info
)
309 mono_arch_patch_code_new (MonoCompile
*cfg
, MonoDomain
*domain
, guint8
*code
,
310 MonoJumpInfo
*ji
, gpointer target
)
315 /* Set arguments in the ccontext (for i2n entry) */
317 mono_arch_set_native_call_context_args (CallContext
*ccontext
, gpointer frame
, MonoMethodSignature
*sig
)
322 /* Set return value in the ccontext (for n2i return) */
324 mono_arch_set_native_call_context_ret (CallContext
*ccontext
, gpointer frame
, MonoMethodSignature
*sig
)
329 /* Gets the arguments from ccontext (for n2i entry) */
331 mono_arch_get_native_call_context_args (CallContext
*ccontext
, gpointer frame
, MonoMethodSignature
*sig
)
336 /* Gets the return value from ccontext (for i2n exit) */
338 mono_arch_get_native_call_context_ret (CallContext
*ccontext
, gpointer frame
, MonoMethodSignature
*sig
)
345 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
348 mono_arch_is_soft_float (void)
350 return !riscv_stdext_d
;
356 mono_arch_opcode_needs_emulation (MonoCompile
*cfg
, int opcode
)
363 #ifdef TARGET_RISCV64
369 return !riscv_stdext_m
;
376 mono_arch_tailcall_supported (MonoCompile
*cfg
, MonoMethodSignature
*caller_sig
, MonoMethodSignature
*callee_sig
, gboolean virtual_
)
382 mono_arch_is_inst_imm (int opcode
, int imm_opcode
, gint64 imm
)
384 // TODO: Make a proper decision based on opcode.
389 mono_arch_get_allocatable_int_vars (MonoCompile
*cfg
)
393 for (guint i
= 0; i
< cfg
->num_varinfo
; i
++) {
394 MonoInst
*ins
= cfg
->varinfo
[i
];
395 MonoMethodVar
*vmv
= MONO_VARINFO (cfg
, i
);
397 if (vmv
->range
.first_use
.abs_pos
>= vmv
->range
.last_use
.abs_pos
)
400 if ((ins
->flags
& (MONO_INST_IS_DEAD
| MONO_INST_VOLATILE
| MONO_INST_INDIRECT
)) ||
401 (ins
->opcode
!= OP_LOCAL
&& ins
->opcode
!= OP_ARG
))
404 if (!mono_is_regsize_var (ins
->inst_vtype
))
407 vars
= g_list_prepend (vars
, vmv
);
410 vars
= mono_varlist_sort (cfg
, vars
, 0);
416 mono_arch_get_global_int_regs (MonoCompile
*cfg
)
420 for (int i
= RISCV_S0
; i
<= RISCV_S11
; i
++)
421 regs
= g_list_prepend (regs
, GUINT_TO_POINTER (i
));
427 mono_arch_regalloc_cost (MonoCompile
*cfg
, MonoMethodVar
*vmv
)
429 return cfg
->varinfo
[vmv
->idx
]->opcode
== OP_ARG
? 1 : 2;
435 mono_arch_get_llvm_call_info (MonoCompile
*cfg
, MonoMethodSignature
*sig
)
443 mono_arch_create_vars (MonoCompile
*cfg
)
449 mono_arch_emit_inst_for_method (MonoCompile
*cfg
, MonoMethod
*cmethod
,
450 MonoMethodSignature
*fsig
, MonoInst
**args
)
456 mono_arch_emit_call (MonoCompile
*cfg
, MonoCallInst
*call
)
462 mono_arch_emit_outarg_vt (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
*src
)
468 mono_arch_emit_setret (MonoCompile
*cfg
, MonoMethod
*method
, MonoInst
*val
)
474 mono_arch_decompose_opts (MonoCompile
*cfg
, MonoInst
*ins
)
480 mono_arch_decompose_long_opts (MonoCompile
*cfg
, MonoInst
*long_ins
)
482 #ifdef TARGET_RISCV32
488 mono_arch_allocate_vars (MonoCompile
*cfg
)
494 mono_arch_lowering_pass (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
500 mono_arch_peephole_pass_1 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
505 mono_arch_peephole_pass_2 (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
509 // Uses at most 8 bytes on RV32I and 16 bytes on RV64I.
511 mono_riscv_emit_imm (guint8
*code
, int rd
, gsize imm
)
513 #ifdef TARGET_RISCV64
514 if (RISCV_VALID_I_IMM (imm
)) {
515 riscv_addi (code
, rd
, RISCV_ZERO
, imm
);
520 * This is not pretty, but RV64I doesn't make it easy to load constants.
521 * Need to figure out something better.
523 riscv_jal (code
, rd
, sizeof (guint64
));
524 *(guint64
*) code
= imm
;
525 code
+= sizeof (guint64
);
526 riscv_ld (code
, rd
, rd
, 0);
528 if (RISCV_VALID_I_IMM (imm
)) {
529 riscv_addi (code
, rd
, RISCV_ZERO
, imm
);
533 riscv_lui (code
, rd
, RISCV_BITS (imm
, 12, 20));
535 if (!RISCV_VALID_U_IMM (imm
))
536 riscv_ori (code
, rd
, rd
, RISCV_BITS (imm
, 0, 12));
542 // Uses at most 16 bytes on RV32I and 24 bytes on RV64I.
544 mono_riscv_emit_load (guint8
*code
, int rd
, int rs1
, gint32 imm
)
546 if (RISCV_VALID_I_IMM (imm
)) {
547 #ifdef TARGET_RISCV64
548 riscv_ld (code
, rd
, rs1
, imm
);
550 riscv_lw (code
, rd
, rs1
, imm
);
553 code
= mono_riscv_emit_imm (code
, rd
, imm
);
554 riscv_add (code
, rd
, rs1
, rd
);
555 #ifdef TARGET_RISCV64
556 riscv_ld (code
, rd
, rd
, 0);
558 riscv_lw (code
, rd
, rd
, 0);
565 // May clobber t1. Uses at most 16 bytes on RV32I and 24 bytes on RV64I.
567 mono_riscv_emit_store (guint8
*code
, int rs1
, int rs2
, gint32 imm
)
569 if (RISCV_VALID_S_IMM (imm
)) {
570 #ifdef TARGET_RISCV64
571 riscv_sd (code
, rs1
, rs2
, imm
);
573 riscv_sw (code
, rs1
, rs2
, imm
);
576 code
= mono_riscv_emit_imm (code
, RISCV_T1
, imm
);
577 riscv_add (code
, RISCV_T1
, rs2
, RISCV_T1
);
578 #ifdef TARGET_RISCV64
579 riscv_sd (code
, rs1
, RISCV_T1
, 0);
581 riscv_sw (code
, rs1
, RISCV_T1
, 0);
589 mono_arch_emit_prolog (MonoCompile
*cfg
)
595 mono_arch_emit_epilog (MonoCompile
*cfg
)
601 mono_arch_output_basic_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
607 mono_arch_emit_exceptions (MonoCompile
*cfg
)
613 mono_arch_get_patch_offset (guint8
*code
)
620 mono_arch_get_trampolines (gboolean aot
)
628 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED)
630 mono_arch_set_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
636 mono_arch_clear_breakpoint (MonoJitInfo
*ji
, guint8
*ip
)
642 mono_arch_start_single_stepping (void)
648 mono_arch_stop_single_stepping (void)
654 mono_arch_is_single_step_event (void *info
, void *sigctx
)
661 mono_arch_is_breakpoint_event (void *info
, void *sigctx
)
668 mono_arch_skip_breakpoint (MonoContext
*ctx
, MonoJitInfo
*ji
)
674 mono_arch_skip_single_step (MonoContext
*ctx
)
680 mono_arch_get_seq_point_info (MonoDomain
*domain
, guint8
*code
)
685 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
688 mono_arch_load_function (MonoJitICallId jit_icall_id
)