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_) |
57 | enum _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 | |
68 | enum _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 | |
78 | enum _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 | |
89 | enum _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 | |
99 | enum _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 | |
110 | enum _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 | |
121 | enum _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 | |
132 | enum _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_ |
157 | typedef unsigned __int64 regMaskTP; |
158 | #else |
159 | typedef unsigned regMaskTP; |
160 | #endif |
161 | |
162 | #if REGMASK_BITS == 8 |
163 | typedef unsigned char regMaskSmall; |
164 | #define REG_MASK_INT_FMT "%02X" |
165 | #define REG_MASK_ALL_FMT "%02X" |
166 | #elif REGMASK_BITS == 16 |
167 | typedef unsigned short regMaskSmall; |
168 | #define REG_MASK_INT_FMT "%04X" |
169 | #define REG_MASK_ALL_FMT "%04X" |
170 | #elif REGMASK_BITS == 32 |
171 | typedef unsigned regMaskSmall; |
172 | #define REG_MASK_INT_FMT "%08X" |
173 | #define REG_MASK_ALL_FMT "%08X" |
174 | #else |
175 | typedef unsigned __int64 regMaskSmall; |
176 | #define REG_MASK_INT_FMT "%04llX" |
177 | #define REG_MASK_ALL_FMT "%016llX" |
178 | #endif |
179 | |
180 | typedef _regNumber_enum regNumber; |
181 | typedef 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 | |
1556 | C_ASSERT(REG_FIRST == 0); |
1557 | C_ASSERT(REG_INT_FIRST < REG_INT_LAST); |
1558 | C_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. |
1564 | C_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 | /*****************************************************************************/ |
1584 | class Target |
1585 | { |
1586 | public: |
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) |
1599 | const char* getRegName(unsigned reg, bool isFloat = false); // this is for gcencode.cpp and disasm.cpp that don't use |
1600 | // the regNumber type |
1601 | const char* getRegName(regNumber reg, bool isFloat = false); |
1602 | #endif // defined(DEBUG) || defined(LATE_DISASM) |
1603 | |
1604 | #ifdef DEBUG |
1605 | const char* getRegNameFloat(regNumber reg, var_types type); |
1606 | extern void dspRegMask(regMaskTP regMask, size_t minSiz = 0); |
1607 | #endif |
1608 | |
1609 | #if CPU_HAS_BYTE_REGS |
1610 | inline BOOL isByteReg(regNumber reg) |
1611 | { |
1612 | return (reg <= REG_EBX); |
1613 | } |
1614 | #else |
1615 | inline BOOL isByteReg(regNumber reg) |
1616 | { |
1617 | return true; |
1618 | } |
1619 | #endif |
1620 | |
1621 | inline regMaskTP genRegMask(regNumber reg); |
1622 | inline regMaskTP genRegMaskFloat(regNumber reg, var_types type = TYP_DOUBLE); |
1623 | |
1624 | /***************************************************************************** |
1625 | * Return true if the register number is valid |
1626 | */ |
1627 | inline 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 | */ |
1636 | inline 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 | */ |
1644 | inline 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 | */ |
1654 | inline 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 | // |
1665 | inline 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 | // |
1678 | inline 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 | // |
1692 | inline 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 | // |
1706 | inline 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 | // |
1721 | inline 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 | // |
1738 | inline 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 | // |
1748 | regNumber genRegArgNext(regNumber argReg); |
1749 | |
1750 | //------------------------------------------------------------------------------------------- |
1751 | // isValidFloatArgReg: |
1752 | // Returns true if the register is a valid floating-point argument register |
1753 | // |
1754 | inline 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_ |
1772 | inline 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. |
1793 | inline 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 | |
1804 | extern const regMaskSmall regMasks[REG_COUNT]; |
1805 | |
1806 | inline 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 | |
1827 | inline 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 | // |
1869 | inline 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 | */ |
1893 | extern const regNumber raRegCalleeSaveOrder[CNT_CALLEE_SAVED]; |
1894 | extern 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. |
1897 | regMaskSmall 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 | |
1905 | inline 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 | |
1947 | inline 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 |
1966 | C_ASSERT((RBM_ALLINT & RBM_SPBASE) == RBM_NONE); |
1967 | C_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 |
1971 | C_ASSERT((RBM_ALLINT & RBM_FPBASE) == RBM_NONE); |
1972 | C_ASSERT((RBM_INT_CALLEE_SAVED & RBM_FPBASE) == RBM_NONE); |
1973 | #endif |
1974 | /*****************************************************************************/ |
1975 | |
1976 | #ifdef _TARGET_64BIT_ |
1977 | typedef unsigned __int64 target_size_t; |
1978 | typedef __int64 target_ssize_t; |
1979 | #else // !_TARGET_64BIT_ |
1980 | typedef unsigned int target_size_t; |
1981 | typedef int target_ssize_t; |
1982 | #endif // !_TARGET_64BIT_ |
1983 | |
1984 | C_ASSERT(sizeof(target_size_t) == TARGET_POINTER_SIZE); |
1985 | C_ASSERT(sizeof(target_ssize_t) == TARGET_POINTER_SIZE); |
1986 | |
1987 | /*****************************************************************************/ |
1988 | #endif // _TARGET_H_ |
1989 | /*****************************************************************************/ |
1990 | |