1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 /*****************************************************************************/
9 #if defined(FEATURE_CORECLR) && defined(_TARGET_UNIX_)
10 #define FEATURE_VARARG 0
11 #else // !(defined(FEATURE_CORECLR) && defined(_TARGET_UNIX_))
12 #define FEATURE_VARARG 1
13 #endif // !(defined(FEATURE_CORECLR) && defined(_TARGET_UNIX_))
15 /*****************************************************************************/
16 // The following are human readable names for the target architectures
17 #if defined(_TARGET_X86_)
18 #define TARGET_READABLE_NAME "X86"
19 #elif defined(_TARGET_AMD64_)
20 #define TARGET_READABLE_NAME "AMD64"
21 #elif defined(_TARGET_ARM_)
22 #define TARGET_READABLE_NAME "ARM"
23 #elif defined(_TARGET_ARM64_)
24 #define TARGET_READABLE_NAME "ARM64"
26 #error Unsupported or unset target architecture
29 /*****************************************************************************/
30 // The following are intended to capture only those #defines that cannot be replaced
31 // with static const members of Target
32 #if defined(_TARGET_XARCH_)
33 #define REGMASK_BITS 32
35 #elif defined(_TARGET_ARM_)
36 #define REGMASK_BITS 64
38 #elif defined(_TARGET_ARM64_)
39 #define REGMASK_BITS 64
42 #error Unsupported or unset target architecture
45 //------------------------------------------------------------------------
47 // Each register list in register.h must declare REG_STK as the last value.
48 // In the following enum declarations, the following REG_XXX are created beyond
49 // the "real" registers:
50 // REG_STK - Used to indicate something evaluated onto the stack.
51 // ACTUAL_REG_COUNT - The number of physical registers. (same as REG_STK).
52 // REG_COUNT - The number of physical register + REG_STK. This is the count of values that may
53 // be assigned during register allocation.
54 // REG_NA - Used to indicate that a register is either not yet assigned or not required.
56 #if defined(_TARGET_ARM_)
57 enum _regNumber_enum : unsigned
59 #define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
60 #define REGALIAS(alias, realname) REG_##alias = REG_##realname,
65 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
68 enum _regMask_enum : unsigned __int64
71 #define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
72 #define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
76 #elif defined(_TARGET_ARM64_)
78 enum _regNumber_enum : unsigned
80 #define REGDEF(name, rnum, mask, xname, wname) REG_##name = rnum,
81 #define REGALIAS(alias, realname) REG_##alias = REG_##realname,
86 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
89 enum _regMask_enum : unsigned __int64
92 #define REGDEF(name, rnum, mask, xname, wname) RBM_##name = mask,
93 #define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
97 #elif defined(_TARGET_AMD64_)
99 enum _regNumber_enum : unsigned
101 #define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
102 #define REGALIAS(alias, realname) REG_##alias = REG_##realname,
103 #include "register.h"
107 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
110 enum _regMask_enum : unsigned
114 #define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
115 #define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
116 #include "register.h"
119 #elif defined(_TARGET_X86_)
121 enum _regNumber_enum : unsigned
123 #define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
124 #define REGALIAS(alias, realname) REG_##alias = REG_##realname,
125 #include "register.h"
129 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
132 enum _regMask_enum : unsigned
136 #define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
137 #define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
138 #include "register.h"
142 #error Unsupported target architecture
145 /*****************************************************************************/
147 // TODO-Cleanup: The types defined below are mildly confusing: why are there both?
148 // regMaskSmall is large enough to represent the entire set of registers.
149 // If regMaskSmall is smaller than a "natural" integer type, regMaskTP is wider, based
150 // on a belief by the original authors of the JIT that in some situations it is more
151 // efficient to have the wider representation. This belief should be tested, and if it
152 // is false, then we should coalesce these two types into one (the Small width, probably).
153 // In any case, we believe that is OK to freely cast between these types; no information will
156 #ifdef _TARGET_ARMARCH_
157 typedef unsigned __int64 regMaskTP;
159 typedef unsigned regMaskTP;
162 #if REGMASK_BITS == 8
163 typedef unsigned char regMaskSmall;
164 #define REG_MASK_INT_FMT "%02X"
165 #define REG_MASK_ALL_FMT "%02X"
166 #elif REGMASK_BITS == 16
167 typedef unsigned short regMaskSmall;
168 #define REG_MASK_INT_FMT "%04X"
169 #define REG_MASK_ALL_FMT "%04X"
170 #elif REGMASK_BITS == 32
171 typedef unsigned regMaskSmall;
172 #define REG_MASK_INT_FMT "%08X"
173 #define REG_MASK_ALL_FMT "%08X"
175 typedef unsigned __int64 regMaskSmall;
176 #define REG_MASK_INT_FMT "%04llX"
177 #define REG_MASK_ALL_FMT "%016llX"
180 typedef _regNumber_enum regNumber;
181 typedef unsigned char regNumberSmall;
183 /*****************************************************************************/
185 #define LEA_AVAILABLE 1
186 #define SCALED_ADDR_MODES 1
188 /*****************************************************************************/
191 #define DSP_SRC_OPER_LEFT 0
192 #define DSP_SRC_OPER_RIGHT 1
193 #define DSP_DST_OPER_LEFT 1
194 #define DSP_DST_OPER_RIGHT 0
197 /*****************************************************************************/
199 // The pseudorandom nop insertion is not necessary for current CoreCLR scenarios
200 // #if defined(FEATURE_CORECLR) && !defined(_TARGET_ARM_)
201 // #define PSEUDORANDOM_NOP_INSERTION
204 // TODO-Cleanup: FEATURE_PREVENT_BAD_BYREFS guards code that prevents creating byref pointers to array elements
205 // that are not "complete". That is, it only allows byref pointers to the exact array element, not to a portion
206 // of the address expression leading to the full addressing expression. This prevents the possibility of creating
207 // an illegal byref, which is an expression that points outside of the "host" object. Such bad byrefs won't get
208 // updated properly during a GC, leaving them to point to garbage. This led to a GC hole on ARM due to ARM's
209 // limited addressing modes (found in GCStress). The change is applicable and possibly desirable for other platforms,
210 // but was put under ifdef to avoid introducing potential destabilizing change to those platforms at the end of the
211 // .NET Core 2.1 ship cycle. More detail here: https://github.com/dotnet/coreclr/pull/17524. Consider making this
212 // all-platform and removing these #ifdefs.
213 #if defined(_TARGET_ARM_)
214 #define FEATURE_PREVENT_BAD_BYREFS 1
216 #define FEATURE_PREVENT_BAD_BYREFS 0
219 /*****************************************************************************/
222 #if defined(_TARGET_X86_)
224 #define CPU_LOAD_STORE_ARCH 0
225 #define CPU_HAS_FP_SUPPORT 1
226 #define ROUND_FLOAT 1 // round intermed float expression results
227 #define CPU_HAS_BYTE_REGS 1
229 // TODO-CQ: Fine tune the following xxBlk threshold values:
231 #define CPBLK_MOVS_LIMIT 16 // When generating code for CpBlk, this is the buffer size
232 // threshold to stop generating rep movs and switch to the helper call.
233 // NOTE: Using rep movs is currently disabled since we found it has bad performance
234 // on pre-Ivy Bridge hardware.
236 #define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk.
237 #define INITBLK_STOS_LIMIT 64 // When generating code for InitBlk, this is the buffer size
238 // NOTE: Using rep stos is currently disabled since we found it has bad performance
239 // on pre-Ivy Bridge hardware.
240 // threshold to stop generating rep movs and switch to the helper call.
241 #define INITBLK_UNROLL_LIMIT 128 // Upper bound to let the code generator to loop unroll InitBlk.
242 #define CPOBJ_NONGC_SLOTS_LIMIT 4 // For CpObj code generation, this is the the threshold of the number
243 // of contiguous non-gc slots that trigger generating rep movsq instead of
244 // sequences of movsq instructions
245 // The way we're currently disabling rep movs/stos is by setting a limit less than
246 // its unrolling counterparts. When lower takes the decision on which one to make it
247 // always asks for the unrolling limit first so you can say the JIT 'favors' unrolling.
248 // Setting the limit to something lower than that makes lower to never consider it.
251 #define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned
252 #endif // FEATURE_SIMD
254 #define FEATURE_FIXED_OUT_ARGS 0 // X86 uses push instructions to pass args
255 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
256 #define FEATURE_MULTIREG_STRUCT_PROMOTE 0 // True when we want to promote fields of a multireg struct into registers
257 #define FEATURE_FASTTAILCALL 0 // Tail calls made as epilog+jmp
258 #define FEATURE_TAILCALL_OPT 0 // opportunistic Tail calls (without ".tail" prefix) made as fast tail calls.
259 #define FEATURE_SET_FLAGS 0 // Set to true to force the JIT to mark the trees with GTF_SET_FLAGS when
260 // the flags need to be set
261 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
262 #define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register
263 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
264 #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments (note this seems wrong as MAX_ARG_REG_COUNT is 2)
265 #define MAX_RET_MULTIREG_BYTES 8 // Maximum size of a struct that could be returned in more than one register
267 #define MAX_ARG_REG_COUNT 2 // Maximum registers used to pass an argument.
268 #define MAX_RET_REG_COUNT 2 // Maximum registers used to return a value.
270 #ifdef FEATURE_USE_ASM_GC_WRITE_BARRIERS
271 #define NOGC_WRITE_BARRIERS 1 // We have specialized WriteBarrier JIT Helpers that DO-NOT trash the
272 // RBM_CALLEE_TRASH registers
274 #define NOGC_WRITE_BARRIERS 0 // Do not modify this -- modify the definition above. (If we're not using
275 // ASM barriers we definitely don't have NOGC barriers).
277 #define USER_ARGS_COME_LAST 0
278 #define EMIT_TRACK_STACK_DEPTH 1
279 #define TARGET_POINTER_SIZE 4 // equal to sizeof(void*) and the managed pointer size in bytes for this
281 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter,
282 // filter-handler, fault) and directly execute 'finally' clauses.
284 #if defined(FEATURE_PAL)
285 #define FEATURE_EH_FUNCLETS 1
286 #else // !FEATURE_PAL
287 #define FEATURE_EH_FUNCLETS 0
288 #endif // !FEATURE_PAL
290 #define FEATURE_EH_CALLFINALLY_THUNKS 0 // Generate call-to-finally code in "thunks" in the enclosing EH region,
291 // protected by "cloned finally" clauses.
292 #define ETW_EBP_FRAMED 1 // if 1 we cannot use EBP as a scratch register and must create EBP based
293 // frames for most methods
294 #define CSE_CONSTS 1 // Enable if we want to CSE constants
296 // The following defines are useful for iterating a regNumber
297 #define REG_FIRST REG_EAX
298 #define REG_INT_FIRST REG_EAX
299 #define REG_INT_LAST REG_EDI
300 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
301 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
302 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
304 #define REG_FP_FIRST REG_XMM0
305 #define REG_FP_LAST REG_XMM7
306 #define FIRST_FP_ARGREG REG_XMM0
307 #define LAST_FP_ARGREG REG_XMM3
308 #define REG_FLTARG_0 REG_XMM0
309 #define REG_FLTARG_1 REG_XMM1
310 #define REG_FLTARG_2 REG_XMM2
311 #define REG_FLTARG_3 REG_XMM3
313 #define RBM_FLTARG_0 RBM_XMM0
314 #define RBM_FLTARG_1 RBM_XMM1
315 #define RBM_FLTARG_2 RBM_XMM2
316 #define RBM_FLTARG_3 RBM_XMM3
318 #define RBM_FLTARG_REGS (RBM_FLTARG_0|RBM_FLTARG_1|RBM_FLTARG_2|RBM_FLTARG_3)
320 #define RBM_ALLFLOAT (RBM_XMM0 | RBM_XMM1 | RBM_XMM2 | RBM_XMM3 | RBM_XMM4 | RBM_XMM5 | RBM_XMM6 | RBM_XMM7)
321 #define RBM_ALLDOUBLE RBM_ALLFLOAT
323 // TODO-CQ: Currently we are following the x86 ABI for SSE2 registers.
324 // This should be reconsidered.
325 #define RBM_FLT_CALLEE_SAVED RBM_NONE
326 #define RBM_FLT_CALLEE_TRASH RBM_ALLFLOAT
327 #define REG_VAR_ORDER_FLT REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3, REG_XMM4, REG_XMM5, REG_XMM6, REG_XMM7
329 #define REG_FLT_CALLEE_SAVED_FIRST REG_XMM6
330 #define REG_FLT_CALLEE_SAVED_LAST REG_XMM7
332 #define XMM_REGSIZE_BYTES 16 // XMM register size in bytes
333 #define YMM_REGSIZE_BYTES 32 // YMM register size in bytes
335 #define REGNUM_BITS 6 // number of bits in a REG_*
337 #define REGSIZE_BYTES 4 // number of bytes in one register
338 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
340 #define CODE_ALIGN 1 // code alignment requirement
341 #if !defined(UNIX_X86_ABI)
342 #define STACK_ALIGN 4 // stack alignment requirement
343 #define STACK_ALIGN_SHIFT 2 // Shift-right amount to convert size in bytes to size in STACK_ALIGN units == log2(STACK_ALIGN)
345 #define STACK_ALIGN 16 // stack alignment requirement
346 #define STACK_ALIGN_SHIFT 4 // Shift-right amount to convert size in bytes to size in STACK_ALIGN units == log2(STACK_ALIGN)
347 #endif // !UNIX_X86_ABI
349 #define RBM_INT_CALLEE_SAVED (RBM_EBX|RBM_ESI|RBM_EDI)
350 #define RBM_INT_CALLEE_TRASH (RBM_EAX|RBM_ECX|RBM_EDX)
352 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
353 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
355 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
357 #define REG_VAR_ORDER REG_EAX,REG_EDX,REG_ECX,REG_ESI,REG_EDI,REG_EBX
358 #define MAX_VAR_ORDER_SIZE 6
360 // The order here is fixed: it must agree with an order assumed in eetwain...
361 #define REG_CALLEE_SAVED_ORDER REG_EDI,REG_ESI,REG_EBX,REG_EBP
362 #define RBM_CALLEE_SAVED_ORDER RBM_EDI,RBM_ESI,RBM_EBX,RBM_EBP
364 #define CNT_CALLEE_SAVED (4)
365 #define CNT_CALLEE_TRASH (3)
366 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
368 #define CNT_CALLEE_SAVED_FLOAT (0)
369 #define CNT_CALLEE_TRASH_FLOAT (6)
371 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED*REGSIZE_BYTES) // EBX,ESI,EDI,EBP
373 #define REG_TMP_0 REG_EAX
375 #define REG_LNGARG_LO REG_EAX
376 #define RBM_LNGARG_LO RBM_EAX
377 #define REG_LNGARG_HI REG_EDX
378 #define RBM_LNGARG_HI RBM_EDX
379 // register to hold shift amount
380 #define REG_SHIFT REG_ECX
381 #define RBM_SHIFT RBM_ECX
383 // register to hold shift amount when shifting 64-bit values
384 #define REG_SHIFT_LNG REG_ECX
385 #define RBM_SHIFT_LNG RBM_ECX
387 // This is a general scratch register that does not conflict with the argument registers
388 #define REG_SCRATCH REG_EAX
390 // Where is the exception object on entry to the handler block?
391 #define REG_EXCEPTION_OBJECT REG_EAX
392 #define RBM_EXCEPTION_OBJECT RBM_EAX
394 // Only used on ARM for GTF_CALL_M_VIRTSTUB_REL_INDIRECT
395 #define REG_JUMP_THUNK_PARAM REG_EAX
396 #define RBM_JUMP_THUNK_PARAM RBM_EAX
398 #if NOGC_WRITE_BARRIERS
399 #define REG_WRITE_BARRIER REG_EDX
400 #define RBM_WRITE_BARRIER RBM_EDX
402 // We don't allow using ebp as a source register. Maybe we should only prevent this for ETW_EBP_FRAMED (but that is always set right now).
403 #define RBM_WRITE_BARRIER_SRC (RBM_EAX|RBM_ECX|RBM_EBX|RBM_ESI|RBM_EDI)
405 #define RBM_CALLEE_TRASH_NOGC RBM_EDX
406 #endif // NOGC_WRITE_BARRIERS
408 // GenericPInvokeCalliHelper unmanaged target parameter
409 #define REG_PINVOKE_TARGET_PARAM REG_EAX
410 #define RBM_PINVOKE_TARGET_PARAM RBM_EAX
412 // GenericPInvokeCalliHelper cookie parameter
413 #define REG_PINVOKE_COOKIE_PARAM REG_STK
415 // IL stub's secret parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
416 #define REG_SECRET_STUB_PARAM REG_EAX
417 #define RBM_SECRET_STUB_PARAM RBM_EAX
419 // VSD target address register
420 #define REG_VIRTUAL_STUB_TARGET REG_EAX
421 #define RBM_VIRTUAL_STUB_TARGET RBM_EAX
423 // Registers used by PInvoke frame setup
424 #define REG_PINVOKE_FRAME REG_EDI // EDI is p/invoke "Frame" pointer argument to CORINFO_HELP_INIT_PINVOKE_FRAME helper
425 #define RBM_PINVOKE_FRAME RBM_EDI
426 #define REG_PINVOKE_TCB REG_ESI // ESI is set to Thread Control Block (TCB) on return from
427 // CORINFO_HELP_INIT_PINVOKE_FRAME helper
428 #define RBM_PINVOKE_TCB RBM_ESI
429 #define REG_PINVOKE_SCRATCH REG_EAX // EAX is trashed by CORINFO_HELP_INIT_PINVOKE_FRAME helper
430 #define RBM_PINVOKE_SCRATCH RBM_EAX
432 // The following defines are useful for iterating a regNumber
433 #define REG_FIRST REG_EAX
434 #define REG_INT_FIRST REG_EAX
435 #define REG_INT_LAST REG_EDI
436 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
437 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
438 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
440 // Which register are int and long values returned in ?
441 #define REG_INTRET REG_EAX
442 #define RBM_INTRET RBM_EAX
443 #define RBM_LNGRET (RBM_EDX|RBM_EAX)
444 #define REG_LNGRET_LO REG_EAX
445 #define RBM_LNGRET_LO RBM_EAX
446 #define REG_LNGRET_HI REG_EDX
447 #define RBM_LNGRET_HI RBM_EDX
449 #define REG_FLOATRET REG_NA
450 #define RBM_FLOATRET RBM_NONE
451 #define RBM_DOUBLERET RBM_NONE
453 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper
454 #define RBM_STOP_FOR_GC_TRASH RBM_CALLEE_TRASH
456 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper. On x86, this helper has a custom calling
457 // convention that takes EDI as argument (but doesn't trash it), trashes EAX, and returns ESI.
458 #define RBM_INIT_PINVOKE_FRAME_TRASH (RBM_PINVOKE_SCRATCH | RBM_PINVOKE_TCB)
460 #define REG_FPBASE REG_EBP
461 #define RBM_FPBASE RBM_EBP
462 #define STR_FPBASE "ebp"
463 #define REG_SPBASE REG_ESP
464 #define RBM_SPBASE RBM_ESP
465 #define STR_SPBASE "esp"
467 #define FIRST_ARG_STACK_OFFS (2*REGSIZE_BYTES) // Caller's saved EBP and return address
469 #define MAX_REG_ARG 2
470 #define MAX_FLOAT_REG_ARG 0
471 #define REG_ARG_FIRST REG_ECX
472 #define REG_ARG_LAST REG_EDX
473 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
475 #define REG_ARG_0 REG_ECX
476 #define REG_ARG_1 REG_EDX
478 SELECTANY const regNumber intArgRegs [] = {REG_ECX, REG_EDX};
479 SELECTANY const regMaskTP intArgMasks[] = {RBM_ECX, RBM_EDX};
480 SELECTANY const regNumber fltArgRegs [] = {REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3};
481 SELECTANY const regMaskTP fltArgMasks[] = {RBM_XMM0, RBM_XMM1, RBM_XMM2, RBM_XMM3};
483 #define RBM_ARG_0 RBM_ECX
484 #define RBM_ARG_1 RBM_EDX
486 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1)
488 // The registers trashed by profiler enter/leave/tailcall hook
489 // See vm\i386\asmhelpers.asm for more details.
490 #define RBM_PROFILER_ENTER_TRASH RBM_NONE
491 #define RBM_PROFILER_LEAVE_TRASH RBM_NONE
492 #define RBM_PROFILER_TAILCALL_TRASH (RBM_ALLINT & ~RBM_ARG_REGS)
494 // What sort of reloc do we use for [disp32] address mode
495 #define IMAGE_REL_BASED_DISP32 IMAGE_REL_BASED_HIGHLOW
497 // What sort of reloc to we use for 'moffset' address mode (for 'mov eax, moffset' or 'mov moffset, eax')
498 #define IMAGE_REL_BASED_MOFFSET IMAGE_REL_BASED_HIGHLOW
500 // Pointer-sized string move instructions
501 #define INS_movsp INS_movsd
502 #define INS_r_movsp INS_r_movsd
503 #define INS_stosp INS_stosd
504 #define INS_r_stosp INS_r_stosd
506 #elif defined(_TARGET_AMD64_)
507 // TODO-AMD64-CQ: Fine tune the following xxBlk threshold values:
509 #define CPU_LOAD_STORE_ARCH 0
510 #define CPU_HAS_FP_SUPPORT 1
511 #define ROUND_FLOAT 0 // Do not round intermed float expression results
512 #define CPU_HAS_BYTE_REGS 0
514 #define CPBLK_MOVS_LIMIT 16 // When generating code for CpBlk, this is the buffer size
515 // threshold to stop generating rep movs and switch to the helper call.
516 // NOTE: Using rep movs is currently disabled since we found it has bad performance
517 // on pre-Ivy Bridge hardware.
519 #define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk.
520 #define INITBLK_STOS_LIMIT 64 // When generating code for InitBlk, this is the buffer size
521 // NOTE: Using rep stos is currently disabled since we found it has bad performance
522 // on pre-Ivy Bridge hardware.
523 // threshold to stop generating rep movs and switch to the helper call.
524 #define INITBLK_UNROLL_LIMIT 128 // Upper bound to let the code generator to loop unroll InitBlk.
525 #define CPOBJ_NONGC_SLOTS_LIMIT 4 // For CpObj code generation, this is the the threshold of the number
526 // of contiguous non-gc slots that trigger generating rep movsq instead of
527 // sequences of movsq instructions
529 // The way we're currently disabling rep movs/stos is by setting a limit less than
530 // its unrolling counterparts. When lower takes the decision on which one to make it
531 // always asks for the unrolling limit first so you can say the JIT 'favors' unrolling.
532 // Setting the limit to something lower than that makes lower to never consider it.
536 #define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned
537 #if defined(UNIX_AMD64_ABI)
538 #define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 0 // Whether SIMD registers are partially saved at calls
539 #else // !UNIX_AMD64_ABI
540 #define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 1 // Whether SIMD registers are partially saved at calls
541 #endif // !UNIX_AMD64_ABI
543 #define FEATURE_FIXED_OUT_ARGS 1 // Preallocate the outgoing arg area in the prolog
544 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
545 #define FEATURE_MULTIREG_STRUCT_PROMOTE 0 // True when we want to promote fields of a multireg struct into registers
546 #define FEATURE_FASTTAILCALL 1 // Tail calls made as epilog+jmp
547 #define FEATURE_TAILCALL_OPT 1 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
548 #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
549 #ifdef UNIX_AMD64_ABI
550 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
551 #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register
552 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
553 #define FEATURE_STRUCT_CLASSIFIER 1 // Uses a classifier function to determine if structs are passed/returned in more than one register
554 #define MAX_PASS_MULTIREG_BYTES 32 // Maximum size of a struct that could be passed in more than one register (Max is two SIMD16s)
555 #define MAX_RET_MULTIREG_BYTES 32 // Maximum size of a struct that could be returned in more than one register (Max is two SIMD16s)
556 #define MAX_ARG_REG_COUNT 2 // Maximum registers used to pass a single argument in multiple registers.
557 #define MAX_RET_REG_COUNT 2 // Maximum registers used to return a value.
558 #else // !UNIX_AMD64_ABI
559 #define WINDOWS_AMD64_ABI // Uses the Windows ABI for AMD64
560 #define FEATURE_MULTIREG_ARGS_OR_RET 0 // Support for passing and/or returning single values in more than one register
561 #define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register
562 #define FEATURE_MULTIREG_RET 0 // Support for returning a single value in more than one register
563 #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments
564 #define MAX_RET_MULTIREG_BYTES 0 // No multireg return values
565 #define MAX_ARG_REG_COUNT 1 // Maximum registers used to pass a single argument (no arguments are passed using multiple registers)
566 #define MAX_RET_REG_COUNT 1 // Maximum registers used to return a value.
567 #endif // !UNIX_AMD64_ABI
569 #define NOGC_WRITE_BARRIERS 0 // We DO-NOT have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers
570 #define USER_ARGS_COME_LAST 1
571 #define EMIT_TRACK_STACK_DEPTH 1
572 #define TARGET_POINTER_SIZE 8 // equal to sizeof(void*) and the managed pointer size in bytes for this target
573 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter, filter-handler, fault) and directly execute 'finally' clauses.
574 #define FEATURE_EH_FUNCLETS 1
575 #define FEATURE_EH_CALLFINALLY_THUNKS 1 // Generate call-to-finally code in "thunks" in the enclosing EH region, protected by "cloned finally" clauses.
576 #ifdef UNIX_AMD64_ABI
577 #define ETW_EBP_FRAMED 1 // if 1 we cannot use EBP as a scratch register and must create EBP based frames for most methods
578 #else // !UNIX_AMD64_ABI
579 #define ETW_EBP_FRAMED 0 // if 1 we cannot use EBP as a scratch register and must create EBP based frames for most methods
580 #endif // !UNIX_AMD64_ABI
581 #define CSE_CONSTS 1 // Enable if we want to CSE constants
583 #define RBM_ALLFLOAT (RBM_XMM0 | RBM_XMM1 | RBM_XMM2 | RBM_XMM3 | RBM_XMM4 | RBM_XMM5 | RBM_XMM6 | RBM_XMM7 | RBM_XMM8 | RBM_XMM9 | RBM_XMM10 | RBM_XMM11 | RBM_XMM12 | RBM_XMM13 | RBM_XMM14 | RBM_XMM15)
584 #define RBM_ALLDOUBLE RBM_ALLFLOAT
585 #define REG_FP_FIRST REG_XMM0
586 #define REG_FP_LAST REG_XMM15
587 #define FIRST_FP_ARGREG REG_XMM0
589 #ifdef UNIX_AMD64_ABI
590 #define LAST_FP_ARGREG REG_XMM7
591 #else // !UNIX_AMD64_ABI
592 #define LAST_FP_ARGREG REG_XMM3
593 #endif // !UNIX_AMD64_ABI
595 #define REGNUM_BITS 6 // number of bits in a REG_*
596 #define REGMASK_BITS 32 // number of bits in a REGNUM_MASK
597 #define REGSIZE_BYTES 8 // number of bytes in one register
598 #define XMM_REGSIZE_BYTES 16 // XMM register size in bytes
599 #define YMM_REGSIZE_BYTES 32 // YMM register size in bytes
601 #define CODE_ALIGN 1 // code alignment requirement
602 #define STACK_ALIGN 16 // stack alignment requirement
603 #define STACK_ALIGN_SHIFT 4 // Shift-right amount to convert size in bytes to size in STACK_ALIGN units == log2(STACK_ALIGN)
606 #define RBM_ETW_FRAMED_EBP RBM_NONE
607 #define RBM_ETW_FRAMED_EBP_LIST
608 #define REG_ETW_FRAMED_EBP_LIST
609 #define REG_ETW_FRAMED_EBP_COUNT 0
610 #else // !ETW_EBP_FRAMED
611 #define RBM_ETW_FRAMED_EBP RBM_EBP
612 #define RBM_ETW_FRAMED_EBP_LIST RBM_EBP,
613 #define REG_ETW_FRAMED_EBP_LIST REG_EBP,
614 #define REG_ETW_FRAMED_EBP_COUNT 1
615 #endif // !ETW_EBP_FRAMED
617 #ifdef UNIX_AMD64_ABI
618 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
620 #define RBM_INT_CALLEE_SAVED (RBM_EBX|RBM_ETW_FRAMED_EBP|RBM_R12|RBM_R13|RBM_R14|RBM_R15)
621 #define RBM_INT_CALLEE_TRASH (RBM_EAX|RBM_RDI|RBM_RSI|RBM_EDX|RBM_ECX|RBM_R8|RBM_R9|RBM_R10|RBM_R11)
622 #define RBM_FLT_CALLEE_SAVED (0)
623 #define RBM_FLT_CALLEE_TRASH (RBM_XMM0|RBM_XMM1|RBM_XMM2|RBM_XMM3|RBM_XMM4|RBM_XMM5|RBM_XMM6|RBM_XMM7| \
624 RBM_XMM8|RBM_XMM9|RBM_XMM10|RBM_XMM11|RBM_XMM12|RBM_XMM13|RBM_XMM14|RBM_XMM15)
625 #define REG_PROFILER_ENTER_ARG_0 REG_R14
626 #define RBM_PROFILER_ENTER_ARG_0 RBM_R14
627 #define REG_PROFILER_ENTER_ARG_1 REG_R15
628 #define RBM_PROFILER_ENTER_ARG_1 RBM_R15
630 #define REG_DEFAULT_PROFILER_CALL_TARGET REG_R11
632 #else // !UNIX_AMD64_ABI
633 #define MIN_ARG_AREA_FOR_CALL (4 * REGSIZE_BYTES) // Minimum required outgoing argument space for a call.
635 #define RBM_INT_CALLEE_SAVED (RBM_EBX|RBM_ESI|RBM_EDI|RBM_ETW_FRAMED_EBP|RBM_R12|RBM_R13|RBM_R14|RBM_R15)
636 #define RBM_INT_CALLEE_TRASH (RBM_EAX|RBM_ECX|RBM_EDX|RBM_R8|RBM_R9|RBM_R10|RBM_R11)
637 #define RBM_FLT_CALLEE_SAVED (RBM_XMM6|RBM_XMM7|RBM_XMM8|RBM_XMM9|RBM_XMM10|RBM_XMM11|RBM_XMM12|RBM_XMM13|RBM_XMM14|RBM_XMM15)
638 #define RBM_FLT_CALLEE_TRASH (RBM_XMM0|RBM_XMM1|RBM_XMM2|RBM_XMM3|RBM_XMM4|RBM_XMM5)
639 #endif // !UNIX_AMD64_ABI
641 #define REG_FLT_CALLEE_SAVED_FIRST REG_XMM6
642 #define REG_FLT_CALLEE_SAVED_LAST REG_XMM15
644 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
645 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
647 #define RBM_CALLEE_TRASH_NOGC RBM_CALLEE_TRASH
649 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
652 #define REG_VAR_ORDER REG_EAX,REG_EDX,REG_ECX,REG_ESI,REG_EDI,REG_EBX,REG_ETW_FRAMED_EBP_LIST \
653 REG_R8,REG_R9,REG_R10,REG_R11,REG_R14,REG_R15,REG_R12,REG_R13
655 // TEMPORARY ORDER TO AVOID CALLEE-SAVES
656 // TODO-CQ: Review this and set appropriately
657 #ifdef UNIX_AMD64_ABI
658 #define REG_VAR_ORDER REG_EAX,REG_EDI,REG_ESI, \
659 REG_EDX,REG_ECX,REG_R8,REG_R9, \
660 REG_R10,REG_R11,REG_EBX,REG_ETW_FRAMED_EBP_LIST \
661 REG_R14,REG_R15,REG_R12,REG_R13
662 #else // !UNIX_AMD64_ABI
663 #define REG_VAR_ORDER REG_EAX,REG_EDX,REG_ECX, \
664 REG_R8,REG_R9,REG_R10,REG_R11, \
665 REG_ESI,REG_EDI,REG_EBX,REG_ETW_FRAMED_EBP_LIST \
666 REG_R14,REG_R15,REG_R12,REG_R13
667 #endif // !UNIX_AMD64_ABI
670 #define REG_VAR_ORDER_FLT REG_XMM0,REG_XMM1,REG_XMM2,REG_XMM3,REG_XMM4,REG_XMM5,REG_XMM6,REG_XMM7,REG_XMM8,REG_XMM9,REG_XMM10,REG_XMM11,REG_XMM12,REG_XMM13,REG_XMM14,REG_XMM15
672 #ifdef UNIX_AMD64_ABI
673 #define CNT_CALLEE_SAVED (5 + REG_ETW_FRAMED_EBP_COUNT)
674 #define CNT_CALLEE_TRASH (9)
675 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED)
677 #define CNT_CALLEE_SAVED_FLOAT (0)
678 #define CNT_CALLEE_TRASH_FLOAT (16)
680 #define REG_CALLEE_SAVED_ORDER REG_EBX,REG_ETW_FRAMED_EBP_LIST REG_R12,REG_R13,REG_R14,REG_R15
681 #define RBM_CALLEE_SAVED_ORDER RBM_EBX,RBM_ETW_FRAMED_EBP_LIST RBM_R12,RBM_R13,RBM_R14,RBM_R15
682 #else // !UNIX_AMD64_ABI
683 #define CNT_CALLEE_SAVED (7 + REG_ETW_FRAMED_EBP_COUNT)
684 #define CNT_CALLEE_TRASH (7)
685 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED)
687 #define CNT_CALLEE_SAVED_FLOAT (10)
688 #define CNT_CALLEE_TRASH_FLOAT (6)
690 #define REG_CALLEE_SAVED_ORDER REG_EBX,REG_ESI,REG_EDI,REG_ETW_FRAMED_EBP_LIST REG_R12,REG_R13,REG_R14,REG_R15
691 #define RBM_CALLEE_SAVED_ORDER RBM_EBX,RBM_ESI,RBM_EDI,RBM_ETW_FRAMED_EBP_LIST RBM_R12,RBM_R13,RBM_R14,RBM_R15
692 #endif // !UNIX_AMD64_ABI
694 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED*REGSIZE_BYTES)
695 #define CALLEE_SAVED_FLOAT_MAXSZ (CNT_CALLEE_SAVED_FLOAT*16)
697 #define REG_TMP_0 REG_EAX
699 // register to hold shift amount
700 #define REG_SHIFT REG_ECX
701 #define RBM_SHIFT RBM_ECX
703 // This is a general scratch register that does not conflict with the argument registers
704 #define REG_SCRATCH REG_EAX
706 // Where is the exception object on entry to the handler block?
707 #ifdef UNIX_AMD64_ABI
708 #define REG_EXCEPTION_OBJECT REG_ESI
709 #define RBM_EXCEPTION_OBJECT RBM_ESI
710 #else // !UNIX_AMD64_ABI
711 #define REG_EXCEPTION_OBJECT REG_EDX
712 #define RBM_EXCEPTION_OBJECT RBM_EDX
713 #endif // !UNIX_AMD64_ABI
715 #define REG_JUMP_THUNK_PARAM REG_EAX
716 #define RBM_JUMP_THUNK_PARAM RBM_EAX
718 // Register to be used for emitting helper calls whose call target is an indir of an
719 // absolute memory address in case of Rel32 overflow i.e. a data address could not be
720 // encoded as PC-relative 32-bit offset.
723 // 1) that RAX is callee trash register that is not used for passing parameter and
724 // also results in smaller instruction encoding.
725 // 2) Profiler Leave callback requires the return value to be preserved
726 // in some form. We can use custom calling convention for Leave callback.
727 // For e.g return value could be preserved in rcx so that it is available for
729 #define REG_DEFAULT_HELPER_CALL_TARGET REG_RAX
730 #define RBM_DEFAULT_HELPER_CALL_TARGET RBM_RAX
732 // GenericPInvokeCalliHelper VASigCookie Parameter
733 #define REG_PINVOKE_COOKIE_PARAM REG_R11
734 #define RBM_PINVOKE_COOKIE_PARAM RBM_R11
736 // GenericPInvokeCalliHelper unmanaged target Parameter
737 #define REG_PINVOKE_TARGET_PARAM REG_R10
738 #define RBM_PINVOKE_TARGET_PARAM RBM_R10
740 // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
741 #define REG_SECRET_STUB_PARAM REG_R10
742 #define RBM_SECRET_STUB_PARAM RBM_R10
744 // Registers used by PInvoke frame setup
745 #define REG_PINVOKE_FRAME REG_EDI
746 #define RBM_PINVOKE_FRAME RBM_EDI
747 #define REG_PINVOKE_TCB REG_EAX
748 #define RBM_PINVOKE_TCB RBM_EAX
749 #define REG_PINVOKE_SCRATCH REG_EAX
750 #define RBM_PINVOKE_SCRATCH RBM_EAX
752 // The following defines are useful for iterating a regNumber
753 #define REG_FIRST REG_EAX
754 #define REG_INT_FIRST REG_EAX
755 #define REG_INT_LAST REG_R15
756 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
757 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
758 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
760 // Which register are int and long values returned in ?
761 #define REG_INTRET REG_EAX
762 #define RBM_INTRET RBM_EAX
764 #define RBM_LNGRET RBM_EAX
766 #ifdef UNIX_AMD64_ABI
767 #define REG_INTRET_1 REG_RDX
768 #define RBM_INTRET_1 RBM_RDX
770 #define REG_LNGRET_1 REG_RDX
771 #define RBM_LNGRET_1 RBM_RDX
772 #endif // UNIX_AMD64_ABI
775 #define REG_FLOATRET REG_XMM0
776 #define RBM_FLOATRET RBM_XMM0
777 #define REG_DOUBLERET REG_XMM0
778 #define RBM_DOUBLERET RBM_XMM0
780 #ifdef UNIX_AMD64_ABI
781 #define REG_FLOATRET_1 REG_XMM1
782 #define RBM_FLOATRET_1 RBM_XMM1
784 #define REG_DOUBLERET_1 REG_XMM1
785 #define RBM_DOUBLERET_1 RBM_XMM1
786 #endif // UNIX_AMD64_ABI
788 #define REG_FPBASE REG_EBP
789 #define RBM_FPBASE RBM_EBP
790 #define STR_FPBASE "rbp"
791 #define REG_SPBASE REG_ESP
792 #define RBM_SPBASE RBM_ESP
793 #define STR_SPBASE "rsp"
795 #define FIRST_ARG_STACK_OFFS (REGSIZE_BYTES) // return address
797 #ifdef UNIX_AMD64_ABI
798 #define MAX_REG_ARG 6
799 #define MAX_FLOAT_REG_ARG 8
800 #define REG_ARG_FIRST REG_EDI
801 #define REG_ARG_LAST REG_R9
802 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
804 #define REG_ARG_0 REG_EDI
805 #define REG_ARG_1 REG_ESI
806 #define REG_ARG_2 REG_EDX
807 #define REG_ARG_3 REG_ECX
808 #define REG_ARG_4 REG_R8
809 #define REG_ARG_5 REG_R9
811 SELECTANY const regNumber intArgRegs [] = { REG_EDI, REG_ESI, REG_EDX, REG_ECX, REG_R8, REG_R9 };
812 SELECTANY const regMaskTP intArgMasks[] = { RBM_EDI, RBM_ESI, RBM_EDX, RBM_ECX, RBM_R8, RBM_R9 };
813 SELECTANY const regNumber fltArgRegs [] = { REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3, REG_XMM4, REG_XMM5, REG_XMM6, REG_XMM7 };
814 SELECTANY const regMaskTP fltArgMasks[] = { RBM_XMM0, RBM_XMM1, RBM_XMM2, RBM_XMM3, RBM_XMM4, RBM_XMM5, RBM_XMM6, RBM_XMM7 };
816 #define RBM_ARG_0 RBM_RDI
817 #define RBM_ARG_1 RBM_RSI
818 #define RBM_ARG_2 RBM_EDX
819 #define RBM_ARG_3 RBM_ECX
820 #define RBM_ARG_4 RBM_R8
821 #define RBM_ARG_5 RBM_R9
822 #else // !UNIX_AMD64_ABI
823 #define MAX_REG_ARG 4
824 #define MAX_FLOAT_REG_ARG 4
825 #define REG_ARG_FIRST REG_ECX
826 #define REG_ARG_LAST REG_R9
827 #define INIT_ARG_STACK_SLOT 4 // 4 outgoing reserved stack slots
829 #define REG_ARG_0 REG_ECX
830 #define REG_ARG_1 REG_EDX
831 #define REG_ARG_2 REG_R8
832 #define REG_ARG_3 REG_R9
834 SELECTANY const regNumber intArgRegs [] = { REG_ECX, REG_EDX, REG_R8, REG_R9 };
835 SELECTANY const regMaskTP intArgMasks[] = { RBM_ECX, RBM_EDX, RBM_R8, RBM_R9 };
836 SELECTANY const regNumber fltArgRegs [] = { REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3 };
837 SELECTANY const regMaskTP fltArgMasks[] = { RBM_XMM0, RBM_XMM1, RBM_XMM2, RBM_XMM3 };
839 #define RBM_ARG_0 RBM_ECX
840 #define RBM_ARG_1 RBM_EDX
841 #define RBM_ARG_2 RBM_R8
842 #define RBM_ARG_3 RBM_R9
843 #endif // !UNIX_AMD64_ABI
845 #define REG_FLTARG_0 REG_XMM0
846 #define REG_FLTARG_1 REG_XMM1
847 #define REG_FLTARG_2 REG_XMM2
848 #define REG_FLTARG_3 REG_XMM3
850 #define RBM_FLTARG_0 RBM_XMM0
851 #define RBM_FLTARG_1 RBM_XMM1
852 #define RBM_FLTARG_2 RBM_XMM2
853 #define RBM_FLTARG_3 RBM_XMM3
855 #ifdef UNIX_AMD64_ABI
856 #define REG_FLTARG_4 REG_XMM4
857 #define REG_FLTARG_5 REG_XMM5
858 #define REG_FLTARG_6 REG_XMM6
859 #define REG_FLTARG_7 REG_XMM7
861 #define RBM_FLTARG_4 RBM_XMM4
862 #define RBM_FLTARG_5 RBM_XMM5
863 #define RBM_FLTARG_6 RBM_XMM6
864 #define RBM_FLTARG_7 RBM_XMM7
866 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1|RBM_ARG_2|RBM_ARG_3|RBM_ARG_4|RBM_ARG_5)
867 #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)
868 #else // !UNIX_AMD64_ABI
869 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1|RBM_ARG_2|RBM_ARG_3)
870 #define RBM_FLTARG_REGS (RBM_FLTARG_0|RBM_FLTARG_1|RBM_FLTARG_2|RBM_FLTARG_3)
871 #endif // !UNIX_AMD64_ABI
873 // The registers trashed by profiler enter/leave/tailcall hook
874 // See vm\amd64\asmhelpers.asm for more details.
875 #define RBM_PROFILER_ENTER_TRASH RBM_CALLEE_TRASH
876 #define RBM_PROFILER_LEAVE_TRASH (RBM_CALLEE_TRASH & ~(RBM_FLOATRET | RBM_INTRET))
877 #define RBM_PROFILER_TAILCALL_TRASH RBM_PROFILER_LEAVE_TRASH
879 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper.
880 #ifdef UNIX_AMD64_ABI
881 // See vm\amd64\unixasmhelpers.S for more details.
883 // On Unix a struct of size >=9 and <=16 bytes in size is returned in two return registers.
884 // The return registers could be any two from the set { RAX, RDX, XMM0, XMM1 }.
885 // STOP_FOR_GC helper preserves all the 4 possible return registers.
886 #define RBM_STOP_FOR_GC_TRASH (RBM_CALLEE_TRASH & ~(RBM_FLOATRET | RBM_INTRET | RBM_FLOATRET_1 | RBM_INTRET_1))
888 // See vm\amd64\asmhelpers.asm for more details.
889 #define RBM_STOP_FOR_GC_TRASH (RBM_CALLEE_TRASH & ~(RBM_FLOATRET | RBM_INTRET))
892 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper.
893 #define RBM_INIT_PINVOKE_FRAME_TRASH RBM_CALLEE_TRASH
895 // What sort of reloc do we use for [disp32] address mode
896 #define IMAGE_REL_BASED_DISP32 IMAGE_REL_BASED_REL32
898 // What sort of reloc to we use for 'moffset' address mode (for 'mov eax, moffset' or 'mov moffset, eax')
899 #define IMAGE_REL_BASED_MOFFSET IMAGE_REL_BASED_DIR64
901 // Pointer-sized string move instructions
902 #define INS_movsp INS_movsq
903 #define INS_r_movsp INS_r_movsq
904 #define INS_stosp INS_stosq
905 #define INS_r_stosp INS_r_stosq
907 #elif defined(_TARGET_ARM_)
909 // TODO-ARM-CQ: Use shift for division by power of 2
910 // TODO-ARM-CQ: Check for sdiv/udiv at runtime and generate it if available
911 #define USE_HELPERS_FOR_INT_DIV 1 // BeagleBoard (ARMv7A) doesn't support SDIV/UDIV
912 #define CPU_LOAD_STORE_ARCH 1
913 #define CPU_HAS_FP_SUPPORT 1
914 #define ROUND_FLOAT 0 // Do not round intermed float expression results
915 #define CPU_HAS_BYTE_REGS 0
917 #define CPBLK_UNROLL_LIMIT 32 // Upper bound to let the code generator to loop unroll CpBlk.
918 #define INITBLK_UNROLL_LIMIT 32 // Upper bound to let the code generator to loop unroll InitBlk.
920 #define FEATURE_FIXED_OUT_ARGS 1 // Preallocate the outgoing arg area in the prolog
921 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
922 #define FEATURE_MULTIREG_STRUCT_PROMOTE 0 // True when we want to promote fields of a multireg struct into registers
923 #define FEATURE_FASTTAILCALL 0 // Tail calls made as epilog+jmp
924 #define FEATURE_TAILCALL_OPT 0 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
925 #define FEATURE_SET_FLAGS 1 // Set to true to force the JIT to mark the trees with GTF_SET_FLAGS when the flags need to be set
926 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register (including HFA support)
927 #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register (including passing HFAs)
928 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register (including HFA returns)
929 #define FEATURE_STRUCT_CLASSIFIER 0 // Uses a classifier function to determine is structs are passed/returned in more than one register
930 #define MAX_PASS_MULTIREG_BYTES 32 // Maximum size of a struct that could be passed in more than one register (Max is an HFA of 4 doubles)
931 #define MAX_RET_MULTIREG_BYTES 32 // Maximum size of a struct that could be returned in more than one register (Max is an HFA of 4 doubles)
932 #define MAX_ARG_REG_COUNT 4 // Maximum registers used to pass a single argument in multiple registers. (max is 4 floats or doubles using an HFA)
933 #define MAX_RET_REG_COUNT 4 // Maximum registers used to return a value.
935 #define NOGC_WRITE_BARRIERS 0 // We DO-NOT have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers
936 #define USER_ARGS_COME_LAST 1
937 #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
938 // need to track stack depth, but this is currently necessary to get GC information reported at call sites.
939 #define TARGET_POINTER_SIZE 4 // equal to sizeof(void*) and the managed pointer size in bytes for this target
940 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter, filter-handler, fault) and directly execute 'finally' clauses.
941 #define FEATURE_EH_FUNCLETS 1
942 #define FEATURE_EH_CALLFINALLY_THUNKS 0 // Generate call-to-finally code in "thunks" in the enclosing EH region, protected by "cloned finally" clauses.
943 #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
944 #define CSE_CONSTS 1 // Enable if we want to CSE constants
946 #define REG_FP_FIRST REG_F0
947 #define REG_FP_LAST REG_F31
948 #define FIRST_FP_ARGREG REG_F0
949 #define LAST_FP_ARGREG REG_F15
951 #define REGNUM_BITS 6 // number of bits in a REG_*
952 #define REGMASK_BITS 64 // number of bits in a REGNUM_MASK
953 #define REGSIZE_BYTES 4 // number of bytes in one register
954 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
956 #define CODE_ALIGN 2 // code alignment requirement
957 #define STACK_ALIGN 8 // stack alignment requirement
959 #define RBM_INT_CALLEE_SAVED (RBM_R4|RBM_R5|RBM_R6|RBM_R7|RBM_R8|RBM_R9|RBM_R10)
960 #define RBM_INT_CALLEE_TRASH (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R12|RBM_LR)
961 #define RBM_FLT_CALLEE_SAVED (RBM_F16|RBM_F17|RBM_F18|RBM_F19|RBM_F20|RBM_F21|RBM_F22|RBM_F23|RBM_F24|RBM_F25|RBM_F26|RBM_F27|RBM_F28|RBM_F29|RBM_F30|RBM_F31)
962 #define RBM_FLT_CALLEE_TRASH (RBM_F0|RBM_F1|RBM_F2|RBM_F3|RBM_F4|RBM_F5|RBM_F6|RBM_F7|RBM_F8|RBM_F9|RBM_F10|RBM_F11|RBM_F12|RBM_F13|RBM_F14|RBM_F15)
964 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
965 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
967 #define REG_DEFAULT_HELPER_CALL_TARGET REG_R12
968 #define RBM_DEFAULT_HELPER_CALL_TARGET RBM_R12
970 #define REG_FASTTAILCALL_TARGET REG_R12 // Target register for fast tail call
971 #define RBM_FASTTAILCALL_TARGET RBM_R12
973 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
974 #define RBM_ALLFLOAT (RBM_FLT_CALLEE_SAVED | RBM_FLT_CALLEE_TRASH)
975 #define RBM_ALLDOUBLE (RBM_F0|RBM_F2|RBM_F4|RBM_F6|RBM_F8|RBM_F10|RBM_F12|RBM_F14|RBM_F16|RBM_F18|RBM_F20|RBM_F22|RBM_F24|RBM_F26|RBM_F28|RBM_F30)
977 #define REG_VAR_ORDER REG_R3,REG_R2,REG_R1,REG_R0,REG_R4,REG_LR,REG_R12,\
978 REG_R5,REG_R6,REG_R7,REG_R8,REG_R9,REG_R10
980 #define REG_VAR_ORDER_FLT REG_F8, REG_F9, REG_F10, REG_F11, \
981 REG_F12, REG_F13, REG_F14, REG_F15, \
982 REG_F6, REG_F7, REG_F4, REG_F5, \
983 REG_F2, REG_F3, REG_F0, REG_F1, \
984 REG_F16, REG_F17, REG_F18, REG_F19, \
985 REG_F20, REG_F21, REG_F22, REG_F23, \
986 REG_F24, REG_F25, REG_F26, REG_F27, \
987 REG_F28, REG_F29, REG_F30, REG_F31,
989 #define RBM_LOW_REGS (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R4|RBM_R5|RBM_R6|RBM_R7)
990 #define RBM_HIGH_REGS (RBM_R8|RBM_R9|RBM_R10|RBM_R11|RBM_R12|RBM_SP|RBM_LR|RBM_PC)
992 #define REG_CALLEE_SAVED_ORDER REG_R4,REG_R5,REG_R6,REG_R7,REG_R8,REG_R9,REG_R10,REG_R11
993 #define RBM_CALLEE_SAVED_ORDER RBM_R4,RBM_R5,RBM_R6,RBM_R7,RBM_R8,RBM_R9,RBM_R10,RBM_R11
995 #define CNT_CALLEE_SAVED (8)
996 #define CNT_CALLEE_TRASH (6)
997 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
999 #define CNT_CALLEE_SAVED_FLOAT (16)
1000 #define CNT_CALLEE_TRASH_FLOAT (16)
1002 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED*REGSIZE_BYTES)
1003 #define CALLEE_SAVED_FLOAT_MAXSZ (CNT_CALLEE_SAVED_FLOAT*sizeof(float))
1005 #define REG_TMP_0 REG_R3
1007 // Temporary registers used for the GS cookie check.
1008 #define REG_GSCOOKIE_TMP_0 REG_R12
1009 #define REG_GSCOOKIE_TMP_1 REG_LR
1011 // register to hold shift amount; no special register is required on the ARM
1012 #define REG_SHIFT REG_NA
1013 #define RBM_SHIFT RBM_ALLINT
1015 // register to hold shift amount when shifting 64-bit values (this uses a helper call)
1016 #define REG_SHIFT_LNG REG_R2 // REG_ARG_2
1017 #define RBM_SHIFT_LNG RBM_R2 // RBM_ARG_2
1019 // This is a general scratch register that does not conflict with the argument registers
1020 #define REG_SCRATCH REG_LR
1022 // This is a general register that can be optionally reserved for other purposes during codegen
1023 #define REG_OPT_RSVD REG_R10
1024 #define RBM_OPT_RSVD RBM_R10
1026 // We reserve R9 to store SP on entry for stack unwinding when localloc is used
1027 #define REG_SAVED_LOCALLOC_SP REG_R9
1028 #define RBM_SAVED_LOCALLOC_SP RBM_R9
1030 // Where is the exception object on entry to the handler block?
1031 #define REG_EXCEPTION_OBJECT REG_R0
1032 #define RBM_EXCEPTION_OBJECT RBM_R0
1034 #define REG_JUMP_THUNK_PARAM REG_R12
1035 #define RBM_JUMP_THUNK_PARAM RBM_R12
1037 // ARM write barrier ABI (see vm\arm\asmhelpers.asm, vm\arm\asmhelpers.S):
1038 // CORINFO_HELP_ASSIGN_REF (JIT_WriteBarrier), CORINFO_HELP_CHECKED_ASSIGN_REF (JIT_CheckedWriteBarrier):
1040 // r0: the destination address (LHS of the assignment)
1041 // r1: the object reference (RHS of the assignment)
1045 // CORINFO_HELP_ASSIGN_BYREF (JIT_ByRefWriteBarrier):
1047 // r0: the destination address (object reference written here)
1048 // r1: the source address (points to object reference to write)
1050 // r0: incremented by 4
1051 // r1: incremented by 4
1055 #define REG_WRITE_BARRIER_DST_BYREF REG_ARG_0
1056 #define RBM_WRITE_BARRIER_DST_BYREF RBM_ARG_0
1058 #define REG_WRITE_BARRIER_SRC_BYREF REG_ARG_1
1059 #define RBM_WRITE_BARRIER_SRC_BYREF RBM_ARG_1
1061 #define RBM_CALLEE_TRASH_NOGC (RBM_R2|RBM_R3|RBM_LR|RBM_DEFAULT_HELPER_CALL_TARGET)
1063 // Registers killed by CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1064 #define RBM_CALLEE_TRASH_WRITEBARRIER (RBM_R0|RBM_R3|RBM_LR|RBM_DEFAULT_HELPER_CALL_TARGET)
1066 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1067 #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_WRITEBARRIER
1069 // Registers killed by CORINFO_HELP_ASSIGN_BYREF.
1070 #define RBM_CALLEE_TRASH_WRITEBARRIER_BYREF (RBM_WRITE_BARRIER_DST_BYREF | RBM_WRITE_BARRIER_SRC_BYREF | RBM_CALLEE_TRASH_NOGC)
1072 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_BYREF.
1073 // Note that r0 and r1 are still valid byref pointers after this helper call, despite their value being changed.
1074 #define RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF RBM_CALLEE_TRASH_NOGC
1076 // GenericPInvokeCalliHelper VASigCookie Parameter
1077 #define REG_PINVOKE_COOKIE_PARAM REG_R4
1078 #define RBM_PINVOKE_COOKIE_PARAM RBM_R4
1080 // GenericPInvokeCalliHelper unmanaged target Parameter
1081 #define REG_PINVOKE_TARGET_PARAM REG_R12
1082 #define RBM_PINVOKE_TARGET_PARAM RBM_R12
1084 // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
1085 #define REG_SECRET_STUB_PARAM REG_R12
1086 #define RBM_SECRET_STUB_PARAM RBM_R12
1088 // R2R indirect call. Use the same registers as VSD
1089 #define REG_R2R_INDIRECT_PARAM REG_R4
1090 #define RBM_R2R_INDIRECT_PARAM RBM_R4
1092 // Registers used by PInvoke frame setup
1093 #define REG_PINVOKE_FRAME REG_R4
1094 #define RBM_PINVOKE_FRAME RBM_R4
1095 #define REG_PINVOKE_TCB REG_R5
1096 #define RBM_PINVOKE_TCB RBM_R5
1097 #define REG_PINVOKE_SCRATCH REG_R6
1098 #define RBM_PINVOKE_SCRATCH RBM_R6
1100 // The following defines are useful for iterating a regNumber
1101 #define REG_FIRST REG_R0
1102 #define REG_INT_FIRST REG_R0
1103 #define REG_INT_LAST REG_LR
1104 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
1105 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
1106 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
1108 // The following registers are used in emitting Enter/Leave/Tailcall profiler callbacks
1109 #define REG_PROFILER_ENTER_ARG REG_R0
1110 #define RBM_PROFILER_ENTER_ARG RBM_R0
1111 #define REG_PROFILER_RET_SCRATCH REG_R2
1112 #define RBM_PROFILER_RET_SCRATCH RBM_R2
1113 #define RBM_PROFILER_RET_USED (RBM_R0 | RBM_R1 | RBM_R2)
1114 #define REG_PROFILER_JMP_ARG REG_R0
1115 #define RBM_PROFILER_JMP_USED RBM_R0
1116 #define RBM_PROFILER_TAIL_USED (RBM_R0 | RBM_R12 | RBM_LR)
1118 // The registers trashed by profiler enter/leave/tailcall hook
1119 // See vm\arm\asmhelpers.asm for more details.
1120 #define RBM_PROFILER_ENTER_TRASH RBM_NONE
1121 #define RBM_PROFILER_LEAVE_TRASH RBM_NONE
1122 #define RBM_PROFILER_TAILCALL_TRASH RBM_NONE
1124 // Which register are int and long values returned in ?
1125 #define REG_INTRET REG_R0
1126 #define RBM_INTRET RBM_R0
1127 #define RBM_LNGRET (RBM_R1|RBM_R0)
1128 #define REG_LNGRET_LO REG_R0
1129 #define REG_LNGRET_HI REG_R1
1130 #define RBM_LNGRET_LO RBM_R0
1131 #define RBM_LNGRET_HI RBM_R1
1133 #define REG_FLOATRET REG_F0
1134 #define RBM_FLOATRET RBM_F0
1135 #define RBM_DOUBLERET (RBM_F0|RBM_F1)
1137 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper (JIT_RareDisableHelper).
1138 // See vm\arm\amshelpers.asm for more details.
1139 #define RBM_STOP_FOR_GC_TRASH (RBM_CALLEE_TRASH & ~(RBM_LNGRET|RBM_R7|RBM_R8|RBM_R11|RBM_DOUBLERET|RBM_F2|RBM_F3|RBM_F4|RBM_F5|RBM_F6|RBM_F7))
1141 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper.
1142 #define RBM_INIT_PINVOKE_FRAME_TRASH (RBM_CALLEE_TRASH | RBM_PINVOKE_TCB | RBM_PINVOKE_SCRATCH)
1144 #define REG_FPBASE REG_R11
1145 #define RBM_FPBASE RBM_R11
1146 #define STR_FPBASE "r11"
1147 #define REG_SPBASE REG_SP
1148 #define RBM_SPBASE RBM_SP
1149 #define STR_SPBASE "sp"
1151 #define FIRST_ARG_STACK_OFFS (2*REGSIZE_BYTES) // Caller's saved FP and return address
1153 #define MAX_REG_ARG 4
1154 #define MAX_FLOAT_REG_ARG 16
1155 #define MAX_HFA_RET_SLOTS 8
1157 #define REG_ARG_FIRST REG_R0
1158 #define REG_ARG_LAST REG_R3
1159 #define REG_ARG_FP_FIRST REG_F0
1160 #define REG_ARG_FP_LAST REG_F7
1161 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
1163 #define REG_ARG_0 REG_R0
1164 #define REG_ARG_1 REG_R1
1165 #define REG_ARG_2 REG_R2
1166 #define REG_ARG_3 REG_R3
1168 SELECTANY const regNumber intArgRegs [] = {REG_R0, REG_R1, REG_R2, REG_R3};
1169 SELECTANY const regMaskTP intArgMasks[] = {RBM_R0, RBM_R1, RBM_R2, RBM_R3};
1171 #define RBM_ARG_0 RBM_R0
1172 #define RBM_ARG_1 RBM_R1
1173 #define RBM_ARG_2 RBM_R2
1174 #define RBM_ARG_3 RBM_R3
1176 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1|RBM_ARG_2|RBM_ARG_3)
1177 #define RBM_FLTARG_REGS (RBM_F0|RBM_F1|RBM_F2|RBM_F3|RBM_F4|RBM_F5|RBM_F6|RBM_F7|RBM_F8|RBM_F9|RBM_F10|RBM_F11|RBM_F12|RBM_F13|RBM_F14|RBM_F15)
1178 #define RBM_DBL_REGS RBM_ALLDOUBLE
1180 SELECTANY const regNumber fltArgRegs [] = {REG_F0, REG_F1, REG_F2, REG_F3, REG_F4, REG_F5, REG_F6, REG_F7, REG_F8, REG_F9, REG_F10, REG_F11, REG_F12, REG_F13, REG_F14, REG_F15 };
1181 SELECTANY const regMaskTP fltArgMasks[] = {RBM_F0, RBM_F1, RBM_F2, RBM_F3, RBM_F4, RBM_F5, RBM_F6, RBM_F7, RBM_F8, RBM_F9, RBM_F10, RBM_F11, RBM_F12, RBM_F13, RBM_F14, RBM_F15 };
1183 #define LBL_DIST_SMALL_MAX_NEG (0)
1184 #define LBL_DIST_SMALL_MAX_POS (+1020)
1185 #define LBL_DIST_MED_MAX_NEG (-4095)
1186 #define LBL_DIST_MED_MAX_POS (+4096)
1188 #define JMP_DIST_SMALL_MAX_NEG (-2048)
1189 #define JMP_DIST_SMALL_MAX_POS (+2046)
1191 #define CALL_DIST_MAX_NEG (-16777216)
1192 #define CALL_DIST_MAX_POS (+16777214)
1194 #define JCC_DIST_SMALL_MAX_NEG (-256)
1195 #define JCC_DIST_SMALL_MAX_POS (+254)
1197 #define JCC_DIST_MEDIUM_MAX_NEG (-1048576)
1198 #define JCC_DIST_MEDIUM_MAX_POS (+1048574)
1200 #define LBL_SIZE_SMALL (2)
1202 #define JMP_SIZE_SMALL (2)
1203 #define JMP_SIZE_LARGE (4)
1205 #define JCC_SIZE_SMALL (2)
1206 #define JCC_SIZE_MEDIUM (4)
1207 #define JCC_SIZE_LARGE (6)
1209 #elif defined(_TARGET_ARM64_)
1211 #define CPU_LOAD_STORE_ARCH 1
1212 #define CPU_HAS_FP_SUPPORT 1
1213 #define ROUND_FLOAT 0 // Do not round intermed float expression results
1214 #define CPU_HAS_BYTE_REGS 0
1216 #define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk.
1217 #define INITBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll InitBlk.
1220 #define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned
1221 #define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 1 // Whether SIMD registers are partially saved at calls
1222 #endif // FEATURE_SIMD
1224 #define FEATURE_FIXED_OUT_ARGS 1 // Preallocate the outgoing arg area in the prolog
1225 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
1226 #define FEATURE_MULTIREG_STRUCT_PROMOTE 1 // True when we want to promote fields of a multireg struct into registers
1227 #define FEATURE_FASTTAILCALL 1 // Tail calls made as epilog+jmp
1228 #define FEATURE_TAILCALL_OPT 1 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
1229 #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
1230 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
1231 #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register
1232 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
1233 #define FEATURE_STRUCT_CLASSIFIER 0 // Uses a classifier function to determine is structs are passed/returned in more than one register
1234 #define MAX_PASS_MULTIREG_BYTES 32 // Maximum size of a struct that could be passed in more than one register (max is 4 doubles using an HFA)
1235 #define MAX_RET_MULTIREG_BYTES 32 // Maximum size of a struct that could be returned in more than one register (Max is an HFA of 4 doubles)
1236 #define MAX_ARG_REG_COUNT 4 // Maximum registers used to pass a single argument in multiple registers. (max is 4 floats or doubles using an HFA)
1237 #define MAX_RET_REG_COUNT 4 // Maximum registers used to return a value.
1239 #define NOGC_WRITE_BARRIERS 1 // We have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers
1240 #define USER_ARGS_COME_LAST 1
1241 #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
1242 // need to track stack depth, but this is currently necessary to get GC information reported at call sites.
1243 #define TARGET_POINTER_SIZE 8 // equal to sizeof(void*) and the managed pointer size in bytes for this target
1244 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter, filter-handler, fault) and directly execute 'finally' clauses.
1245 #define FEATURE_EH_FUNCLETS 1
1246 #define FEATURE_EH_CALLFINALLY_THUNKS 1 // Generate call-to-finally code in "thunks" in the enclosing EH region, protected by "cloned finally" clauses.
1247 #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
1248 #define CSE_CONSTS 1 // Enable if we want to CSE constants
1250 #define REG_FP_FIRST REG_V0
1251 #define REG_FP_LAST REG_V31
1252 #define FIRST_FP_ARGREG REG_V0
1253 #define LAST_FP_ARGREG REG_V15
1255 #define REGNUM_BITS 6 // number of bits in a REG_*
1256 #define REGMASK_BITS 64 // number of bits in a REGNUM_MASK
1257 #define REGSIZE_BYTES 8 // number of bytes in one general purpose register
1258 #define FP_REGSIZE_BYTES 16 // number of bytes in one FP/SIMD register
1259 #define FPSAVE_REGSIZE_BYTES 8 // number of bytes in one FP/SIMD register that are saved/restored, for callee-saved registers
1261 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
1263 #define CODE_ALIGN 4 // code alignment requirement
1264 #define STACK_ALIGN 16 // stack alignment requirement
1266 #define RBM_INT_CALLEE_SAVED (RBM_R19|RBM_R20|RBM_R21|RBM_R22|RBM_R23|RBM_R24|RBM_R25|RBM_R26|RBM_R27|RBM_R28)
1267 #define RBM_INT_CALLEE_TRASH (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R4|RBM_R5|RBM_R6|RBM_R7|RBM_R8|RBM_R9|RBM_R10|RBM_R11|RBM_R12|RBM_R13|RBM_R14|RBM_R15|RBM_IP0|RBM_IP1|RBM_LR)
1268 #define RBM_FLT_CALLEE_SAVED (RBM_V8|RBM_V9|RBM_V10|RBM_V11|RBM_V12|RBM_V13|RBM_V14|RBM_V15)
1269 #define RBM_FLT_CALLEE_TRASH (RBM_V0|RBM_V1|RBM_V2|RBM_V3|RBM_V4|RBM_V5|RBM_V6|RBM_V7|RBM_V16|RBM_V17|RBM_V18|RBM_V19|RBM_V20|RBM_V21|RBM_V22|RBM_V23|RBM_V24|RBM_V25|RBM_V26|RBM_V27|RBM_V28|RBM_V29|RBM_V30|RBM_V31)
1271 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
1272 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
1274 #define REG_DEFAULT_HELPER_CALL_TARGET REG_R12
1275 #define RBM_DEFAULT_HELPER_CALL_TARGET RBM_R12
1277 #define REG_FASTTAILCALL_TARGET REG_IP0 // Target register for fast tail call
1278 #define RBM_FASTTAILCALL_TARGET RBM_IP0
1280 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
1281 #define RBM_ALLFLOAT (RBM_FLT_CALLEE_SAVED | RBM_FLT_CALLEE_TRASH)
1282 #define RBM_ALLDOUBLE RBM_ALLFLOAT
1284 // REG_VAR_ORDER is: (CALLEE_TRASH & ~CALLEE_TRASH_NOGC), CALLEE_TRASH_NOGC, CALLEE_SAVED
1285 #define REG_VAR_ORDER REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, \
1286 REG_R6, REG_R7, REG_R8, REG_R9, REG_R10, \
1287 REG_R11, REG_R13, REG_R14, \
1288 REG_R12, REG_R15, REG_IP0, REG_IP1, \
1289 REG_CALLEE_SAVED_ORDER
1291 #define REG_VAR_ORDER_FLT REG_V16, REG_V17, REG_V18, REG_V19, \
1292 REG_V20, REG_V21, REG_V22, REG_V23, \
1293 REG_V24, REG_V25, REG_V26, REG_V27, \
1294 REG_V28, REG_V29, REG_V30, REG_V31, \
1295 REG_V7, REG_V6, REG_V5, REG_V4, \
1296 REG_V8, REG_V9, REG_V10, REG_V11, \
1297 REG_V12, REG_V13, REG_V14, REG_V15, \
1298 REG_V3, REG_V2, REG_V1, REG_V0
1300 #define REG_CALLEE_SAVED_ORDER REG_R19,REG_R20,REG_R21,REG_R22,REG_R23,REG_R24,REG_R25,REG_R26,REG_R27,REG_R28
1301 #define RBM_CALLEE_SAVED_ORDER RBM_R19,RBM_R20,RBM_R21,RBM_R22,RBM_R23,RBM_R24,RBM_R25,RBM_R26,RBM_R27,RBM_R28
1303 #define CNT_CALLEE_SAVED (11)
1304 #define CNT_CALLEE_TRASH (17)
1305 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
1307 #define CNT_CALLEE_SAVED_FLOAT (8)
1308 #define CNT_CALLEE_TRASH_FLOAT (24)
1310 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED * REGSIZE_BYTES)
1311 #define CALLEE_SAVED_FLOAT_MAXSZ (CNT_CALLEE_SAVED_FLOAT * FPSAVE_REGSIZE_BYTES)
1313 #define REG_TMP_0 REG_R9
1315 // Temporary registers used for the GS cookie check.
1316 #define REG_GSCOOKIE_TMP_0 REG_R9
1317 #define REG_GSCOOKIE_TMP_1 REG_R10
1319 // register to hold shift amount; no special register is required on ARM64.
1320 #define REG_SHIFT REG_NA
1321 #define RBM_SHIFT RBM_ALLINT
1323 // This is a general scratch register that does not conflict with the argument registers
1324 #define REG_SCRATCH REG_R9
1326 // This is a general register that can be optionally reserved for other purposes during codegen
1327 #define REG_OPT_RSVD REG_IP1
1328 #define RBM_OPT_RSVD RBM_IP1
1330 // Where is the exception object on entry to the handler block?
1331 #define REG_EXCEPTION_OBJECT REG_R0
1332 #define RBM_EXCEPTION_OBJECT RBM_R0
1334 #define REG_JUMP_THUNK_PARAM REG_R12
1335 #define RBM_JUMP_THUNK_PARAM RBM_R12
1337 // ARM64 write barrier ABI (see vm\arm64\asmhelpers.asm, vm\arm64\asmhelpers.S):
1338 // CORINFO_HELP_ASSIGN_REF (JIT_WriteBarrier), CORINFO_HELP_CHECKED_ASSIGN_REF (JIT_CheckedWriteBarrier):
1340 // x14: the destination address (LHS of the assignment)
1341 // x15: the object reference (RHS of the assignment)
1344 // x14: incremented by 8
1346 // x17: trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP (currently non-Windows)
1347 // CORINFO_HELP_ASSIGN_BYREF (JIT_ByRefWriteBarrier):
1349 // x13: the source address (points to object reference to write)
1350 // x14: the destination address (object reference written here)
1353 // x13: incremented by 8
1354 // x14: incremented by 8
1356 // x17: trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP (currently non-Windows)
1358 // Note that while x17 (ip1) is currently only trashed under FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP,
1359 // currently only set for non-Windows, it is expected to be set in the future for Windows, and for R2R.
1360 // So simply always consider it trashed, to avoid later breaking changes.
1362 #define REG_WRITE_BARRIER_DST REG_R14
1363 #define RBM_WRITE_BARRIER_DST RBM_R14
1365 #define REG_WRITE_BARRIER_SRC REG_R15
1366 #define RBM_WRITE_BARRIER_SRC RBM_R15
1368 #define REG_WRITE_BARRIER_DST_BYREF REG_R14
1369 #define RBM_WRITE_BARRIER_DST_BYREF RBM_R14
1371 #define REG_WRITE_BARRIER_SRC_BYREF REG_R13
1372 #define RBM_WRITE_BARRIER_SRC_BYREF RBM_R13
1374 #define RBM_CALLEE_TRASH_NOGC (RBM_R12|RBM_R15|RBM_IP0|RBM_IP1|RBM_DEFAULT_HELPER_CALL_TARGET)
1376 // Registers killed by CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1377 #define RBM_CALLEE_TRASH_WRITEBARRIER (RBM_R14|RBM_CALLEE_TRASH_NOGC)
1379 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1380 #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_NOGC
1382 // Registers killed by CORINFO_HELP_ASSIGN_BYREF.
1383 #define RBM_CALLEE_TRASH_WRITEBARRIER_BYREF (RBM_WRITE_BARRIER_DST_BYREF | RBM_WRITE_BARRIER_SRC_BYREF | RBM_CALLEE_TRASH_NOGC)
1385 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_BYREF.
1386 // Note that x13 and x14 are still valid byref pointers after this helper call, despite their value being changed.
1387 #define RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF RBM_CALLEE_TRASH_NOGC
1389 // GenericPInvokeCalliHelper VASigCookie Parameter
1390 #define REG_PINVOKE_COOKIE_PARAM REG_R15
1391 #define RBM_PINVOKE_COOKIE_PARAM RBM_R15
1393 // GenericPInvokeCalliHelper unmanaged target Parameter
1394 #define REG_PINVOKE_TARGET_PARAM REG_R12
1395 #define RBM_PINVOKE_TARGET_PARAM RBM_R12
1397 // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
1398 #define REG_SECRET_STUB_PARAM REG_R12
1399 #define RBM_SECRET_STUB_PARAM RBM_R12
1401 // R2R indirect call. Use the same registers as VSD
1402 #define REG_R2R_INDIRECT_PARAM REG_R11
1403 #define RBM_R2R_INDIRECT_PARAM RBM_R11
1405 // Registers used by PInvoke frame setup
1406 #define REG_PINVOKE_FRAME REG_R9
1407 #define RBM_PINVOKE_FRAME RBM_R9
1408 #define REG_PINVOKE_TCB REG_R10
1409 #define RBM_PINVOKE_TCB RBM_R10
1410 #define REG_PINVOKE_SCRATCH REG_R10
1411 #define RBM_PINVOKE_SCRATCH RBM_R10
1413 // The following defines are useful for iterating a regNumber
1414 #define REG_FIRST REG_R0
1415 #define REG_INT_FIRST REG_R0
1416 #define REG_INT_LAST REG_ZR
1417 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
1418 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
1419 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
1421 // The following registers are used in emitting Enter/Leave/Tailcall profiler callbacks
1422 #define REG_PROFILER_ENTER_ARG REG_R0
1423 #define RBM_PROFILER_ENTER_ARG RBM_R0
1424 #define REG_PROFILER_RET_SCRATCH REG_R2
1425 #define RBM_PROFILER_RET_SCRATCH RBM_R2
1426 #define RBM_PROFILER_RET_USED (RBM_R0 | RBM_R1 | RBM_R2)
1427 #define REG_PROFILER_JMP_ARG REG_R0
1428 #define RBM_PROFILER_JMP_USED RBM_R0
1429 #define RBM_PROFILER_TAIL_USED (RBM_R0 | RBM_R12 | RBM_LR)
1431 // Which register are int and long values returned in ?
1432 #define REG_INTRET REG_R0
1433 #define RBM_INTRET RBM_R0
1434 #define RBM_LNGRET RBM_R0
1435 // second return register for 16-byte structs
1436 #define REG_INTRET_1 REG_R1
1437 #define RBM_INTRET_1 RBM_R1
1439 #define REG_FLOATRET REG_V0
1440 #define RBM_FLOATRET RBM_V0
1441 #define RBM_DOUBLERET RBM_V0
1443 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper
1444 #define RBM_STOP_FOR_GC_TRASH RBM_CALLEE_TRASH
1446 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper.
1447 #define RBM_INIT_PINVOKE_FRAME_TRASH RBM_CALLEE_TRASH
1449 #define REG_FPBASE REG_FP
1450 #define RBM_FPBASE RBM_FP
1451 #define STR_FPBASE "fp"
1452 #define REG_SPBASE REG_SP
1453 #define RBM_SPBASE RBM_ZR // reuse the RBM for REG_ZR
1454 #define STR_SPBASE "sp"
1456 #define FIRST_ARG_STACK_OFFS (2*REGSIZE_BYTES) // Caller's saved FP and return address
1458 // On ARM64 the calling convention defines REG_R8 (x8) as an additional argument register.
1459 // It isn't allocated for the normal user arguments, so it isn't counted by MAX_REG_ARG.
1460 // Whether we use this register to pass the RetBuff is controlled by the function hasFixedRetBuffReg().
1461 // It is considered to be the next integer argnum, which is 8.
1463 #define REG_ARG_RET_BUFF REG_R8
1464 #define RBM_ARG_RET_BUFF RBM_R8
1465 #define RET_BUFF_ARGNUM 8
1467 #define MAX_REG_ARG 8
1468 #define MAX_FLOAT_REG_ARG 8
1470 #define REG_ARG_FIRST REG_R0
1471 #define REG_ARG_LAST REG_R7
1472 #define REG_ARG_FP_FIRST REG_V0
1473 #define REG_ARG_FP_LAST REG_V7
1474 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
1476 #define REG_ARG_0 REG_R0
1477 #define REG_ARG_1 REG_R1
1478 #define REG_ARG_2 REG_R2
1479 #define REG_ARG_3 REG_R3
1480 #define REG_ARG_4 REG_R4
1481 #define REG_ARG_5 REG_R5
1482 #define REG_ARG_6 REG_R6
1483 #define REG_ARG_7 REG_R7
1485 SELECTANY const regNumber intArgRegs [] = {REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7};
1486 SELECTANY const regMaskTP intArgMasks[] = {RBM_R0, RBM_R1, RBM_R2, RBM_R3, RBM_R4, RBM_R5, RBM_R6, RBM_R7};
1488 #define RBM_ARG_0 RBM_R0
1489 #define RBM_ARG_1 RBM_R1
1490 #define RBM_ARG_2 RBM_R2
1491 #define RBM_ARG_3 RBM_R3
1492 #define RBM_ARG_4 RBM_R4
1493 #define RBM_ARG_5 RBM_R5
1494 #define RBM_ARG_6 RBM_R6
1495 #define RBM_ARG_7 RBM_R7
1497 #define REG_FLTARG_0 REG_V0
1498 #define REG_FLTARG_1 REG_V1
1499 #define REG_FLTARG_2 REG_V2
1500 #define REG_FLTARG_3 REG_V3
1501 #define REG_FLTARG_4 REG_V4
1502 #define REG_FLTARG_5 REG_V5
1503 #define REG_FLTARG_6 REG_V6
1504 #define REG_FLTARG_7 REG_V7
1506 #define RBM_FLTARG_0 RBM_V0
1507 #define RBM_FLTARG_1 RBM_V1
1508 #define RBM_FLTARG_2 RBM_V2
1509 #define RBM_FLTARG_3 RBM_V3
1510 #define RBM_FLTARG_4 RBM_V4
1511 #define RBM_FLTARG_5 RBM_V5
1512 #define RBM_FLTARG_6 RBM_V6
1513 #define RBM_FLTARG_7 RBM_V7
1515 #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)
1516 #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)
1518 SELECTANY const regNumber fltArgRegs [] = {REG_V0, REG_V1, REG_V2, REG_V3, REG_V4, REG_V5, REG_V6, REG_V7 };
1519 SELECTANY const regMaskTP fltArgMasks[] = {RBM_V0, RBM_V1, RBM_V2, RBM_V3, RBM_V4, RBM_V5, RBM_V6, RBM_V7 };
1521 #define LBL_DIST_SMALL_MAX_NEG (-1048576)
1522 #define LBL_DIST_SMALL_MAX_POS (+1048575)
1524 #define LBL_SIZE_SMALL (4)
1526 #define JCC_DIST_SMALL_MAX_NEG (-1048576)
1527 #define JCC_DIST_SMALL_MAX_POS (+1048575)
1529 #define TB_DIST_SMALL_MAX_NEG (-32768)
1530 #define TB_DIST_SMALL_MAX_POS (+32767)
1532 #define JCC_SIZE_SMALL (4)
1533 #define JCC_SIZE_LARGE (8)
1535 #define LDC_DIST_SMALL_MAX_NEG (-1048576)
1536 #define LDC_DIST_SMALL_MAX_POS (+1048575)
1538 #define LDC_SIZE_SMALL (4)
1540 #define JMP_SIZE_SMALL (4)
1543 #error Unsupported or unset target architecture
1546 #ifdef _TARGET_XARCH_
1548 #define JMP_DIST_SMALL_MAX_NEG (-128)
1549 #define JMP_DIST_SMALL_MAX_POS (+127)
1551 #define JCC_DIST_SMALL_MAX_NEG (-128)
1552 #define JCC_DIST_SMALL_MAX_POS (+127)
1554 #define JMP_SIZE_SMALL (2)
1555 #define JMP_SIZE_LARGE (5)
1557 #define JCC_SIZE_SMALL (2)
1558 #define JCC_SIZE_LARGE (6)
1560 #define PUSH_INST_SIZE (5)
1561 #define CALL_INST_SIZE (5)
1563 #endif // _TARGET_XARCH_
1565 C_ASSERT(REG_FIRST == 0);
1566 C_ASSERT(REG_INT_FIRST < REG_INT_LAST);
1567 C_ASSERT(REG_FP_FIRST < REG_FP_LAST);
1569 // Opportunistic tail call feature converts non-tail prefixed calls into
1570 // tail calls where possible. It requires fast tail calling mechanism for
1571 // performance. Otherwise, we are better off not converting non-tail prefixed
1572 // calls into tail calls.
1573 C_ASSERT((FEATURE_TAILCALL_OPT == 0) || (FEATURE_FASTTAILCALL == 1));
1575 /*****************************************************************************/
1577 #define BITS_PER_BYTE 8
1578 #define REGNUM_MASK ((1 << REGNUM_BITS) - 1) // a n-bit mask use to encode multiple REGNUMs into a unsigned int
1579 #define RBM_ALL(type) (varTypeIsFloating(type) ? RBM_ALLFLOAT : RBM_ALLINT)
1581 /*****************************************************************************/
1583 #if CPU_HAS_BYTE_REGS
1584 #define RBM_BYTE_REGS (RBM_EAX|RBM_ECX|RBM_EDX|RBM_EBX)
1585 #define RBM_NON_BYTE_REGS (RBM_ESI|RBM_EDI)
1587 #define RBM_BYTE_REGS RBM_ALLINT
1588 #define RBM_NON_BYTE_REGS RBM_NONE
1592 /*****************************************************************************/
1596 static const char* g_tgtCPUName;
1597 static const char* g_tgtPlatformName;
1604 static const enum ArgOrder g_tgtArgOrder;
1607 #if defined(DEBUG) || defined(LATE_DISASM)
1608 const char* getRegName(unsigned reg, bool isFloat = false); // this is for gcencode.cpp and disasm.cpp that don't use
1609 // the regNumber type
1610 const char* getRegName(regNumber reg, bool isFloat = false);
1611 #endif // defined(DEBUG) || defined(LATE_DISASM)
1614 const char* getRegNameFloat(regNumber reg, var_types type);
1615 extern void dspRegMask(regMaskTP regMask, size_t minSiz = 0);
1618 #if CPU_HAS_BYTE_REGS
1619 inline BOOL isByteReg(regNumber reg)
1621 return (reg <= REG_EBX);
1624 inline BOOL isByteReg(regNumber reg)
1630 inline regMaskTP genRegMask(regNumber reg);
1631 inline regMaskTP genRegMaskFloat(regNumber reg, var_types type = TYP_DOUBLE);
1633 /*****************************************************************************
1634 * Return true if the register number is valid
1636 inline bool genIsValidReg(regNumber reg)
1638 /* It's safest to perform an unsigned comparison in case reg is negative */
1639 return ((unsigned)reg < (unsigned)REG_COUNT);
1642 /*****************************************************************************
1643 * Return true if the register is a valid integer register
1645 inline bool genIsValidIntReg(regNumber reg)
1647 return reg >= REG_INT_FIRST && reg <= REG_INT_LAST;
1650 /*****************************************************************************
1651 * Return true if the register is a valid floating point register
1653 inline bool genIsValidFloatReg(regNumber reg)
1655 return reg >= REG_FP_FIRST && reg <= REG_FP_LAST;
1660 /*****************************************************************************
1661 * Return true if the register is a valid floating point double register
1663 inline bool genIsValidDoubleReg(regNumber reg)
1665 return genIsValidFloatReg(reg) && (((reg - REG_FP_FIRST) & 0x1) == 0);
1668 #endif // _TARGET_ARM_
1670 //-------------------------------------------------------------------------------------------
1671 // hasFixedRetBuffReg:
1672 // Returns true if our target architecture uses a fixed return buffer register
1674 inline bool hasFixedRetBuffReg()
1676 #ifdef _TARGET_ARM64_
1683 //-------------------------------------------------------------------------------------------
1684 // theFixedRetBuffReg:
1685 // Returns the regNumber to use for the fixed return buffer
1687 inline regNumber theFixedRetBuffReg()
1689 assert(hasFixedRetBuffReg()); // This predicate should be checked before calling this method
1690 #ifdef _TARGET_ARM64_
1691 return REG_ARG_RET_BUFF;
1697 //-------------------------------------------------------------------------------------------
1698 // theFixedRetBuffMask:
1699 // Returns the regNumber to use for the fixed return buffer
1701 inline regMaskTP theFixedRetBuffMask()
1703 assert(hasFixedRetBuffReg()); // This predicate should be checked before calling this method
1704 #ifdef _TARGET_ARM64_
1705 return RBM_ARG_RET_BUFF;
1711 //-------------------------------------------------------------------------------------------
1712 // theFixedRetBuffArgNum:
1713 // Returns the argNum to use for the fixed return buffer
1715 inline unsigned theFixedRetBuffArgNum()
1717 assert(hasFixedRetBuffReg()); // This predicate should be checked before calling this method
1718 #ifdef _TARGET_ARM64_
1719 return RET_BUFF_ARGNUM;
1725 //-------------------------------------------------------------------------------------------
1726 // fullIntArgRegMask:
1727 // Returns the full mask of all possible integer registers
1728 // Note this includes the fixed return buffer register on Arm64
1730 inline regMaskTP fullIntArgRegMask()
1732 if (hasFixedRetBuffReg())
1734 return RBM_ARG_REGS | theFixedRetBuffMask();
1738 return RBM_ARG_REGS;
1742 //-------------------------------------------------------------------------------------------
1743 // isValidIntArgReg:
1744 // Returns true if the register is a valid integer argument register
1745 // Note this method also returns true on Arm64 when 'reg' is the RetBuff register
1747 inline bool isValidIntArgReg(regNumber reg)
1749 return (genRegMask(reg) & fullIntArgRegMask()) != 0;
1752 //-------------------------------------------------------------------------------------------
1754 // Given a register that is an integer or floating point argument register
1755 // returns the next argument register
1757 regNumber genRegArgNext(regNumber argReg);
1759 //-------------------------------------------------------------------------------------------
1760 // isValidFloatArgReg:
1761 // Returns true if the register is a valid floating-point argument register
1763 inline bool isValidFloatArgReg(regNumber reg)
1771 return (reg >= FIRST_FP_ARGREG) && (reg <= LAST_FP_ARGREG);
1775 /*****************************************************************************
1777 * Can the register hold the argument type?
1781 inline bool floatRegCanHoldType(regNumber reg, var_types type)
1783 assert(genIsValidFloatReg(reg));
1784 if (type == TYP_DOUBLE)
1786 return ((reg - REG_F0) % 2) == 0;
1790 // Can be TYP_STRUCT for HFA. It's not clear that's correct; what about
1791 // HFA of double? We wouldn't be asserting the right alignment, and
1792 // callers like genRegMaskFloat() wouldn't be generating the right mask.
1794 assert((type == TYP_FLOAT) || (type == TYP_STRUCT));
1799 // AMD64: xmm registers can hold any float type
1800 // x86: FP stack can hold any float type
1801 // ARM64: Floating-point/SIMD registers can hold any type.
1802 inline bool floatRegCanHoldType(regNumber reg, var_types type)
1808 /*****************************************************************************
1810 * Map a register number to a register mask.
1813 extern const regMaskSmall regMasks[REG_COUNT];
1815 inline regMaskTP genRegMask(regNumber reg)
1817 assert((unsigned)reg < ArrLen(regMasks));
1818 #ifdef _TARGET_AMD64_
1819 // shift is faster than a L1 hit on modern x86
1820 // (L1 latency on sandy bridge is 4 cycles for [base] and 5 for [base + index*c] )
1821 // the reason this is AMD-only is because the x86 BE will try to get reg masks for REG_STK
1822 // and the result needs to be zero.
1823 regMaskTP result = 1 << reg;
1824 assert(result == regMasks[reg]);
1827 return regMasks[reg];
1831 /*****************************************************************************
1833 * Map a register number to a floating-point register mask.
1836 inline regMaskTP genRegMaskFloat(regNumber reg, var_types type /* = TYP_DOUBLE */)
1838 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) || defined(_TARGET_X86_)
1839 assert(genIsValidFloatReg(reg));
1840 assert((unsigned)reg < ArrLen(regMasks));
1841 return regMasks[reg];
1842 #elif defined(_TARGET_ARM_)
1843 assert(floatRegCanHoldType(reg, type));
1844 assert(reg >= REG_F0 && reg <= REG_F31);
1846 if (type == TYP_DOUBLE)
1848 return regMasks[reg] | regMasks[reg + 1];
1852 return regMasks[reg];
1855 #error Unsupported or unset target architecture
1859 //------------------------------------------------------------------------
1860 // genRegMask: Given a register, and its type, generate the appropriate regMask
1863 // regNum - the register of interest
1864 // type - the type of regNum (i.e. the type it is being used as)
1867 // This will usually return the same value as genRegMask(regNum), but
1868 // on architectures where multiple registers are used for certain types
1869 // (e.g. TYP_DOUBLE on ARM), it will return a regMask that includes
1870 // all the registers.
1871 // Registers that are used in pairs, but separately named (e.g. TYP_LONG
1872 // on ARM) will return just the regMask for the given register.
1875 // For registers that are used in pairs, the caller will be handling
1876 // each member of the pair separately.
1878 inline regMaskTP genRegMask(regNumber regNum, var_types type)
1880 #ifndef _TARGET_ARM_
1881 return genRegMask(regNum);
1883 regMaskTP regMask = RBM_NONE;
1885 if (varTypeIsFloating(type))
1887 regMask = genRegMaskFloat(regNum, type);
1891 regMask = genRegMask(regNum);
1897 /*****************************************************************************
1899 * These arrays list the callee-saved register numbers (and bitmaps, respectively) for
1900 * the current architecture.
1902 extern const regNumber raRegCalleeSaveOrder[CNT_CALLEE_SAVED];
1903 extern const regMaskTP raRbmCalleeSaveOrder[CNT_CALLEE_SAVED];
1905 // This method takes a "compact" bitset of the callee-saved registers, and "expands" it to a full register mask.
1906 regMaskSmall genRegMaskFromCalleeSavedMask(unsigned short);
1908 /*****************************************************************************
1910 * Assumes that "reg" is of the given "type". Return the next unused reg number after "reg"
1911 * of this type, else REG_NA if there are no more.
1914 inline regNumber regNextOfType(regNumber reg, var_types type)
1916 regNumber regReturn;
1919 if (type == TYP_DOUBLE)
1921 // Skip odd FP registers for double-precision types
1922 assert(floatRegCanHoldType(reg, type));
1923 regReturn = regNumber(reg + 2);
1927 regReturn = REG_NEXT(reg);
1929 #else // _TARGET_ARM_
1930 regReturn = REG_NEXT(reg);
1933 if (varTypeIsFloating(type))
1935 if (regReturn > REG_FP_LAST)
1942 if (regReturn > REG_INT_LAST)
1951 /*****************************************************************************
1956 inline bool isFloatRegType(int /* s/b "var_types" */ type)
1958 #if CPU_HAS_FP_SUPPORT
1959 return type == TYP_DOUBLE || type == TYP_FLOAT;
1965 // If the WINDOWS_AMD64_ABI is defined make sure that _TARGET_AMD64_ is also defined.
1966 #if defined(WINDOWS_AMD64_ABI)
1967 #if !defined(_TARGET_AMD64_)
1968 #error When WINDOWS_AMD64_ABI is defined you must define _TARGET_AMD64_ defined as well.
1972 /*****************************************************************************/
1973 // Some sanity checks on some of the register masks
1974 // Stack pointer is never part of RBM_ALLINT
1975 C_ASSERT((RBM_ALLINT & RBM_SPBASE) == RBM_NONE);
1976 C_ASSERT((RBM_INT_CALLEE_SAVED & RBM_SPBASE) == RBM_NONE);
1979 // Frame pointer isn't either if we're supporting ETW frame chaining
1980 C_ASSERT((RBM_ALLINT & RBM_FPBASE) == RBM_NONE);
1981 C_ASSERT((RBM_INT_CALLEE_SAVED & RBM_FPBASE) == RBM_NONE);
1983 /*****************************************************************************/
1985 #ifdef _TARGET_64BIT_
1986 typedef unsigned __int64 target_size_t;
1988 typedef unsigned int target_size_t;
1991 C_ASSERT(sizeof(target_size_t) == TARGET_POINTER_SIZE);
1993 /*****************************************************************************/
1994 #endif // _TARGET_H_
1995 /*****************************************************************************/