1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
5 #if !defined(TARGET_RISCV64)
6 #error The file should not be included for this platform.
10 #define CPU_LOAD_STORE_ARCH 1
11 #define CPU_HAS_FP_SUPPORT 1
12 #define ROUND_FLOAT 0 // Do not round intermed float expression results
13 #define CPU_HAS_BYTE_REGS 0
17 #pragma error("SIMD Unimplemented yet RISCV64")
18 #endif // FEATURE_SIMD
20 #define FEATURE_FIXED_OUT_ARGS 1 // Preallocate the outgoing arg area in the prolog
21 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
22 #define FEATURE_MULTIREG_STRUCT_PROMOTE 1 // True when we want to promote fields of a multireg struct into registers
23 #define FEATURE_FASTTAILCALL 1 // Tail calls made as epilog+jmp
24 #define FEATURE_TAILCALL_OPT 1 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
25 #define FEATURE_SET_FLAGS 0 // Set to true to force the JIT to mark the trees with GTF_SET_FLAGS when the flags need to be set
26 #define FEATURE_IMPLICIT_BYREFS 1 // Support for struct parameters passed via pointers to shadow copies
27 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
28 #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register
29 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
30 #define FEATURE_STRUCT_CLASSIFIER 0 // Uses a classifier function to determine is structs are passed/returned in more than one register
31 #define MAX_PASS_SINGLEREG_BYTES 8 // Maximum size of a struct passed in a single register (8-byte vector).
32 #define MAX_PASS_MULTIREG_BYTES 16 // Maximum size of a struct that could be passed in more than one register
33 #define MAX_RET_MULTIREG_BYTES 16 // Maximum size of a struct that could be returned in more than one register (Max is an HFA or 2 doubles)
34 #define MAX_ARG_REG_COUNT 2 // Maximum registers used to pass a single argument in multiple registers.
35 #define MAX_RET_REG_COUNT 2 // Maximum registers used to return a value.
36 #define MAX_MULTIREG_COUNT 2 // Maximum number of registers defined by a single instruction (including calls).
37 // This is also the maximum number of registers for a MultiReg node.
39 #define NOGC_WRITE_BARRIERS 1 // We have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers
40 #define USER_ARGS_COME_LAST 1
41 #define EMIT_TRACK_STACK_DEPTH 1 // This is something of a workaround. For both ARM and AMD64, the frame size is fixed, so we don't really
42 // need to track stack depth, but this is currently necessary to get GC information reported at call sites.
43 #define TARGET_POINTER_SIZE 8 // equal to sizeof(void*) and the managed pointer size in bytes for this target
44 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter, filter-handler, fault) and directly execute 'finally' clauses.
45 #define FEATURE_EH_CALLFINALLY_THUNKS 1 // Generate call-to-finally code in "thunks" in the enclosing EH region, protected by "cloned finally" clauses.
46 #define ETW_EBP_FRAMED 1 // if 1 we cannot use REG_FP as a scratch register and must setup the frame pointer for most methods
47 #define CSE_CONSTS 1 // Enable if we want to CSE constants
49 #define REG_FP_FIRST REG_F0
50 #define REG_FP_LAST REG_F31
51 #define FIRST_FP_ARGREG REG_F10
52 #define LAST_FP_ARGREG REG_F17
54 #define REGNUM_BITS 6 // number of bits in a REG_*
55 #define REGSIZE_BYTES 8 // number of bytes in one general purpose register
56 #define FP_REGSIZE_BYTES 8 // number of bytes in one FP/SIMD register
57 #define FPSAVE_REGSIZE_BYTES 8 // number of bytes in one FP/SIMD register that are saved/restored, for callee-saved registers
59 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
61 #define CODE_ALIGN 4 // code alignment requirement
62 #define STACK_ALIGN 16 // stack alignment requirement
64 #define RBM_INT_CALLEE_SAVED (RBM_S1|RBM_S2|RBM_S3|RBM_S4|RBM_S5|RBM_S6|RBM_S7|RBM_S8|RBM_S9|RBM_S10|RBM_S11)
65 #define RBM_INT_CALLEE_TRASH (RBM_A0|RBM_A1|RBM_A2|RBM_A3|RBM_A4|RBM_A5|RBM_A6|RBM_A7|RBM_T0|RBM_T1|RBM_T2|RBM_T3|RBM_T4|RBM_T5|RBM_T6)
66 #define RBM_FLT_CALLEE_SAVED (RBM_F8|RBM_F9|RBM_F18|RBM_F19|RBM_F20|RBM_F21|RBM_F22|RBM_F23|RBM_F24|RBM_F25|RBM_F26|RBM_F27)
67 #define RBM_FLT_CALLEE_TRASH (RBM_F10|RBM_F11|RBM_F12|RBM_F13|RBM_F14|RBM_F15|RBM_F16|RBM_F17)
69 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
70 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
72 #define REG_DEFAULT_HELPER_CALL_TARGET REG_T2
73 #define RBM_DEFAULT_HELPER_CALL_TARGET RBM_T2
75 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
76 #define RBM_ALLFLOAT (RBM_FLT_CALLEE_SAVED | RBM_FLT_CALLEE_TRASH)
77 #define RBM_ALLDOUBLE RBM_ALLFLOAT
79 // REG_VAR_ORDER is: (CALLEE_TRASH & ~CALLEE_TRASH_NOGC), CALLEE_TRASH_NOGC, CALLEE_SAVED
80 #define REG_VAR_ORDER REG_A0,REG_A1,REG_A2,REG_A3,REG_A4,REG_A5,REG_A6,REG_A7, \
81 REG_T0,REG_T1,REG_T2,REG_T3,REG_T4,REG_T5,REG_T6, \
82 REG_CALLEE_SAVED_ORDER
84 #define REG_VAR_ORDER_FLT REG_F12,REG_F13,REG_F14,REG_F15,REG_F16,REG_F17,REG_F18,REG_F19, \
85 REG_F2,REG_F3,REG_F4,REG_F5,REG_F6,REG_F7,REG_F8,REG_F9,REG_F10, \
86 REG_F20,REG_F21,REG_F22,REG_F23, \
87 REG_F24,REG_F25,REG_F26,REG_F27,REG_F28,REG_F29,REG_F30,REG_F31, \
90 #define REG_CALLEE_SAVED_ORDER REG_S1,REG_S2,REG_S3,REG_S4,REG_S5,REG_S6,REG_S7,REG_S8,REG_S9,REG_S10,REG_S11
91 #define RBM_CALLEE_SAVED_ORDER RBM_S1,RBM_S2,RBM_S3,RBM_S4,RBM_S5,RBM_S6,RBM_S7,RBM_S8,RBM_S9,RBM_S10,RBM_S11
93 #define CNT_CALLEE_SAVED (11)
94 #define CNT_CALLEE_TRASH (15)
95 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
97 #define CNT_CALLEE_SAVED_FLOAT (12)
98 #define CNT_CALLEE_TRASH_FLOAT (20)
100 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED * REGSIZE_BYTES)
101 #define CALLEE_SAVED_FLOAT_MAXSZ (CNT_CALLEE_SAVED_FLOAT * FPSAVE_REGSIZE_BYTES)
103 #define REG_TMP_0 REG_T0
105 // Temporary registers used for the GS cookie check.
106 #define REG_GSCOOKIE_TMP_0 REG_T0
107 #define REG_GSCOOKIE_TMP_1 REG_T1
109 // register to hold shift amount; no special register is required on ARM64.
110 #define REG_SHIFT REG_NA
111 #define RBM_SHIFT RBM_ALLINT
113 // This is a general scratch register that does not conflict with the argument registers
114 #define REG_SCRATCH REG_T0
116 // This is a float scratch register that does not conflict with the argument registers
117 #define REG_SCRATCH_FLT REG_F28
119 // This is a general register that can be optionally reserved for other purposes during codegen
120 #define REG_OPT_RSVD REG_T6
121 #define RBM_OPT_RSVD RBM_T6
123 // Where is the exception object on entry to the handler block?
124 #define REG_EXCEPTION_OBJECT REG_A0
125 #define RBM_EXCEPTION_OBJECT RBM_A0
127 #define REG_JUMP_THUNK_PARAM REG_T2
128 #define RBM_JUMP_THUNK_PARAM RBM_T2
130 #define REG_WRITE_BARRIER_DST REG_T3
131 #define RBM_WRITE_BARRIER_DST RBM_T3
133 #define REG_WRITE_BARRIER_SRC REG_T4
134 #define RBM_WRITE_BARRIER_SRC RBM_T4
136 #define REG_WRITE_BARRIER_DST_BYREF REG_T3
137 #define RBM_WRITE_BARRIER_DST_BYREF RBM_T3
139 #define REG_WRITE_BARRIER_SRC_BYREF REG_T5
140 #define RBM_WRITE_BARRIER_SRC_BYREF RBM_T5
142 #define RBM_CALLEE_TRASH_NOGC (RBM_T0|RBM_T1|RBM_T2|RBM_T3|RBM_T4|RBM_T5|RBM_T6|RBM_DEFAULT_HELPER_CALL_TARGET)
144 // Registers killed by CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
145 #define RBM_CALLEE_TRASH_WRITEBARRIER (RBM_WRITE_BARRIER_DST|RBM_CALLEE_TRASH_NOGC)
147 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
148 #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_NOGC
150 // Registers killed by CORINFO_HELP_ASSIGN_BYREF.
151 #define RBM_CALLEE_TRASH_WRITEBARRIER_BYREF (RBM_WRITE_BARRIER_DST_BYREF | RBM_WRITE_BARRIER_SRC_BYREF | RBM_CALLEE_TRASH_NOGC)
153 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_BYREF.
154 // Note that x13 and x14 are still valid byref pointers after this helper call, despite their value being changed.
155 #define RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF RBM_CALLEE_TRASH_NOGC
157 // GenericPInvokeCalliHelper VASigCookie Parameter
158 #define REG_PINVOKE_COOKIE_PARAM REG_T3
159 #define RBM_PINVOKE_COOKIE_PARAM RBM_T3
161 // GenericPInvokeCalliHelper unmanaged target Parameter
162 #define REG_PINVOKE_TARGET_PARAM REG_T2
163 #define RBM_PINVOKE_TARGET_PARAM RBM_T2
165 // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
166 #define REG_SECRET_STUB_PARAM REG_T2
167 #define RBM_SECRET_STUB_PARAM RBM_T2
169 // R2R indirect call. Use the same registers as VSD
170 #define REG_R2R_INDIRECT_PARAM REG_T5
171 #define RBM_R2R_INDIRECT_PARAM RBM_T5
173 // JMP Indirect call register
174 #define REG_INDIRECT_CALL_TARGET_REG REG_T5
176 // Registers used by PInvoke frame setup
177 #define REG_PINVOKE_FRAME REG_T0
178 #define RBM_PINVOKE_FRAME RBM_T0
179 #define REG_PINVOKE_TCB REG_T1
180 #define RBM_PINVOKE_TCB RBM_T1
181 #define REG_PINVOKE_SCRATCH REG_T1
182 #define RBM_PINVOKE_SCRATCH RBM_T1
184 // The following defines are useful for iterating a regNumber
185 #define REG_FIRST REG_R0
186 #define REG_INT_FIRST REG_R0
187 #define REG_INT_LAST REG_T6
188 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
189 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
190 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
192 // The following registers are used in emitting Enter/Leave/Tailcall profiler callbacks
193 #define REG_PROFILER_ENTER_ARG_FUNC_ID REG_T0
194 #define RBM_PROFILER_ENTER_ARG_FUNC_ID RBM_T0
195 #define REG_PROFILER_ENTER_ARG_CALLER_SP REG_T1
196 #define RBM_PROFILER_ENTER_ARG_CALLER_SP RBM_T1
197 #define REG_PROFILER_LEAVE_ARG_FUNC_ID REG_PROFILER_ENTER_ARG_FUNC_ID
198 #define RBM_PROFILER_LEAVE_ARG_FUNC_ID RBM_PROFILER_ENTER_ARG_FUNC_ID
199 #define REG_PROFILER_LEAVE_ARG_CALLER_SP REG_PROFILER_ENTER_ARG_CALLER_SP
200 #define RBM_PROFILER_LEAVE_ARG_CALLER_SP RBM_PROFILER_ENTER_ARG_CALLER_SP
202 // The registers trashed by profiler enter/leave/tailcall hook
203 #define RBM_PROFILER_ENTER_TRASH (RBM_CALLEE_TRASH & ~(RBM_ARG_REGS|RBM_FLTARG_REGS|RBM_FP))
204 #define RBM_PROFILER_LEAVE_TRASH RBM_PROFILER_ENTER_TRASH
205 #define RBM_PROFILER_TAILCALL_TRASH RBM_PROFILER_LEAVE_TRASH
207 // Which register are int and long values returned in ?
208 #define REG_INTRET REG_A0
209 #define RBM_INTRET RBM_A0
210 #define REG_LNGRET REG_A0
211 #define RBM_LNGRET RBM_A0
212 // second return register for 16-byte structs
213 #define REG_INTRET_1 REG_A1
214 #define RBM_INTRET_1 RBM_A1
216 #define REG_FLOATRET REG_F10
217 #define RBM_FLOATRET RBM_F10
218 #define RBM_DOUBLERET RBM_F10
219 #define REG_FLOATRET_1 REG_F11
220 #define RBM_FLOATRET_1 RBM_F11
221 #define RBM_DOUBLERET_1 RBM_F11
223 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper
224 #define RBM_STOP_FOR_GC_TRASH RBM_CALLEE_TRASH
226 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper.
227 #define RBM_INIT_PINVOKE_FRAME_TRASH RBM_CALLEE_TRASH
229 #define RBM_VALIDATE_INDIRECT_CALL_TRASH (RBM_INT_CALLEE_TRASH & ~(RBM_A0 | RBM_A1 | RBM_A2 | RBM_A3 | RBM_A4 | RBM_A5 | RBM_A6 | RBM_A7 | RBM_T3))
230 #define REG_VALIDATE_INDIRECT_CALL_ADDR REG_T3
231 #define REG_DISPATCH_INDIRECT_CALL_ADDR REG_T0
233 #define REG_FPBASE REG_FP
234 #define RBM_FPBASE RBM_FP
235 #define STR_FPBASE "fp"
236 #define REG_SPBASE REG_SP
237 #define RBM_SPBASE RBM_SP // reuse the RBM for REG_ZR
238 #define STR_SPBASE "sp"
240 #define FIRST_ARG_STACK_OFFS (2*REGSIZE_BYTES) // Caller's saved FP and return address
242 #define MAX_REG_ARG 8
243 #define MAX_FLOAT_REG_ARG 8
245 #define REG_ARG_FIRST REG_A0
246 #define REG_ARG_LAST REG_A7
247 #define REG_ARG_FP_FIRST REG_F10
248 #define REG_ARG_FP_LAST REG_F17
249 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
251 #define REG_ARG_0 REG_A0
252 #define REG_ARG_1 REG_A1
253 #define REG_ARG_2 REG_A2
254 #define REG_ARG_3 REG_A3
255 #define REG_ARG_4 REG_A4
256 #define REG_ARG_5 REG_A5
257 #define REG_ARG_6 REG_A6
258 #define REG_ARG_7 REG_A7
260 extern const regNumber intArgRegs [MAX_REG_ARG];
261 extern const regMaskTP intArgMasks[MAX_REG_ARG];
263 #define RBM_ARG_0 RBM_A0
264 #define RBM_ARG_1 RBM_A1
265 #define RBM_ARG_2 RBM_A2
266 #define RBM_ARG_3 RBM_A3
267 #define RBM_ARG_4 RBM_A4
268 #define RBM_ARG_5 RBM_A5
269 #define RBM_ARG_6 RBM_A6
270 #define RBM_ARG_7 RBM_A7
272 #define REG_FLTARG_0 REG_F10
273 #define REG_FLTARG_1 REG_F11
274 #define REG_FLTARG_2 REG_F12
275 #define REG_FLTARG_3 REG_F13
276 #define REG_FLTARG_4 REG_F14
277 #define REG_FLTARG_5 REG_F15
278 #define REG_FLTARG_6 REG_F16
279 #define REG_FLTARG_7 REG_F17
281 #define RBM_FLTARG_0 RBM_F10
282 #define RBM_FLTARG_1 RBM_F11
283 #define RBM_FLTARG_2 RBM_F12
284 #define RBM_FLTARG_3 RBM_F13
285 #define RBM_FLTARG_4 RBM_F14
286 #define RBM_FLTARG_5 RBM_F15
287 #define RBM_FLTARG_6 RBM_F16
288 #define RBM_FLTARG_7 RBM_F17
290 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1|RBM_ARG_2|RBM_ARG_3|RBM_ARG_4|RBM_ARG_5|RBM_ARG_6|RBM_ARG_7)
291 #define RBM_FLTARG_REGS (RBM_FLTARG_0|RBM_FLTARG_1|RBM_FLTARG_2|RBM_FLTARG_3|RBM_FLTARG_4|RBM_FLTARG_5|RBM_FLTARG_6|RBM_FLTARG_7)
293 extern const regNumber fltArgRegs [MAX_FLOAT_REG_ARG];
294 extern const regMaskTP fltArgMasks[MAX_FLOAT_REG_ARG];
296 #define B_DIST_SMALL_MAX_NEG (-4096)
297 #define B_DIST_SMALL_MAX_POS (+4095)
299 // The number of bytes from the end the last probed page that must also be probed, to allow for some
300 // small SP adjustments without probes. If zero, then the stack pointer can point to the last byte/word
301 // on the stack guard page, and must be touched before any further "SUB SP".
302 #define STACK_PROBE_BOUNDARY_THRESHOLD_BYTES 0