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.
4
5/*****************************************************************************/
6#ifndef _TARGET_H_
7#define _TARGET_H_
8
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_))
14
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"
25#else
26#error Unsupported or unset target architecture
27#endif
28
29/*****************************************************************************/
30// The following are intended to capture only those #defines that cannot be replaced
31// with static const members of Target
32#if defined(_TARGET_XARCH_)
33#define REGMASK_BITS 32
34
35#elif defined(_TARGET_ARM_)
36#define REGMASK_BITS 64
37
38#elif defined(_TARGET_ARM64_)
39#define REGMASK_BITS 64
40
41#else
42#error Unsupported or unset target architecture
43#endif
44
45//------------------------------------------------------------------------
46//
47// Each register list in register.h must declare REG_STK as the last value.
48// In the following enum declarations, the following REG_XXX are created beyond
49// the "real" registers:
50// REG_STK - Used to indicate something evaluated onto the stack.
51// ACTUAL_REG_COUNT - The number of physical registers. (same as REG_STK).
52// REG_COUNT - The number of physical register + REG_STK. This is the count of values that may
53// be assigned during register allocation.
54// REG_NA - Used to indicate that a register is either not yet assigned or not required.
55//
56#if defined(_TARGET_ARM_)
57enum _regNumber_enum : unsigned
58{
59#define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
60#define REGALIAS(alias, realname) REG_##alias = REG_##realname,
61#include "register.h"
62
63 REG_COUNT,
64 REG_NA = REG_COUNT,
65 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
66};
67
68enum _regMask_enum : unsigned __int64
69{
70 RBM_NONE = 0,
71#define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
72#define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
73#include "register.h"
74};
75
76#elif defined(_TARGET_ARM64_)
77
78enum _regNumber_enum : unsigned
79{
80#define REGDEF(name, rnum, mask, xname, wname) REG_##name = rnum,
81#define REGALIAS(alias, realname) REG_##alias = REG_##realname,
82#include "register.h"
83
84 REG_COUNT,
85 REG_NA = REG_COUNT,
86 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
87};
88
89enum _regMask_enum : unsigned __int64
90{
91 RBM_NONE = 0,
92#define REGDEF(name, rnum, mask, xname, wname) RBM_##name = mask,
93#define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
94#include "register.h"
95};
96
97#elif defined(_TARGET_AMD64_)
98
99enum _regNumber_enum : unsigned
100{
101#define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
102#define REGALIAS(alias, realname) REG_##alias = REG_##realname,
103#include "register.h"
104
105 REG_COUNT,
106 REG_NA = REG_COUNT,
107 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
108};
109
110enum _regMask_enum : unsigned
111{
112 RBM_NONE = 0,
113
114#define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
115#define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
116#include "register.h"
117};
118
119#elif defined(_TARGET_X86_)
120
121enum _regNumber_enum : unsigned
122{
123#define REGDEF(name, rnum, mask, sname) REG_##name = rnum,
124#define REGALIAS(alias, realname) REG_##alias = REG_##realname,
125#include "register.h"
126
127 REG_COUNT,
128 REG_NA = REG_COUNT,
129 ACTUAL_REG_COUNT = REG_COUNT - 1 // everything but REG_STK (only real regs)
130};
131
132enum _regMask_enum : unsigned
133{
134 RBM_NONE = 0,
135
136#define REGDEF(name, rnum, mask, sname) RBM_##name = mask,
137#define REGALIAS(alias, realname) RBM_##alias = RBM_##realname,
138#include "register.h"
139};
140
141#else
142#error Unsupported target architecture
143#endif
144
145/*****************************************************************************/
146
147// TODO-Cleanup: The types defined below are mildly confusing: why are there both?
148// regMaskSmall is large enough to represent the entire set of registers.
149// If regMaskSmall is smaller than a "natural" integer type, regMaskTP is wider, based
150// on a belief by the original authors of the JIT that in some situations it is more
151// efficient to have the wider representation. This belief should be tested, and if it
152// is false, then we should coalesce these two types into one (the Small width, probably).
153// In any case, we believe that is OK to freely cast between these types; no information will
154// be lost.
155
156#ifdef _TARGET_ARMARCH_
157typedef unsigned __int64 regMaskTP;
158#else
159typedef unsigned regMaskTP;
160#endif
161
162#if REGMASK_BITS == 8
163typedef unsigned char regMaskSmall;
164#define REG_MASK_INT_FMT "%02X"
165#define REG_MASK_ALL_FMT "%02X"
166#elif REGMASK_BITS == 16
167typedef unsigned short regMaskSmall;
168#define REG_MASK_INT_FMT "%04X"
169#define REG_MASK_ALL_FMT "%04X"
170#elif REGMASK_BITS == 32
171typedef unsigned regMaskSmall;
172#define REG_MASK_INT_FMT "%08X"
173#define REG_MASK_ALL_FMT "%08X"
174#else
175typedef unsigned __int64 regMaskSmall;
176#define REG_MASK_INT_FMT "%04llX"
177#define REG_MASK_ALL_FMT "%016llX"
178#endif
179
180typedef _regNumber_enum regNumber;
181typedef unsigned char regNumberSmall;
182
183/*****************************************************************************/
184
185#define LEA_AVAILABLE 1
186#define SCALED_ADDR_MODES 1
187
188/*****************************************************************************/
189
190#ifdef DEBUG
191#define DSP_SRC_OPER_LEFT 0
192#define DSP_SRC_OPER_RIGHT 1
193#define DSP_DST_OPER_LEFT 1
194#define DSP_DST_OPER_RIGHT 0
195#endif
196
197/*****************************************************************************/
198
199// The pseudorandom nop insertion is not necessary for current CoreCLR scenarios
200// #if defined(FEATURE_CORECLR) && !defined(_TARGET_ARM_)
201// #define PSEUDORANDOM_NOP_INSERTION
202// #endif
203
204/*****************************************************************************/
205
206// clang-format off
207#if defined(_TARGET_X86_)
208
209 #define CPU_LOAD_STORE_ARCH 0
210 #define CPU_HAS_FP_SUPPORT 1
211 #define ROUND_FLOAT 1 // round intermed float expression results
212 #define CPU_HAS_BYTE_REGS 1
213
214 // TODO-CQ: Fine tune the following xxBlk threshold values:
215
216 #define CPBLK_MOVS_LIMIT 16 // When generating code for CpBlk, this is the buffer size
217 // threshold to stop generating rep movs and switch to the helper call.
218 // NOTE: Using rep movs is currently disabled since we found it has bad performance
219 // on pre-Ivy Bridge hardware.
220
221 #define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk.
222 #define INITBLK_STOS_LIMIT 64 // When generating code for InitBlk, this is the buffer size
223 // NOTE: Using rep stos is currently disabled since we found it has bad performance
224 // on pre-Ivy Bridge hardware.
225 // threshold to stop generating rep movs and switch to the helper call.
226 #define INITBLK_UNROLL_LIMIT 128 // Upper bound to let the code generator to loop unroll InitBlk.
227 #define CPOBJ_NONGC_SLOTS_LIMIT 4 // For CpObj code generation, this is the the threshold of the number
228 // of contiguous non-gc slots that trigger generating rep movsq instead of
229 // sequences of movsq instructions
230 // The way we're currently disabling rep movs/stos is by setting a limit less than
231 // its unrolling counterparts. When lower takes the decision on which one to make it
232 // always asks for the unrolling limit first so you can say the JIT 'favors' unrolling.
233 // Setting the limit to something lower than that makes lower to never consider it.
234
235#ifdef FEATURE_SIMD
236 #define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned
237#endif // FEATURE_SIMD
238
239 #define FEATURE_FIXED_OUT_ARGS 0 // X86 uses push instructions to pass args
240 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
241 #define FEATURE_MULTIREG_STRUCT_PROMOTE 0 // True when we want to promote fields of a multireg struct into registers
242 #define FEATURE_FASTTAILCALL 0 // Tail calls made as epilog+jmp
243 #define FEATURE_TAILCALL_OPT 0 // opportunistic Tail calls (without ".tail" prefix) made as fast tail calls.
244 #define FEATURE_SET_FLAGS 0 // Set to true to force the JIT to mark the trees with GTF_SET_FLAGS when
245 // the flags need to be set
246 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
247 #define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register
248 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
249 #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments (note this seems wrong as MAX_ARG_REG_COUNT is 2)
250 #define MAX_RET_MULTIREG_BYTES 8 // Maximum size of a struct that could be returned in more than one register
251
252 #define MAX_ARG_REG_COUNT 2 // Maximum registers used to pass an argument.
253 #define MAX_RET_REG_COUNT 2 // Maximum registers used to return a value.
254
255#ifdef FEATURE_USE_ASM_GC_WRITE_BARRIERS
256 #define NOGC_WRITE_BARRIERS 1 // We have specialized WriteBarrier JIT Helpers that DO-NOT trash the
257 // RBM_CALLEE_TRASH registers
258#else
259 #define NOGC_WRITE_BARRIERS 0 // Do not modify this -- modify the definition above. (If we're not using
260 // ASM barriers we definitely don't have NOGC barriers).
261#endif
262 #define USER_ARGS_COME_LAST 0
263 #define EMIT_TRACK_STACK_DEPTH 1
264 #define TARGET_POINTER_SIZE 4 // equal to sizeof(void*) and the managed pointer size in bytes for this
265 // target
266 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter,
267 // filter-handler, fault) and directly execute 'finally' clauses.
268
269#if defined(FEATURE_PAL)
270 #define FEATURE_EH_FUNCLETS 1
271#else // !FEATURE_PAL
272 #define FEATURE_EH_FUNCLETS 0
273#endif // !FEATURE_PAL
274
275 #define FEATURE_EH_CALLFINALLY_THUNKS 0 // Generate call-to-finally code in "thunks" in the enclosing EH region,
276 // protected by "cloned finally" clauses.
277 #define ETW_EBP_FRAMED 1 // if 1 we cannot use EBP as a scratch register and must create EBP based
278 // frames for most methods
279 #define CSE_CONSTS 1 // Enable if we want to CSE constants
280
281 // The following defines are useful for iterating a regNumber
282 #define REG_FIRST REG_EAX
283 #define REG_INT_FIRST REG_EAX
284 #define REG_INT_LAST REG_EDI
285 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
286 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
287 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
288
289 #define REG_FP_FIRST REG_XMM0
290 #define REG_FP_LAST REG_XMM7
291 #define FIRST_FP_ARGREG REG_XMM0
292 #define LAST_FP_ARGREG REG_XMM3
293 #define REG_FLTARG_0 REG_XMM0
294 #define REG_FLTARG_1 REG_XMM1
295 #define REG_FLTARG_2 REG_XMM2
296 #define REG_FLTARG_3 REG_XMM3
297
298 #define RBM_FLTARG_0 RBM_XMM0
299 #define RBM_FLTARG_1 RBM_XMM1
300 #define RBM_FLTARG_2 RBM_XMM2
301 #define RBM_FLTARG_3 RBM_XMM3
302
303 #define RBM_FLTARG_REGS (RBM_FLTARG_0|RBM_FLTARG_1|RBM_FLTARG_2|RBM_FLTARG_3)
304
305 #define RBM_ALLFLOAT (RBM_XMM0 | RBM_XMM1 | RBM_XMM2 | RBM_XMM3 | RBM_XMM4 | RBM_XMM5 | RBM_XMM6 | RBM_XMM7)
306 #define RBM_ALLDOUBLE RBM_ALLFLOAT
307
308 // TODO-CQ: Currently we are following the x86 ABI for SSE2 registers.
309 // This should be reconsidered.
310 #define RBM_FLT_CALLEE_SAVED RBM_NONE
311 #define RBM_FLT_CALLEE_TRASH RBM_ALLFLOAT
312 #define REG_VAR_ORDER_FLT REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3, REG_XMM4, REG_XMM5, REG_XMM6, REG_XMM7
313
314 #define REG_FLT_CALLEE_SAVED_FIRST REG_XMM6
315 #define REG_FLT_CALLEE_SAVED_LAST REG_XMM7
316
317 #define XMM_REGSIZE_BYTES 16 // XMM register size in bytes
318 #define YMM_REGSIZE_BYTES 32 // YMM register size in bytes
319
320 #define REGNUM_BITS 6 // number of bits in a REG_*
321
322 #define REGSIZE_BYTES 4 // number of bytes in one register
323 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
324
325 #define CODE_ALIGN 1 // code alignment requirement
326#if !defined(UNIX_X86_ABI)
327 #define STACK_ALIGN 4 // stack alignment requirement
328 #define STACK_ALIGN_SHIFT 2 // Shift-right amount to convert size in bytes to size in STACK_ALIGN units == log2(STACK_ALIGN)
329#else
330 #define STACK_ALIGN 16 // stack alignment requirement
331 #define STACK_ALIGN_SHIFT 4 // Shift-right amount to convert size in bytes to size in STACK_ALIGN units == log2(STACK_ALIGN)
332#endif // !UNIX_X86_ABI
333
334 #define RBM_INT_CALLEE_SAVED (RBM_EBX|RBM_ESI|RBM_EDI)
335 #define RBM_INT_CALLEE_TRASH (RBM_EAX|RBM_ECX|RBM_EDX)
336
337 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
338 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
339
340 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
341
342 #define REG_VAR_ORDER REG_EAX,REG_EDX,REG_ECX,REG_ESI,REG_EDI,REG_EBX
343 #define MAX_VAR_ORDER_SIZE 6
344
345 // The order here is fixed: it must agree with an order assumed in eetwain...
346 #define REG_CALLEE_SAVED_ORDER REG_EDI,REG_ESI,REG_EBX,REG_EBP
347 #define RBM_CALLEE_SAVED_ORDER RBM_EDI,RBM_ESI,RBM_EBX,RBM_EBP
348
349 #define CNT_CALLEE_SAVED (4)
350 #define CNT_CALLEE_TRASH (3)
351 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
352
353 #define CNT_CALLEE_SAVED_FLOAT (0)
354 #define CNT_CALLEE_TRASH_FLOAT (6)
355
356 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED*REGSIZE_BYTES) // EBX,ESI,EDI,EBP
357
358 #define REG_TMP_0 REG_EAX
359
360 #define REG_LNGARG_LO REG_EAX
361 #define RBM_LNGARG_LO RBM_EAX
362 #define REG_LNGARG_HI REG_EDX
363 #define RBM_LNGARG_HI RBM_EDX
364 // register to hold shift amount
365 #define REG_SHIFT REG_ECX
366 #define RBM_SHIFT RBM_ECX
367
368 // register to hold shift amount when shifting 64-bit values
369 #define REG_SHIFT_LNG REG_ECX
370 #define RBM_SHIFT_LNG RBM_ECX
371
372 // This is a general scratch register that does not conflict with the argument registers
373 #define REG_SCRATCH REG_EAX
374
375 // Where is the exception object on entry to the handler block?
376 #define REG_EXCEPTION_OBJECT REG_EAX
377 #define RBM_EXCEPTION_OBJECT RBM_EAX
378
379 // Only used on ARM for GTF_CALL_M_VIRTSTUB_REL_INDIRECT
380 #define REG_JUMP_THUNK_PARAM REG_EAX
381 #define RBM_JUMP_THUNK_PARAM RBM_EAX
382
383#if NOGC_WRITE_BARRIERS
384 #define REG_WRITE_BARRIER REG_EDX
385 #define RBM_WRITE_BARRIER RBM_EDX
386
387 // 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).
388 #define RBM_WRITE_BARRIER_SRC (RBM_EAX|RBM_ECX|RBM_EBX|RBM_ESI|RBM_EDI)
389
390 #define RBM_CALLEE_TRASH_NOGC RBM_EDX
391#endif // NOGC_WRITE_BARRIERS
392
393 // GenericPInvokeCalliHelper unmanaged target parameter
394 #define REG_PINVOKE_TARGET_PARAM REG_EAX
395 #define RBM_PINVOKE_TARGET_PARAM RBM_EAX
396
397 // GenericPInvokeCalliHelper cookie parameter
398 #define REG_PINVOKE_COOKIE_PARAM REG_STK
399
400 // IL stub's secret parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
401 #define REG_SECRET_STUB_PARAM REG_EAX
402 #define RBM_SECRET_STUB_PARAM RBM_EAX
403
404 // VSD target address register
405 #define REG_VIRTUAL_STUB_TARGET REG_EAX
406 #define RBM_VIRTUAL_STUB_TARGET RBM_EAX
407
408 // Registers used by PInvoke frame setup
409 #define REG_PINVOKE_FRAME REG_EDI // EDI is p/invoke "Frame" pointer argument to CORINFO_HELP_INIT_PINVOKE_FRAME helper
410 #define RBM_PINVOKE_FRAME RBM_EDI
411 #define REG_PINVOKE_TCB REG_ESI // ESI is set to Thread Control Block (TCB) on return from
412 // CORINFO_HELP_INIT_PINVOKE_FRAME helper
413 #define RBM_PINVOKE_TCB RBM_ESI
414 #define REG_PINVOKE_SCRATCH REG_EAX // EAX is trashed by CORINFO_HELP_INIT_PINVOKE_FRAME helper
415 #define RBM_PINVOKE_SCRATCH RBM_EAX
416
417 // The following defines are useful for iterating a regNumber
418 #define REG_FIRST REG_EAX
419 #define REG_INT_FIRST REG_EAX
420 #define REG_INT_LAST REG_EDI
421 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
422 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
423 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
424
425 // Which register are int and long values returned in ?
426 #define REG_INTRET REG_EAX
427 #define RBM_INTRET RBM_EAX
428 #define RBM_LNGRET (RBM_EDX|RBM_EAX)
429 #define REG_LNGRET_LO REG_EAX
430 #define RBM_LNGRET_LO RBM_EAX
431 #define REG_LNGRET_HI REG_EDX
432 #define RBM_LNGRET_HI RBM_EDX
433
434 #define REG_FLOATRET REG_NA
435 #define RBM_FLOATRET RBM_NONE
436 #define RBM_DOUBLERET RBM_NONE
437
438 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper
439 #define RBM_STOP_FOR_GC_TRASH RBM_CALLEE_TRASH
440
441 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper. On x86, this helper has a custom calling
442 // convention that takes EDI as argument (but doesn't trash it), trashes EAX, and returns ESI.
443 #define RBM_INIT_PINVOKE_FRAME_TRASH (RBM_PINVOKE_SCRATCH | RBM_PINVOKE_TCB)
444
445 #define REG_FPBASE REG_EBP
446 #define RBM_FPBASE RBM_EBP
447 #define STR_FPBASE "ebp"
448 #define REG_SPBASE REG_ESP
449 #define RBM_SPBASE RBM_ESP
450 #define STR_SPBASE "esp"
451
452 #define FIRST_ARG_STACK_OFFS (2*REGSIZE_BYTES) // Caller's saved EBP and return address
453
454 #define MAX_REG_ARG 2
455 #define MAX_FLOAT_REG_ARG 0
456 #define REG_ARG_FIRST REG_ECX
457 #define REG_ARG_LAST REG_EDX
458 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
459
460 #define REG_ARG_0 REG_ECX
461 #define REG_ARG_1 REG_EDX
462
463 SELECTANY const regNumber intArgRegs [] = {REG_ECX, REG_EDX};
464 SELECTANY const regMaskTP intArgMasks[] = {RBM_ECX, RBM_EDX};
465 SELECTANY const regNumber fltArgRegs [] = {REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3};
466 SELECTANY const regMaskTP fltArgMasks[] = {RBM_XMM0, RBM_XMM1, RBM_XMM2, RBM_XMM3};
467
468 #define RBM_ARG_0 RBM_ECX
469 #define RBM_ARG_1 RBM_EDX
470
471 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1)
472
473 // The registers trashed by profiler enter/leave/tailcall hook
474 // See vm\i386\asmhelpers.asm for more details.
475 #define RBM_PROFILER_ENTER_TRASH RBM_NONE
476 #define RBM_PROFILER_LEAVE_TRASH RBM_NONE
477 #define RBM_PROFILER_TAILCALL_TRASH (RBM_ALLINT & ~RBM_ARG_REGS)
478
479 // What sort of reloc do we use for [disp32] address mode
480 #define IMAGE_REL_BASED_DISP32 IMAGE_REL_BASED_HIGHLOW
481
482 // What sort of reloc to we use for 'moffset' address mode (for 'mov eax, moffset' or 'mov moffset, eax')
483 #define IMAGE_REL_BASED_MOFFSET IMAGE_REL_BASED_HIGHLOW
484
485 // Pointer-sized string move instructions
486 #define INS_movsp INS_movsd
487 #define INS_r_movsp INS_r_movsd
488 #define INS_stosp INS_stosd
489 #define INS_r_stosp INS_r_stosd
490
491#elif defined(_TARGET_AMD64_)
492 // TODO-AMD64-CQ: Fine tune the following xxBlk threshold values:
493
494 #define CPU_LOAD_STORE_ARCH 0
495 #define CPU_HAS_FP_SUPPORT 1
496 #define ROUND_FLOAT 0 // Do not round intermed float expression results
497 #define CPU_HAS_BYTE_REGS 0
498
499 #define CPBLK_MOVS_LIMIT 16 // When generating code for CpBlk, this is the buffer size
500 // threshold to stop generating rep movs and switch to the helper call.
501 // NOTE: Using rep movs is currently disabled since we found it has bad performance
502 // on pre-Ivy Bridge hardware.
503
504 #define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk.
505 #define INITBLK_STOS_LIMIT 64 // When generating code for InitBlk, this is the buffer size
506 // NOTE: Using rep stos is currently disabled since we found it has bad performance
507 // on pre-Ivy Bridge hardware.
508 // threshold to stop generating rep movs and switch to the helper call.
509 #define INITBLK_UNROLL_LIMIT 128 // Upper bound to let the code generator to loop unroll InitBlk.
510 #define CPOBJ_NONGC_SLOTS_LIMIT 4 // For CpObj code generation, this is the the threshold of the number
511 // of contiguous non-gc slots that trigger generating rep movsq instead of
512 // sequences of movsq instructions
513
514 // The way we're currently disabling rep movs/stos is by setting a limit less than
515 // its unrolling counterparts. When lower takes the decision on which one to make it
516 // always asks for the unrolling limit first so you can say the JIT 'favors' unrolling.
517 // Setting the limit to something lower than that makes lower to never consider it.
518
519
520#ifdef FEATURE_SIMD
521 #define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned
522#if defined(UNIX_AMD64_ABI)
523 #define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 0 // Whether SIMD registers are partially saved at calls
524#else // !UNIX_AMD64_ABI
525 #define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 1 // Whether SIMD registers are partially saved at calls
526#endif // !UNIX_AMD64_ABI
527#endif
528 #define FEATURE_FIXED_OUT_ARGS 1 // Preallocate the outgoing arg area in the prolog
529 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
530 #define FEATURE_MULTIREG_STRUCT_PROMOTE 0 // True when we want to promote fields of a multireg struct into registers
531 #define FEATURE_FASTTAILCALL 1 // Tail calls made as epilog+jmp
532 #define FEATURE_TAILCALL_OPT 1 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
533 #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
534#ifdef UNIX_AMD64_ABI
535 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
536 #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register
537 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
538 #define FEATURE_STRUCT_CLASSIFIER 1 // Uses a classifier function to determine if structs are passed/returned in more than one register
539 #define MAX_PASS_MULTIREG_BYTES 32 // Maximum size of a struct that could be passed in more than one register (Max is two SIMD16s)
540 #define MAX_RET_MULTIREG_BYTES 32 // Maximum size of a struct that could be returned in more than one register (Max is two SIMD16s)
541 #define MAX_ARG_REG_COUNT 2 // Maximum registers used to pass a single argument in multiple registers.
542 #define MAX_RET_REG_COUNT 2 // Maximum registers used to return a value.
543#else // !UNIX_AMD64_ABI
544 #define WINDOWS_AMD64_ABI // Uses the Windows ABI for AMD64
545 #define FEATURE_MULTIREG_ARGS_OR_RET 0 // Support for passing and/or returning single values in more than one register
546 #define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register
547 #define FEATURE_MULTIREG_RET 0 // Support for returning a single value in more than one register
548 #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments
549 #define MAX_RET_MULTIREG_BYTES 0 // No multireg return values
550 #define MAX_ARG_REG_COUNT 1 // Maximum registers used to pass a single argument (no arguments are passed using multiple registers)
551 #define MAX_RET_REG_COUNT 1 // Maximum registers used to return a value.
552#endif // !UNIX_AMD64_ABI
553
554 #define NOGC_WRITE_BARRIERS 0 // We DO-NOT have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers
555 #define USER_ARGS_COME_LAST 1
556 #define EMIT_TRACK_STACK_DEPTH 1
557 #define TARGET_POINTER_SIZE 8 // equal to sizeof(void*) and the managed pointer size in bytes for this target
558 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter, filter-handler, fault) and directly execute 'finally' clauses.
559 #define FEATURE_EH_FUNCLETS 1
560 #define FEATURE_EH_CALLFINALLY_THUNKS 1 // Generate call-to-finally code in "thunks" in the enclosing EH region, protected by "cloned finally" clauses.
561#ifdef UNIX_AMD64_ABI
562 #define ETW_EBP_FRAMED 1 // if 1 we cannot use EBP as a scratch register and must create EBP based frames for most methods
563#else // !UNIX_AMD64_ABI
564 #define ETW_EBP_FRAMED 0 // if 1 we cannot use EBP as a scratch register and must create EBP based frames for most methods
565#endif // !UNIX_AMD64_ABI
566 #define CSE_CONSTS 1 // Enable if we want to CSE constants
567
568 #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)
569 #define RBM_ALLDOUBLE RBM_ALLFLOAT
570 #define REG_FP_FIRST REG_XMM0
571 #define REG_FP_LAST REG_XMM15
572 #define FIRST_FP_ARGREG REG_XMM0
573
574#ifdef UNIX_AMD64_ABI
575 #define LAST_FP_ARGREG REG_XMM7
576#else // !UNIX_AMD64_ABI
577 #define LAST_FP_ARGREG REG_XMM3
578#endif // !UNIX_AMD64_ABI
579
580 #define REGNUM_BITS 6 // number of bits in a REG_*
581 #define REGMASK_BITS 32 // number of bits in a REGNUM_MASK
582 #define REGSIZE_BYTES 8 // number of bytes in one register
583 #define XMM_REGSIZE_BYTES 16 // XMM register size in bytes
584 #define YMM_REGSIZE_BYTES 32 // YMM register size in bytes
585
586 #define CODE_ALIGN 1 // code alignment requirement
587 #define STACK_ALIGN 16 // stack alignment requirement
588 #define STACK_ALIGN_SHIFT 4 // Shift-right amount to convert size in bytes to size in STACK_ALIGN units == log2(STACK_ALIGN)
589
590#if ETW_EBP_FRAMED
591 #define RBM_ETW_FRAMED_EBP RBM_NONE
592 #define RBM_ETW_FRAMED_EBP_LIST
593 #define REG_ETW_FRAMED_EBP_LIST
594 #define REG_ETW_FRAMED_EBP_COUNT 0
595#else // !ETW_EBP_FRAMED
596 #define RBM_ETW_FRAMED_EBP RBM_EBP
597 #define RBM_ETW_FRAMED_EBP_LIST RBM_EBP,
598 #define REG_ETW_FRAMED_EBP_LIST REG_EBP,
599 #define REG_ETW_FRAMED_EBP_COUNT 1
600#endif // !ETW_EBP_FRAMED
601
602#ifdef UNIX_AMD64_ABI
603 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
604
605 #define RBM_INT_CALLEE_SAVED (RBM_EBX|RBM_ETW_FRAMED_EBP|RBM_R12|RBM_R13|RBM_R14|RBM_R15)
606 #define RBM_INT_CALLEE_TRASH (RBM_EAX|RBM_RDI|RBM_RSI|RBM_EDX|RBM_ECX|RBM_R8|RBM_R9|RBM_R10|RBM_R11)
607 #define RBM_FLT_CALLEE_SAVED (0)
608 #define RBM_FLT_CALLEE_TRASH (RBM_XMM0|RBM_XMM1|RBM_XMM2|RBM_XMM3|RBM_XMM4|RBM_XMM5|RBM_XMM6|RBM_XMM7| \
609 RBM_XMM8|RBM_XMM9|RBM_XMM10|RBM_XMM11|RBM_XMM12|RBM_XMM13|RBM_XMM14|RBM_XMM15)
610 #define REG_PROFILER_ENTER_ARG_0 REG_R14
611 #define RBM_PROFILER_ENTER_ARG_0 RBM_R14
612 #define REG_PROFILER_ENTER_ARG_1 REG_R15
613 #define RBM_PROFILER_ENTER_ARG_1 RBM_R15
614
615 #define REG_DEFAULT_PROFILER_CALL_TARGET REG_R11
616
617#else // !UNIX_AMD64_ABI
618#define MIN_ARG_AREA_FOR_CALL (4 * REGSIZE_BYTES) // Minimum required outgoing argument space for a call.
619
620 #define RBM_INT_CALLEE_SAVED (RBM_EBX|RBM_ESI|RBM_EDI|RBM_ETW_FRAMED_EBP|RBM_R12|RBM_R13|RBM_R14|RBM_R15)
621 #define RBM_INT_CALLEE_TRASH (RBM_EAX|RBM_ECX|RBM_EDX|RBM_R8|RBM_R9|RBM_R10|RBM_R11)
622 #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)
623 #define RBM_FLT_CALLEE_TRASH (RBM_XMM0|RBM_XMM1|RBM_XMM2|RBM_XMM3|RBM_XMM4|RBM_XMM5)
624#endif // !UNIX_AMD64_ABI
625
626 #define REG_FLT_CALLEE_SAVED_FIRST REG_XMM6
627 #define REG_FLT_CALLEE_SAVED_LAST REG_XMM15
628
629 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
630 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
631
632 #define RBM_CALLEE_TRASH_NOGC RBM_CALLEE_TRASH
633
634 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
635
636#if 0
637#define REG_VAR_ORDER REG_EAX,REG_EDX,REG_ECX,REG_ESI,REG_EDI,REG_EBX,REG_ETW_FRAMED_EBP_LIST \
638 REG_R8,REG_R9,REG_R10,REG_R11,REG_R14,REG_R15,REG_R12,REG_R13
639#else
640 // TEMPORARY ORDER TO AVOID CALLEE-SAVES
641 // TODO-CQ: Review this and set appropriately
642#ifdef UNIX_AMD64_ABI
643 #define REG_VAR_ORDER REG_EAX,REG_EDI,REG_ESI, \
644 REG_EDX,REG_ECX,REG_R8,REG_R9, \
645 REG_R10,REG_R11,REG_EBX,REG_ETW_FRAMED_EBP_LIST \
646 REG_R14,REG_R15,REG_R12,REG_R13
647#else // !UNIX_AMD64_ABI
648 #define REG_VAR_ORDER REG_EAX,REG_EDX,REG_ECX, \
649 REG_R8,REG_R9,REG_R10,REG_R11, \
650 REG_ESI,REG_EDI,REG_EBX,REG_ETW_FRAMED_EBP_LIST \
651 REG_R14,REG_R15,REG_R12,REG_R13
652#endif // !UNIX_AMD64_ABI
653#endif
654
655 #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
656
657#ifdef UNIX_AMD64_ABI
658 #define CNT_CALLEE_SAVED (5 + REG_ETW_FRAMED_EBP_COUNT)
659 #define CNT_CALLEE_TRASH (9)
660 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED)
661
662 #define CNT_CALLEE_SAVED_FLOAT (0)
663 #define CNT_CALLEE_TRASH_FLOAT (16)
664
665 #define REG_CALLEE_SAVED_ORDER REG_EBX,REG_ETW_FRAMED_EBP_LIST REG_R12,REG_R13,REG_R14,REG_R15
666 #define RBM_CALLEE_SAVED_ORDER RBM_EBX,RBM_ETW_FRAMED_EBP_LIST RBM_R12,RBM_R13,RBM_R14,RBM_R15
667#else // !UNIX_AMD64_ABI
668 #define CNT_CALLEE_SAVED (7 + REG_ETW_FRAMED_EBP_COUNT)
669 #define CNT_CALLEE_TRASH (7)
670 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED)
671
672 #define CNT_CALLEE_SAVED_FLOAT (10)
673 #define CNT_CALLEE_TRASH_FLOAT (6)
674
675 #define REG_CALLEE_SAVED_ORDER REG_EBX,REG_ESI,REG_EDI,REG_ETW_FRAMED_EBP_LIST REG_R12,REG_R13,REG_R14,REG_R15
676 #define RBM_CALLEE_SAVED_ORDER RBM_EBX,RBM_ESI,RBM_EDI,RBM_ETW_FRAMED_EBP_LIST RBM_R12,RBM_R13,RBM_R14,RBM_R15
677#endif // !UNIX_AMD64_ABI
678
679 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED*REGSIZE_BYTES)
680 #define CALLEE_SAVED_FLOAT_MAXSZ (CNT_CALLEE_SAVED_FLOAT*16)
681
682 #define REG_TMP_0 REG_EAX
683
684 // register to hold shift amount
685 #define REG_SHIFT REG_ECX
686 #define RBM_SHIFT RBM_ECX
687
688 // This is a general scratch register that does not conflict with the argument registers
689 #define REG_SCRATCH REG_EAX
690
691// Where is the exception object on entry to the handler block?
692#ifdef UNIX_AMD64_ABI
693 #define REG_EXCEPTION_OBJECT REG_ESI
694 #define RBM_EXCEPTION_OBJECT RBM_ESI
695#else // !UNIX_AMD64_ABI
696 #define REG_EXCEPTION_OBJECT REG_EDX
697 #define RBM_EXCEPTION_OBJECT RBM_EDX
698#endif // !UNIX_AMD64_ABI
699
700 #define REG_JUMP_THUNK_PARAM REG_EAX
701 #define RBM_JUMP_THUNK_PARAM RBM_EAX
702
703 // Register to be used for emitting helper calls whose call target is an indir of an
704 // absolute memory address in case of Rel32 overflow i.e. a data address could not be
705 // encoded as PC-relative 32-bit offset.
706 //
707 // Notes:
708 // 1) that RAX is callee trash register that is not used for passing parameter and
709 // also results in smaller instruction encoding.
710 // 2) Profiler Leave callback requires the return value to be preserved
711 // in some form. We can use custom calling convention for Leave callback.
712 // For e.g return value could be preserved in rcx so that it is available for
713 // profiler.
714 #define REG_DEFAULT_HELPER_CALL_TARGET REG_RAX
715 #define RBM_DEFAULT_HELPER_CALL_TARGET RBM_RAX
716
717 // GenericPInvokeCalliHelper VASigCookie Parameter
718 #define REG_PINVOKE_COOKIE_PARAM REG_R11
719 #define RBM_PINVOKE_COOKIE_PARAM RBM_R11
720
721 // GenericPInvokeCalliHelper unmanaged target Parameter
722 #define REG_PINVOKE_TARGET_PARAM REG_R10
723 #define RBM_PINVOKE_TARGET_PARAM RBM_R10
724
725 // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
726 #define REG_SECRET_STUB_PARAM REG_R10
727 #define RBM_SECRET_STUB_PARAM RBM_R10
728
729 // Registers used by PInvoke frame setup
730 #define REG_PINVOKE_FRAME REG_EDI
731 #define RBM_PINVOKE_FRAME RBM_EDI
732 #define REG_PINVOKE_TCB REG_EAX
733 #define RBM_PINVOKE_TCB RBM_EAX
734 #define REG_PINVOKE_SCRATCH REG_EAX
735 #define RBM_PINVOKE_SCRATCH RBM_EAX
736
737 // The following defines are useful for iterating a regNumber
738 #define REG_FIRST REG_EAX
739 #define REG_INT_FIRST REG_EAX
740 #define REG_INT_LAST REG_R15
741 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
742 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
743 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
744
745 // Which register are int and long values returned in ?
746 #define REG_INTRET REG_EAX
747 #define RBM_INTRET RBM_EAX
748
749 #define RBM_LNGRET RBM_EAX
750
751#ifdef UNIX_AMD64_ABI
752 #define REG_INTRET_1 REG_RDX
753 #define RBM_INTRET_1 RBM_RDX
754
755 #define REG_LNGRET_1 REG_RDX
756 #define RBM_LNGRET_1 RBM_RDX
757#endif // UNIX_AMD64_ABI
758
759
760 #define REG_FLOATRET REG_XMM0
761 #define RBM_FLOATRET RBM_XMM0
762 #define REG_DOUBLERET REG_XMM0
763 #define RBM_DOUBLERET RBM_XMM0
764
765#ifdef UNIX_AMD64_ABI
766#define REG_FLOATRET_1 REG_XMM1
767#define RBM_FLOATRET_1 RBM_XMM1
768
769#define REG_DOUBLERET_1 REG_XMM1
770#define RBM_DOUBLERET_1 RBM_XMM1
771#endif // UNIX_AMD64_ABI
772
773 #define REG_FPBASE REG_EBP
774 #define RBM_FPBASE RBM_EBP
775 #define STR_FPBASE "rbp"
776 #define REG_SPBASE REG_ESP
777 #define RBM_SPBASE RBM_ESP
778 #define STR_SPBASE "rsp"
779
780 #define FIRST_ARG_STACK_OFFS (REGSIZE_BYTES) // return address
781
782#ifdef UNIX_AMD64_ABI
783 #define MAX_REG_ARG 6
784 #define MAX_FLOAT_REG_ARG 8
785 #define REG_ARG_FIRST REG_EDI
786 #define REG_ARG_LAST REG_R9
787 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
788
789 #define REG_ARG_0 REG_EDI
790 #define REG_ARG_1 REG_ESI
791 #define REG_ARG_2 REG_EDX
792 #define REG_ARG_3 REG_ECX
793 #define REG_ARG_4 REG_R8
794 #define REG_ARG_5 REG_R9
795
796 SELECTANY const regNumber intArgRegs [] = { REG_EDI, REG_ESI, REG_EDX, REG_ECX, REG_R8, REG_R9 };
797 SELECTANY const regMaskTP intArgMasks[] = { RBM_EDI, RBM_ESI, RBM_EDX, RBM_ECX, RBM_R8, RBM_R9 };
798 SELECTANY const regNumber fltArgRegs [] = { REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3, REG_XMM4, REG_XMM5, REG_XMM6, REG_XMM7 };
799 SELECTANY const regMaskTP fltArgMasks[] = { RBM_XMM0, RBM_XMM1, RBM_XMM2, RBM_XMM3, RBM_XMM4, RBM_XMM5, RBM_XMM6, RBM_XMM7 };
800
801 #define RBM_ARG_0 RBM_RDI
802 #define RBM_ARG_1 RBM_RSI
803 #define RBM_ARG_2 RBM_EDX
804 #define RBM_ARG_3 RBM_ECX
805 #define RBM_ARG_4 RBM_R8
806 #define RBM_ARG_5 RBM_R9
807#else // !UNIX_AMD64_ABI
808 #define MAX_REG_ARG 4
809 #define MAX_FLOAT_REG_ARG 4
810 #define REG_ARG_FIRST REG_ECX
811 #define REG_ARG_LAST REG_R9
812 #define INIT_ARG_STACK_SLOT 4 // 4 outgoing reserved stack slots
813
814 #define REG_ARG_0 REG_ECX
815 #define REG_ARG_1 REG_EDX
816 #define REG_ARG_2 REG_R8
817 #define REG_ARG_3 REG_R9
818
819 SELECTANY const regNumber intArgRegs [] = { REG_ECX, REG_EDX, REG_R8, REG_R9 };
820 SELECTANY const regMaskTP intArgMasks[] = { RBM_ECX, RBM_EDX, RBM_R8, RBM_R9 };
821 SELECTANY const regNumber fltArgRegs [] = { REG_XMM0, REG_XMM1, REG_XMM2, REG_XMM3 };
822 SELECTANY const regMaskTP fltArgMasks[] = { RBM_XMM0, RBM_XMM1, RBM_XMM2, RBM_XMM3 };
823
824 #define RBM_ARG_0 RBM_ECX
825 #define RBM_ARG_1 RBM_EDX
826 #define RBM_ARG_2 RBM_R8
827 #define RBM_ARG_3 RBM_R9
828#endif // !UNIX_AMD64_ABI
829
830 #define REG_FLTARG_0 REG_XMM0
831 #define REG_FLTARG_1 REG_XMM1
832 #define REG_FLTARG_2 REG_XMM2
833 #define REG_FLTARG_3 REG_XMM3
834
835 #define RBM_FLTARG_0 RBM_XMM0
836 #define RBM_FLTARG_1 RBM_XMM1
837 #define RBM_FLTARG_2 RBM_XMM2
838 #define RBM_FLTARG_3 RBM_XMM3
839
840#ifdef UNIX_AMD64_ABI
841 #define REG_FLTARG_4 REG_XMM4
842 #define REG_FLTARG_5 REG_XMM5
843 #define REG_FLTARG_6 REG_XMM6
844 #define REG_FLTARG_7 REG_XMM7
845
846 #define RBM_FLTARG_4 RBM_XMM4
847 #define RBM_FLTARG_5 RBM_XMM5
848 #define RBM_FLTARG_6 RBM_XMM6
849 #define RBM_FLTARG_7 RBM_XMM7
850
851 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1|RBM_ARG_2|RBM_ARG_3|RBM_ARG_4|RBM_ARG_5)
852 #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)
853#else // !UNIX_AMD64_ABI
854 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1|RBM_ARG_2|RBM_ARG_3)
855 #define RBM_FLTARG_REGS (RBM_FLTARG_0|RBM_FLTARG_1|RBM_FLTARG_2|RBM_FLTARG_3)
856#endif // !UNIX_AMD64_ABI
857
858 // The registers trashed by profiler enter/leave/tailcall hook
859 // See vm\amd64\asmhelpers.asm for more details.
860 #define RBM_PROFILER_ENTER_TRASH RBM_CALLEE_TRASH
861 #define RBM_PROFILER_LEAVE_TRASH (RBM_CALLEE_TRASH & ~(RBM_FLOATRET | RBM_INTRET))
862 #define RBM_PROFILER_TAILCALL_TRASH RBM_PROFILER_LEAVE_TRASH
863
864 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper.
865#ifdef UNIX_AMD64_ABI
866 // See vm\amd64\unixasmhelpers.S for more details.
867 //
868 // On Unix a struct of size >=9 and <=16 bytes in size is returned in two return registers.
869 // The return registers could be any two from the set { RAX, RDX, XMM0, XMM1 }.
870 // STOP_FOR_GC helper preserves all the 4 possible return registers.
871 #define RBM_STOP_FOR_GC_TRASH (RBM_CALLEE_TRASH & ~(RBM_FLOATRET | RBM_INTRET | RBM_FLOATRET_1 | RBM_INTRET_1))
872#else
873 // See vm\amd64\asmhelpers.asm for more details.
874 #define RBM_STOP_FOR_GC_TRASH (RBM_CALLEE_TRASH & ~(RBM_FLOATRET | RBM_INTRET))
875#endif
876
877 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper.
878 #define RBM_INIT_PINVOKE_FRAME_TRASH RBM_CALLEE_TRASH
879
880 // What sort of reloc do we use for [disp32] address mode
881 #define IMAGE_REL_BASED_DISP32 IMAGE_REL_BASED_REL32
882
883 // What sort of reloc to we use for 'moffset' address mode (for 'mov eax, moffset' or 'mov moffset, eax')
884 #define IMAGE_REL_BASED_MOFFSET IMAGE_REL_BASED_DIR64
885
886 // Pointer-sized string move instructions
887 #define INS_movsp INS_movsq
888 #define INS_r_movsp INS_r_movsq
889 #define INS_stosp INS_stosq
890 #define INS_r_stosp INS_r_stosq
891
892#elif defined(_TARGET_ARM_)
893
894 // TODO-ARM-CQ: Use shift for division by power of 2
895 // TODO-ARM-CQ: Check for sdiv/udiv at runtime and generate it if available
896 #define USE_HELPERS_FOR_INT_DIV 1 // BeagleBoard (ARMv7A) doesn't support SDIV/UDIV
897 #define CPU_LOAD_STORE_ARCH 1
898 #define CPU_HAS_FP_SUPPORT 1
899 #define ROUND_FLOAT 0 // Do not round intermed float expression results
900 #define CPU_HAS_BYTE_REGS 0
901
902 #define CPBLK_UNROLL_LIMIT 32 // Upper bound to let the code generator to loop unroll CpBlk.
903 #define INITBLK_UNROLL_LIMIT 32 // Upper bound to let the code generator to loop unroll InitBlk.
904
905 #define FEATURE_FIXED_OUT_ARGS 1 // Preallocate the outgoing arg area in the prolog
906 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
907 #define FEATURE_MULTIREG_STRUCT_PROMOTE 0 // True when we want to promote fields of a multireg struct into registers
908 #define FEATURE_FASTTAILCALL 0 // Tail calls made as epilog+jmp
909 #define FEATURE_TAILCALL_OPT 0 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
910 #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
911 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register (including HFA support)
912 #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register (including passing HFAs)
913 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register (including HFA returns)
914 #define FEATURE_STRUCT_CLASSIFIER 0 // Uses a classifier function to determine is structs are passed/returned in more than one register
915 #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)
916 #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)
917 #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)
918 #define MAX_RET_REG_COUNT 4 // Maximum registers used to return a value.
919
920 #define NOGC_WRITE_BARRIERS 0 // We DO-NOT have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers
921 #define USER_ARGS_COME_LAST 1
922 #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
923 // need to track stack depth, but this is currently necessary to get GC information reported at call sites.
924 #define TARGET_POINTER_SIZE 4 // equal to sizeof(void*) and the managed pointer size in bytes for this target
925 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter, filter-handler, fault) and directly execute 'finally' clauses.
926 #define FEATURE_EH_FUNCLETS 1
927 #define FEATURE_EH_CALLFINALLY_THUNKS 0 // Generate call-to-finally code in "thunks" in the enclosing EH region, protected by "cloned finally" clauses.
928 #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
929 #define CSE_CONSTS 1 // Enable if we want to CSE constants
930
931 #define REG_FP_FIRST REG_F0
932 #define REG_FP_LAST REG_F31
933 #define FIRST_FP_ARGREG REG_F0
934 #define LAST_FP_ARGREG REG_F15
935
936 #define REGNUM_BITS 6 // number of bits in a REG_*
937 #define REGMASK_BITS 64 // number of bits in a REGNUM_MASK
938 #define REGSIZE_BYTES 4 // number of bytes in one register
939 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
940
941 #define CODE_ALIGN 2 // code alignment requirement
942 #define STACK_ALIGN 8 // stack alignment requirement
943
944 #define RBM_INT_CALLEE_SAVED (RBM_R4|RBM_R5|RBM_R6|RBM_R7|RBM_R8|RBM_R9|RBM_R10)
945 #define RBM_INT_CALLEE_TRASH (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R12|RBM_LR)
946 #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)
947 #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)
948
949 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
950 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
951
952 #define REG_DEFAULT_HELPER_CALL_TARGET REG_R12
953 #define RBM_DEFAULT_HELPER_CALL_TARGET RBM_R12
954
955 #define REG_FASTTAILCALL_TARGET REG_R12 // Target register for fast tail call
956 #define RBM_FASTTAILCALL_TARGET RBM_R12
957
958 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
959 #define RBM_ALLFLOAT (RBM_FLT_CALLEE_SAVED | RBM_FLT_CALLEE_TRASH)
960 #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)
961
962 #define REG_VAR_ORDER REG_R3,REG_R2,REG_R1,REG_R0,REG_R4,REG_LR,REG_R12,\
963 REG_R5,REG_R6,REG_R7,REG_R8,REG_R9,REG_R10
964
965 #define REG_VAR_ORDER_FLT REG_F8, REG_F9, REG_F10, REG_F11, \
966 REG_F12, REG_F13, REG_F14, REG_F15, \
967 REG_F6, REG_F7, REG_F4, REG_F5, \
968 REG_F2, REG_F3, REG_F0, REG_F1, \
969 REG_F16, REG_F17, REG_F18, REG_F19, \
970 REG_F20, REG_F21, REG_F22, REG_F23, \
971 REG_F24, REG_F25, REG_F26, REG_F27, \
972 REG_F28, REG_F29, REG_F30, REG_F31,
973
974 #define RBM_LOW_REGS (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R4|RBM_R5|RBM_R6|RBM_R7)
975 #define RBM_HIGH_REGS (RBM_R8|RBM_R9|RBM_R10|RBM_R11|RBM_R12|RBM_SP|RBM_LR|RBM_PC)
976
977 #define REG_CALLEE_SAVED_ORDER REG_R4,REG_R5,REG_R6,REG_R7,REG_R8,REG_R9,REG_R10,REG_R11
978 #define RBM_CALLEE_SAVED_ORDER RBM_R4,RBM_R5,RBM_R6,RBM_R7,RBM_R8,RBM_R9,RBM_R10,RBM_R11
979
980 #define CNT_CALLEE_SAVED (8)
981 #define CNT_CALLEE_TRASH (6)
982 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
983
984 #define CNT_CALLEE_SAVED_FLOAT (16)
985 #define CNT_CALLEE_TRASH_FLOAT (16)
986
987 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED*REGSIZE_BYTES)
988 #define CALLEE_SAVED_FLOAT_MAXSZ (CNT_CALLEE_SAVED_FLOAT*sizeof(float))
989
990 #define REG_TMP_0 REG_R3
991
992 // Temporary registers used for the GS cookie check.
993 #define REG_GSCOOKIE_TMP_0 REG_R12
994 #define REG_GSCOOKIE_TMP_1 REG_LR
995
996 // register to hold shift amount; no special register is required on the ARM
997 #define REG_SHIFT REG_NA
998 #define RBM_SHIFT RBM_ALLINT
999
1000 // register to hold shift amount when shifting 64-bit values (this uses a helper call)
1001 #define REG_SHIFT_LNG REG_R2 // REG_ARG_2
1002 #define RBM_SHIFT_LNG RBM_R2 // RBM_ARG_2
1003
1004 // This is a general scratch register that does not conflict with the argument registers
1005 #define REG_SCRATCH REG_LR
1006
1007 // This is a general register that can be optionally reserved for other purposes during codegen
1008 #define REG_OPT_RSVD REG_R10
1009 #define RBM_OPT_RSVD RBM_R10
1010
1011 // We reserve R9 to store SP on entry for stack unwinding when localloc is used
1012 #define REG_SAVED_LOCALLOC_SP REG_R9
1013 #define RBM_SAVED_LOCALLOC_SP RBM_R9
1014
1015 // Where is the exception object on entry to the handler block?
1016 #define REG_EXCEPTION_OBJECT REG_R0
1017 #define RBM_EXCEPTION_OBJECT RBM_R0
1018
1019 #define REG_JUMP_THUNK_PARAM REG_R12
1020 #define RBM_JUMP_THUNK_PARAM RBM_R12
1021
1022 // ARM write barrier ABI (see vm\arm\asmhelpers.asm, vm\arm\asmhelpers.S):
1023 // CORINFO_HELP_ASSIGN_REF (JIT_WriteBarrier), CORINFO_HELP_CHECKED_ASSIGN_REF (JIT_CheckedWriteBarrier):
1024 // On entry:
1025 // r0: the destination address (LHS of the assignment)
1026 // r1: the object reference (RHS of the assignment)
1027 // On exit:
1028 // r0: trashed
1029 // r3: trashed
1030 // CORINFO_HELP_ASSIGN_BYREF (JIT_ByRefWriteBarrier):
1031 // On entry:
1032 // r0: the destination address (object reference written here)
1033 // r1: the source address (points to object reference to write)
1034 // On exit:
1035 // r0: incremented by 4
1036 // r1: incremented by 4
1037 // r2: trashed
1038 // r3: trashed
1039
1040 #define REG_WRITE_BARRIER_DST_BYREF REG_ARG_0
1041 #define RBM_WRITE_BARRIER_DST_BYREF RBM_ARG_0
1042
1043 #define REG_WRITE_BARRIER_SRC_BYREF REG_ARG_1
1044 #define RBM_WRITE_BARRIER_SRC_BYREF RBM_ARG_1
1045
1046 #define RBM_CALLEE_TRASH_NOGC (RBM_R2|RBM_R3|RBM_LR|RBM_DEFAULT_HELPER_CALL_TARGET)
1047
1048 // Registers killed by CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1049 #define RBM_CALLEE_TRASH_WRITEBARRIER (RBM_R0|RBM_R3|RBM_LR|RBM_DEFAULT_HELPER_CALL_TARGET)
1050
1051 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1052 #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_WRITEBARRIER
1053
1054 // Registers killed by CORINFO_HELP_ASSIGN_BYREF.
1055 #define RBM_CALLEE_TRASH_WRITEBARRIER_BYREF (RBM_WRITE_BARRIER_DST_BYREF | RBM_WRITE_BARRIER_SRC_BYREF | RBM_CALLEE_TRASH_NOGC)
1056
1057 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_BYREF.
1058 // Note that r0 and r1 are still valid byref pointers after this helper call, despite their value being changed.
1059 #define RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF RBM_CALLEE_TRASH_NOGC
1060
1061 // GenericPInvokeCalliHelper VASigCookie Parameter
1062 #define REG_PINVOKE_COOKIE_PARAM REG_R4
1063 #define RBM_PINVOKE_COOKIE_PARAM RBM_R4
1064
1065 // GenericPInvokeCalliHelper unmanaged target Parameter
1066 #define REG_PINVOKE_TARGET_PARAM REG_R12
1067 #define RBM_PINVOKE_TARGET_PARAM RBM_R12
1068
1069 // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
1070 #define REG_SECRET_STUB_PARAM REG_R12
1071 #define RBM_SECRET_STUB_PARAM RBM_R12
1072
1073 // R2R indirect call. Use the same registers as VSD
1074 #define REG_R2R_INDIRECT_PARAM REG_R4
1075 #define RBM_R2R_INDIRECT_PARAM RBM_R4
1076
1077 // JMP Indirect call register
1078 #define REG_INDIRECT_CALL_TARGET_REG REG_R12
1079
1080 // Registers used by PInvoke frame setup
1081 #define REG_PINVOKE_FRAME REG_R4
1082 #define RBM_PINVOKE_FRAME RBM_R4
1083 #define REG_PINVOKE_TCB REG_R5
1084 #define RBM_PINVOKE_TCB RBM_R5
1085 #define REG_PINVOKE_SCRATCH REG_R6
1086 #define RBM_PINVOKE_SCRATCH RBM_R6
1087
1088 // The following defines are useful for iterating a regNumber
1089 #define REG_FIRST REG_R0
1090 #define REG_INT_FIRST REG_R0
1091 #define REG_INT_LAST REG_LR
1092 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
1093 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
1094 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
1095
1096 // The following registers are used in emitting Enter/Leave/Tailcall profiler callbacks
1097 #define REG_PROFILER_ENTER_ARG REG_R0
1098 #define RBM_PROFILER_ENTER_ARG RBM_R0
1099 #define REG_PROFILER_RET_SCRATCH REG_R2
1100 #define RBM_PROFILER_RET_SCRATCH RBM_R2
1101 #define RBM_PROFILER_RET_USED (RBM_R0 | RBM_R1 | RBM_R2)
1102 #define REG_PROFILER_JMP_ARG REG_R0
1103 #define RBM_PROFILER_JMP_USED RBM_R0
1104 #define RBM_PROFILER_TAIL_USED (RBM_R0 | RBM_R12 | RBM_LR)
1105
1106 // The registers trashed by profiler enter/leave/tailcall hook
1107 // See vm\arm\asmhelpers.asm for more details.
1108 #define RBM_PROFILER_ENTER_TRASH RBM_NONE
1109 #define RBM_PROFILER_LEAVE_TRASH RBM_NONE
1110 #define RBM_PROFILER_TAILCALL_TRASH RBM_NONE
1111
1112 // Which register are int and long values returned in ?
1113 #define REG_INTRET REG_R0
1114 #define RBM_INTRET RBM_R0
1115 #define RBM_LNGRET (RBM_R1|RBM_R0)
1116 #define REG_LNGRET_LO REG_R0
1117 #define REG_LNGRET_HI REG_R1
1118 #define RBM_LNGRET_LO RBM_R0
1119 #define RBM_LNGRET_HI RBM_R1
1120
1121 #define REG_FLOATRET REG_F0
1122 #define RBM_FLOATRET RBM_F0
1123 #define RBM_DOUBLERET (RBM_F0|RBM_F1)
1124
1125 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper (JIT_RareDisableHelper).
1126 // See vm\arm\amshelpers.asm for more details.
1127 #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))
1128
1129 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper.
1130 #define RBM_INIT_PINVOKE_FRAME_TRASH (RBM_CALLEE_TRASH | RBM_PINVOKE_TCB | RBM_PINVOKE_SCRATCH)
1131
1132 #define REG_FPBASE REG_R11
1133 #define RBM_FPBASE RBM_R11
1134 #define STR_FPBASE "r11"
1135 #define REG_SPBASE REG_SP
1136 #define RBM_SPBASE RBM_SP
1137 #define STR_SPBASE "sp"
1138
1139 #define FIRST_ARG_STACK_OFFS (2*REGSIZE_BYTES) // Caller's saved FP and return address
1140
1141 #define MAX_REG_ARG 4
1142 #define MAX_FLOAT_REG_ARG 16
1143 #define MAX_HFA_RET_SLOTS 8
1144
1145 #define REG_ARG_FIRST REG_R0
1146 #define REG_ARG_LAST REG_R3
1147 #define REG_ARG_FP_FIRST REG_F0
1148 #define REG_ARG_FP_LAST REG_F7
1149 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
1150
1151 #define REG_ARG_0 REG_R0
1152 #define REG_ARG_1 REG_R1
1153 #define REG_ARG_2 REG_R2
1154 #define REG_ARG_3 REG_R3
1155
1156 SELECTANY const regNumber intArgRegs [] = {REG_R0, REG_R1, REG_R2, REG_R3};
1157 SELECTANY const regMaskTP intArgMasks[] = {RBM_R0, RBM_R1, RBM_R2, RBM_R3};
1158
1159 #define RBM_ARG_0 RBM_R0
1160 #define RBM_ARG_1 RBM_R1
1161 #define RBM_ARG_2 RBM_R2
1162 #define RBM_ARG_3 RBM_R3
1163
1164 #define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1|RBM_ARG_2|RBM_ARG_3)
1165 #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)
1166 #define RBM_DBL_REGS RBM_ALLDOUBLE
1167
1168 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 };
1169 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 };
1170
1171 #define LBL_DIST_SMALL_MAX_NEG (0)
1172 #define LBL_DIST_SMALL_MAX_POS (+1020)
1173 #define LBL_DIST_MED_MAX_NEG (-4095)
1174 #define LBL_DIST_MED_MAX_POS (+4096)
1175
1176 #define JMP_DIST_SMALL_MAX_NEG (-2048)
1177 #define JMP_DIST_SMALL_MAX_POS (+2046)
1178
1179 #define CALL_DIST_MAX_NEG (-16777216)
1180 #define CALL_DIST_MAX_POS (+16777214)
1181
1182 #define JCC_DIST_SMALL_MAX_NEG (-256)
1183 #define JCC_DIST_SMALL_MAX_POS (+254)
1184
1185 #define JCC_DIST_MEDIUM_MAX_NEG (-1048576)
1186 #define JCC_DIST_MEDIUM_MAX_POS (+1048574)
1187
1188 #define LBL_SIZE_SMALL (2)
1189
1190 #define JMP_SIZE_SMALL (2)
1191 #define JMP_SIZE_LARGE (4)
1192
1193 #define JCC_SIZE_SMALL (2)
1194 #define JCC_SIZE_MEDIUM (4)
1195 #define JCC_SIZE_LARGE (6)
1196
1197#elif defined(_TARGET_ARM64_)
1198
1199 #define CPU_LOAD_STORE_ARCH 1
1200 #define CPU_HAS_FP_SUPPORT 1
1201 #define ROUND_FLOAT 0 // Do not round intermed float expression results
1202 #define CPU_HAS_BYTE_REGS 0
1203
1204 #define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk.
1205 #define INITBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll InitBlk.
1206
1207#ifdef FEATURE_SIMD
1208 #define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned
1209 #define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 1 // Whether SIMD registers are partially saved at calls
1210#endif // FEATURE_SIMD
1211
1212 #define FEATURE_FIXED_OUT_ARGS 1 // Preallocate the outgoing arg area in the prolog
1213 #define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
1214 #define FEATURE_MULTIREG_STRUCT_PROMOTE 1 // True when we want to promote fields of a multireg struct into registers
1215 #define FEATURE_FASTTAILCALL 1 // Tail calls made as epilog+jmp
1216 #define FEATURE_TAILCALL_OPT 1 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls.
1217 #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
1218 #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register
1219 #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register
1220 #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register
1221 #define FEATURE_STRUCT_CLASSIFIER 0 // Uses a classifier function to determine is structs are passed/returned in more than one register
1222 #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)
1223 #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)
1224 #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)
1225 #define MAX_RET_REG_COUNT 4 // Maximum registers used to return a value.
1226
1227 #define NOGC_WRITE_BARRIERS 1 // We have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers
1228 #define USER_ARGS_COME_LAST 1
1229 #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
1230 // need to track stack depth, but this is currently necessary to get GC information reported at call sites.
1231 #define TARGET_POINTER_SIZE 8 // equal to sizeof(void*) and the managed pointer size in bytes for this target
1232 #define FEATURE_EH 1 // To aid platform bring-up, eliminate exceptional EH clauses (catch, filter, filter-handler, fault) and directly execute 'finally' clauses.
1233 #define FEATURE_EH_FUNCLETS 1
1234 #define FEATURE_EH_CALLFINALLY_THUNKS 1 // Generate call-to-finally code in "thunks" in the enclosing EH region, protected by "cloned finally" clauses.
1235 #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
1236 #define CSE_CONSTS 1 // Enable if we want to CSE constants
1237
1238 #define REG_FP_FIRST REG_V0
1239 #define REG_FP_LAST REG_V31
1240 #define FIRST_FP_ARGREG REG_V0
1241 #define LAST_FP_ARGREG REG_V15
1242
1243 #define REGNUM_BITS 6 // number of bits in a REG_*
1244 #define REGMASK_BITS 64 // number of bits in a REGNUM_MASK
1245 #define REGSIZE_BYTES 8 // number of bytes in one general purpose register
1246 #define FP_REGSIZE_BYTES 16 // number of bytes in one FP/SIMD register
1247 #define FPSAVE_REGSIZE_BYTES 8 // number of bytes in one FP/SIMD register that are saved/restored, for callee-saved registers
1248
1249 #define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
1250
1251 #define CODE_ALIGN 4 // code alignment requirement
1252 #define STACK_ALIGN 16 // stack alignment requirement
1253
1254 #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)
1255 #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)
1256 #define RBM_FLT_CALLEE_SAVED (RBM_V8|RBM_V9|RBM_V10|RBM_V11|RBM_V12|RBM_V13|RBM_V14|RBM_V15)
1257 #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)
1258
1259 #define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
1260 #define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
1261
1262 #define REG_DEFAULT_HELPER_CALL_TARGET REG_R12
1263 #define RBM_DEFAULT_HELPER_CALL_TARGET RBM_R12
1264
1265 #define REG_FASTTAILCALL_TARGET REG_IP0 // Target register for fast tail call
1266 #define RBM_FASTTAILCALL_TARGET RBM_IP0
1267
1268 #define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
1269 #define RBM_ALLFLOAT (RBM_FLT_CALLEE_SAVED | RBM_FLT_CALLEE_TRASH)
1270 #define RBM_ALLDOUBLE RBM_ALLFLOAT
1271
1272 // REG_VAR_ORDER is: (CALLEE_TRASH & ~CALLEE_TRASH_NOGC), CALLEE_TRASH_NOGC, CALLEE_SAVED
1273 #define REG_VAR_ORDER REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, \
1274 REG_R6, REG_R7, REG_R8, REG_R9, REG_R10, \
1275 REG_R11, REG_R13, REG_R14, \
1276 REG_R12, REG_R15, REG_IP0, REG_IP1, \
1277 REG_CALLEE_SAVED_ORDER
1278
1279 #define REG_VAR_ORDER_FLT REG_V16, REG_V17, REG_V18, REG_V19, \
1280 REG_V20, REG_V21, REG_V22, REG_V23, \
1281 REG_V24, REG_V25, REG_V26, REG_V27, \
1282 REG_V28, REG_V29, REG_V30, REG_V31, \
1283 REG_V7, REG_V6, REG_V5, REG_V4, \
1284 REG_V8, REG_V9, REG_V10, REG_V11, \
1285 REG_V12, REG_V13, REG_V14, REG_V15, \
1286 REG_V3, REG_V2, REG_V1, REG_V0
1287
1288 #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
1289 #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
1290
1291 #define CNT_CALLEE_SAVED (11)
1292 #define CNT_CALLEE_TRASH (17)
1293 #define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
1294
1295 #define CNT_CALLEE_SAVED_FLOAT (8)
1296 #define CNT_CALLEE_TRASH_FLOAT (24)
1297
1298 #define CALLEE_SAVED_REG_MAXSZ (CNT_CALLEE_SAVED * REGSIZE_BYTES)
1299 #define CALLEE_SAVED_FLOAT_MAXSZ (CNT_CALLEE_SAVED_FLOAT * FPSAVE_REGSIZE_BYTES)
1300
1301 #define REG_TMP_0 REG_R9
1302
1303 // Temporary registers used for the GS cookie check.
1304 #define REG_GSCOOKIE_TMP_0 REG_R9
1305 #define REG_GSCOOKIE_TMP_1 REG_R10
1306
1307 // register to hold shift amount; no special register is required on ARM64.
1308 #define REG_SHIFT REG_NA
1309 #define RBM_SHIFT RBM_ALLINT
1310
1311 // This is a general scratch register that does not conflict with the argument registers
1312 #define REG_SCRATCH REG_R9
1313
1314 // This is a general register that can be optionally reserved for other purposes during codegen
1315 #define REG_OPT_RSVD REG_IP1
1316 #define RBM_OPT_RSVD RBM_IP1
1317
1318 // Where is the exception object on entry to the handler block?
1319 #define REG_EXCEPTION_OBJECT REG_R0
1320 #define RBM_EXCEPTION_OBJECT RBM_R0
1321
1322 #define REG_JUMP_THUNK_PARAM REG_R12
1323 #define RBM_JUMP_THUNK_PARAM RBM_R12
1324
1325 // ARM64 write barrier ABI (see vm\arm64\asmhelpers.asm, vm\arm64\asmhelpers.S):
1326 // CORINFO_HELP_ASSIGN_REF (JIT_WriteBarrier), CORINFO_HELP_CHECKED_ASSIGN_REF (JIT_CheckedWriteBarrier):
1327 // On entry:
1328 // x14: the destination address (LHS of the assignment)
1329 // x15: the object reference (RHS of the assignment)
1330 // On exit:
1331 // x12: trashed
1332 // x14: incremented by 8
1333 // x15: trashed
1334 // x17: trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP (currently non-Windows)
1335 // CORINFO_HELP_ASSIGN_BYREF (JIT_ByRefWriteBarrier):
1336 // On entry:
1337 // x13: the source address (points to object reference to write)
1338 // x14: the destination address (object reference written here)
1339 // On exit:
1340 // x12: trashed
1341 // x13: incremented by 8
1342 // x14: incremented by 8
1343 // x15: trashed
1344 // x17: trashed (ip1) if FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP (currently non-Windows)
1345 //
1346 // Note that while x17 (ip1) is currently only trashed under FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP,
1347 // currently only set for non-Windows, it is expected to be set in the future for Windows, and for R2R.
1348 // So simply always consider it trashed, to avoid later breaking changes.
1349
1350 #define REG_WRITE_BARRIER_DST REG_R14
1351 #define RBM_WRITE_BARRIER_DST RBM_R14
1352
1353 #define REG_WRITE_BARRIER_SRC REG_R15
1354 #define RBM_WRITE_BARRIER_SRC RBM_R15
1355
1356 #define REG_WRITE_BARRIER_DST_BYREF REG_R14
1357 #define RBM_WRITE_BARRIER_DST_BYREF RBM_R14
1358
1359 #define REG_WRITE_BARRIER_SRC_BYREF REG_R13
1360 #define RBM_WRITE_BARRIER_SRC_BYREF RBM_R13
1361
1362 #define RBM_CALLEE_TRASH_NOGC (RBM_R12|RBM_R15|RBM_IP0|RBM_IP1|RBM_DEFAULT_HELPER_CALL_TARGET)
1363
1364 // Registers killed by CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1365 #define RBM_CALLEE_TRASH_WRITEBARRIER (RBM_R14|RBM_CALLEE_TRASH_NOGC)
1366
1367 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
1368 #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_NOGC
1369
1370 // Registers killed by CORINFO_HELP_ASSIGN_BYREF.
1371 #define RBM_CALLEE_TRASH_WRITEBARRIER_BYREF (RBM_WRITE_BARRIER_DST_BYREF | RBM_WRITE_BARRIER_SRC_BYREF | RBM_CALLEE_TRASH_NOGC)
1372
1373 // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_BYREF.
1374 // Note that x13 and x14 are still valid byref pointers after this helper call, despite their value being changed.
1375 #define RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF RBM_CALLEE_TRASH_NOGC
1376
1377 // GenericPInvokeCalliHelper VASigCookie Parameter
1378 #define REG_PINVOKE_COOKIE_PARAM REG_R15
1379 #define RBM_PINVOKE_COOKIE_PARAM RBM_R15
1380
1381 // GenericPInvokeCalliHelper unmanaged target Parameter
1382 #define REG_PINVOKE_TARGET_PARAM REG_R12
1383 #define RBM_PINVOKE_TARGET_PARAM RBM_R12
1384
1385 // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM)
1386 #define REG_SECRET_STUB_PARAM REG_R12
1387 #define RBM_SECRET_STUB_PARAM RBM_R12
1388
1389 // R2R indirect call. Use the same registers as VSD
1390 #define REG_R2R_INDIRECT_PARAM REG_R11
1391 #define RBM_R2R_INDIRECT_PARAM RBM_R11
1392
1393 // JMP Indirect call register
1394 #define REG_INDIRECT_CALL_TARGET_REG REG_IP0
1395
1396 // Registers used by PInvoke frame setup
1397 #define REG_PINVOKE_FRAME REG_R9
1398 #define RBM_PINVOKE_FRAME RBM_R9
1399 #define REG_PINVOKE_TCB REG_R10
1400 #define RBM_PINVOKE_TCB RBM_R10
1401 #define REG_PINVOKE_SCRATCH REG_R10
1402 #define RBM_PINVOKE_SCRATCH RBM_R10
1403
1404 // The following defines are useful for iterating a regNumber
1405 #define REG_FIRST REG_R0
1406 #define REG_INT_FIRST REG_R0
1407 #define REG_INT_LAST REG_ZR
1408 #define REG_INT_COUNT (REG_INT_LAST - REG_INT_FIRST + 1)
1409 #define REG_NEXT(reg) ((regNumber)((unsigned)(reg) + 1))
1410 #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1))
1411
1412 // The following registers are used in emitting Enter/Leave/Tailcall profiler callbacks
1413 #define REG_PROFILER_ENTER_ARG REG_R0
1414 #define RBM_PROFILER_ENTER_ARG RBM_R0
1415 #define REG_PROFILER_RET_SCRATCH REG_R2
1416 #define RBM_PROFILER_RET_SCRATCH RBM_R2
1417 #define RBM_PROFILER_RET_USED (RBM_R0 | RBM_R1 | RBM_R2)
1418 #define REG_PROFILER_JMP_ARG REG_R0
1419 #define RBM_PROFILER_JMP_USED RBM_R0
1420 #define RBM_PROFILER_TAIL_USED (RBM_R0 | RBM_R12 | RBM_LR)
1421
1422 // Which register are int and long values returned in ?
1423 #define REG_INTRET REG_R0
1424 #define RBM_INTRET RBM_R0
1425 #define RBM_LNGRET RBM_R0
1426 // second return register for 16-byte structs
1427 #define REG_INTRET_1 REG_R1
1428 #define RBM_INTRET_1 RBM_R1
1429
1430 #define REG_FLOATRET REG_V0
1431 #define RBM_FLOATRET RBM_V0
1432 #define RBM_DOUBLERET RBM_V0
1433
1434 // The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper
1435 #define RBM_STOP_FOR_GC_TRASH RBM_CALLEE_TRASH
1436
1437 // The registers trashed by the CORINFO_HELP_INIT_PINVOKE_FRAME helper.
1438 #define RBM_INIT_PINVOKE_FRAME_TRASH RBM_CALLEE_TRASH
1439
1440 #define REG_FPBASE REG_FP
1441 #define RBM_FPBASE RBM_FP
1442 #define STR_FPBASE "fp"
1443 #define REG_SPBASE REG_SP
1444 #define RBM_SPBASE RBM_ZR // reuse the RBM for REG_ZR
1445 #define STR_SPBASE "sp"
1446
1447 #define FIRST_ARG_STACK_OFFS (2*REGSIZE_BYTES) // Caller's saved FP and return address
1448
1449 // On ARM64 the calling convention defines REG_R8 (x8) as an additional argument register.
1450 // It isn't allocated for the normal user arguments, so it isn't counted by MAX_REG_ARG.
1451 // Whether we use this register to pass the RetBuff is controlled by the function hasFixedRetBuffReg().
1452 // It is considered to be the next integer argnum, which is 8.
1453 //
1454 #define REG_ARG_RET_BUFF REG_R8
1455 #define RBM_ARG_RET_BUFF RBM_R8
1456 #define RET_BUFF_ARGNUM 8
1457
1458 #define MAX_REG_ARG 8
1459 #define MAX_FLOAT_REG_ARG 8
1460
1461 #define REG_ARG_FIRST REG_R0
1462 #define REG_ARG_LAST REG_R7
1463 #define REG_ARG_FP_FIRST REG_V0
1464 #define REG_ARG_FP_LAST REG_V7
1465 #define INIT_ARG_STACK_SLOT 0 // No outgoing reserved stack slots
1466
1467 #define REG_ARG_0 REG_R0
1468 #define REG_ARG_1 REG_R1
1469 #define REG_ARG_2 REG_R2
1470 #define REG_ARG_3 REG_R3
1471 #define REG_ARG_4 REG_R4
1472 #define REG_ARG_5 REG_R5
1473 #define REG_ARG_6 REG_R6
1474 #define REG_ARG_7 REG_R7
1475
1476 SELECTANY const regNumber intArgRegs [] = {REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7};
1477 SELECTANY const regMaskTP intArgMasks[] = {RBM_R0, RBM_R1, RBM_R2, RBM_R3, RBM_R4, RBM_R5, RBM_R6, RBM_R7};
1478
1479 #define RBM_ARG_0 RBM_R0
1480 #define RBM_ARG_1 RBM_R1
1481 #define RBM_ARG_2 RBM_R2
1482 #define RBM_ARG_3 RBM_R3
1483 #define RBM_ARG_4 RBM_R4
1484 #define RBM_ARG_5 RBM_R5
1485 #define RBM_ARG_6 RBM_R6
1486 #define RBM_ARG_7 RBM_R7
1487
1488 #define REG_FLTARG_0 REG_V0
1489 #define REG_FLTARG_1 REG_V1
1490 #define REG_FLTARG_2 REG_V2
1491 #define REG_FLTARG_3 REG_V3
1492 #define REG_FLTARG_4 REG_V4
1493 #define REG_FLTARG_5 REG_V5
1494 #define REG_FLTARG_6 REG_V6
1495 #define REG_FLTARG_7 REG_V7
1496
1497 #define RBM_FLTARG_0 RBM_V0
1498 #define RBM_FLTARG_1 RBM_V1
1499 #define RBM_FLTARG_2 RBM_V2
1500 #define RBM_FLTARG_3 RBM_V3
1501 #define RBM_FLTARG_4 RBM_V4
1502 #define RBM_FLTARG_5 RBM_V5
1503 #define RBM_FLTARG_6 RBM_V6
1504 #define RBM_FLTARG_7 RBM_V7
1505
1506 #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)
1507 #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)
1508
1509 SELECTANY const regNumber fltArgRegs [] = {REG_V0, REG_V1, REG_V2, REG_V3, REG_V4, REG_V5, REG_V6, REG_V7 };
1510 SELECTANY const regMaskTP fltArgMasks[] = {RBM_V0, RBM_V1, RBM_V2, RBM_V3, RBM_V4, RBM_V5, RBM_V6, RBM_V7 };
1511
1512 #define LBL_DIST_SMALL_MAX_NEG (-1048576)
1513 #define LBL_DIST_SMALL_MAX_POS (+1048575)
1514
1515 #define LBL_SIZE_SMALL (4)
1516
1517 #define JCC_DIST_SMALL_MAX_NEG (-1048576)
1518 #define JCC_DIST_SMALL_MAX_POS (+1048575)
1519
1520 #define TB_DIST_SMALL_MAX_NEG (-32768)
1521 #define TB_DIST_SMALL_MAX_POS (+32767)
1522
1523 #define JCC_SIZE_SMALL (4)
1524 #define JCC_SIZE_LARGE (8)
1525
1526 #define LDC_DIST_SMALL_MAX_NEG (-1048576)
1527 #define LDC_DIST_SMALL_MAX_POS (+1048575)
1528
1529 #define LDC_SIZE_SMALL (4)
1530
1531 #define JMP_SIZE_SMALL (4)
1532
1533#else
1534 #error Unsupported or unset target architecture
1535#endif
1536
1537#ifdef _TARGET_XARCH_
1538
1539 #define JMP_DIST_SMALL_MAX_NEG (-128)
1540 #define JMP_DIST_SMALL_MAX_POS (+127)
1541
1542 #define JCC_DIST_SMALL_MAX_NEG (-128)
1543 #define JCC_DIST_SMALL_MAX_POS (+127)
1544
1545 #define JMP_SIZE_SMALL (2)
1546 #define JMP_SIZE_LARGE (5)
1547
1548 #define JCC_SIZE_SMALL (2)
1549 #define JCC_SIZE_LARGE (6)
1550
1551 #define PUSH_INST_SIZE (5)
1552 #define CALL_INST_SIZE (5)
1553
1554#endif // _TARGET_XARCH_
1555
1556C_ASSERT(REG_FIRST == 0);
1557C_ASSERT(REG_INT_FIRST < REG_INT_LAST);
1558C_ASSERT(REG_FP_FIRST < REG_FP_LAST);
1559
1560// Opportunistic tail call feature converts non-tail prefixed calls into
1561// tail calls where possible. It requires fast tail calling mechanism for
1562// performance. Otherwise, we are better off not converting non-tail prefixed
1563// calls into tail calls.
1564C_ASSERT((FEATURE_TAILCALL_OPT == 0) || (FEATURE_FASTTAILCALL == 1));
1565
1566/*****************************************************************************/
1567
1568#define BITS_PER_BYTE 8
1569#define REGNUM_MASK ((1 << REGNUM_BITS) - 1) // a n-bit mask use to encode multiple REGNUMs into a unsigned int
1570#define RBM_ALL(type) (varTypeIsFloating(type) ? RBM_ALLFLOAT : RBM_ALLINT)
1571
1572/*****************************************************************************/
1573
1574#if CPU_HAS_BYTE_REGS
1575 #define RBM_BYTE_REGS (RBM_EAX|RBM_ECX|RBM_EDX|RBM_EBX)
1576 #define RBM_NON_BYTE_REGS (RBM_ESI|RBM_EDI)
1577#else
1578 #define RBM_BYTE_REGS RBM_ALLINT
1579 #define RBM_NON_BYTE_REGS RBM_NONE
1580#endif
1581// clang-format on
1582
1583/*****************************************************************************/
1584class Target
1585{
1586public:
1587 static const char* g_tgtCPUName;
1588 static const char* g_tgtPlatformName;
1589
1590 enum ArgOrder
1591 {
1592 ARG_ORDER_R2L,
1593 ARG_ORDER_L2R
1594 };
1595 static const enum ArgOrder g_tgtArgOrder;
1596};
1597
1598#if defined(DEBUG) || defined(LATE_DISASM)
1599const char* getRegName(unsigned reg, bool isFloat = false); // this is for gcencode.cpp and disasm.cpp that don't use
1600 // the regNumber type
1601const char* getRegName(regNumber reg, bool isFloat = false);
1602#endif // defined(DEBUG) || defined(LATE_DISASM)
1603
1604#ifdef DEBUG
1605const char* getRegNameFloat(regNumber reg, var_types type);
1606extern void dspRegMask(regMaskTP regMask, size_t minSiz = 0);
1607#endif
1608
1609#if CPU_HAS_BYTE_REGS
1610inline BOOL isByteReg(regNumber reg)
1611{
1612 return (reg <= REG_EBX);
1613}
1614#else
1615inline BOOL isByteReg(regNumber reg)
1616{
1617 return true;
1618}
1619#endif
1620
1621inline regMaskTP genRegMask(regNumber reg);
1622inline regMaskTP genRegMaskFloat(regNumber reg, var_types type = TYP_DOUBLE);
1623
1624/*****************************************************************************
1625 * Return true if the register number is valid
1626 */
1627inline bool genIsValidReg(regNumber reg)
1628{
1629 /* It's safest to perform an unsigned comparison in case reg is negative */
1630 return ((unsigned)reg < (unsigned)REG_COUNT);
1631}
1632
1633/*****************************************************************************
1634 * Return true if the register is a valid integer register
1635 */
1636inline bool genIsValidIntReg(regNumber reg)
1637{
1638 return reg >= REG_INT_FIRST && reg <= REG_INT_LAST;
1639}
1640
1641/*****************************************************************************
1642 * Return true if the register is a valid floating point register
1643 */
1644inline bool genIsValidFloatReg(regNumber reg)
1645{
1646 return reg >= REG_FP_FIRST && reg <= REG_FP_LAST;
1647}
1648
1649#ifdef _TARGET_ARM_
1650
1651/*****************************************************************************
1652 * Return true if the register is a valid floating point double register
1653 */
1654inline bool genIsValidDoubleReg(regNumber reg)
1655{
1656 return genIsValidFloatReg(reg) && (((reg - REG_FP_FIRST) & 0x1) == 0);
1657}
1658
1659#endif // _TARGET_ARM_
1660
1661//-------------------------------------------------------------------------------------------
1662// hasFixedRetBuffReg:
1663// Returns true if our target architecture uses a fixed return buffer register
1664//
1665inline bool hasFixedRetBuffReg()
1666{
1667#ifdef _TARGET_ARM64_
1668 return true;
1669#else
1670 return false;
1671#endif
1672}
1673
1674//-------------------------------------------------------------------------------------------
1675// theFixedRetBuffReg:
1676// Returns the regNumber to use for the fixed return buffer
1677//
1678inline regNumber theFixedRetBuffReg()
1679{
1680 assert(hasFixedRetBuffReg()); // This predicate should be checked before calling this method
1681#ifdef _TARGET_ARM64_
1682 return REG_ARG_RET_BUFF;
1683#else
1684 return REG_NA;
1685#endif
1686}
1687
1688//-------------------------------------------------------------------------------------------
1689// theFixedRetBuffMask:
1690// Returns the regNumber to use for the fixed return buffer
1691//
1692inline regMaskTP theFixedRetBuffMask()
1693{
1694 assert(hasFixedRetBuffReg()); // This predicate should be checked before calling this method
1695#ifdef _TARGET_ARM64_
1696 return RBM_ARG_RET_BUFF;
1697#else
1698 return 0;
1699#endif
1700}
1701
1702//-------------------------------------------------------------------------------------------
1703// theFixedRetBuffArgNum:
1704// Returns the argNum to use for the fixed return buffer
1705//
1706inline unsigned theFixedRetBuffArgNum()
1707{
1708 assert(hasFixedRetBuffReg()); // This predicate should be checked before calling this method
1709#ifdef _TARGET_ARM64_
1710 return RET_BUFF_ARGNUM;
1711#else
1712 return BAD_VAR_NUM;
1713#endif
1714}
1715
1716//-------------------------------------------------------------------------------------------
1717// fullIntArgRegMask:
1718// Returns the full mask of all possible integer registers
1719// Note this includes the fixed return buffer register on Arm64
1720//
1721inline regMaskTP fullIntArgRegMask()
1722{
1723 if (hasFixedRetBuffReg())
1724 {
1725 return RBM_ARG_REGS | theFixedRetBuffMask();
1726 }
1727 else
1728 {
1729 return RBM_ARG_REGS;
1730 }
1731}
1732
1733//-------------------------------------------------------------------------------------------
1734// isValidIntArgReg:
1735// Returns true if the register is a valid integer argument register
1736// Note this method also returns true on Arm64 when 'reg' is the RetBuff register
1737//
1738inline bool isValidIntArgReg(regNumber reg)
1739{
1740 return (genRegMask(reg) & fullIntArgRegMask()) != 0;
1741}
1742
1743//-------------------------------------------------------------------------------------------
1744// genRegArgNext:
1745// Given a register that is an integer or floating point argument register
1746// returns the next argument register
1747//
1748regNumber genRegArgNext(regNumber argReg);
1749
1750//-------------------------------------------------------------------------------------------
1751// isValidFloatArgReg:
1752// Returns true if the register is a valid floating-point argument register
1753//
1754inline bool isValidFloatArgReg(regNumber reg)
1755{
1756 if (reg == REG_NA)
1757 {
1758 return false;
1759 }
1760 else
1761 {
1762 return (reg >= FIRST_FP_ARGREG) && (reg <= LAST_FP_ARGREG);
1763 }
1764}
1765
1766/*****************************************************************************
1767 *
1768 * Can the register hold the argument type?
1769 */
1770
1771#ifdef _TARGET_ARM_
1772inline bool floatRegCanHoldType(regNumber reg, var_types type)
1773{
1774 assert(genIsValidFloatReg(reg));
1775 if (type == TYP_DOUBLE)
1776 {
1777 return ((reg - REG_F0) % 2) == 0;
1778 }
1779 else
1780 {
1781 // Can be TYP_STRUCT for HFA. It's not clear that's correct; what about
1782 // HFA of double? We wouldn't be asserting the right alignment, and
1783 // callers like genRegMaskFloat() wouldn't be generating the right mask.
1784
1785 assert((type == TYP_FLOAT) || (type == TYP_STRUCT));
1786 return true;
1787 }
1788}
1789#else
1790// AMD64: xmm registers can hold any float type
1791// x86: FP stack can hold any float type
1792// ARM64: Floating-point/SIMD registers can hold any type.
1793inline bool floatRegCanHoldType(regNumber reg, var_types type)
1794{
1795 return true;
1796}
1797#endif
1798
1799/*****************************************************************************
1800 *
1801 * Map a register number to a register mask.
1802 */
1803
1804extern const regMaskSmall regMasks[REG_COUNT];
1805
1806inline regMaskTP genRegMask(regNumber reg)
1807{
1808 assert((unsigned)reg < ArrLen(regMasks));
1809#ifdef _TARGET_AMD64_
1810 // shift is faster than a L1 hit on modern x86
1811 // (L1 latency on sandy bridge is 4 cycles for [base] and 5 for [base + index*c] )
1812 // the reason this is AMD-only is because the x86 BE will try to get reg masks for REG_STK
1813 // and the result needs to be zero.
1814 regMaskTP result = 1 << reg;
1815 assert(result == regMasks[reg]);
1816 return result;
1817#else
1818 return regMasks[reg];
1819#endif
1820}
1821
1822/*****************************************************************************
1823 *
1824 * Map a register number to a floating-point register mask.
1825 */
1826
1827inline regMaskTP genRegMaskFloat(regNumber reg, var_types type /* = TYP_DOUBLE */)
1828{
1829#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) || defined(_TARGET_X86_)
1830 assert(genIsValidFloatReg(reg));
1831 assert((unsigned)reg < ArrLen(regMasks));
1832 return regMasks[reg];
1833#elif defined(_TARGET_ARM_)
1834 assert(floatRegCanHoldType(reg, type));
1835 assert(reg >= REG_F0 && reg <= REG_F31);
1836
1837 if (type == TYP_DOUBLE)
1838 {
1839 return regMasks[reg] | regMasks[reg + 1];
1840 }
1841 else
1842 {
1843 return regMasks[reg];
1844 }
1845#else
1846#error Unsupported or unset target architecture
1847#endif
1848}
1849
1850//------------------------------------------------------------------------
1851// genRegMask: Given a register, and its type, generate the appropriate regMask
1852//
1853// Arguments:
1854// regNum - the register of interest
1855// type - the type of regNum (i.e. the type it is being used as)
1856//
1857// Return Value:
1858// This will usually return the same value as genRegMask(regNum), but
1859// on architectures where multiple registers are used for certain types
1860// (e.g. TYP_DOUBLE on ARM), it will return a regMask that includes
1861// all the registers.
1862// Registers that are used in pairs, but separately named (e.g. TYP_LONG
1863// on ARM) will return just the regMask for the given register.
1864//
1865// Assumptions:
1866// For registers that are used in pairs, the caller will be handling
1867// each member of the pair separately.
1868//
1869inline regMaskTP genRegMask(regNumber regNum, var_types type)
1870{
1871#ifndef _TARGET_ARM_
1872 return genRegMask(regNum);
1873#else
1874 regMaskTP regMask = RBM_NONE;
1875
1876 if (varTypeIsFloating(type))
1877 {
1878 regMask = genRegMaskFloat(regNum, type);
1879 }
1880 else
1881 {
1882 regMask = genRegMask(regNum);
1883 }
1884 return regMask;
1885#endif
1886}
1887
1888/*****************************************************************************
1889 *
1890 * These arrays list the callee-saved register numbers (and bitmaps, respectively) for
1891 * the current architecture.
1892 */
1893extern const regNumber raRegCalleeSaveOrder[CNT_CALLEE_SAVED];
1894extern const regMaskTP raRbmCalleeSaveOrder[CNT_CALLEE_SAVED];
1895
1896// This method takes a "compact" bitset of the callee-saved registers, and "expands" it to a full register mask.
1897regMaskSmall genRegMaskFromCalleeSavedMask(unsigned short);
1898
1899/*****************************************************************************
1900 *
1901 * Assumes that "reg" is of the given "type". Return the next unused reg number after "reg"
1902 * of this type, else REG_NA if there are no more.
1903 */
1904
1905inline regNumber regNextOfType(regNumber reg, var_types type)
1906{
1907 regNumber regReturn;
1908
1909#ifdef _TARGET_ARM_
1910 if (type == TYP_DOUBLE)
1911 {
1912 // Skip odd FP registers for double-precision types
1913 assert(floatRegCanHoldType(reg, type));
1914 regReturn = regNumber(reg + 2);
1915 }
1916 else
1917 {
1918 regReturn = REG_NEXT(reg);
1919 }
1920#else // _TARGET_ARM_
1921 regReturn = REG_NEXT(reg);
1922#endif
1923
1924 if (varTypeIsFloating(type))
1925 {
1926 if (regReturn > REG_FP_LAST)
1927 {
1928 regReturn = REG_NA;
1929 }
1930 }
1931 else
1932 {
1933 if (regReturn > REG_INT_LAST)
1934 {
1935 regReturn = REG_NA;
1936 }
1937 }
1938
1939 return regReturn;
1940}
1941
1942/*****************************************************************************
1943 *
1944 * Type checks
1945 */
1946
1947inline bool isFloatRegType(int /* s/b "var_types" */ type)
1948{
1949#if CPU_HAS_FP_SUPPORT
1950 return type == TYP_DOUBLE || type == TYP_FLOAT;
1951#else
1952 return false;
1953#endif
1954}
1955
1956// If the WINDOWS_AMD64_ABI is defined make sure that _TARGET_AMD64_ is also defined.
1957#if defined(WINDOWS_AMD64_ABI)
1958#if !defined(_TARGET_AMD64_)
1959#error When WINDOWS_AMD64_ABI is defined you must define _TARGET_AMD64_ defined as well.
1960#endif
1961#endif
1962
1963/*****************************************************************************/
1964// Some sanity checks on some of the register masks
1965// Stack pointer is never part of RBM_ALLINT
1966C_ASSERT((RBM_ALLINT & RBM_SPBASE) == RBM_NONE);
1967C_ASSERT((RBM_INT_CALLEE_SAVED & RBM_SPBASE) == RBM_NONE);
1968
1969#if ETW_EBP_FRAMED
1970// Frame pointer isn't either if we're supporting ETW frame chaining
1971C_ASSERT((RBM_ALLINT & RBM_FPBASE) == RBM_NONE);
1972C_ASSERT((RBM_INT_CALLEE_SAVED & RBM_FPBASE) == RBM_NONE);
1973#endif
1974/*****************************************************************************/
1975
1976#ifdef _TARGET_64BIT_
1977typedef unsigned __int64 target_size_t;
1978typedef __int64 target_ssize_t;
1979#else // !_TARGET_64BIT_
1980typedef unsigned int target_size_t;
1981typedef int target_ssize_t;
1982#endif // !_TARGET_64BIT_
1983
1984C_ASSERT(sizeof(target_size_t) == TARGET_POINTER_SIZE);
1985C_ASSERT(sizeof(target_ssize_t) == TARGET_POINTER_SIZE);
1986
1987/*****************************************************************************/
1988#endif // _TARGET_H_
1989/*****************************************************************************/
1990