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_X86_) && defined(LEGACY_BACKEND)
33 #define REGMASK_BITS 8 // number of bits used to represent register mask
34 #elif defined(_TARGET_XARCH_)
35 #define REGMASK_BITS 32
37 #elif defined(_TARGET_ARM_)
38 #define REGMASK_BITS 64
40 #elif defined(_TARGET_ARM64_)
41 #define REGMASK_BITS 64
44 #error Unsupported or unset target architecture
47 //------------------------------------------------------------------------
49 // Each register list in register.h must declare REG_STK as the last value.
50 // In the following enum declarations, the following REG_XXX are created beyond
51 // the "real" registers:
52 // REG_STK - Used to indicate something evaluated onto the stack.
53 // ACTUAL_REG_COUNT - The number of physical registers. (same as REG_STK).
54 // REG_COUNT - The number of physical register + REG_STK. This is the count of values that may
55 // be assigned during register allocation.
56 // REG_NA - Used to indicate that a register is either not yet assigned or not required.
58 #if defined(_TARGET_ARM_)
59 enum _regNumber_enum : unsigned
61 #define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
62 #define REGALIAS(alias, realname) REG_##alias = REG_##realname,
67 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
70 enum _regMask_enum : unsigned __int64
73 #define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
74 #define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
78 #elif defined(_TARGET_ARM64_)
80 enum _regNumber_enum : unsigned
82 #define REGDEF(name, rnum, mask, xname, wname) REG_##name = rnum,
83 #define REGALIAS(alias, realname) REG_##alias = REG_##realname,
88 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
91 enum _regMask_enum : unsigned __int64
94 #define REGDEF(name, rnum, mask, xname, wname) RBM_##name = mask,
95 #define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
99 #elif defined(_TARGET_AMD64_)
101 enum _regNumber_enum : unsigned
103 #define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
104 #define REGALIAS(alias, realname) REG_##alias = REG_##realname,
105 #include "register.h"
109 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
112 enum _regMask_enum : unsigned
116 #define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
117 #define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
118 #include "register.h"
121 #elif defined(_TARGET_X86_)
123 #ifndef LEGACY_BACKEND
124 enum _regNumber_enum : unsigned
126 #define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
127 #define REGALIAS(alias, realname) REG_##alias = REG_##realname,
128 #include "register.h"
132 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
135 enum _regMask_enum : unsigned
139 #define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
140 #define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
141 #include "register.h"
144 #else // LEGACY_BACKEND
145 enum _regNumber_enum : unsigned
147 #define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
148 #define REGALIAS(alias, realname) REG_##alias = REG_##realname,
149 #include "register.h"
153 ACTUAL_REG_COUNT = REG_COUNT - 1, // everything but REG_STK (only real regs)
155 #define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
156 #include "registerfp.h"
159 REG_FPNONE = REG_FPCOUNT,
161 #define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
162 #include "registerxmm.h"
167 enum _regMask_enum : unsigned
171 #define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
172 #define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
173 #include "register.h"
175 #define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
176 #include "registerfp.h"
178 #define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
179 #include "registerxmm.h"
182 #endif // LEGACY_BACKEND
184 #error Unsupported target architecture
187 /* The following are used to hold 'long' (64-bit integer) operands */
190 The following yield the number of bits and the mask of a register
191 number in a register pair.
195 #define REG_PAIR_NBITS 6
197 #define REG_PAIR_NBITS 4
199 #define REG_PAIR_NMASK ((1 << REG_PAIR_NBITS) - 1)
202 // Under DEBUG, we want to make sure that code doesn't accidentally confuse a reg pair value
203 // with a simple register number. Thus, we offset the reg pair numbers so they are distinct
204 // from all register numbers. Note that this increases the minimum size of a regPairNoSmall
205 // type due to the additional bits used for this offset.
206 #define REG_PAIR_FIRST (7 << REG_PAIR_NBITS)
207 #define REG_PAIR_NBITS_DEBUG \
209 3) // extra bits needed by the debug shifting (3 instead of 0 because we shift "7", not "1", above).
210 C_ASSERT(REG_COUNT < REG_PAIR_FIRST); // make sure the register numbers (including REG_NA, ignoring fp/xmm regs on
211 // x86/x64) are distinct from the pair numbers
213 #define REG_PAIR_FIRST 0
216 enum _regPairNo_enum : unsigned
218 #define PAIRDEF(rlo, rhi) REG_PAIR_##rlo##rhi = REG_##rlo + (REG_##rhi << REG_PAIR_NBITS) + REG_PAIR_FIRST,
221 REG_PAIR_LAST = (REG_COUNT - 1) + ((REG_COUNT - 1) << REG_PAIR_NBITS) + REG_PAIR_FIRST,
223 REG_PAIR_NONE = REG_PAIR_LAST + 1
228 #define PAIRDEF(rlo, rhi) RBM_PAIR_##rlo##rhi = (RBM_##rlo | RBM_##rhi),
232 /*****************************************************************************/
234 // TODO-Cleanup: The types defined below are mildly confusing: why are there both?
235 // regMaskSmall is large enough to represent the entire set of registers.
236 // If regMaskSmall is smaller than a "natural" integer type, regMaskTP is wider, based
237 // on a belief by the original authors of the JIT that in some situations it is more
238 // efficient to have the wider representation. This belief should be tested, and if it
239 // is false, then we should coalesce these two types into one (the Small width, probably).
240 // In any case, we believe that is OK to freely cast between these types; no information will
243 #ifdef _TARGET_ARMARCH_
244 typedef unsigned __int64 regMaskTP;
246 typedef unsigned regMaskTP;
249 #if REGMASK_BITS == 8
250 typedef unsigned char regMaskSmall;
251 #define REG_MASK_INT_FMT "%02X"
252 #define REG_MASK_ALL_FMT "%02X"
253 #elif REGMASK_BITS == 16
254 typedef unsigned short regMaskSmall;
255 #define REG_MASK_INT_FMT "%04X"
256 #define REG_MASK_ALL_FMT "%04X"
257 #elif REGMASK_BITS == 32
258 typedef unsigned regMaskSmall;
259 #define REG_MASK_INT_FMT "%08X"
260 #define REG_MASK_ALL_FMT "%08X"
262 typedef unsigned __int64 regMaskSmall;
263 #define REG_MASK_INT_FMT "%04llX"
264 #define REG_MASK_ALL_FMT "%016llX"
267 typedef _regNumber_enum regNumber;
268 typedef _regPairNo_enum regPairNo;
270 // LSRA currently converts freely between regNumber and regPairNo, so make sure they are the same size.
271 C_ASSERT(sizeof(regPairNo) == sizeof(regNumber));
273 typedef unsigned char regNumberSmall;
277 // Under DEBUG, we shift the reg pair numbers to be independent of the regNumber range,
278 // so we need additional bits. See the definition of REG_PAIR_FIRST for details.
280 #if ((2 * REG_PAIR_NBITS) + REG_PAIR_NBITS_DEBUG) <= 16
281 C_ASSERT(((2 * REG_PAIR_NBITS) + REG_PAIR_NBITS_DEBUG) > 8); // assert that nobody fits in 8 bits
282 typedef unsigned short regPairNoSmall; // x86/x64: need 15 bits
284 C_ASSERT(((2 * REG_PAIR_NBITS) + REG_PAIR_NBITS_DEBUG) <= 32);
285 typedef unsigned regPairNoSmall; // arm: need 21 bits
290 #if (2 * REG_PAIR_NBITS) <= 8
291 typedef unsigned char regPairNoSmall; // x86/x64: need 8 bits
293 C_ASSERT((2 * REG_PAIR_NBITS) <= 16); // assert that nobody needs more than 16 bits
294 typedef unsigned short regPairNoSmall; // arm: need 12 bits
299 /*****************************************************************************/
301 #define LEA_AVAILABLE 1
302 #define SCALED_ADDR_MODES 1
304 /*****************************************************************************/
307 #define DSP_SRC_OPER_LEFT 0
308 #define DSP_SRC_OPER_RIGHT 1
309 #define DSP_DST_OPER_LEFT 1
310 #define DSP_DST_OPER_RIGHT 0
313 /*****************************************************************************/
315 // The pseudorandom nop insertion is not necessary for current CoreCLR scenarios
316 // #if defined(FEATURE_CORECLR) && !defined(_TARGET_ARM_)
317 // #define PSEUDORANDOM_NOP_INSERTION
320 // TODO-Cleanup: FEATURE_PREVENT_BAD_BYREFS guards code that prevents creating byref pointers to array elements
321 // that are not "complete". That is, it only allows byref pointers to the exact array element, not to a portion
322 // of the address expression leading to the full addressing expression. This prevents the possibility of creating
323 // an illegal byref, which is an expression that points outside of the "host" object. Such bad byrefs won't get
324 // updated properly during a GC, leaving them to point to garbage. This led to a GC hole on ARM due to ARM's
325 // limited addressing modes (found in GCStress). The change is applicable and possibly desirable for other platforms,
326 // but was put under ifdef to avoid introducing potential destabilizing change to those platforms at the end of the
327 // .NET Core 2.1 ship cycle. More detail here: https://github.com/dotnet/coreclr/pull/17524. Consider making this
328 // all-platform and removing these #ifdefs.
329 #if defined(_TARGET_ARM_)
330 #define FEATURE_PREVENT_BAD_BYREFS 1
332 #define FEATURE_PREVENT_BAD_BYREFS 0
335 /*****************************************************************************/
338 #if defined(_TARGET_X86_)
340 #define CPU_LOAD_STORE_ARCH 0
342 #ifdef LEGACY_BACKEND
343 #define CPU_LONG_USES_REGPAIR 1
345 #define CPU_LONG_USES_REGPAIR 0 // RyuJIT x86 doesn't use the regPairNo field to record register pairs for long
346 // type tree nodes, and instead either decomposes them (for non-atomic operations)
347 // or stores multiple regNumber values for operations such as calls where the
348 // register definitions are effectively "atomic".
349 #endif // LEGACY_BACKEND
351 #define CPU_HAS_FP_SUPPORT 1
352 #define ROUND_FLOAT 1 // round intermed float expression results
353 #define CPU_HAS_BYTE_REGS 1
354 #define CPU_USES_BLOCK_MOVE 1
356 #ifndef LEGACY_BACKEND
357 // TODO-CQ: Fine tune the following xxBlk threshold values:
359 #define CPBLK_MOVS_LIMIT 16 // When generating code for CpBlk, this is the buffer size
360 // threshold to stop generating rep movs and switch to the helper call.
361 // NOTE: Using rep movs is currently disabled since we found it has bad performance
362 // on pre-Ivy Bridge hardware.
364 #define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk.
365 #define INITBLK_STOS_LIMIT 64 // When generating code for InitBlk, this is the buffer size
366 // NOTE: Using rep stos is currently disabled since we found it has bad performance
367 // on pre-Ivy Bridge hardware.
368 // threshold to stop generating rep movs and switch to the helper call.
369 #define INITBLK_UNROLL_LIMIT 128 // Upper bound to let the code generator to loop unroll InitBlk.
370 #define CPOBJ_NONGC_SLOTS_LIMIT 4 // For CpObj code generation, this is the the threshold of the number
371 // of contiguous non-gc slots that trigger generating rep movsq instead of
372 // sequences of movsq instructions
373 // The way we're currently disabling rep movs/stos is by setting a limit less than
374 // its unrolling counterparts. When lower takes the decision on which one to make it
375 // always asks for the unrolling limit first so you can say the JIT 'favors' unrolling.
376 // Setting the limit to something lower than that makes lower to never consider it.
378 #endif // !LEGACY_BACKEND
381 #define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned
382 #endif // FEATURE_SIMD
384 #define FEATURE_FIXED_OUT_ARGS 0 // X86 uses push instructions to pass args
385 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
386 #define FEATURE_MULTIREG_STRUCT_PROMOTE 0 // True when we want to promote fields of a multireg struct into registers
387 #define FEATURE_FASTTAILCALL 0 // Tail calls made as epilog+jmp
388 #define FEATURE_TAILCALL_OPT 0 // opportunistic Tail calls (without ".tail" prefix) made as fast tail calls.
389 #define FEATURE_SET_FLAGS 0 // Set to true to force the JIT to mark the trees with GTF_SET_FLAGS when
390 // the flags need to be set
391 #ifdef LEGACY_BACKEND
392 #define FEATURE_MULTIREG_ARGS_OR_RET 0 // Support for passing and/or returning single values in more than one register
393 #define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register
394 #define FEATURE_MULTIREG_RET 0 // Support for returning a single value in more than one register
395 #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments
396 #define MAX_RET_MULTIREG_BYTES 0 // No multireg return values
398 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
399 #define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register
400 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
401 #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments (note this seems wrong as MAX_ARG_REG_COUNT is 2)
402 #define MAX_RET_MULTIREG_BYTES 8 // Maximum size of a struct that could be returned in more than one register
405 #define MAX_ARG_REG_COUNT 2 // Maximum registers used to pass an argument.
406 #define MAX_RET_REG_COUNT 2 // Maximum registers used to return a value.
408 #ifdef FEATURE_USE_ASM_GC_WRITE_BARRIERS
409 #define NOGC_WRITE_BARRIERS 1 // We have specialized WriteBarrier JIT Helpers that DO-NOT trash the
410 // RBM_CALLEE_TRASH registers
412 #define NOGC_WRITE_BARRIERS 0 // Do not modify this -- modify the definition above. (If we're not using
413 // ASM barriers we definitely don't have NOGC barriers).
415 #define USER_ARGS_COME_LAST 0
416 #define EMIT_TRACK_STACK_DEPTH 1
417 #define TARGET_POINTER_SIZE 4 // equal to sizeof(void*) and the managed pointer size in bytes for this
419 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter,
420 // filter-handler, fault) and directly execute 'finally' clauses.
421 #if defined(FEATURE_PAL) && !defined(LEGACY_BACKEND)
422 #define FEATURE_EH_FUNCLETS 1
423 #else // FEATURE_PAL && !LEGACY_BACKEND
424 #define FEATURE_EH_FUNCLETS 0
425 #endif // FEATURE_PAL && !LEGACY_BACKEND
426 #define FEATURE_EH_CALLFINALLY_THUNKS 0 // Generate call-to-finally code in "thunks" in the enclosing EH region,
427 // protected by "cloned finally" clauses.
428 #ifndef LEGACY_BACKEND
429 #define FEATURE_STACK_FP_X87 0
430 #else // LEGACY_BACKEND
431 #define FEATURE_STACK_FP_X87 1 // Use flat register file model
432 #endif // LEGACY_BACKEND
433 #define FEATURE_X87_DOUBLES 0 // FP tree temps always use x87 doubles (when 1) or can be double or float
435 #define ETW_EBP_FRAMED 1 // if 1 we cannot use EBP as a scratch register and must create EBP based
436 // frames for most methods
437 #define CSE_CONSTS 1 // Enable if we want to CSE constants
439 #ifndef LEGACY_BACKEND
440 // The following defines are useful for iterating a regNumber
441 #define REG_FIRST REG_EAX
442 #define REG_INT_FIRST REG_EAX
443 #define REG_INT_LAST REG_EDI
444 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
445 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
446 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
448 #define REG_FP_FIRST REG_XMM0
449 #define REG_FP_LAST REG_XMM7
450 #define FIRST_FP_ARGREG REG_XMM0
451 #define LAST_FP_ARGREG REG_XMM3
452 #define REG_FLTARG_0 REG_XMM0
453 #define REG_FLTARG_1 REG_XMM1
454 #define REG_FLTARG_2 REG_XMM2
455 #define REG_FLTARG_3 REG_XMM3
457 #define RBM_FLTARG_0 RBM_XMM0
458 #define RBM_FLTARG_1 RBM_XMM1
459 #define RBM_FLTARG_2 RBM_XMM2
460 #define RBM_FLTARG_3 RBM_XMM3
462 #define RBM_FLTARG_REGS (RBM_FLTARG_0|RBM_FLTARG_1|RBM_FLTARG_2|RBM_FLTARG_3)
464 #define RBM_ALLFLOAT (RBM_XMM0 | RBM_XMM1 | RBM_XMM2 | RBM_XMM3 | RBM_XMM4 | RBM_XMM5 | RBM_XMM6 | RBM_XMM7)
465 #define RBM_ALLDOUBLE RBM_ALLFLOAT
467 // TODO-CQ: Currently we are following the x86 ABI for SSE2 registers.
468 // This should be reconsidered.
469 #define RBM_FLT_CALLEE_SAVED RBM_NONE
470 #define RBM_FLT_CALLEE_TRASH RBM_ALLFLOAT
471 #define REG_VAR_ORDER_FLT REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3, REG_XMM4, REG_XMM5, REG_XMM6, REG_XMM7
473 #define REG_FLT_CALLEE_SAVED_FIRST REG_XMM6
474 #define REG_FLT_CALLEE_SAVED_LAST REG_XMM7
476 #define XMM_REGSIZE_BYTES 16 // XMM register size in bytes
477 #define YMM_REGSIZE_BYTES 32 // YMM register size in bytes
479 #define REGNUM_BITS 6 // number of bits in a REG_*
480 #define TINY_REGNUM_BITS 6 // number used in a tiny instrdesc (same)
482 #else // LEGACY_BACKEND
483 #define FEATURE_FP_REGALLOC 0 // Enabled if RegAlloc is used to enregister Floating Point LclVars
485 #define FP_STK_SIZE 8
486 #define RBM_ALLFLOAT (RBM_FPV0 | RBM_FPV1 | RBM_FPV2 | RBM_FPV3 | RBM_FPV4 | RBM_FPV5 | RBM_FPV6)
487 #define REG_FP_FIRST REG_FPV0
488 #define REG_FP_LAST REG_FPV7
489 #define FIRST_FP_ARGREG REG_NA
490 #define LAST_FP_ARGREG REG_NA
493 #define REGNUM_BITS 3 // number of bits in a REG_*
494 #define TINY_REGNUM_BITS 3
495 #define REGMASK_BITS 8 // number of bits in a REGNUM_MASK
497 #define RBM_FLTARG_REGS 0
498 #define RBM_FLT_CALLEE_SAVED 0
499 #define RBM_FLT_CALLEE_TRASH 0
501 #endif // LEGACY_BACKEND
503 #define REGSIZE_BYTES 4 // number of bytes in one register
504 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
506 #define CODE_ALIGN 1 // code alignment requirement
507 #if !defined(UNIX_X86_ABI)
508 #define STACK_ALIGN 4 // stack alignment requirement
509 #define STACK_ALIGN_SHIFT 2 // Shift-right amount to convert stack size in bytes to size in DWORD_PTRs
510 #define STACK_ALIGN_SHIFT_ALL 2 // Shift-right amount to convert stack size in bytes to size in STACK_ALIGN units
512 #define STACK_ALIGN 16 // stack alignment requirement
513 #define STACK_ALIGN_SHIFT 4 // Shift-right amount to convert stack size in bytes to size in DWORD_PTRs
514 #define STACK_ALIGN_SHIFT_ALL 4 // Shift-right amount to convert stack size in bytes to size in STACK_ALIGN units
515 #endif // !UNIX_X86_ABI
517 #define RBM_INT_CALLEE_SAVED (RBM_EBX|RBM_ESI|RBM_EDI)
518 #define RBM_INT_CALLEE_TRASH (RBM_EAX|RBM_ECX|RBM_EDX)
520 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
521 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
523 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
525 #define REG_VAR_ORDER REG_EAX,REG_EDX,REG_ECX,REG_ESI,REG_EDI,REG_EBX
526 #define MAX_VAR_ORDER_SIZE 6
528 #ifdef LEGACY_BACKEND
529 #define REG_TMP_ORDER REG_EAX,REG_EDX,REG_ECX,REG_EBX,REG_ESI,REG_EDI
530 #define REG_TMP_ORDER_COUNT 6
532 #define REG_PREDICT_ORDER REG_EAX,REG_EDX,REG_ECX,REG_EBX,REG_ESI,REG_EDI
533 #endif // LEGACY_BACKEND
535 // The order here is fixed: it must agree with an order assumed in eetwain...
536 #define REG_CALLEE_SAVED_ORDER REG_EDI,REG_ESI,REG_EBX,REG_EBP
537 #define RBM_CALLEE_SAVED_ORDER RBM_EDI,RBM_ESI,RBM_EBX,RBM_EBP
539 #define CNT_CALLEE_SAVED (4)
540 #define CNT_CALLEE_TRASH (3)
541 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
543 #define CNT_CALLEE_SAVED_FLOAT (0)
544 #define CNT_CALLEE_TRASH_FLOAT (6)
546 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED*REGSIZE_BYTES) // EBX,ESI,EDI,EBP
548 // We reuse the ESP register as a illegal value in the register predictor
549 #define RBM_ILLEGAL RBM_ESP
550 // We reuse the ESP register as a flag for last use handling in the register predictor
551 #define RBM_LASTUSE RBM_ESP
552 // We're using the encoding for ESP to indicate a half-long on the frame
553 #define REG_L_STK REG_ESP
555 // This is the first register in REG_TMP_ORDER
556 #define REG_TMP_0 REG_EAX
557 #define RBM_TMP_0 RBM_EAX
559 // This is the second register in REG_TMP_ORDER
560 #define REG_TMP_1 REG_EDX
561 #define RBM_TMP_1 RBM_EDX
563 #define REG_PAIR_TMP REG_PAIR_EAXEDX
564 #define REG_PAIR_TMP_REVERSE REG_PAIR_EDXEAX
565 #define RBM_PAIR_TMP (RBM_EAX|RBM_EDX)
566 #define REG_PAIR_TMP_LO REG_EAX
567 #define RBM_PAIR_TMP_LO RBM_EAX
568 #define REG_PAIR_TMP_HI REG_EDX
569 #define RBM_PAIR_TMP_HI RBM_EDX
570 #define PREDICT_PAIR_TMP PREDICT_PAIR_EAXEDX
571 #define PREDICT_PAIR_TMP_LO PREDICT_REG_EAX
573 // Used when calling the 64-bit Variable shift helper
574 #define REG_LNGARG_0 REG_PAIR_EAXEDX
575 #define RBM_LNGARG_0 (RBM_EAX|RBM_EDX)
576 #define PREDICT_PAIR_LNGARG_0 PREDICT_PAIR_EAXEDX
578 #define REG_LNGARG_LO REG_EAX
579 #define RBM_LNGARG_LO RBM_EAX
580 #define REG_LNGARG_HI REG_EDX
581 #define RBM_LNGARG_HI RBM_EDX
582 // register to hold shift amount
583 #define REG_SHIFT REG_ECX
584 #define RBM_SHIFT RBM_ECX
585 #define PREDICT_REG_SHIFT PREDICT_REG_ECX
587 // register to hold shift amount when shifting 64-bit values
588 #define REG_SHIFT_LNG REG_ECX
589 #define RBM_SHIFT_LNG RBM_ECX
590 #define PREDICT_REG_SHIFT_LNG PREDICT_REG_ECX
592 // This is a general scratch register that does not conflict with the argument registers
593 #define REG_SCRATCH REG_EAX
594 #define RBM_SCRATCH RBM_EAX
596 // Where is the exception object on entry to the handler block?
597 #define REG_EXCEPTION_OBJECT REG_EAX
598 #define RBM_EXCEPTION_OBJECT RBM_EAX
600 // Only used on ARM for GTF_CALL_M_VIRTSTUB_REL_INDIRECT
601 #define REG_JUMP_THUNK_PARAM REG_EAX
602 #define RBM_JUMP_THUNK_PARAM RBM_EAX
604 #if NOGC_WRITE_BARRIERS
605 #define REG_WRITE_BARRIER REG_EDX
606 #define RBM_WRITE_BARRIER RBM_EDX
608 // 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).
609 #define RBM_WRITE_BARRIER_SRC (RBM_EAX|RBM_ECX|RBM_EBX|RBM_ESI|RBM_EDI)
611 #define RBM_CALLEE_TRASH_NOGC RBM_EDX
612 #endif // NOGC_WRITE_BARRIERS
614 // GenericPInvokeCalliHelper unmanaged target parameter
615 #define REG_PINVOKE_TARGET_PARAM REG_EAX
616 #define RBM_PINVOKE_TARGET_PARAM RBM_EAX
618 // GenericPInvokeCalliHelper cookie parameter
619 #define REG_PINVOKE_COOKIE_PARAM REG_STK
621 // IL stub's secret parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
622 #define REG_SECRET_STUB_PARAM REG_EAX
623 #define RBM_SECRET_STUB_PARAM RBM_EAX
625 // VSD target address register
626 #define REG_VIRTUAL_STUB_TARGET REG_EAX
627 #define RBM_VIRTUAL_STUB_TARGET RBM_EAX
629 // Registers used by PInvoke frame setup
630 #define REG_PINVOKE_FRAME REG_EDI // EDI is p/invoke "Frame" pointer argument to CORINFO_HELP_INIT_PINVOKE_FRAME helper
631 #define RBM_PINVOKE_FRAME RBM_EDI
632 #define REG_PINVOKE_TCB REG_ESI // ESI is set to Thread Control Block (TCB) on return from
633 // CORINFO_HELP_INIT_PINVOKE_FRAME helper
634 #define RBM_PINVOKE_TCB RBM_ESI
635 #define REG_PINVOKE_SCRATCH REG_EAX // EAX is trashed by CORINFO_HELP_INIT_PINVOKE_FRAME helper
636 #define RBM_PINVOKE_SCRATCH RBM_EAX
638 #ifdef LEGACY_BACKEND
639 #define REG_SPILL_CHOICE REG_EAX
640 #define RBM_SPILL_CHOICE RBM_EAX
641 #endif // LEGACY_BACKEND
643 // The following defines are useful for iterating a regNumber
644 #define REG_FIRST REG_EAX
645 #define REG_INT_FIRST REG_EAX
646 #define REG_INT_LAST REG_EDI
647 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
648 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
649 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
651 // genCodeForCall() moves the target address of the tailcall into this register, before pushing it on the stack
652 #define REG_TAILCALL_ADDR REG_EAX
654 // Which register are int and long values returned in ?
655 #define REG_INTRET REG_EAX
656 #define RBM_INTRET RBM_EAX
657 #define REG_LNGRET REG_PAIR_EAXEDX
658 #define RBM_LNGRET (RBM_EDX|RBM_EAX)
659 #define REG_LNGRET_LO REG_EAX
660 #define RBM_LNGRET_LO RBM_EAX
661 #define REG_LNGRET_HI REG_EDX
662 #define RBM_LNGRET_HI RBM_EDX
664 #define REG_FLOATRET REG_NA
665 #define RBM_FLOATRET RBM_NONE
666 #define RBM_DOUBLERET RBM_NONE
668 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper
669 #define RBM_STOP_FOR_GC_TRASH RBM_CALLEE_TRASH
671 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper. On x86, this helper has a custom calling
672 // convention that takes EDI as argument (but doesn't trash it), trashes EAX, and returns ESI.
673 #define RBM_INIT_PINVOKE_FRAME_TRASH (RBM_PINVOKE_SCRATCH | RBM_PINVOKE_TCB)
675 #define REG_FPBASE REG_EBP
676 #define RBM_FPBASE RBM_EBP
677 #define STR_FPBASE "ebp"
678 #define REG_SPBASE REG_ESP
679 #define RBM_SPBASE RBM_ESP
680 #define STR_SPBASE "esp"
682 #define FIRST_ARG_STACK_OFFS (2*REGSIZE_BYTES) // Caller's saved EBP and return address
684 #define MAX_REG_ARG 2
685 #define MAX_FLOAT_REG_ARG 0
686 #define REG_ARG_FIRST REG_ECX
687 #define REG_ARG_LAST REG_EDX
688 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
690 #define REG_ARG_0 REG_ECX
691 #define REG_ARG_1 REG_EDX
693 SELECTANY const regNumber intArgRegs [] = {REG_ECX, REG_EDX};
694 SELECTANY const regMaskTP intArgMasks[] = {RBM_ECX, RBM_EDX};
695 #if !FEATURE_STACK_FP_X87
696 SELECTANY const regNumber fltArgRegs [] = {REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3};
697 SELECTANY const regMaskTP fltArgMasks[] = {RBM_XMM0, RBM_XMM1, RBM_XMM2, RBM_XMM3};
698 #endif // FEATURE_STACK_FP_X87
700 #define RBM_ARG_0 RBM_ECX
701 #define RBM_ARG_1 RBM_EDX
703 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1)
705 // The registers trashed by profiler enter/leave/tailcall hook
706 // See vm\i386\asmhelpers.asm for more details.
707 #define RBM_PROFILER_ENTER_TRASH RBM_NONE
708 #define RBM_PROFILER_LEAVE_TRASH RBM_NONE
709 #define RBM_PROFILER_TAILCALL_TRASH (RBM_ALLINT & ~RBM_ARG_REGS)
711 // What sort of reloc do we use for [disp32] address mode
712 #define IMAGE_REL_BASED_DISP32 IMAGE_REL_BASED_HIGHLOW
714 // What sort of reloc to we use for 'moffset' address mode (for 'mov eax, moffset' or 'mov moffset, eax')
715 #define IMAGE_REL_BASED_MOFFSET IMAGE_REL_BASED_HIGHLOW
717 // Pointer-sized string move instructions
718 #define INS_movsp INS_movsd
719 #define INS_r_movsp INS_r_movsd
720 #define INS_stosp INS_stosd
721 #define INS_r_stosp INS_r_stosd
723 #elif defined(_TARGET_AMD64_)
724 // TODO-AMD64-CQ: Fine tune the following xxBlk threshold values:
726 #define CPU_LOAD_STORE_ARCH 0
727 #define CPU_LONG_USES_REGPAIR 0
728 #define CPU_HAS_FP_SUPPORT 1
729 #define ROUND_FLOAT 0 // Do not round intermed float expression results
730 #define CPU_HAS_BYTE_REGS 0
731 #define CPU_USES_BLOCK_MOVE 1
733 #define CPBLK_MOVS_LIMIT 16 // When generating code for CpBlk, this is the buffer size
734 // threshold to stop generating rep movs and switch to the helper call.
735 // NOTE: Using rep movs is currently disabled since we found it has bad performance
736 // on pre-Ivy Bridge hardware.
738 #define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk.
739 #define INITBLK_STOS_LIMIT 64 // When generating code for InitBlk, this is the buffer size
740 // NOTE: Using rep stos is currently disabled since we found it has bad performance
741 // on pre-Ivy Bridge hardware.
742 // threshold to stop generating rep movs and switch to the helper call.
743 #define INITBLK_UNROLL_LIMIT 128 // Upper bound to let the code generator to loop unroll InitBlk.
744 #define CPOBJ_NONGC_SLOTS_LIMIT 4 // For CpObj code generation, this is the the threshold of the number
745 // of contiguous non-gc slots that trigger generating rep movsq instead of
746 // sequences of movsq instructions
748 // The way we're currently disabling rep movs/stos is by setting a limit less than
749 // its unrolling counterparts. When lower takes the decision on which one to make it
750 // always asks for the unrolling limit first so you can say the JIT 'favors' unrolling.
751 // Setting the limit to something lower than that makes lower to never consider it.
755 #define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned
756 #if defined(UNIX_AMD64_ABI)
757 #define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 0 // Whether SIMD registers are partially saved at calls
758 #else // !UNIX_AMD64_ABI
759 #define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 1 // Whether SIMD registers are partially saved at calls
760 #endif // !UNIX_AMD64_ABI
762 #define FEATURE_FIXED_OUT_ARGS 1 // Preallocate the outgoing arg area in the prolog
763 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
764 #define FEATURE_MULTIREG_STRUCT_PROMOTE 0 // True when we want to promote fields of a multireg struct into registers
765 #define FEATURE_FASTTAILCALL 1 // Tail calls made as epilog+jmp
766 #define FEATURE_TAILCALL_OPT 1 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
767 #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
768 #ifdef UNIX_AMD64_ABI
769 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
770 #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register
771 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
772 #define FEATURE_STRUCT_CLASSIFIER 1 // Uses a classifier function to determine if structs are passed/returned in more than one register
773 #define MAX_PASS_MULTIREG_BYTES 32 // Maximum size of a struct that could be passed in more than one register (Max is two SIMD16s)
774 #define MAX_RET_MULTIREG_BYTES 32 // Maximum size of a struct that could be returned in more than one register (Max is two SIMD16s)
775 #define MAX_ARG_REG_COUNT 2 // Maximum registers used to pass a single argument in multiple registers.
776 #define MAX_RET_REG_COUNT 2 // Maximum registers used to return a value.
777 #else // !UNIX_AMD64_ABI
778 #define WINDOWS_AMD64_ABI // Uses the Windows ABI for AMD64
779 #define FEATURE_MULTIREG_ARGS_OR_RET 0 // Support for passing and/or returning single values in more than one register
780 #define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register
781 #define FEATURE_MULTIREG_RET 0 // Support for returning a single value in more than one register
782 #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments
783 #define MAX_RET_MULTIREG_BYTES 0 // No multireg return values
784 #define MAX_ARG_REG_COUNT 1 // Maximum registers used to pass a single argument (no arguments are passed using multiple registers)
785 #define MAX_RET_REG_COUNT 1 // Maximum registers used to return a value.
786 #endif // !UNIX_AMD64_ABI
788 #define NOGC_WRITE_BARRIERS 0 // We DO-NOT have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers
789 #define USER_ARGS_COME_LAST 1
790 #define EMIT_TRACK_STACK_DEPTH 1
791 #define TARGET_POINTER_SIZE 8 // equal to sizeof(void*) and the managed pointer size in bytes for this target
792 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter, filter-handler, fault) and directly execute 'finally' clauses.
793 #define FEATURE_EH_FUNCLETS 1
794 #define FEATURE_EH_CALLFINALLY_THUNKS 1 // Generate call-to-finally code in "thunks" in the enclosing EH region, protected by "cloned finally" clauses.
795 #define FEATURE_STACK_FP_X87 0
796 #ifdef UNIX_AMD64_ABI
797 #define ETW_EBP_FRAMED 1 // if 1 we cannot use EBP as a scratch register and must create EBP based frames for most methods
798 #else // !UNIX_AMD64_ABI
799 #define ETW_EBP_FRAMED 0 // if 1 we cannot use EBP as a scratch register and must create EBP based frames for most methods
800 #endif // !UNIX_AMD64_ABI
801 #define FEATURE_FP_REGALLOC 0 // Enabled if RegAlloc is used to enregister Floating Point LclVars
802 #define CSE_CONSTS 1 // Enable if we want to CSE constants
804 #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)
805 #define RBM_ALLDOUBLE RBM_ALLFLOAT
806 #define REG_FP_FIRST REG_XMM0
807 #define REG_FP_LAST REG_XMM15
808 #define FIRST_FP_ARGREG REG_XMM0
810 #ifdef UNIX_AMD64_ABI
811 #define LAST_FP_ARGREG REG_XMM7
812 #else // !UNIX_AMD64_ABI
813 #define LAST_FP_ARGREG REG_XMM3
814 #endif // !UNIX_AMD64_ABI
816 #define REGNUM_BITS 6 // number of bits in a REG_*
817 #define TINY_REGNUM_BITS 6 // number used in a tiny instrdesc (same)
818 #define REGMASK_BITS 32 // number of bits in a REGNUM_MASK
819 #define REGSIZE_BYTES 8 // number of bytes in one register
820 #define XMM_REGSIZE_BYTES 16 // XMM register size in bytes
821 #define YMM_REGSIZE_BYTES 32 // YMM register size in bytes
823 #define CODE_ALIGN 1 // code alignment requirement
824 #define STACK_ALIGN 16 // stack alignment requirement
825 #define STACK_ALIGN_SHIFT 3 // Shift-right amount to convert stack size in bytes to size in pointer sized words
826 #define STACK_ALIGN_SHIFT_ALL 4 // Shift-right amount to convert stack size in bytes to size in STACK_ALIGN units
829 #define RBM_ETW_FRAMED_EBP RBM_NONE
830 #define RBM_ETW_FRAMED_EBP_LIST
831 #define REG_ETW_FRAMED_EBP_LIST
832 #define REG_ETW_FRAMED_EBP_COUNT 0
833 #else // !ETW_EBP_FRAMED
834 #define RBM_ETW_FRAMED_EBP RBM_EBP
835 #define RBM_ETW_FRAMED_EBP_LIST RBM_EBP,
836 #define REG_ETW_FRAMED_EBP_LIST REG_EBP,
837 #define REG_ETW_FRAMED_EBP_COUNT 1
838 #endif // !ETW_EBP_FRAMED
840 #ifdef UNIX_AMD64_ABI
841 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
843 #define RBM_INT_CALLEE_SAVED (RBM_EBX|RBM_ETW_FRAMED_EBP|RBM_R12|RBM_R13|RBM_R14|RBM_R15)
844 #define RBM_INT_CALLEE_TRASH (RBM_EAX|RBM_RDI|RBM_RSI|RBM_EDX|RBM_ECX|RBM_R8|RBM_R9|RBM_R10|RBM_R11)
845 #define RBM_FLT_CALLEE_SAVED (0)
846 #define RBM_FLT_CALLEE_TRASH (RBM_XMM0|RBM_XMM1|RBM_XMM2|RBM_XMM3|RBM_XMM4|RBM_XMM5|RBM_XMM6|RBM_XMM7| \
847 RBM_XMM8|RBM_XMM9|RBM_XMM10|RBM_XMM11|RBM_XMM12|RBM_XMM13|RBM_XMM14|RBM_XMM15)
848 #define REG_PROFILER_ENTER_ARG_0 REG_R14
849 #define RBM_PROFILER_ENTER_ARG_0 RBM_R14
850 #define REG_PROFILER_ENTER_ARG_1 REG_R15
851 #define RBM_PROFILER_ENTER_ARG_1 RBM_R15
853 #define REG_DEFAULT_PROFILER_CALL_TARGET REG_R11
855 #else // !UNIX_AMD64_ABI
856 #define MIN_ARG_AREA_FOR_CALL (4 * REGSIZE_BYTES) // Minimum required outgoing argument space for a call.
858 #define RBM_INT_CALLEE_SAVED (RBM_EBX|RBM_ESI|RBM_EDI|RBM_ETW_FRAMED_EBP|RBM_R12|RBM_R13|RBM_R14|RBM_R15)
859 #define RBM_INT_CALLEE_TRASH (RBM_EAX|RBM_ECX|RBM_EDX|RBM_R8|RBM_R9|RBM_R10|RBM_R11)
860 #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)
861 #define RBM_FLT_CALLEE_TRASH (RBM_XMM0|RBM_XMM1|RBM_XMM2|RBM_XMM3|RBM_XMM4|RBM_XMM5)
862 #endif // !UNIX_AMD64_ABI
864 #define REG_FLT_CALLEE_SAVED_FIRST REG_XMM6
865 #define REG_FLT_CALLEE_SAVED_LAST REG_XMM15
867 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
868 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
870 #define RBM_CALLEE_TRASH_NOGC RBM_CALLEE_TRASH
872 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
875 #define REG_VAR_ORDER REG_EAX,REG_EDX,REG_ECX,REG_ESI,REG_EDI,REG_EBX,REG_ETW_FRAMED_EBP_LIST \
876 REG_R8,REG_R9,REG_R10,REG_R11,REG_R14,REG_R15,REG_R12,REG_R13
878 // TEMPORARY ORDER TO AVOID CALLEE-SAVES
879 // TODO-CQ: Review this and set appropriately
880 #ifdef UNIX_AMD64_ABI
881 #define REG_VAR_ORDER REG_EAX,REG_EDI,REG_ESI, \
882 REG_EDX,REG_ECX,REG_R8,REG_R9, \
883 REG_R10,REG_R11,REG_EBX,REG_ETW_FRAMED_EBP_LIST \
884 REG_R14,REG_R15,REG_R12,REG_R13
885 #else // !UNIX_AMD64_ABI
886 #define REG_VAR_ORDER REG_EAX,REG_EDX,REG_ECX, \
887 REG_R8,REG_R9,REG_R10,REG_R11, \
888 REG_ESI,REG_EDI,REG_EBX,REG_ETW_FRAMED_EBP_LIST \
889 REG_R14,REG_R15,REG_R12,REG_R13
890 #endif // !UNIX_AMD64_ABI
893 #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
895 #ifdef UNIX_AMD64_ABI
896 #define CNT_CALLEE_SAVED (5 + REG_ETW_FRAMED_EBP_COUNT)
897 #define CNT_CALLEE_TRASH (9)
898 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED)
900 #define CNT_CALLEE_SAVED_FLOAT (0)
901 #define CNT_CALLEE_TRASH_FLOAT (16)
903 #define REG_CALLEE_SAVED_ORDER REG_EBX,REG_ETW_FRAMED_EBP_LIST REG_R12,REG_R13,REG_R14,REG_R15
904 #define RBM_CALLEE_SAVED_ORDER RBM_EBX,RBM_ETW_FRAMED_EBP_LIST RBM_R12,RBM_R13,RBM_R14,RBM_R15
905 #else // !UNIX_AMD64_ABI
906 #define CNT_CALLEE_SAVED (7 + REG_ETW_FRAMED_EBP_COUNT)
907 #define CNT_CALLEE_TRASH (7)
908 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED)
910 #define CNT_CALLEE_SAVED_FLOAT (10)
911 #define CNT_CALLEE_TRASH_FLOAT (6)
913 #define REG_CALLEE_SAVED_ORDER REG_EBX,REG_ESI,REG_EDI,REG_ETW_FRAMED_EBP_LIST REG_R12,REG_R13,REG_R14,REG_R15
914 #define RBM_CALLEE_SAVED_ORDER RBM_EBX,RBM_ESI,RBM_EDI,RBM_ETW_FRAMED_EBP_LIST RBM_R12,RBM_R13,RBM_R14,RBM_R15
915 #endif // !UNIX_AMD64_ABI
917 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED*REGSIZE_BYTES)
918 #define CALLEE_SAVED_FLOAT_MAXSZ (CNT_CALLEE_SAVED_FLOAT*16)
920 // We reuse the ESP register as a illegal value in the register predictor
921 #define RBM_ILLEGAL RBM_ESP
922 // We reuse the ESP register as a flag for last use handling in the register predictor
923 #define RBM_LASTUSE RBM_ESP
924 // We're using the encoding for ESP to indicate a half-long on the frame
925 #define REG_L_STK REG_ESP
927 // This is the first register in REG_TMP_ORDER
928 #define REG_TMP_0 REG_EAX
929 #define RBM_TMP_0 RBM_EAX
931 // This is the second register in REG_TMP_ORDER
932 #ifdef UNIX_AMD64_ABI
933 #define REG_TMP_1 REG_EDI
934 #define RBM_TMP_1 RBM_EDI
935 #else // !UNIX_AMD64_ABI
936 #define REG_TMP_1 REG_EDX
937 #define RBM_TMP_1 RBM_EDX
938 #endif // !UNIX_AMD64_ABI
939 #define REG_PAIR_TMP REG_PAIR_EAXEDX
940 #define RBM_PAIR_TMP (RBM_EAX|RBM_EDX)
941 #define REG_PAIR_TMP_LO REG_EAX
942 #define RBM_PAIR_TMP_LO RBM_EAX
943 #define REG_PAIR_TMP_HI REG_EDX
944 #define RBM_PAIR_TMP_HI RBM_EDX
945 #define PREDICT_PAIR_TMP PREDICT_PAIR_RAXRDX
946 #define PREDICT_PAIR_TMP_LO PREDICT_REG_EAX
948 // register to hold shift amount
949 #define REG_SHIFT REG_ECX
950 #define RBM_SHIFT RBM_ECX
951 #define PREDICT_REG_SHIFT PREDICT_REG_ECX
953 // This is a general scratch register that does not conflict with the argument registers
954 #define REG_SCRATCH REG_EAX
955 #define RBM_SCRATCH RBM_EAX
957 // Where is the exception object on entry to the handler block?
958 #ifdef UNIX_AMD64_ABI
959 #define REG_EXCEPTION_OBJECT REG_ESI
960 #define RBM_EXCEPTION_OBJECT RBM_ESI
961 #else // !UNIX_AMD64_ABI
962 #define REG_EXCEPTION_OBJECT REG_EDX
963 #define RBM_EXCEPTION_OBJECT RBM_EDX
964 #endif // !UNIX_AMD64_ABI
966 #define REG_JUMP_THUNK_PARAM REG_EAX
967 #define RBM_JUMP_THUNK_PARAM RBM_EAX
969 // Register to be used for emitting helper calls whose call target is an indir of an
970 // absolute memory address in case of Rel32 overflow i.e. a data address could not be
971 // encoded as PC-relative 32-bit offset.
974 // 1) that RAX is callee trash register that is not used for passing parameter and
975 // also results in smaller instruction encoding.
976 // 2) Profiler Leave callback requires the return value to be preserved
977 // in some form. We can use custom calling convention for Leave callback.
978 // For e.g return value could be preserved in rcx so that it is available for
980 #define REG_DEFAULT_HELPER_CALL_TARGET REG_RAX
981 #define RBM_DEFAULT_HELPER_CALL_TARGET RBM_RAX
983 // GenericPInvokeCalliHelper VASigCookie Parameter
984 #define REG_PINVOKE_COOKIE_PARAM REG_R11
985 #define RBM_PINVOKE_COOKIE_PARAM RBM_R11
987 // GenericPInvokeCalliHelper unmanaged target Parameter
988 #define REG_PINVOKE_TARGET_PARAM REG_R10
989 #define RBM_PINVOKE_TARGET_PARAM RBM_R10
991 // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
992 #define REG_SECRET_STUB_PARAM REG_R10
993 #define RBM_SECRET_STUB_PARAM RBM_R10
995 // Registers used by PInvoke frame setup
996 #define REG_PINVOKE_FRAME REG_EDI
997 #define RBM_PINVOKE_FRAME RBM_EDI
998 #define REG_PINVOKE_TCB REG_EAX
999 #define RBM_PINVOKE_TCB RBM_EAX
1000 #define REG_PINVOKE_SCRATCH REG_EAX
1001 #define RBM_PINVOKE_SCRATCH RBM_EAX
1003 // The following defines are useful for iterating a regNumber
1004 #define REG_FIRST REG_EAX
1005 #define REG_INT_FIRST REG_EAX
1006 #define REG_INT_LAST REG_R15
1007 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
1008 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
1009 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
1011 // genCodeForCall() moves the target address of the tailcall into this register, before pushing it on the stack
1012 #define REG_TAILCALL_ADDR REG_RDX
1014 // Which register are int and long values returned in ?
1015 #define REG_INTRET REG_EAX
1016 #define RBM_INTRET RBM_EAX
1018 #define REG_LNGRET REG_EAX
1019 #define RBM_LNGRET RBM_EAX
1021 #ifdef UNIX_AMD64_ABI
1022 #define REG_INTRET_1 REG_RDX
1023 #define RBM_INTRET_1 RBM_RDX
1025 #define REG_LNGRET_1 REG_RDX
1026 #define RBM_LNGRET_1 RBM_RDX
1027 #endif // UNIX_AMD64_ABI
1030 #define REG_FLOATRET REG_XMM0
1031 #define RBM_FLOATRET RBM_XMM0
1032 #define REG_DOUBLERET REG_XMM0
1033 #define RBM_DOUBLERET RBM_XMM0
1035 #ifdef UNIX_AMD64_ABI
1036 #define REG_FLOATRET_1 REG_XMM1
1037 #define RBM_FLOATRET_1 RBM_XMM1
1039 #define REG_DOUBLERET_1 REG_XMM1
1040 #define RBM_DOUBLERET_1 RBM_XMM1
1041 #endif // UNIX_AMD64_ABI
1043 #define REG_FPBASE REG_EBP
1044 #define RBM_FPBASE RBM_EBP
1045 #define STR_FPBASE "rbp"
1046 #define REG_SPBASE REG_ESP
1047 #define RBM_SPBASE RBM_ESP
1048 #define STR_SPBASE "rsp"
1050 #define FIRST_ARG_STACK_OFFS (REGSIZE_BYTES) // return address
1052 #ifdef UNIX_AMD64_ABI
1053 #define MAX_REG_ARG 6
1054 #define MAX_FLOAT_REG_ARG 8
1055 #define REG_ARG_FIRST REG_EDI
1056 #define REG_ARG_LAST REG_R9
1057 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
1059 #define REG_ARG_0 REG_EDI
1060 #define REG_ARG_1 REG_ESI
1061 #define REG_ARG_2 REG_EDX
1062 #define REG_ARG_3 REG_ECX
1063 #define REG_ARG_4 REG_R8
1064 #define REG_ARG_5 REG_R9
1066 SELECTANY const regNumber intArgRegs [] = { REG_EDI, REG_ESI, REG_EDX, REG_ECX, REG_R8, REG_R9 };
1067 SELECTANY const regMaskTP intArgMasks[] = { RBM_EDI, RBM_ESI, RBM_EDX, RBM_ECX, RBM_R8, RBM_R9 };
1068 SELECTANY const regNumber fltArgRegs [] = { REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3, REG_XMM4, REG_XMM5, REG_XMM6, REG_XMM7 };
1069 SELECTANY const regMaskTP fltArgMasks[] = { RBM_XMM0, RBM_XMM1, RBM_XMM2, RBM_XMM3, RBM_XMM4, RBM_XMM5, RBM_XMM6, RBM_XMM7 };
1071 #define RBM_ARG_0 RBM_RDI
1072 #define RBM_ARG_1 RBM_RSI
1073 #define RBM_ARG_2 RBM_EDX
1074 #define RBM_ARG_3 RBM_ECX
1075 #define RBM_ARG_4 RBM_R8
1076 #define RBM_ARG_5 RBM_R9
1077 #else // !UNIX_AMD64_ABI
1078 #define MAX_REG_ARG 4
1079 #define MAX_FLOAT_REG_ARG 4
1080 #define REG_ARG_FIRST REG_ECX
1081 #define REG_ARG_LAST REG_R9
1082 #define INIT_ARG_STACK_SLOT 4 // 4 outgoing reserved stack slots
1084 #define REG_ARG_0 REG_ECX
1085 #define REG_ARG_1 REG_EDX
1086 #define REG_ARG_2 REG_R8
1087 #define REG_ARG_3 REG_R9
1089 SELECTANY const regNumber intArgRegs [] = { REG_ECX, REG_EDX, REG_R8, REG_R9 };
1090 SELECTANY const regMaskTP intArgMasks[] = { RBM_ECX, RBM_EDX, RBM_R8, RBM_R9 };
1091 SELECTANY const regNumber fltArgRegs [] = { REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3 };
1092 SELECTANY const regMaskTP fltArgMasks[] = { RBM_XMM0, RBM_XMM1, RBM_XMM2, RBM_XMM3 };
1094 #define RBM_ARG_0 RBM_ECX
1095 #define RBM_ARG_1 RBM_EDX
1096 #define RBM_ARG_2 RBM_R8
1097 #define RBM_ARG_3 RBM_R9
1098 #endif // !UNIX_AMD64_ABI
1100 #define REG_FLTARG_0 REG_XMM0
1101 #define REG_FLTARG_1 REG_XMM1
1102 #define REG_FLTARG_2 REG_XMM2
1103 #define REG_FLTARG_3 REG_XMM3
1105 #define RBM_FLTARG_0 RBM_XMM0
1106 #define RBM_FLTARG_1 RBM_XMM1
1107 #define RBM_FLTARG_2 RBM_XMM2
1108 #define RBM_FLTARG_3 RBM_XMM3
1110 #ifdef UNIX_AMD64_ABI
1111 #define REG_FLTARG_4 REG_XMM4
1112 #define REG_FLTARG_5 REG_XMM5
1113 #define REG_FLTARG_6 REG_XMM6
1114 #define REG_FLTARG_7 REG_XMM7
1116 #define RBM_FLTARG_4 RBM_XMM4
1117 #define RBM_FLTARG_5 RBM_XMM5
1118 #define RBM_FLTARG_6 RBM_XMM6
1119 #define RBM_FLTARG_7 RBM_XMM7
1121 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1|RBM_ARG_2|RBM_ARG_3|RBM_ARG_4|RBM_ARG_5)
1122 #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)
1123 #else // !UNIX_AMD64_ABI
1124 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1|RBM_ARG_2|RBM_ARG_3)
1125 #define RBM_FLTARG_REGS (RBM_FLTARG_0|RBM_FLTARG_1|RBM_FLTARG_2|RBM_FLTARG_3)
1126 #endif // !UNIX_AMD64_ABI
1128 // The registers trashed by profiler enter/leave/tailcall hook
1129 // See vm\amd64\asmhelpers.asm for more details.
1130 #define RBM_PROFILER_ENTER_TRASH RBM_CALLEE_TRASH
1131 #define RBM_PROFILER_LEAVE_TRASH (RBM_CALLEE_TRASH & ~(RBM_FLOATRET | RBM_INTRET))
1132 #define RBM_PROFILER_TAILCALL_TRASH RBM_PROFILER_LEAVE_TRASH
1134 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper.
1135 #ifdef UNIX_AMD64_ABI
1136 // See vm\amd64\unixasmhelpers.S for more details.
1138 // On Unix a struct of size >=9 and <=16 bytes in size is returned in two return registers.
1139 // The return registers could be any two from the set { RAX, RDX, XMM0, XMM1 }.
1140 // STOP_FOR_GC helper preserves all the 4 possible return registers.
1141 #define RBM_STOP_FOR_GC_TRASH (RBM_CALLEE_TRASH & ~(RBM_FLOATRET | RBM_INTRET | RBM_FLOATRET_1 | RBM_INTRET_1))
1143 // See vm\amd64\asmhelpers.asm for more details.
1144 #define RBM_STOP_FOR_GC_TRASH (RBM_CALLEE_TRASH & ~(RBM_FLOATRET | RBM_INTRET))
1147 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper.
1148 #define RBM_INIT_PINVOKE_FRAME_TRASH RBM_CALLEE_TRASH
1150 // What sort of reloc do we use for [disp32] address mode
1151 #define IMAGE_REL_BASED_DISP32 IMAGE_REL_BASED_REL32
1153 // What sort of reloc to we use for 'moffset' address mode (for 'mov eax, moffset' or 'mov moffset, eax')
1154 #define IMAGE_REL_BASED_MOFFSET IMAGE_REL_BASED_DIR64
1156 // Pointer-sized string move instructions
1157 #define INS_movsp INS_movsq
1158 #define INS_r_movsp INS_r_movsq
1159 #define INS_stosp INS_stosq
1160 #define INS_r_stosp INS_r_stosq
1162 #elif defined(_TARGET_ARM_)
1164 // TODO-ARM-CQ: Use shift for division by power of 2
1165 // TODO-ARM-CQ: Check for sdiv/udiv at runtime and generate it if available
1166 #define USE_HELPERS_FOR_INT_DIV 1 // BeagleBoard (ARMv7A) doesn't support SDIV/UDIV
1167 #define CPU_LOAD_STORE_ARCH 1
1168 #ifdef LEGACY_BACKEND
1169 #define CPU_LONG_USES_REGPAIR 1
1171 #define CPU_LONG_USES_REGPAIR 0
1173 #define CPU_HAS_FP_SUPPORT 1
1174 #define ROUND_FLOAT 0 // Do not round intermed float expression results
1175 #define CPU_HAS_BYTE_REGS 0
1176 #define CPU_USES_BLOCK_MOVE 0
1178 #define CPBLK_UNROLL_LIMIT 32 // Upper bound to let the code generator to loop unroll CpBlk.
1179 #define INITBLK_UNROLL_LIMIT 32 // Upper bound to let the code generator to loop unroll InitBlk.
1181 #define FEATURE_FIXED_OUT_ARGS 1 // Preallocate the outgoing arg area in the prolog
1182 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
1183 #define FEATURE_MULTIREG_STRUCT_PROMOTE 0 // True when we want to promote fields of a multireg struct into registers
1184 #define FEATURE_FASTTAILCALL 0 // Tail calls made as epilog+jmp
1185 #define FEATURE_TAILCALL_OPT 0 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
1186 #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
1187 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register (including HFA support)
1188 #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register (including passing HFAs)
1189 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register (including HFA returns)
1190 #define FEATURE_STRUCT_CLASSIFIER 0 // Uses a classifier function to determine is structs are passed/returned in more than one register
1191 #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)
1192 #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)
1193 #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)
1194 #define MAX_RET_REG_COUNT 4 // Maximum registers used to return a value.
1196 #define NOGC_WRITE_BARRIERS 0 // We DO-NOT have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers
1197 #define USER_ARGS_COME_LAST 1
1198 #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
1199 // need to track stack depth, but this is currently necessary to get GC information reported at call sites.
1200 #define TARGET_POINTER_SIZE 4 // equal to sizeof(void*) and the managed pointer size in bytes for this target
1201 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter, filter-handler, fault) and directly execute 'finally' clauses.
1202 #define FEATURE_EH_FUNCLETS 1
1203 #define FEATURE_EH_CALLFINALLY_THUNKS 0 // Generate call-to-finally code in "thunks" in the enclosing EH region, protected by "cloned finally" clauses.
1204 #define FEATURE_STACK_FP_X87 0
1205 #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
1206 #define FEATURE_FP_REGALLOC 1 // Enabled if RegAlloc is used to enregister Floating Point LclVars
1207 #define CSE_CONSTS 1 // Enable if we want to CSE constants
1209 #define REG_FP_FIRST REG_F0
1210 #define REG_FP_LAST REG_F31
1211 #define FIRST_FP_ARGREG REG_F0
1212 #define LAST_FP_ARGREG REG_F15
1214 #define REGNUM_BITS 6 // number of bits in a REG_*
1215 #define TINY_REGNUM_BITS 4 // number of bits we will use for a tiny instr desc (may not use float)
1216 #define REGMASK_BITS 64 // number of bits in a REGNUM_MASK
1217 #define REGSIZE_BYTES 4 // number of bytes in one register
1218 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
1220 #define CODE_ALIGN 2 // code alignment requirement
1221 #define STACK_ALIGN 8 // stack alignment requirement
1222 #define STACK_ALIGN_SHIFT 2 // Shift-right amount to convert stack size in bytes to size in DWORD_PTRs
1224 #define RBM_INT_CALLEE_SAVED (RBM_R4|RBM_R5|RBM_R6|RBM_R7|RBM_R8|RBM_R9|RBM_R10)
1225 #define RBM_INT_CALLEE_TRASH (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R12|RBM_LR)
1226 #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)
1227 #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)
1229 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
1230 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
1232 #define REG_DEFAULT_HELPER_CALL_TARGET REG_R12
1233 #define RBM_DEFAULT_HELPER_CALL_TARGET RBM_R12
1235 #define REG_FASTTAILCALL_TARGET REG_R12 // Target register for fast tail call
1236 #define RBM_FASTTAILCALL_TARGET RBM_R12
1238 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
1239 #define RBM_ALLFLOAT (RBM_FLT_CALLEE_SAVED | RBM_FLT_CALLEE_TRASH)
1240 #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)
1242 #define REG_VAR_ORDER REG_R3,REG_R2,REG_R1,REG_R0,REG_R4,REG_LR,REG_R12,\
1243 REG_R5,REG_R6,REG_R7,REG_R8,REG_R9,REG_R10
1245 #define REG_VAR_ORDER_FLT REG_F8, REG_F9, REG_F10, REG_F11, \
1246 REG_F12, REG_F13, REG_F14, REG_F15, \
1247 REG_F6, REG_F7, REG_F4, REG_F5, \
1248 REG_F2, REG_F3, REG_F0, REG_F1, \
1249 REG_F16, REG_F17, REG_F18, REG_F19, \
1250 REG_F20, REG_F21, REG_F22, REG_F23, \
1251 REG_F24, REG_F25, REG_F26, REG_F27, \
1252 REG_F28, REG_F29, REG_F30, REG_F31,
1254 #ifdef LEGACY_BACKEND
1255 #define MAX_VAR_ORDER_SIZE 32
1257 #define REG_TMP_ORDER REG_R3,REG_R2,REG_R1,REG_R0, REG_R4,REG_R5,REG_R6,REG_R7,\
1258 REG_LR,REG_R12, REG_R8,REG_R9,REG_R10
1259 #define REG_TMP_ORDER_COUNT 13
1261 #define REG_FLT_TMP_ORDER REG_F14, REG_F15, REG_F12, REG_F13, \
1262 REG_F10, REG_F11, REG_F8, REG_F9, \
1263 REG_F6, REG_F7, REG_F4, REG_F5, \
1264 REG_F2, REG_F3, REG_F0, REG_F1, \
1265 REG_F16, REG_F17, REG_F18, REG_F19, \
1266 REG_F20, REG_F21, REG_F22, REG_F23, \
1267 REG_F24, REG_F25, REG_F26, REG_F27, \
1268 REG_F28, REG_F29, REG_F30, REG_F31,
1270 #define REG_FLT_TMP_ORDER_COUNT 32
1272 #define REG_PREDICT_ORDER REG_LR,REG_R12,REG_R3,REG_R2,REG_R1,REG_R0, \
1273 REG_R7,REG_R6,REG_R5,REG_R4,REG_R8,REG_R9,REG_R10
1274 #endif // LEGACY_BACKEND
1276 #define RBM_LOW_REGS (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R4|RBM_R5|RBM_R6|RBM_R7)
1277 #define RBM_HIGH_REGS (RBM_R8|RBM_R9|RBM_R10|RBM_R11|RBM_R12|RBM_SP|RBM_LR|RBM_PC)
1279 #define REG_CALLEE_SAVED_ORDER REG_R4,REG_R5,REG_R6,REG_R7,REG_R8,REG_R9,REG_R10,REG_R11
1280 #define RBM_CALLEE_SAVED_ORDER RBM_R4,RBM_R5,RBM_R6,RBM_R7,RBM_R8,RBM_R9,RBM_R10,RBM_R11
1282 #define CNT_CALLEE_SAVED (8)
1283 #define CNT_CALLEE_TRASH (6)
1284 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
1286 #define CNT_CALLEE_SAVED_FLOAT (16)
1287 #define CNT_CALLEE_TRASH_FLOAT (16)
1289 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED*REGSIZE_BYTES)
1290 #define CALLEE_SAVED_FLOAT_MAXSZ (CNT_CALLEE_SAVED_FLOAT*sizeof(float))
1292 // We reuse the ESP register as a illegal value in the register predictor
1293 #define RBM_ILLEGAL RBM_SP
1294 // We reuse the ESP register as a flag for last use handling in the register predictor
1295 #define RBM_LASTUSE RBM_SP
1296 // We're using the encoding for ESP to indicate a half-long on the frame
1297 #define REG_L_STK REG_SP
1299 // This is the first register in REG_TMP_ORDER
1300 #define REG_TMP_0 REG_R3
1301 #define RBM_TMP_0 RBM_R3
1303 // This is the second register in REG_TMP_ORDER
1304 #define REG_TMP_1 REG_R2
1305 #define RBM_TMP_1 RBM_R2
1307 #ifndef LEGACY_BACKEND
1308 // Temporary registers used for the GS cookie check.
1309 #define REG_GSCOOKIE_TMP_0 REG_R12
1310 #define REG_GSCOOKIE_TMP_1 REG_LR
1311 #endif // !LEGACY_BACKEND
1313 // This is the first register pair in REG_TMP_ORDER
1314 #define REG_PAIR_TMP REG_PAIR_R2R3
1315 #define REG_PAIR_TMP_REVERSE REG_PAIR_R3R2
1316 #define RBM_PAIR_TMP (RBM_R2|RBM_R3)
1317 #define REG_PAIR_TMP_LO REG_R2
1318 #define RBM_PAIR_TMP_LO RBM_R2
1319 #define REG_PAIR_TMP_HI REG_R3
1320 #define RBM_PAIR_TMP_HI RBM_R3
1321 #define PREDICT_PAIR_TMP PREDICT_PAIR_R2R3
1322 #define PREDICT_PAIR_TMP_LO PREDICT_REG_R2
1324 // Used when calling the 64-bit Variable shift helper
1325 #define REG_LNGARG_0 REG_PAIR_R0R1
1326 #define RBM_LNGARG_0 (RBM_R0|RBM_R1)
1327 #define PREDICT_PAIR_LNGARG_0 PREDICT_PAIR_R0R1
1329 // register to hold shift amount; no special register is required on the ARM
1330 #define REG_SHIFT REG_NA
1331 #define RBM_SHIFT RBM_ALLINT
1332 #define PREDICT_REG_SHIFT PREDICT_REG
1334 // register to hold shift amount when shifting 64-bit values (this uses a helper call)
1335 #define REG_SHIFT_LNG REG_R2 // REG_ARG_2
1336 #define RBM_SHIFT_LNG RBM_R2 // RBM_ARG_2
1337 #define PREDICT_REG_SHIFT_LNG PREDICT_REG_R2
1340 // This is a general scratch register that does not conflict with the argument registers
1341 #define REG_SCRATCH REG_LR
1342 #define RBM_SCRATCH RBM_LR
1344 // This is a general register that can be optionally reserved for other purposes during codegen
1345 #define REG_OPT_RSVD REG_R10
1346 #define RBM_OPT_RSVD RBM_R10
1348 // We reserve R9 to store SP on entry for stack unwinding when localloc is used
1349 #define REG_SAVED_LOCALLOC_SP REG_R9
1350 #define RBM_SAVED_LOCALLOC_SP RBM_R9
1352 // Where is the exception object on entry to the handler block?
1353 #define REG_EXCEPTION_OBJECT REG_R0
1354 #define RBM_EXCEPTION_OBJECT RBM_R0
1356 #define REG_JUMP_THUNK_PARAM REG_R12
1357 #define RBM_JUMP_THUNK_PARAM RBM_R12
1359 // ARM write barrier ABI (see vm\arm\asmhelpers.asm, vm\arm\asmhelpers.S):
1360 // CORINFO_HELP_ASSIGN_REF (JIT_WriteBarrier), CORINFO_HELP_CHECKED_ASSIGN_REF (JIT_CheckedWriteBarrier):
1362 // r0: the destination address (LHS of the assignment)
1363 // r1: the object reference (RHS of the assignment)
1367 // CORINFO_HELP_ASSIGN_BYREF (JIT_ByRefWriteBarrier):
1369 // r0: the destination address (object reference written here)
1370 // r1: the source address (points to object reference to write)
1372 // r0: incremented by 4
1373 // r1: incremented by 4
1377 #define REG_WRITE_BARRIER_DST_BYREF REG_ARG_0
1378 #define RBM_WRITE_BARRIER_DST_BYREF RBM_ARG_0
1380 #define REG_WRITE_BARRIER_SRC_BYREF REG_ARG_1
1381 #define RBM_WRITE_BARRIER_SRC_BYREF RBM_ARG_1
1383 #define RBM_CALLEE_TRASH_NOGC (RBM_R2|RBM_R3|RBM_LR|RBM_DEFAULT_HELPER_CALL_TARGET)
1385 // Registers killed by CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1386 #define RBM_CALLEE_TRASH_WRITEBARRIER (RBM_R0|RBM_R3|RBM_LR|RBM_DEFAULT_HELPER_CALL_TARGET)
1388 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1389 #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_WRITEBARRIER
1391 // Registers killed by CORINFO_HELP_ASSIGN_BYREF.
1392 #define RBM_CALLEE_TRASH_WRITEBARRIER_BYREF (RBM_WRITE_BARRIER_DST_BYREF | RBM_WRITE_BARRIER_SRC_BYREF | RBM_CALLEE_TRASH_NOGC)
1394 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_BYREF.
1395 // Note that r0 and r1 are still valid byref pointers after this helper call, despite their value being changed.
1396 #define RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF RBM_CALLEE_TRASH_NOGC
1398 // GenericPInvokeCalliHelper VASigCookie Parameter
1399 #define REG_PINVOKE_COOKIE_PARAM REG_R4
1400 #define RBM_PINVOKE_COOKIE_PARAM RBM_R4
1402 #ifdef LEGACY_BACKEND
1403 #define PREDICT_REG_PINVOKE_COOKIE_PARAM PREDICT_REG_R4
1404 #endif // LEGACY_BACKEND
1406 // GenericPInvokeCalliHelper unmanaged target Parameter
1407 #define REG_PINVOKE_TARGET_PARAM REG_R12
1408 #define RBM_PINVOKE_TARGET_PARAM RBM_R12
1410 #ifdef LEGACY_BACKEND
1411 #define PREDICT_REG_PINVOKE_TARGET_PARAM PREDICT_REG_R12
1412 #endif // LEGACY_BACKEND
1414 // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
1415 #define REG_SECRET_STUB_PARAM REG_R12
1416 #define RBM_SECRET_STUB_PARAM RBM_R12
1418 // R2R indirect call. Use the same registers as VSD
1419 #define REG_R2R_INDIRECT_PARAM REG_R4
1420 #define RBM_R2R_INDIRECT_PARAM RBM_R4
1422 // Registers used by PInvoke frame setup
1423 #define REG_PINVOKE_FRAME REG_R4
1424 #define RBM_PINVOKE_FRAME RBM_R4
1425 #define REG_PINVOKE_TCB REG_R5
1426 #define RBM_PINVOKE_TCB RBM_R5
1427 #define REG_PINVOKE_SCRATCH REG_R6
1428 #define RBM_PINVOKE_SCRATCH RBM_R6
1430 #ifdef LEGACY_BACKEND
1431 #define REG_SPILL_CHOICE REG_LR
1432 #define RBM_SPILL_CHOICE RBM_LR
1433 #define REG_SPILL_CHOICE_FLT REG_F14
1434 #define RBM_SPILL_CHOICE_FLT (RBM_F14|RBM_F15)
1435 #endif // LEGACY_BACKEND
1437 // The following defines are useful for iterating a regNumber
1438 #define REG_FIRST REG_R0
1439 #define REG_INT_FIRST REG_R0
1440 #define REG_INT_LAST REG_LR
1441 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
1442 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
1443 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
1445 // genCodeForCall() moves the target address of the tailcall into this register, before pushing it on the stack
1446 #define REG_TAILCALL_ADDR REG_R1
1448 // The following registers are used in emitting Enter/Leave/Tailcall profiler callbacks
1449 #define REG_PROFILER_ENTER_ARG REG_R0
1450 #define RBM_PROFILER_ENTER_ARG RBM_R0
1451 #define REG_PROFILER_RET_SCRATCH REG_R2
1452 #define RBM_PROFILER_RET_SCRATCH RBM_R2
1453 #define RBM_PROFILER_RET_USED (RBM_R0 | RBM_R1 | RBM_R2)
1454 #define REG_PROFILER_JMP_ARG REG_R0
1455 #define RBM_PROFILER_JMP_USED RBM_R0
1456 #define RBM_PROFILER_TAIL_USED (RBM_R0 | RBM_R12 | RBM_LR)
1458 // The registers trashed by profiler enter/leave/tailcall hook
1459 // See vm\arm\asmhelpers.asm for more details.
1460 #define RBM_PROFILER_ENTER_TRASH RBM_NONE
1461 #define RBM_PROFILER_LEAVE_TRASH RBM_NONE
1462 #define RBM_PROFILER_TAILCALL_TRASH RBM_NONE
1464 // Which register are int and long values returned in ?
1465 #define REG_INTRET REG_R0
1466 #define RBM_INTRET RBM_R0
1467 #define REG_LNGRET REG_PAIR_R0R1
1468 #define RBM_LNGRET (RBM_R1|RBM_R0)
1469 #define REG_LNGRET_LO REG_R0
1470 #define REG_LNGRET_HI REG_R1
1471 #define RBM_LNGRET_LO RBM_R0
1472 #define RBM_LNGRET_HI RBM_R1
1474 #define REG_FLOATRET REG_F0
1475 #define RBM_FLOATRET RBM_F0
1476 #define RBM_DOUBLERET (RBM_F0|RBM_F1)
1478 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper (JIT_RareDisableHelper).
1479 // See vm\arm\amshelpers.asm for more details.
1480 #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))
1482 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper.
1483 #define RBM_INIT_PINVOKE_FRAME_TRASH (RBM_CALLEE_TRASH | RBM_PINVOKE_TCB | RBM_PINVOKE_SCRATCH)
1485 #define REG_FPBASE REG_R11
1486 #define RBM_FPBASE RBM_R11
1487 #define STR_FPBASE "r11"
1488 #define REG_SPBASE REG_SP
1489 #define RBM_SPBASE RBM_SP
1490 #define STR_SPBASE "sp"
1492 #define FIRST_ARG_STACK_OFFS (2*REGSIZE_BYTES) // Caller's saved FP and return address
1494 #define MAX_REG_ARG 4
1495 #define MAX_FLOAT_REG_ARG 16
1496 #define MAX_HFA_RET_SLOTS 8
1498 #define REG_ARG_FIRST REG_R0
1499 #define REG_ARG_LAST REG_R3
1500 #define REG_ARG_FP_FIRST REG_F0
1501 #define REG_ARG_FP_LAST REG_F7
1502 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
1504 #define REG_ARG_0 REG_R0
1505 #define REG_ARG_1 REG_R1
1506 #define REG_ARG_2 REG_R2
1507 #define REG_ARG_3 REG_R3
1509 SELECTANY const regNumber intArgRegs [] = {REG_R0, REG_R1, REG_R2, REG_R3};
1510 SELECTANY const regMaskTP intArgMasks[] = {RBM_R0, RBM_R1, RBM_R2, RBM_R3};
1512 #define RBM_ARG_0 RBM_R0
1513 #define RBM_ARG_1 RBM_R1
1514 #define RBM_ARG_2 RBM_R2
1515 #define RBM_ARG_3 RBM_R3
1517 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1|RBM_ARG_2|RBM_ARG_3)
1518 #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)
1519 #define RBM_DBL_REGS RBM_ALLDOUBLE
1521 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 };
1522 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 };
1524 #define LBL_DIST_SMALL_MAX_NEG (0)
1525 #define LBL_DIST_SMALL_MAX_POS (+1020)
1526 #define LBL_DIST_MED_MAX_NEG (-4095)
1527 #define LBL_DIST_MED_MAX_POS (+4096)
1529 #define JMP_DIST_SMALL_MAX_NEG (-2048)
1530 #define JMP_DIST_SMALL_MAX_POS (+2046)
1532 #define CALL_DIST_MAX_NEG (-16777216)
1533 #define CALL_DIST_MAX_POS (+16777214)
1535 #define JCC_DIST_SMALL_MAX_NEG (-256)
1536 #define JCC_DIST_SMALL_MAX_POS (+254)
1538 #define JCC_DIST_MEDIUM_MAX_NEG (-1048576)
1539 #define JCC_DIST_MEDIUM_MAX_POS (+1048574)
1541 #define LBL_SIZE_SMALL (2)
1543 #define JMP_SIZE_SMALL (2)
1544 #define JMP_SIZE_LARGE (4)
1546 #define JCC_SIZE_SMALL (2)
1547 #define JCC_SIZE_MEDIUM (4)
1548 #define JCC_SIZE_LARGE (6)
1550 #elif defined(_TARGET_ARM64_)
1552 #define CPU_LOAD_STORE_ARCH 1
1553 #define CPU_LONG_USES_REGPAIR 0
1554 #define CPU_HAS_FP_SUPPORT 1
1555 #define ROUND_FLOAT 0 // Do not round intermed float expression results
1556 #define CPU_HAS_BYTE_REGS 0
1557 #define CPU_USES_BLOCK_MOVE 0
1559 #define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk.
1560 #define INITBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll InitBlk.
1563 #define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned
1564 #define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 1 // Whether SIMD registers are partially saved at calls
1565 #endif // FEATURE_SIMD
1567 #define FEATURE_FIXED_OUT_ARGS 1 // Preallocate the outgoing arg area in the prolog
1568 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
1569 #define FEATURE_MULTIREG_STRUCT_PROMOTE 1 // True when we want to promote fields of a multireg struct into registers
1570 #define FEATURE_FASTTAILCALL 1 // Tail calls made as epilog+jmp
1571 #define FEATURE_TAILCALL_OPT 1 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
1572 #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
1573 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
1574 #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register
1575 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
1576 #define FEATURE_STRUCT_CLASSIFIER 0 // Uses a classifier function to determine is structs are passed/returned in more than one register
1577 #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)
1578 #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)
1579 #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)
1580 #define MAX_RET_REG_COUNT 4 // Maximum registers used to return a value.
1582 #define NOGC_WRITE_BARRIERS 1 // We have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers
1583 #define USER_ARGS_COME_LAST 1
1584 #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
1585 // need to track stack depth, but this is currently necessary to get GC information reported at call sites.
1586 #define TARGET_POINTER_SIZE 8 // equal to sizeof(void*) and the managed pointer size in bytes for this target
1587 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter, filter-handler, fault) and directly execute 'finally' clauses.
1588 #define FEATURE_EH_FUNCLETS 1
1589 #define FEATURE_EH_CALLFINALLY_THUNKS 1 // Generate call-to-finally code in "thunks" in the enclosing EH region, protected by "cloned finally" clauses.
1590 #define FEATURE_STACK_FP_X87 0
1591 #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
1592 #define FEATURE_FP_REGALLOC 0 // Enabled if RegAlloc is used to enregister Floating Point LclVars
1593 #define CSE_CONSTS 1 // Enable if we want to CSE constants
1595 #define REG_FP_FIRST REG_V0
1596 #define REG_FP_LAST REG_V31
1597 #define FIRST_FP_ARGREG REG_V0
1598 #define LAST_FP_ARGREG REG_V15
1600 #define REGNUM_BITS 6 // number of bits in a REG_*
1601 #define TINY_REGNUM_BITS 5 // number of bits we will use for a tiny instr desc (may not use float)
1602 #define REGMASK_BITS 64 // number of bits in a REGNUM_MASK
1603 #define REGSIZE_BYTES 8 // number of bytes in one general purpose register
1604 #define FP_REGSIZE_BYTES 16 // number of bytes in one FP/SIMD register
1605 #define FPSAVE_REGSIZE_BYTES 8 // number of bytes in one FP/SIMD register that are saved/restored, for callee-saved registers
1607 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
1609 #define CODE_ALIGN 4 // code alignment requirement
1610 #define STACK_ALIGN 16 // stack alignment requirement
1611 #define STACK_ALIGN_SHIFT 3 // Shift-right amount to convert stack size in bytes to size in DWORD_PTRs
1613 #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)
1614 #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)
1615 #define RBM_FLT_CALLEE_SAVED (RBM_V8|RBM_V9|RBM_V10|RBM_V11|RBM_V12|RBM_V13|RBM_V14|RBM_V15)
1616 #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)
1618 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
1619 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
1621 #define REG_DEFAULT_HELPER_CALL_TARGET REG_R12
1622 #define RBM_DEFAULT_HELPER_CALL_TARGET RBM_R12
1624 #define REG_FASTTAILCALL_TARGET REG_IP0 // Target register for fast tail call
1625 #define RBM_FASTTAILCALL_TARGET RBM_IP0
1627 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
1628 #define RBM_ALLFLOAT (RBM_FLT_CALLEE_SAVED | RBM_FLT_CALLEE_TRASH)
1629 #define RBM_ALLDOUBLE RBM_ALLFLOAT
1631 #define REG_VAR_ORDER REG_R9,REG_R10,REG_R11,REG_R12,REG_R13,REG_R14,REG_R15,\
1632 REG_R8,REG_R7,REG_R6,REG_R5,REG_R4,REG_R3,REG_R2,REG_R1,REG_R0,\
1633 REG_R19,REG_R20,REG_R21,REG_R22,REG_R23,REG_R24,REG_R25,REG_R26,REG_R27,REG_R28,\
1635 #define REG_VAR_ORDER_FLT REG_V16, REG_V17, REG_V18, REG_V19, \
1636 REG_V20, REG_V21, REG_V22, REG_V23, \
1637 REG_V24, REG_V25, REG_V26, REG_V27, \
1638 REG_V28, REG_V29, REG_V30, REG_V31, \
1639 REG_V7, REG_V6, REG_V5, REG_V4, \
1640 REG_V8, REG_V9, REG_V10, REG_V11, \
1641 REG_V12, REG_V13, REG_V14, REG_V15, \
1642 REG_V3, REG_V2, REG_V1, REG_V0
1644 #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
1645 #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
1647 #define CNT_CALLEE_SAVED (11)
1648 #define CNT_CALLEE_TRASH (17)
1649 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
1651 #define CNT_CALLEE_SAVED_FLOAT (8)
1652 #define CNT_CALLEE_TRASH_FLOAT (24)
1654 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED * REGSIZE_BYTES)
1655 #define CALLEE_SAVED_FLOAT_MAXSZ (CNT_CALLEE_SAVED_FLOAT * FPSAVE_REGSIZE_BYTES)
1657 // TODO-ARM64-Cleanup: Remove this
1658 #define REG_L_STK REG_ZR
1660 // This is the first register in REG_TMP_ORDER
1661 #define REG_TMP_0 REG_R9
1662 #define RBM_TMP_0 RBM_R9
1664 // This is the second register in REG_TMP_ORDER
1665 #define REG_TMP_1 REG_R10
1666 #define RBM_TMP_1 RBM_R10
1668 // Temporary registers used for the GS cookie check.
1669 #define REG_GSCOOKIE_TMP_0 REG_R9
1670 #define REG_GSCOOKIE_TMP_1 REG_R10
1672 // register to hold shift amount; no special register is required on ARM64.
1673 #define REG_SHIFT REG_NA
1674 #define RBM_SHIFT RBM_ALLINT
1675 #define PREDICT_REG_SHIFT PREDICT_REG
1677 // This is a general scratch register that does not conflict with the argument registers
1678 #define REG_SCRATCH REG_R9
1679 #define RBM_SCRATCH RBM_R9
1681 // This is a general register that can be optionally reserved for other purposes during codegen
1682 #define REG_OPT_RSVD REG_IP1
1683 #define RBM_OPT_RSVD RBM_IP1
1685 // Where is the exception object on entry to the handler block?
1686 #define REG_EXCEPTION_OBJECT REG_R0
1687 #define RBM_EXCEPTION_OBJECT RBM_R0
1689 #define REG_JUMP_THUNK_PARAM REG_R12
1690 #define RBM_JUMP_THUNK_PARAM RBM_R12
1692 // ARM64 write barrier ABI (see vm\arm64\asmhelpers.asm, vm\arm64\asmhelpers.S):
1693 // CORINFO_HELP_ASSIGN_REF (JIT_WriteBarrier), CORINFO_HELP_CHECKED_ASSIGN_REF (JIT_CheckedWriteBarrier):
1695 // x14: the destination address (LHS of the assignment)
1696 // x15: the object reference (RHS of the assignment)
1699 // x14: incremented by 8
1701 // x17: trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP (currently non-Windows)
1702 // CORINFO_HELP_ASSIGN_BYREF (JIT_ByRefWriteBarrier):
1704 // x13: the source address (points to object reference to write)
1705 // x14: the destination address (object reference written here)
1708 // x13: incremented by 8
1709 // x14: incremented by 8
1711 // x17: trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP (currently non-Windows)
1713 // Note that while x17 (ip1) is currently only trashed under FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP,
1714 // currently only set for non-Windows, it is expected to be set in the future for Windows, and for R2R.
1715 // So simply always consider it trashed, to avoid later breaking changes.
1717 #define REG_WRITE_BARRIER_DST REG_R14
1718 #define RBM_WRITE_BARRIER_DST RBM_R14
1720 #define REG_WRITE_BARRIER_SRC REG_R15
1721 #define RBM_WRITE_BARRIER_SRC RBM_R15
1723 #define REG_WRITE_BARRIER_DST_BYREF REG_R14
1724 #define RBM_WRITE_BARRIER_DST_BYREF RBM_R14
1726 #define REG_WRITE_BARRIER_SRC_BYREF REG_R13
1727 #define RBM_WRITE_BARRIER_SRC_BYREF RBM_R13
1729 #define RBM_CALLEE_TRASH_NOGC (RBM_R12|RBM_R15|RBM_IP1|RBM_DEFAULT_HELPER_CALL_TARGET)
1731 // Registers killed by CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1732 #define RBM_CALLEE_TRASH_WRITEBARRIER (RBM_R14|RBM_CALLEE_TRASH_NOGC)
1734 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1735 #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_NOGC
1737 // Registers killed by CORINFO_HELP_ASSIGN_BYREF.
1738 #define RBM_CALLEE_TRASH_WRITEBARRIER_BYREF (RBM_WRITE_BARRIER_DST_BYREF | RBM_WRITE_BARRIER_SRC_BYREF | RBM_CALLEE_TRASH_NOGC)
1740 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_BYREF.
1741 // Note that x13 and x14 are still valid byref pointers after this helper call, despite their value being changed.
1742 #define RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF RBM_CALLEE_TRASH_NOGC
1744 // GenericPInvokeCalliHelper VASigCookie Parameter
1745 #define REG_PINVOKE_COOKIE_PARAM REG_R15
1746 #define RBM_PINVOKE_COOKIE_PARAM RBM_R15
1748 // GenericPInvokeCalliHelper unmanaged target Parameter
1749 #define REG_PINVOKE_TARGET_PARAM REG_R12
1750 #define RBM_PINVOKE_TARGET_PARAM RBM_R12
1752 // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
1753 #define REG_SECRET_STUB_PARAM REG_R12
1754 #define RBM_SECRET_STUB_PARAM RBM_R12
1756 // R2R indirect call. Use the same registers as VSD
1757 #define REG_R2R_INDIRECT_PARAM REG_R11
1758 #define RBM_R2R_INDIRECT_PARAM RBM_R11
1760 // Registers used by PInvoke frame setup
1761 #define REG_PINVOKE_FRAME REG_R9
1762 #define RBM_PINVOKE_FRAME RBM_R9
1763 #define REG_PINVOKE_TCB REG_R10
1764 #define RBM_PINVOKE_TCB RBM_R10
1765 #define REG_PINVOKE_SCRATCH REG_R10
1766 #define RBM_PINVOKE_SCRATCH RBM_R10
1768 // The following defines are useful for iterating a regNumber
1769 #define REG_FIRST REG_R0
1770 #define REG_INT_FIRST REG_R0
1771 #define REG_INT_LAST REG_ZR
1772 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
1773 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
1774 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
1776 // genCodeForCall() moves the target address of the tailcall into this register, before pushing it on the stack
1777 #define REG_TAILCALL_ADDR REG_R9
1779 // The following registers are used in emitting Enter/Leave/Tailcall profiler callbacks
1780 #define REG_PROFILER_ENTER_ARG REG_R0
1781 #define RBM_PROFILER_ENTER_ARG RBM_R0
1782 #define REG_PROFILER_RET_SCRATCH REG_R2
1783 #define RBM_PROFILER_RET_SCRATCH RBM_R2
1784 #define RBM_PROFILER_RET_USED (RBM_R0 | RBM_R1 | RBM_R2)
1785 #define REG_PROFILER_JMP_ARG REG_R0
1786 #define RBM_PROFILER_JMP_USED RBM_R0
1787 #define RBM_PROFILER_TAIL_USED (RBM_R0 | RBM_R12 | RBM_LR)
1790 // Which register are int and long values returned in ?
1791 #define REG_INTRET REG_R0
1792 #define RBM_INTRET RBM_R0
1793 #define REG_LNGRET REG_R0
1794 #define RBM_LNGRET RBM_R0
1795 // second return register for 16-byte structs
1796 #define REG_INTRET_1 REG_R1
1797 #define RBM_INTRET_1 RBM_R1
1799 #define REG_FLOATRET REG_V0
1800 #define RBM_FLOATRET RBM_V0
1801 #define RBM_DOUBLERET RBM_V0
1803 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper
1804 #define RBM_STOP_FOR_GC_TRASH RBM_CALLEE_TRASH
1806 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper.
1807 #define RBM_INIT_PINVOKE_FRAME_TRASH RBM_CALLEE_TRASH
1809 #define REG_FPBASE REG_FP
1810 #define RBM_FPBASE RBM_FP
1811 #define STR_FPBASE "fp"
1812 #define REG_SPBASE REG_SP
1813 #define RBM_SPBASE RBM_ZR // reuse the RBM for REG_ZR
1814 #define STR_SPBASE "sp"
1816 #define FIRST_ARG_STACK_OFFS (2*REGSIZE_BYTES) // Caller's saved FP and return address
1818 // On ARM64 the calling convention defines REG_R8 (x8) as an additional argument register
1819 // It isn't allocated for the normal user arguments, so it isn't counted by MAX_REG_ARG
1820 // whether we use this register to pass the RetBuff is controlled by the function hasFixedRetBuffReg()
1821 // it is consider to be the next integer argnum, which is 8
1823 #define REG_ARG_RET_BUFF REG_R8
1824 #define RBM_ARG_RET_BUFF RBM_R8
1825 #define RET_BUFF_ARGNUM 8
1827 #define MAX_REG_ARG 8
1828 #define MAX_FLOAT_REG_ARG 8
1830 #define REG_ARG_FIRST REG_R0
1831 #define REG_ARG_LAST REG_R7
1832 #define REG_ARG_FP_FIRST REG_V0
1833 #define REG_ARG_FP_LAST REG_V7
1834 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
1836 #define REG_ARG_0 REG_R0
1837 #define REG_ARG_1 REG_R1
1838 #define REG_ARG_2 REG_R2
1839 #define REG_ARG_3 REG_R3
1840 #define REG_ARG_4 REG_R4
1841 #define REG_ARG_5 REG_R5
1842 #define REG_ARG_6 REG_R6
1843 #define REG_ARG_7 REG_R7
1845 SELECTANY const regNumber intArgRegs [] = {REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7};
1846 SELECTANY const regMaskTP intArgMasks[] = {RBM_R0, RBM_R1, RBM_R2, RBM_R3, RBM_R4, RBM_R5, RBM_R6, RBM_R7};
1848 #define RBM_ARG_0 RBM_R0
1849 #define RBM_ARG_1 RBM_R1
1850 #define RBM_ARG_2 RBM_R2
1851 #define RBM_ARG_3 RBM_R3
1852 #define RBM_ARG_4 RBM_R4
1853 #define RBM_ARG_5 RBM_R5
1854 #define RBM_ARG_6 RBM_R6
1855 #define RBM_ARG_7 RBM_R7
1857 #define REG_FLTARG_0 REG_V0
1858 #define REG_FLTARG_1 REG_V1
1859 #define REG_FLTARG_2 REG_V2
1860 #define REG_FLTARG_3 REG_V3
1861 #define REG_FLTARG_4 REG_V4
1862 #define REG_FLTARG_5 REG_V5
1863 #define REG_FLTARG_6 REG_V6
1864 #define REG_FLTARG_7 REG_V7
1866 #define RBM_FLTARG_0 RBM_V0
1867 #define RBM_FLTARG_1 RBM_V1
1868 #define RBM_FLTARG_2 RBM_V2
1869 #define RBM_FLTARG_3 RBM_V3
1870 #define RBM_FLTARG_4 RBM_V4
1871 #define RBM_FLTARG_5 RBM_V5
1872 #define RBM_FLTARG_6 RBM_V6
1873 #define RBM_FLTARG_7 RBM_V7
1875 #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)
1876 #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)
1878 SELECTANY const regNumber fltArgRegs [] = {REG_V0, REG_V1, REG_V2, REG_V3, REG_V4, REG_V5, REG_V6, REG_V7 };
1879 SELECTANY const regMaskTP fltArgMasks[] = {RBM_V0, RBM_V1, RBM_V2, RBM_V3, RBM_V4, RBM_V5, RBM_V6, RBM_V7 };
1881 #define LBL_DIST_SMALL_MAX_NEG (-1048576)
1882 #define LBL_DIST_SMALL_MAX_POS (+1048575)
1884 #define LBL_SIZE_SMALL (4)
1885 #define LBL_SIZE_LARGE (8)
1887 #define JCC_DIST_SMALL_MAX_NEG (-1048576)
1888 #define JCC_DIST_SMALL_MAX_POS (+1048575)
1890 #define TB_DIST_SMALL_MAX_NEG (-32768)
1891 #define TB_DIST_SMALL_MAX_POS (+32767)
1893 #define JCC_SIZE_SMALL (4)
1894 #define JCC_SIZE_LARGE (8)
1896 #define LDC_DIST_SMALL_MAX_NEG (-1048576)
1897 #define LDC_DIST_SMALL_MAX_POS (+1048575)
1899 #define LDC_SIZE_SMALL (4)
1900 #define LDC_SIZE_LARGE (8)
1902 #define JMP_SIZE_SMALL (4)
1905 #error Unsupported or unset target architecture
1908 #ifdef _TARGET_XARCH_
1910 #define JMP_DIST_SMALL_MAX_NEG (-128)
1911 #define JMP_DIST_SMALL_MAX_POS (+127)
1913 #define JCC_DIST_SMALL_MAX_NEG (-128)
1914 #define JCC_DIST_SMALL_MAX_POS (+127)
1916 #define JMP_SIZE_SMALL (2)
1917 #define JMP_SIZE_LARGE (5)
1919 #define JCC_SIZE_SMALL (2)
1920 #define JCC_SIZE_LARGE (6)
1922 #define PUSH_INST_SIZE (5)
1923 #define CALL_INST_SIZE (5)
1925 #endif // _TARGET_XARCH_
1927 C_ASSERT(REG_FIRST == 0);
1928 C_ASSERT(REG_INT_FIRST < REG_INT_LAST);
1929 C_ASSERT(REG_FP_FIRST < REG_FP_LAST);
1931 // Opportunistic tail call feature converts non-tail prefixed calls into
1932 // tail calls where possible. It requires fast tail calling mechanism for
1933 // performance. Otherwise, we are better off not converting non-tail prefixed
1934 // calls into tail calls.
1935 C_ASSERT((FEATURE_TAILCALL_OPT == 0) || (FEATURE_FASTTAILCALL == 1));
1937 /*****************************************************************************/
1939 #define BITS_PER_BYTE 8
1940 #define REGNUM_MASK ((1 << REGNUM_BITS) - 1) // a n-bit mask use to encode multiple REGNUMs into a unsigned int
1941 #define RBM_ALL(type) (varTypeIsFloating(type) ? RBM_ALLFLOAT : RBM_ALLINT)
1943 /*****************************************************************************/
1945 #if CPU_HAS_BYTE_REGS
1946 #define RBM_BYTE_REGS (RBM_EAX|RBM_ECX|RBM_EDX|RBM_EBX)
1947 #define RBM_NON_BYTE_REGS (RBM_ESI|RBM_EDI)
1948 // We reuse the ESP register as a flag for byteable registers in lvPrefReg
1949 #define RBM_BYTE_REG_FLAG RBM_ESP
1951 #define RBM_BYTE_REGS RBM_ALLINT
1952 #define RBM_NON_BYTE_REGS RBM_NONE
1953 #define RBM_BYTE_REG_FLAG RBM_NONE
1957 /*****************************************************************************/
1961 static const char* g_tgtCPUName;
1962 static const char* g_tgtPlatformName;
1969 static const enum ArgOrder g_tgtArgOrder;
1971 #ifdef LEGACY_BACKEND
1972 #if NOGC_WRITE_BARRIERS
1973 static regMaskTP exclude_WriteBarrierReg(regMaskTP mask)
1975 unsigned result = (mask & ~RBM_WRITE_BARRIER);
1979 return RBM_ALLINT & ~RBM_WRITE_BARRIER;
1981 #endif // NOGC_WRITE_BARRIERS
1982 #endif // LEGACY_BACKEND
1985 #if defined(DEBUG) || defined(LATE_DISASM)
1986 const char* getRegName(unsigned reg, bool isFloat = false); // this is for gcencode.cpp and disasm.cpp that don't use
1987 // the regNumber type
1988 const char* getRegName(regNumber reg, bool isFloat = false);
1989 #endif // defined(DEBUG) || defined(LATE_DISASM)
1992 const char* getRegNameFloat(regNumber reg, var_types type);
1993 extern void dspRegMask(regMaskTP regMask, size_t minSiz = 0);
1996 #if CPU_HAS_BYTE_REGS
1997 inline BOOL isByteReg(regNumber reg)
1999 return (reg <= REG_EBX);
2002 inline BOOL isByteReg(regNumber reg)
2008 #ifdef LEGACY_BACKEND
2009 extern const regNumber raRegTmpOrder[REG_TMP_ORDER_COUNT];
2010 extern const regNumber rpRegTmpOrder[REG_TMP_ORDER_COUNT];
2011 #if FEATURE_FP_REGALLOC
2012 extern const regNumber raRegFltTmpOrder[REG_FLT_TMP_ORDER_COUNT];
2014 #endif // LEGACY_BACKEND
2016 inline regMaskTP genRegMask(regNumber reg);
2017 inline regMaskTP genRegMaskFloat(regNumber reg, var_types type = TYP_DOUBLE);
2019 /*****************************************************************************
2020 * Return true if the register number is valid
2022 inline bool genIsValidReg(regNumber reg)
2024 /* It's safest to perform an unsigned comparison in case reg is negative */
2025 return ((unsigned)reg < (unsigned)REG_COUNT);
2028 /*****************************************************************************
2029 * Return true if the register is a valid integer register
2031 inline bool genIsValidIntReg(regNumber reg)
2033 return reg >= REG_INT_FIRST && reg <= REG_INT_LAST;
2036 /*****************************************************************************
2037 * Return true if the register is a valid floating point register
2039 inline bool genIsValidFloatReg(regNumber reg)
2041 return reg >= REG_FP_FIRST && reg <= REG_FP_LAST;
2046 /*****************************************************************************
2047 * Return true if the register is a valid floating point double register
2049 inline bool genIsValidDoubleReg(regNumber reg)
2051 return genIsValidFloatReg(reg) && (((reg - REG_FP_FIRST) & 0x1) == 0);
2054 #endif // _TARGET_ARM_
2056 //-------------------------------------------------------------------------------------------
2057 // hasFixedRetBuffReg:
2058 // Returns true if our target architecture uses a fixed return buffer register
2060 inline bool hasFixedRetBuffReg()
2062 #ifdef _TARGET_ARM64_
2069 //-------------------------------------------------------------------------------------------
2070 // theFixedRetBuffReg:
2071 // Returns the regNumber to use for the fixed return buffer
2073 inline regNumber theFixedRetBuffReg()
2075 assert(hasFixedRetBuffReg()); // This predicate should be checked before calling this method
2076 #ifdef _TARGET_ARM64_
2077 return REG_ARG_RET_BUFF;
2083 //-------------------------------------------------------------------------------------------
2084 // theFixedRetBuffMask:
2085 // Returns the regNumber to use for the fixed return buffer
2087 inline regMaskTP theFixedRetBuffMask()
2089 assert(hasFixedRetBuffReg()); // This predicate should be checked before calling this method
2090 #ifdef _TARGET_ARM64_
2091 return RBM_ARG_RET_BUFF;
2097 //-------------------------------------------------------------------------------------------
2098 // theFixedRetBuffArgNum:
2099 // Returns the argNum to use for the fixed return buffer
2101 inline unsigned theFixedRetBuffArgNum()
2103 assert(hasFixedRetBuffReg()); // This predicate should be checked before calling this method
2104 #ifdef _TARGET_ARM64_
2105 return RET_BUFF_ARGNUM;
2111 //-------------------------------------------------------------------------------------------
2112 // fullIntArgRegMask:
2113 // Returns the full mask of all possible integer registers
2114 // Note this includes the fixed return buffer register on Arm64
2116 inline regMaskTP fullIntArgRegMask()
2118 if (hasFixedRetBuffReg())
2120 return RBM_ARG_REGS | theFixedRetBuffMask();
2124 return RBM_ARG_REGS;
2128 //-------------------------------------------------------------------------------------------
2129 // isValidIntArgReg:
2130 // Returns true if the register is a valid integer argument register
2131 // Note this method also returns true on Arm64 when 'reg' is the RetBuff register
2133 inline bool isValidIntArgReg(regNumber reg)
2135 return (genRegMask(reg) & fullIntArgRegMask()) != 0;
2138 //-------------------------------------------------------------------------------------------
2140 // Given a register that is an integer or floating point argument register
2141 // returns the next argument register
2143 regNumber genRegArgNext(regNumber argReg);
2145 //-------------------------------------------------------------------------------------------
2146 // isValidFloatArgReg:
2147 // Returns true if the register is a valid floating-point argument register
2149 inline bool isValidFloatArgReg(regNumber reg)
2157 return (reg >= FIRST_FP_ARGREG) && (reg <= LAST_FP_ARGREG);
2161 /*****************************************************************************
2163 * Can the register hold the argument type?
2167 inline bool floatRegCanHoldType(regNumber reg, var_types type)
2169 assert(genIsValidFloatReg(reg));
2170 if (type == TYP_DOUBLE)
2172 return ((reg - REG_F0) % 2) == 0;
2176 // Can be TYP_STRUCT for HFA. It's not clear that's correct; what about
2177 // HFA of double? We wouldn't be asserting the right alignment, and
2178 // callers like genRegMaskFloat() wouldn't be generating the right mask.
2180 assert((type == TYP_FLOAT) || (type == TYP_STRUCT));
2185 // AMD64: xmm registers can hold any float type
2186 // x86: FP stack can hold any float type
2187 // ARM64: Floating-point/SIMD registers can hold any type.
2188 inline bool floatRegCanHoldType(regNumber reg, var_types type)
2194 /*****************************************************************************
2196 * Map a register number to a register mask.
2199 extern const regMaskSmall regMasks[REG_COUNT];
2201 inline regMaskTP genRegMask(regNumber reg)
2203 assert((unsigned)reg < ArrLen(regMasks));
2204 #ifdef _TARGET_AMD64_
2205 // shift is faster than a L1 hit on modern x86
2206 // (L1 latency on sandy bridge is 4 cycles for [base] and 5 for [base + index*c] )
2207 // the reason this is AMD-only is because the x86 BE will try to get reg masks for REG_STK
2208 // and the result needs to be zero.
2209 regMaskTP result = 1 << reg;
2210 assert(result == regMasks[reg]);
2213 return regMasks[reg];
2217 /*****************************************************************************
2219 * Map a register number to a floating-point register mask.
2222 #if defined(_TARGET_X86_) && defined(LEGACY_BACKEND)
2223 extern const regMaskSmall regFPMasks[REG_FPCOUNT];
2224 #endif // defined(_TARGET_X86_) && defined(LEGACY_BACKEND)
2226 inline regMaskTP genRegMaskFloat(regNumber reg, var_types type /* = TYP_DOUBLE */)
2228 #if defined(_TARGET_X86_) && defined(LEGACY_BACKEND)
2229 assert(reg >= REG_FPV0 && reg < REG_FPCOUNT);
2230 assert((unsigned)reg < ArrLen(regFPMasks));
2231 return regFPMasks[reg];
2232 #elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) || defined(_TARGET_X86_)
2233 assert(genIsValidFloatReg(reg));
2234 assert((unsigned)reg < ArrLen(regMasks));
2235 return regMasks[reg];
2236 #elif defined _TARGET_ARM_
2237 assert(floatRegCanHoldType(reg, type));
2238 assert(reg >= REG_F0 && reg <= REG_F31);
2240 if (type == TYP_DOUBLE)
2242 return regMasks[reg] | regMasks[reg + 1];
2246 return regMasks[reg];
2249 #error Unsupported or unset target architecture
2253 //------------------------------------------------------------------------
2254 // genRegMask: Given a register, and its type, generate the appropriate regMask
2257 // regNum - the register of interest
2258 // type - the type of regNum (i.e. the type it is being used as)
2261 // This will usually return the same value as genRegMask(regNum), but
2262 // on architectures where multiple registers are used for certain types
2263 // (e.g. TYP_DOUBLE on ARM), it will return a regMask that includes
2264 // all the registers.
2265 // Registers that are used in pairs, but separately named (e.g. TYP_LONG
2266 // on ARM) will return just the regMask for the given register.
2269 // For registers that are used in pairs, the caller will be handling
2270 // each member of the pair separately.
2272 inline regMaskTP genRegMask(regNumber regNum, var_types type)
2274 #ifndef _TARGET_ARM_
2275 return genRegMask(regNum);
2277 regMaskTP regMask = RBM_NONE;
2279 if (varTypeIsFloating(type))
2281 regMask = genRegMaskFloat(regNum, type);
2285 regMask = genRegMask(regNum);
2291 /*****************************************************************************
2293 * These arrays list the callee-saved register numbers (and bitmaps, respectively) for
2294 * the current architecture.
2296 extern const regNumber raRegCalleeSaveOrder[CNT_CALLEE_SAVED];
2297 extern const regMaskTP raRbmCalleeSaveOrder[CNT_CALLEE_SAVED];
2299 // This method takes a "compact" bitset of the callee-saved registers, and "expands" it to a full register mask.
2300 regMaskSmall genRegMaskFromCalleeSavedMask(unsigned short);
2302 /*****************************************************************************
2304 * Returns the register that holds the low 32 bits of the long value given
2305 * by the register pair 'regPair'.
2307 inline regNumber genRegPairLo(regPairNo regPair)
2309 assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
2311 return (regNumber)((regPair - REG_PAIR_FIRST) & REG_PAIR_NMASK);
2314 /*****************************************************************************
2316 * Returns the register that holds the high 32 bits of the long value given
2317 * by the register pair 'regPair'.
2319 inline regNumber genRegPairHi(regPairNo regPair)
2321 assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
2323 return (regNumber)(((regPair - REG_PAIR_FIRST) >> REG_PAIR_NBITS) & REG_PAIR_NMASK);
2326 /*****************************************************************************
2328 * Returns whether regPair is a combination of two "real" registers
2329 * or whether it contains a pseudo register.
2331 * In debug it also asserts that reg1 and reg2 are not the same.
2333 bool genIsProperRegPair(regPairNo regPair);
2335 /*****************************************************************************
2337 * Returns the register pair number that corresponds to the given two regs.
2339 inline regPairNo gen2regs2pair(regNumber regLo, regNumber regHi)
2341 assert(regLo != regHi || regLo == REG_STK);
2342 assert(genIsValidReg(regLo) && genIsValidReg(regHi));
2343 assert(regLo != REG_L_STK && regHi != REG_L_STK);
2345 regPairNo regPair = (regPairNo)(regLo + (regHi << REG_PAIR_NBITS) + REG_PAIR_FIRST);
2347 assert(regLo == genRegPairLo(regPair));
2348 assert(regHi == genRegPairHi(regPair));
2353 /*****************************************************************************/
2354 inline regMaskTP genRegPairMask(regPairNo regPair)
2356 assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
2358 return genRegMask(genRegPairLo(regPair)) | genRegMask(genRegPairHi(regPair));
2361 /*****************************************************************************
2363 * Assumes that "reg" is of the given "type". Return the next unused reg number after "reg"
2364 * of this type, else REG_NA if there are no more.
2367 inline regNumber regNextOfType(regNumber reg, var_types type)
2369 regNumber regReturn;
2372 if (type == TYP_DOUBLE)
2374 // Skip odd FP registers for double-precision types
2375 assert(floatRegCanHoldType(reg, type));
2376 regReturn = regNumber(reg + 2);
2380 regReturn = REG_NEXT(reg);
2382 #else // _TARGET_ARM_
2383 regReturn = REG_NEXT(reg);
2386 if (varTypeIsFloating(type))
2388 if (regReturn > REG_FP_LAST)
2395 if (regReturn > REG_INT_LAST)
2404 /*****************************************************************************
2409 inline bool isRegPairType(int /* s/b "var_types" */ type)
2411 #if !CPU_LONG_USES_REGPAIR
2414 #ifdef _TARGET_64BIT_
2416 #elif CPU_HAS_FP_SUPPORT
2417 return type == TYP_LONG;
2419 return type == TYP_LONG || type == TYP_DOUBLE;
2421 #endif // CPU_LONG_USES_REGPAIR
2424 inline bool isFloatRegType(int /* s/b "var_types" */ type)
2426 #if CPU_HAS_FP_SUPPORT
2427 return type == TYP_DOUBLE || type == TYP_FLOAT;
2433 // If the WINDOWS_AMD64_ABI is defined make sure that _TARGET_AMD64_ is also defined.
2434 #if defined(WINDOWS_AMD64_ABI)
2435 #if !defined(_TARGET_AMD64_)
2436 #error When WINDOWS_AMD64_ABI is defined you must define _TARGET_AMD64_ defined as well.
2440 /*****************************************************************************/
2441 // Some sanity checks on some of the register masks
2442 // Stack pointer is never part of RBM_ALLINT
2443 C_ASSERT((RBM_ALLINT & RBM_SPBASE) == RBM_NONE);
2444 C_ASSERT((RBM_INT_CALLEE_SAVED & RBM_SPBASE) == RBM_NONE);
2447 // Frame pointer isn't either if we're supporting ETW frame chaining
2448 C_ASSERT((RBM_ALLINT & RBM_FPBASE) == RBM_NONE);
2449 C_ASSERT((RBM_INT_CALLEE_SAVED & RBM_FPBASE) == RBM_NONE);
2451 /*****************************************************************************/
2453 #ifdef _TARGET_64BIT_
2454 typedef unsigned __int64 target_size_t;
2456 typedef unsigned int target_size_t;
2459 C_ASSERT(sizeof(target_size_t) == TARGET_POINTER_SIZE);
2461 /*****************************************************************************/
2462 #endif // _TARGET_H_
2463 /*****************************************************************************/