c9ab053a4ee626b447247d04eaabbb80cb8a7abf
[platform/upstream/coreclr.git] / src / jit / lclvars.cpp
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 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                           LclVarsInfo                                     XX
9 XX                                                                           XX
10 XX   The variables to be used by the code generator.                         XX
11 XX                                                                           XX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14 */
15
16 #include "jitpch.h"
17 #ifdef _MSC_VER
18 #pragma hdrstop
19 #endif
20 #include "emit.h"
21
22 #include "register_arg_convention.h"
23
24 /*****************************************************************************/
25
26 #ifdef DEBUG
27 #if DOUBLE_ALIGN
28 /* static */
29 unsigned Compiler::s_lvaDoubleAlignedProcsCount = 0;
30 #endif
31 #endif
32
33 /*****************************************************************************/
34
35 void Compiler::lvaInit()
36 {
37     /* We haven't allocated stack variables yet */
38     lvaRefCountingStarted = false;
39     lvaLocalVarRefCounted = false;
40
41     lvaSortAgain    = false; // false: We don't need to call lvaSortOnly()
42     lvaTrackedFixed = false; // false: We can still add new tracked variables
43
44     lvaDoneFrameLayout = NO_FRAME_LAYOUT;
45 #if !FEATURE_EH_FUNCLETS
46     lvaShadowSPslotsVar = BAD_VAR_NUM;
47 #endif // !FEATURE_EH_FUNCLETS
48     lvaInlinedPInvokeFrameVar = BAD_VAR_NUM;
49     lvaReversePInvokeFrameVar = BAD_VAR_NUM;
50 #if FEATURE_FIXED_OUT_ARGS
51     lvaPInvokeFrameRegSaveVar = BAD_VAR_NUM;
52     lvaOutgoingArgSpaceVar    = BAD_VAR_NUM;
53 #endif // FEATURE_FIXED_OUT_ARGS
54 #ifdef _TARGET_ARM_
55     lvaPromotedStructAssemblyScratchVar = BAD_VAR_NUM;
56 #endif // _TARGET_ARM_
57     lvaLocAllocSPvar    = BAD_VAR_NUM;
58     lvaNewObjArrayArgs  = BAD_VAR_NUM;
59     lvaGSSecurityCookie = BAD_VAR_NUM;
60 #ifdef _TARGET_X86_
61     lvaVarargsBaseOfStkArgs = BAD_VAR_NUM;
62 #endif // _TARGET_X86_
63     lvaVarargsHandleArg = BAD_VAR_NUM;
64     lvaSecurityObject   = BAD_VAR_NUM;
65     lvaStubArgumentVar  = BAD_VAR_NUM;
66     lvaArg0Var          = BAD_VAR_NUM;
67     lvaMonAcquired      = BAD_VAR_NUM;
68
69     lvaInlineeReturnSpillTemp = BAD_VAR_NUM;
70
71     gsShadowVarInfo = nullptr;
72 #if FEATURE_EH_FUNCLETS
73     lvaPSPSym = BAD_VAR_NUM;
74 #endif
75 #if FEATURE_SIMD
76     lvaSIMDInitTempVarNum = BAD_VAR_NUM;
77 #endif // FEATURE_SIMD
78     lvaCurEpoch = 0;
79 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
80     lvaFirstStackIncomingArgNum = BAD_VAR_NUM;
81 #endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
82 }
83
84 /*****************************************************************************/
85
86 void Compiler::lvaInitTypeRef()
87 {
88
89     /* x86 args look something like this:
90         [this ptr] [hidden return buffer] [declared arguments]* [generic context] [var arg cookie]
91
92        x64 is closer to the native ABI:
93         [this ptr] [hidden return buffer] [generic context] [var arg cookie] [declared arguments]*
94         (Note: prior to .NET Framework 4.5.1 for Windows 8.1 (but not .NET Framework 4.5.1 "downlevel"),
95         the "hidden return buffer" came before the "this ptr". Now, the "this ptr" comes first. This
96         is different from the C++ order, where the "hidden return buffer" always comes first.)
97
98        ARM and ARM64 are the same as the current x64 convention:
99         [this ptr] [hidden return buffer] [generic context] [var arg cookie] [declared arguments]*
100
101        Key difference:
102            The var arg cookie and generic context are swapped with respect to the user arguments
103     */
104
105     /* Set compArgsCount and compLocalsCount */
106
107     info.compArgsCount = info.compMethodInfo->args.numArgs;
108
109     // Is there a 'this' pointer
110
111     if (!info.compIsStatic)
112     {
113         info.compArgsCount++;
114     }
115     else
116     {
117         info.compThisArg = BAD_VAR_NUM;
118     }
119
120     info.compILargsCount = info.compArgsCount;
121
122 #ifdef FEATURE_SIMD
123     if (featureSIMD && (info.compRetNativeType == TYP_STRUCT))
124     {
125         var_types structType = impNormStructType(info.compMethodInfo->args.retTypeClass);
126         info.compRetType     = structType;
127     }
128 #endif // FEATURE_SIMD
129
130     // Are we returning a struct using a return buffer argument?
131     //
132     const bool hasRetBuffArg = impMethodInfo_hasRetBuffArg(info.compMethodInfo);
133
134     // Possibly change the compRetNativeType from TYP_STRUCT to a "primitive" type
135     // when we are returning a struct by value and it fits in one register
136     //
137     if (!hasRetBuffArg && varTypeIsStruct(info.compRetNativeType))
138     {
139         CORINFO_CLASS_HANDLE retClsHnd = info.compMethodInfo->args.retTypeClass;
140
141         Compiler::structPassingKind howToReturnStruct;
142         var_types                   returnType = getReturnTypeForStruct(retClsHnd, &howToReturnStruct);
143
144         if (howToReturnStruct == SPK_PrimitiveType)
145         {
146             assert(returnType != TYP_UNKNOWN);
147             assert(returnType != TYP_STRUCT);
148
149             info.compRetNativeType = returnType;
150
151             // ToDo: Refactor this common code sequence into its own method as it is used 4+ times
152             if ((returnType == TYP_LONG) && (compLongUsed == false))
153             {
154                 compLongUsed = true;
155             }
156             else if (((returnType == TYP_FLOAT) || (returnType == TYP_DOUBLE)) && (compFloatingPointUsed == false))
157             {
158                 compFloatingPointUsed = true;
159             }
160         }
161     }
162
163     // Do we have a RetBuffArg?
164
165     if (hasRetBuffArg)
166     {
167         info.compArgsCount++;
168     }
169     else
170     {
171         info.compRetBuffArg = BAD_VAR_NUM;
172     }
173
174     /* There is a 'hidden' cookie pushed last when the
175        calling convention is varargs */
176
177     if (info.compIsVarArgs)
178     {
179         info.compArgsCount++;
180     }
181
182     // Is there an extra parameter used to pass instantiation info to
183     // shared generic methods and shared generic struct instance methods?
184     if (info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE)
185     {
186         info.compArgsCount++;
187     }
188     else
189     {
190         info.compTypeCtxtArg = BAD_VAR_NUM;
191     }
192
193     lvaCount = info.compLocalsCount = info.compArgsCount + info.compMethodInfo->locals.numArgs;
194
195     info.compILlocalsCount = info.compILargsCount + info.compMethodInfo->locals.numArgs;
196
197     /* Now allocate the variable descriptor table */
198
199     if (compIsForInlining())
200     {
201         lvaTable    = impInlineInfo->InlinerCompiler->lvaTable;
202         lvaCount    = impInlineInfo->InlinerCompiler->lvaCount;
203         lvaTableCnt = impInlineInfo->InlinerCompiler->lvaTableCnt;
204
205         // No more stuff needs to be done.
206         return;
207     }
208
209     lvaTableCnt = lvaCount * 2;
210
211     if (lvaTableCnt < 16)
212     {
213         lvaTableCnt = 16;
214     }
215
216     lvaTable         = (LclVarDsc*)compGetMemArray(lvaTableCnt, sizeof(*lvaTable), CMK_LvaTable);
217     size_t tableSize = lvaTableCnt * sizeof(*lvaTable);
218     memset(lvaTable, 0, tableSize);
219     for (unsigned i = 0; i < lvaTableCnt; i++)
220     {
221         new (&lvaTable[i], jitstd::placement_t()) LclVarDsc(this); // call the constructor.
222     }
223
224     //-------------------------------------------------------------------------
225     // Count the arguments and initialize the respective lvaTable[] entries
226     //
227     // First the implicit arguments
228     //-------------------------------------------------------------------------
229
230     InitVarDscInfo varDscInfo;
231     varDscInfo.Init(lvaTable, hasRetBuffArg);
232
233     lvaInitArgs(&varDscInfo);
234
235     //-------------------------------------------------------------------------
236     // Finally the local variables
237     //-------------------------------------------------------------------------
238
239     unsigned                varNum    = varDscInfo.varNum;
240     LclVarDsc*              varDsc    = varDscInfo.varDsc;
241     CORINFO_ARG_LIST_HANDLE localsSig = info.compMethodInfo->locals.args;
242
243     for (unsigned i = 0; i < info.compMethodInfo->locals.numArgs;
244          i++, varNum++, varDsc++, localsSig = info.compCompHnd->getArgNext(localsSig))
245     {
246         CORINFO_CLASS_HANDLE typeHnd;
247         CorInfoTypeWithMod   corInfoType =
248             info.compCompHnd->getArgType(&info.compMethodInfo->locals, localsSig, &typeHnd);
249         lvaInitVarDsc(varDsc, varNum, strip(corInfoType), typeHnd, localsSig, &info.compMethodInfo->locals);
250
251         varDsc->lvPinned  = ((corInfoType & CORINFO_TYPE_MOD_PINNED) != 0);
252         varDsc->lvOnFrame = true; // The final home for this local variable might be our local stack frame
253     }
254
255     if ( // If there already exist unsafe buffers, don't mark more structs as unsafe
256         // as that will cause them to be placed along with the real unsafe buffers,
257         // unnecessarily exposing them to overruns. This can affect GS tests which
258         // intentionally do buffer-overruns.
259         !getNeedsGSSecurityCookie() &&
260         // GS checks require the stack to be re-ordered, which can't be done with EnC
261         !opts.compDbgEnC && compStressCompile(STRESS_UNSAFE_BUFFER_CHECKS, 25))
262     {
263         setNeedsGSSecurityCookie();
264         compGSReorderStackLayout = true;
265
266         for (unsigned i = 0; i < lvaCount; i++)
267         {
268             if ((lvaTable[i].lvType == TYP_STRUCT) && compStressCompile(STRESS_GENERIC_VARN, 60))
269             {
270                 lvaTable[i].lvIsUnsafeBuffer = true;
271             }
272         }
273     }
274
275     if (getNeedsGSSecurityCookie())
276     {
277         // Ensure that there will be at least one stack variable since
278         // we require that the GSCookie does not have a 0 stack offset.
279         unsigned dummy         = lvaGrabTempWithImplicitUse(false DEBUGARG("GSCookie dummy"));
280         lvaTable[dummy].lvType = TYP_INT;
281     }
282
283 #ifdef DEBUG
284     if (verbose)
285     {
286         lvaTableDump(INITIAL_FRAME_LAYOUT);
287     }
288 #endif
289 }
290
291 /*****************************************************************************/
292 void Compiler::lvaInitArgs(InitVarDscInfo* varDscInfo)
293 {
294     compArgSize = 0;
295
296 #if defined(_TARGET_ARM_) && defined(PROFILING_SUPPORTED)
297     // Prespill all argument regs on to stack in case of Arm when under profiler.
298     if (compIsProfilerHookNeeded())
299     {
300         codeGen->regSet.rsMaskPreSpillRegArg |= RBM_ARG_REGS;
301     }
302 #endif
303
304     //----------------------------------------------------------------------
305
306     /* Is there a "this" pointer ? */
307     lvaInitThisPtr(varDscInfo);
308
309     /* If we have a hidden return-buffer parameter, that comes here */
310     lvaInitRetBuffArg(varDscInfo);
311
312 //======================================================================
313
314 #if USER_ARGS_COME_LAST
315     //@GENERICS: final instantiation-info argument for shared generic methods
316     // and shared generic struct instance methods
317     lvaInitGenericsCtxt(varDscInfo);
318
319     /* If the method is varargs, process the varargs cookie */
320     lvaInitVarArgsHandle(varDscInfo);
321 #endif
322
323     //-------------------------------------------------------------------------
324     // Now walk the function signature for the explicit user arguments
325     //-------------------------------------------------------------------------
326     lvaInitUserArgs(varDscInfo);
327
328 #if !USER_ARGS_COME_LAST
329     //@GENERICS: final instantiation-info argument for shared generic methods
330     // and shared generic struct instance methods
331     lvaInitGenericsCtxt(varDscInfo);
332
333     /* If the method is varargs, process the varargs cookie */
334     lvaInitVarArgsHandle(varDscInfo);
335 #endif
336
337     //----------------------------------------------------------------------
338
339     // We have set info.compArgsCount in compCompile()
340     noway_assert(varDscInfo->varNum == info.compArgsCount);
341     assert(varDscInfo->intRegArgNum <= MAX_REG_ARG);
342
343     codeGen->intRegState.rsCalleeRegArgCount = varDscInfo->intRegArgNum;
344 #if !FEATURE_STACK_FP_X87
345     codeGen->floatRegState.rsCalleeRegArgCount = varDscInfo->floatRegArgNum;
346 #endif // FEATURE_STACK_FP_X87
347
348     // The total argument size must be aligned.
349     noway_assert((compArgSize % sizeof(void*)) == 0);
350
351 #ifdef _TARGET_X86_
352     /* We can not pass more than 2^16 dwords as arguments as the "ret"
353        instruction can only pop 2^16 arguments. Could be handled correctly
354        but it will be very difficult for fully interruptible code */
355
356     if (compArgSize != (size_t)(unsigned short)compArgSize)
357         NO_WAY("Too many arguments for the \"ret\" instruction to pop");
358 #endif
359 }
360
361 /*****************************************************************************/
362 void Compiler::lvaInitThisPtr(InitVarDscInfo* varDscInfo)
363 {
364     LclVarDsc* varDsc = varDscInfo->varDsc;
365     if (!info.compIsStatic)
366     {
367         varDsc->lvIsParam = 1;
368 #if ASSERTION_PROP
369         varDsc->lvSingleDef = 1;
370 #endif
371
372         varDsc->lvIsPtr = 1;
373
374         lvaArg0Var = info.compThisArg = varDscInfo->varNum;
375         noway_assert(info.compThisArg == 0);
376
377         if (eeIsValueClass(info.compClassHnd))
378         {
379             varDsc->lvType = TYP_BYREF;
380 #ifdef FEATURE_SIMD
381             if (featureSIMD)
382             {
383                 var_types simdBaseType = TYP_UNKNOWN;
384                 var_types type         = impNormStructType(info.compClassHnd, nullptr, nullptr, &simdBaseType);
385                 if (simdBaseType != TYP_UNKNOWN)
386                 {
387                     assert(varTypeIsSIMD(type));
388                     varDsc->lvSIMDType = true;
389                     varDsc->lvBaseType = simdBaseType;
390                 }
391             }
392 #endif // FEATURE_SIMD
393         }
394         else
395         {
396             varDsc->lvType = TYP_REF;
397         }
398
399         if (tiVerificationNeeded)
400         {
401             varDsc->lvVerTypeInfo = verMakeTypeInfo(info.compClassHnd);
402
403             if (varDsc->lvVerTypeInfo.IsValueClass())
404             {
405                 varDsc->lvVerTypeInfo.MakeByRef();
406             }
407         }
408         else
409         {
410             varDsc->lvVerTypeInfo = typeInfo();
411         }
412
413         // Mark the 'this' pointer for the method
414         varDsc->lvVerTypeInfo.SetIsThisPtr();
415
416         varDsc->lvIsRegArg = 1;
417         noway_assert(varDscInfo->intRegArgNum == 0);
418
419         varDsc->lvArgReg = genMapRegArgNumToRegNum(varDscInfo->allocRegArg(TYP_INT), varDsc->TypeGet());
420 #if FEATURE_MULTIREG_ARGS
421         varDsc->lvOtherArgReg = REG_NA;
422 #endif
423         varDsc->setPrefReg(varDsc->lvArgReg, this);
424         varDsc->lvOnFrame = true; // The final home for this incoming register might be our local stack frame
425
426 #ifdef DEBUG
427         if (verbose)
428         {
429             printf("'this'    passed in register %s\n", getRegName(varDsc->lvArgReg));
430         }
431 #endif
432         compArgSize += TARGET_POINTER_SIZE;
433
434         varDscInfo->varNum++;
435         varDscInfo->varDsc++;
436     }
437 }
438
439 /*****************************************************************************/
440 void Compiler::lvaInitRetBuffArg(InitVarDscInfo* varDscInfo)
441 {
442     LclVarDsc* varDsc        = varDscInfo->varDsc;
443     bool       hasRetBuffArg = impMethodInfo_hasRetBuffArg(info.compMethodInfo);
444
445     // These two should always match
446     noway_assert(hasRetBuffArg == varDscInfo->hasRetBufArg);
447
448     if (hasRetBuffArg)
449     {
450         info.compRetBuffArg = varDscInfo->varNum;
451         varDsc->lvType      = TYP_BYREF;
452         varDsc->lvIsParam   = 1;
453         varDsc->lvIsRegArg  = 1;
454 #if ASSERTION_PROP
455         varDsc->lvSingleDef = 1;
456 #endif
457         if (hasFixedRetBuffReg())
458         {
459             varDsc->lvArgReg = theFixedRetBuffReg();
460         }
461         else
462         {
463             unsigned retBuffArgNum = varDscInfo->allocRegArg(TYP_INT);
464             varDsc->lvArgReg       = genMapIntRegArgNumToRegNum(retBuffArgNum);
465         }
466
467 #if FEATURE_MULTIREG__ARGS
468         varDsc->lvOtherArgReg = REG_NA;
469 #endif
470         varDsc->setPrefReg(varDsc->lvArgReg, this);
471         varDsc->lvOnFrame = true; // The final home for this incoming register might be our local stack frame
472
473         info.compRetBuffDefStack = 0;
474         if (info.compRetType == TYP_STRUCT)
475         {
476             CORINFO_SIG_INFO sigInfo;
477             info.compCompHnd->getMethodSig(info.compMethodHnd, &sigInfo);
478             assert(JITtype2varType(sigInfo.retType) == info.compRetType); // Else shouldn't have a ret buff.
479
480             info.compRetBuffDefStack =
481                 (info.compCompHnd->isStructRequiringStackAllocRetBuf(sigInfo.retTypeClass) == TRUE);
482             if (info.compRetBuffDefStack)
483             {
484                 // If we're assured that the ret buff argument points into a callers stack, we will type it as
485                 // "TYP_I_IMPL"
486                 // (native int/unmanaged pointer) so that it's not tracked as a GC ref.
487                 varDsc->lvType = TYP_I_IMPL;
488             }
489         }
490         assert(isValidIntArgReg(varDsc->lvArgReg));
491
492 #ifdef DEBUG
493         if (verbose)
494         {
495             printf("'__retBuf'  passed in register %s\n", getRegName(varDsc->lvArgReg));
496         }
497 #endif
498
499         /* Update the total argument size, count and varDsc */
500
501         compArgSize += TARGET_POINTER_SIZE;
502         varDscInfo->varNum++;
503         varDscInfo->varDsc++;
504     }
505 }
506
507 /*****************************************************************************/
508 void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo)
509 {
510 //-------------------------------------------------------------------------
511 // Walk the function signature for the explicit arguments
512 //-------------------------------------------------------------------------
513
514 #if defined(_TARGET_X86_)
515     // Only (some of) the implicit args are enregistered for varargs
516     varDscInfo->maxIntRegArgNum = info.compIsVarArgs ? varDscInfo->intRegArgNum : MAX_REG_ARG;
517 #elif defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI)
518     // On System V type environment the float registers are not indexed together with the int ones.
519     varDscInfo->floatRegArgNum = varDscInfo->intRegArgNum;
520 #endif // _TARGET_*
521
522     CORINFO_ARG_LIST_HANDLE argLst = info.compMethodInfo->args.args;
523
524     const unsigned argSigLen = info.compMethodInfo->args.numArgs;
525
526     regMaskTP doubleAlignMask = RBM_NONE;
527     for (unsigned i = 0; i < argSigLen;
528          i++, varDscInfo->varNum++, varDscInfo->varDsc++, argLst = info.compCompHnd->getArgNext(argLst))
529     {
530         LclVarDsc*           varDsc  = varDscInfo->varDsc;
531         CORINFO_CLASS_HANDLE typeHnd = nullptr;
532
533         CorInfoTypeWithMod corInfoType = info.compCompHnd->getArgType(&info.compMethodInfo->args, argLst, &typeHnd);
534         varDsc->lvIsParam              = 1;
535 #if ASSERTION_PROP
536         varDsc->lvSingleDef = 1;
537 #endif
538
539         lvaInitVarDsc(varDsc, varDscInfo->varNum, strip(corInfoType), typeHnd, argLst, &info.compMethodInfo->args);
540
541         // For ARM, ARM64, and AMD64 varargs, all arguments go in integer registers
542         var_types argType     = mangleVarArgsType(varDsc->TypeGet());
543         var_types origArgType = argType;
544         // ARM softfp calling convention should affect only the floating point arguments.
545         // Otherwise there appear too many surplus pre-spills and other memory operations
546         // with the associated locations .
547         bool      isSoftFPPreSpill = opts.compUseSoftFP && varTypeIsFloating(varDsc->TypeGet());
548         unsigned  argSize          = eeGetArgSize(argLst, &info.compMethodInfo->args);
549         unsigned  cSlots           = argSize / TARGET_POINTER_SIZE; // the total number of slots of this argument
550         bool      isHfaArg         = false;
551         var_types hfaType          = TYP_UNDEF;
552
553         // Methods that use VarArg or SoftFP cannot have HFA arguments
554         if (!info.compIsVarArgs && !opts.compUseSoftFP)
555         {
556             // If the argType is a struct, then check if it is an HFA
557             if (varTypeIsStruct(argType))
558             {
559                 hfaType  = GetHfaType(typeHnd); // set to float or double if it is an HFA, otherwise TYP_UNDEF
560                 isHfaArg = varTypeIsFloating(hfaType);
561             }
562         }
563         if (isHfaArg)
564         {
565             // We have an HFA argument, so from here on out treat the type as a float or double.
566             // The orginal struct type is available by using origArgType
567             // We also update the cSlots to be the number of float/double fields in the HFA
568             argType = hfaType;
569             cSlots  = varDsc->lvHfaSlots();
570         }
571         // The number of slots that must be enregistered if we are to consider this argument enregistered.
572         // This is normally the same as cSlots, since we normally either enregister the entire object,
573         // or none of it. For structs on ARM, however, we only need to enregister a single slot to consider
574         // it enregistered, as long as we can split the rest onto the stack.
575         unsigned cSlotsToEnregister = cSlots;
576
577 #ifdef _TARGET_ARM_
578         // On ARM we pass the first 4 words of integer arguments and non-HFA structs in registers.
579         // But we pre-spill user arguments in varargs methods and structs.
580         //
581         unsigned cAlign;
582         bool     preSpill = info.compIsVarArgs || isSoftFPPreSpill;
583
584         switch (origArgType)
585         {
586             case TYP_STRUCT:
587                 assert(varDsc->lvSize() == argSize);
588                 cAlign = varDsc->lvStructDoubleAlign ? 2 : 1;
589
590                 // HFA arguments go on the stack frame. They don't get spilled in the prolog like struct
591                 // arguments passed in the integer registers but get homed immediately after the prolog.
592                 if (!isHfaArg)
593                 {
594                     cSlotsToEnregister = 1; // HFAs must be totally enregistered or not, but other structs can be split.
595                     preSpill           = true;
596                 }
597                 break;
598
599             case TYP_DOUBLE:
600             case TYP_LONG:
601                 cAlign = 2;
602                 break;
603
604             default:
605                 cAlign = 1;
606                 break;
607         }
608
609         if (isRegParamType(argType))
610         {
611             compArgSize += varDscInfo->alignReg(argType, cAlign) * REGSIZE_BYTES;
612         }
613
614         if (argType == TYP_STRUCT)
615         {
616             // Are we going to split the struct between registers and stack? We can do that as long as
617             // no floating-point arguments have been put on the stack.
618             //
619             // From the ARM Procedure Call Standard:
620             // Rule C.5: "If the NCRN is less than r4 **and** the NSAA is equal to the SP,"
621             // then split the argument between registers and stack. Implication: if something
622             // has already been spilled to the stack, then anything that would normally be
623             // split between the core registers and the stack will be put on the stack.
624             // Anything that follows will also be on the stack. However, if something from
625             // floating point regs has been spilled to the stack, we can still use r0-r3 until they are full.
626
627             if (varDscInfo->canEnreg(TYP_INT, 1) &&       // The beginning of the struct can go in a register
628                 !varDscInfo->canEnreg(TYP_INT, cSlots) && // The end of the struct can't fit in a register
629                 varDscInfo->existAnyFloatStackArgs())     // There's at least one stack-based FP arg already
630             {
631                 varDscInfo->setAllRegArgUsed(TYP_INT); // Prevent all future use of integer registers
632                 preSpill = false;                      // This struct won't be prespilled, since it will go on the stack
633             }
634         }
635
636         if (preSpill)
637         {
638             for (unsigned ix = 0; ix < cSlots; ix++)
639             {
640                 if (!varDscInfo->canEnreg(TYP_INT, ix + 1))
641                 {
642                     break;
643                 }
644                 regMaskTP regMask = genMapArgNumToRegMask(varDscInfo->regArgNum(TYP_INT) + ix, TYP_INT);
645                 if (cAlign == 2)
646                 {
647                     doubleAlignMask |= regMask;
648                 }
649                 codeGen->regSet.rsMaskPreSpillRegArg |= regMask;
650             }
651         }
652         else
653         {
654             varDsc->lvOnFrame = true; // The final home for this incoming register might be our local stack frame
655         }
656
657 #else // !_TARGET_ARM_
658 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
659         SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
660         if (varTypeIsStruct(argType))
661         {
662             assert(typeHnd != nullptr);
663             eeGetSystemVAmd64PassStructInRegisterDescriptor(typeHnd, &structDesc);
664             if (structDesc.passedInRegisters)
665             {
666                 unsigned intRegCount   = 0;
667                 unsigned floatRegCount = 0;
668
669                 for (unsigned int i = 0; i < structDesc.eightByteCount; i++)
670                 {
671                     if (structDesc.IsIntegralSlot(i))
672                     {
673                         intRegCount++;
674                     }
675                     else if (structDesc.IsSseSlot(i))
676                     {
677                         floatRegCount++;
678                     }
679                     else
680                     {
681                         assert(false && "Invalid eightbyte classification type.");
682                         break;
683                     }
684                 }
685
686                 if (intRegCount != 0 && !varDscInfo->canEnreg(TYP_INT, intRegCount))
687                 {
688                     structDesc.passedInRegisters = false; // No register to enregister the eightbytes.
689                 }
690
691                 if (floatRegCount != 0 && !varDscInfo->canEnreg(TYP_FLOAT, floatRegCount))
692                 {
693                     structDesc.passedInRegisters = false; // No register to enregister the eightbytes.
694                 }
695             }
696         }
697 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
698
699         // The final home for this incoming register might be our local stack frame.
700         // For System V platforms the final home will always be on the local stack frame.
701         varDsc->lvOnFrame = true;
702
703 #endif // !_TARGET_ARM_
704
705         bool canPassArgInRegisters = false;
706
707 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
708         if (varTypeIsStruct(argType))
709         {
710             canPassArgInRegisters = structDesc.passedInRegisters;
711         }
712         else
713 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
714         {
715             canPassArgInRegisters = varDscInfo->canEnreg(argType, cSlotsToEnregister);
716         }
717
718         if (canPassArgInRegisters)
719         {
720             /* Another register argument */
721
722             // Allocate the registers we need. allocRegArg() returns the first argument register number of the set.
723             // For non-HFA structs, we still "try" to enregister the whole thing; it will just max out if splitting
724             // to the stack happens.
725             unsigned firstAllocatedRegArgNum = 0;
726
727 #if FEATURE_MULTIREG_ARGS
728             varDsc->lvOtherArgReg = REG_NA;
729 #endif // FEATURE_MULTIREG_ARGS
730
731 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
732             unsigned  secondAllocatedRegArgNum = 0;
733             var_types firstEightByteType       = TYP_UNDEF;
734             var_types secondEightByteType      = TYP_UNDEF;
735
736             if (varTypeIsStruct(argType))
737             {
738                 if (structDesc.eightByteCount >= 1)
739                 {
740                     firstEightByteType      = GetEightByteType(structDesc, 0);
741                     firstAllocatedRegArgNum = varDscInfo->allocRegArg(firstEightByteType, 1);
742                 }
743             }
744             else
745 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
746             {
747                 firstAllocatedRegArgNum = varDscInfo->allocRegArg(argType, cSlots);
748             }
749
750             if (isHfaArg)
751             {
752                 // We need to save the fact that this HFA is enregistered
753                 varDsc->lvSetIsHfa();
754                 varDsc->lvSetIsHfaRegArg();
755                 varDsc->SetHfaType(hfaType);
756                 varDsc->lvIsMultiRegArg = (varDsc->lvHfaSlots() > 1);
757             }
758
759             varDsc->lvIsRegArg = 1;
760
761 #if FEATURE_MULTIREG_ARGS
762             if (varTypeIsStruct(argType))
763             {
764 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
765                 varDsc->lvArgReg = genMapRegArgNumToRegNum(firstAllocatedRegArgNum, firstEightByteType);
766
767                 // If there is a second eightbyte, get a register for it too and map the arg to the reg number.
768                 if (structDesc.eightByteCount >= 2)
769                 {
770                     secondEightByteType      = GetEightByteType(structDesc, 1);
771                     secondAllocatedRegArgNum = varDscInfo->allocRegArg(secondEightByteType, 1);
772                 }
773
774                 if (secondEightByteType != TYP_UNDEF)
775                 {
776                     varDsc->lvOtherArgReg = genMapRegArgNumToRegNum(secondAllocatedRegArgNum, secondEightByteType);
777                     varDsc->addPrefReg(genRegMask(varDsc->lvOtherArgReg), this);
778                 }
779 #else // ARM32 or ARM64
780                 varDsc->lvArgReg = genMapRegArgNumToRegNum(firstAllocatedRegArgNum, TYP_I_IMPL);
781 #ifdef _TARGET_ARM64_
782                 if (cSlots == 2)
783                 {
784                     varDsc->lvOtherArgReg = genMapRegArgNumToRegNum(firstAllocatedRegArgNum + 1, TYP_I_IMPL);
785                     varDsc->addPrefReg(genRegMask(varDsc->lvOtherArgReg), this);
786                 }
787 #endif //  _TARGET_ARM64_
788 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
789             }
790             else
791 #endif // FEATURE_MULTIREG_ARGS
792             {
793                 varDsc->lvArgReg = genMapRegArgNumToRegNum(firstAllocatedRegArgNum, argType);
794             }
795
796             varDsc->setPrefReg(varDsc->lvArgReg, this);
797
798 #ifdef _TARGET_ARM_
799             if (varDsc->TypeGet() == TYP_LONG)
800             {
801                 varDsc->lvOtherReg = genMapRegArgNumToRegNum(firstAllocatedRegArgNum + 1, TYP_INT);
802                 varDsc->addPrefReg(genRegMask(varDsc->lvOtherReg), this);
803             }
804 #endif // _TARGET_ARM_
805
806 #ifdef DEBUG
807             if (verbose)
808             {
809                 printf("Arg #%u    passed in register(s) ", varDscInfo->varNum);
810                 bool isFloat = false;
811 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
812                 // In case of one eightbyte struct the type is already normalized earlier.
813                 // The varTypeIsFloating(argType) is good for this case.
814                 if (varTypeIsStruct(argType) && (structDesc.eightByteCount >= 1))
815                 {
816                     isFloat = varTypeIsFloating(firstEightByteType);
817                 }
818                 else
819 #else  // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
820                 {
821                     isFloat = varTypeIsFloating(argType);
822                 }
823 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
824
825 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
826                     if (varTypeIsStruct(argType))
827                 {
828                     // Print both registers, just to be clear
829                     if (firstEightByteType == TYP_UNDEF)
830                     {
831                         printf("firstEightByte: <not used>");
832                     }
833                     else
834                     {
835                         printf("firstEightByte: %s",
836                                getRegName(genMapRegArgNumToRegNum(firstAllocatedRegArgNum, firstEightByteType),
837                                           isFloat));
838                     }
839
840                     if (secondEightByteType == TYP_UNDEF)
841                     {
842                         printf(", secondEightByte: <not used>");
843                     }
844                     else
845                     {
846                         printf(", secondEightByte: %s",
847                                getRegName(genMapRegArgNumToRegNum(secondAllocatedRegArgNum, secondEightByteType),
848                                           varTypeIsFloating(secondEightByteType)));
849                     }
850                 }
851                 else
852 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
853                 {
854                     unsigned regArgNum = genMapRegNumToRegArgNum(varDsc->lvArgReg, argType);
855
856                     for (unsigned ix = 0; ix < cSlots; ix++, regArgNum++)
857                     {
858                         if (ix > 0)
859                         {
860                             printf(",");
861                         }
862
863                         if (!isFloat && (regArgNum >= varDscInfo->maxIntRegArgNum)) // a struct has been split between
864                                                                                     // registers and stack
865                         {
866                             printf(" stack slots:%d", cSlots - ix);
867                             break;
868                         }
869
870 #ifdef _TARGET_ARM_
871                         if (isFloat)
872                         {
873                             // Print register size prefix
874                             if (argType == TYP_DOUBLE)
875                             {
876                                 // Print both registers, just to be clear
877                                 printf("%s/%s", getRegName(genMapRegArgNumToRegNum(regArgNum, argType), isFloat),
878                                        getRegName(genMapRegArgNumToRegNum(regArgNum + 1, argType), isFloat));
879
880                                 // doubles take 2 slots
881                                 assert(ix + 1 < cSlots);
882                                 ++ix;
883                                 ++regArgNum;
884                             }
885                             else
886                             {
887                                 printf("%s", getRegName(genMapRegArgNumToRegNum(regArgNum, argType), isFloat));
888                             }
889                         }
890                         else
891 #endif // _TARGET_ARM_
892                         {
893                             printf("%s", getRegName(genMapRegArgNumToRegNum(regArgNum, argType), isFloat));
894                         }
895                     }
896                 }
897                 printf("\n");
898             }
899 #endif    // DEBUG
900         } // end if (canPassArgInRegisters)
901         else
902         {
903 #if defined(_TARGET_ARM_)
904
905             varDscInfo->setAllRegArgUsed(argType);
906             if (varTypeIsFloating(argType))
907             {
908                 varDscInfo->setAnyFloatStackArgs();
909             }
910
911 #elif defined(_TARGET_ARM64_)
912
913             // If we needed to use the stack in order to pass this argument then
914             // record the fact that we have used up any remaining registers of this 'type'
915             // This prevents any 'backfilling' from occuring on ARM64
916             //
917             varDscInfo->setAllRegArgUsed(argType);
918
919 #endif // _TARGET_XXX_
920         }
921
922 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
923         // The arg size is returning the number of bytes of the argument. For a struct it could return a size not a
924         // multiple of TARGET_POINTER_SIZE. The stack allocated space should always be multiple of TARGET_POINTER_SIZE,
925         // so round it up.
926         compArgSize += (unsigned)roundUp(argSize, TARGET_POINTER_SIZE);
927 #else  // !FEATURE_UNIX_AMD64_STRUCT_PASSING
928         compArgSize += argSize;
929 #endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
930         if (info.compIsVarArgs || isHfaArg || isSoftFPPreSpill)
931         {
932 #if defined(_TARGET_X86_)
933             varDsc->lvStkOffs = compArgSize;
934 #else  // !_TARGET_X86_
935             // TODO-CQ: We shouldn't have to go as far as to declare these
936             // address-exposed -- DoNotEnregister should suffice.
937             lvaSetVarAddrExposed(varDscInfo->varNum);
938 #endif // !_TARGET_X86_
939         }
940     } // for each user arg
941
942 #ifdef _TARGET_ARM_
943     if (doubleAlignMask != RBM_NONE)
944     {
945         assert(RBM_ARG_REGS == 0xF);
946         assert((doubleAlignMask & RBM_ARG_REGS) == doubleAlignMask);
947         if (doubleAlignMask != RBM_NONE && doubleAlignMask != RBM_ARG_REGS)
948         {
949             // doubleAlignMask can only be 0011 and/or 1100 as 'double aligned types' can
950             // begin at r0 or r2.
951             assert(doubleAlignMask == 0x3 || doubleAlignMask == 0xC /* || 0xF is if'ed out */);
952
953             // Now if doubleAlignMask is 0011 i.e., {r0,r1} and we prespill r2 or r3
954             // but not both, then the stack would be misaligned for r0. So spill both
955             // r2 and r3.
956             //
957             // ; +0 --- caller SP double aligned ----
958             // ; -4 r2    r3
959             // ; -8 r1    r1
960             // ; -c r0    r0   <-- misaligned.
961             // ; callee saved regs
962             if (doubleAlignMask == 0x3 && doubleAlignMask != codeGen->regSet.rsMaskPreSpillRegArg)
963             {
964                 codeGen->regSet.rsMaskPreSpillAlign =
965                     (~codeGen->regSet.rsMaskPreSpillRegArg & ~doubleAlignMask) & RBM_ARG_REGS;
966             }
967         }
968     }
969 #endif // _TARGET_ARM_
970 }
971
972 /*****************************************************************************/
973 void Compiler::lvaInitGenericsCtxt(InitVarDscInfo* varDscInfo)
974 {
975     //@GENERICS: final instantiation-info argument for shared generic methods
976     // and shared generic struct instance methods
977     if (info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE)
978     {
979         info.compTypeCtxtArg = varDscInfo->varNum;
980
981         LclVarDsc* varDsc = varDscInfo->varDsc;
982         varDsc->lvIsParam = 1;
983 #if ASSERTION_PROP
984         varDsc->lvSingleDef = 1;
985 #endif
986
987         varDsc->lvType = TYP_I_IMPL;
988
989         if (varDscInfo->canEnreg(TYP_I_IMPL))
990         {
991             /* Another register argument */
992
993             varDsc->lvIsRegArg = 1;
994             varDsc->lvArgReg   = genMapRegArgNumToRegNum(varDscInfo->regArgNum(TYP_INT), varDsc->TypeGet());
995 #if FEATURE_MULTIREG_ARGS
996             varDsc->lvOtherArgReg = REG_NA;
997 #endif
998             varDsc->setPrefReg(varDsc->lvArgReg, this);
999             varDsc->lvOnFrame = true; // The final home for this incoming register might be our local stack frame
1000
1001             varDscInfo->intRegArgNum++;
1002
1003 #ifdef DEBUG
1004             if (verbose)
1005             {
1006                 printf("'GenCtxt'   passed in register %s\n", getRegName(varDsc->lvArgReg));
1007             }
1008 #endif
1009         }
1010 #ifndef LEGACY_BACKEND
1011         else
1012         {
1013             // For the RyuJIT backend, we need to mark these as being on the stack,
1014             // as this is not done elsewhere in the case that canEnreg returns false.
1015             varDsc->lvOnFrame = true;
1016         }
1017 #endif // !LEGACY_BACKEND
1018
1019         compArgSize += TARGET_POINTER_SIZE;
1020
1021 #if defined(_TARGET_X86_)
1022         if (info.compIsVarArgs)
1023             varDsc->lvStkOffs = compArgSize;
1024 #endif // _TARGET_X86_
1025
1026         varDscInfo->varNum++;
1027         varDscInfo->varDsc++;
1028     }
1029 }
1030
1031 /*****************************************************************************/
1032 void Compiler::lvaInitVarArgsHandle(InitVarDscInfo* varDscInfo)
1033 {
1034     if (info.compIsVarArgs)
1035     {
1036         lvaVarargsHandleArg = varDscInfo->varNum;
1037
1038         LclVarDsc* varDsc = varDscInfo->varDsc;
1039         varDsc->lvType    = TYP_I_IMPL;
1040         varDsc->lvIsParam = 1;
1041         // Make sure this lives in the stack -- address may be reported to the VM.
1042         // TODO-CQ: This should probably be:
1043         //   lvaSetVarDoNotEnregister(varDscInfo->varNum DEBUGARG(DNER_VMNeedsStackAddr));
1044         // But that causes problems, so, for expedience, I switched back to this heavyweight
1045         // hammer.  But I think it should be possible to switch; it may just work now
1046         // that other problems are fixed.
1047         lvaSetVarAddrExposed(varDscInfo->varNum);
1048
1049 #if ASSERTION_PROP
1050         varDsc->lvSingleDef = 1;
1051 #endif
1052
1053         if (varDscInfo->canEnreg(TYP_I_IMPL))
1054         {
1055             /* Another register argument */
1056
1057             unsigned varArgHndArgNum = varDscInfo->allocRegArg(TYP_I_IMPL);
1058
1059             varDsc->lvIsRegArg = 1;
1060             varDsc->lvArgReg   = genMapRegArgNumToRegNum(varArgHndArgNum, TYP_I_IMPL);
1061 #if FEATURE_MULTIREG__ARGS
1062             varDsc->lvOtherArgReg = REG_NA;
1063 #endif
1064             varDsc->setPrefReg(varDsc->lvArgReg, this);
1065             varDsc->lvOnFrame = true; // The final home for this incoming register might be our local stack frame
1066 #ifdef _TARGET_ARM_
1067             // This has to be spilled right in front of the real arguments and we have
1068             // to pre-spill all the argument registers explicitly because we only have
1069             // have symbols for the declared ones, not any potential variadic ones.
1070             for (unsigned ix = varArgHndArgNum; ix < ArrLen(intArgMasks); ix++)
1071             {
1072                 codeGen->regSet.rsMaskPreSpillRegArg |= intArgMasks[ix];
1073             }
1074 #endif // _TARGET_ARM_
1075
1076 #ifdef DEBUG
1077             if (verbose)
1078             {
1079                 printf("'VarArgHnd' passed in register %s\n", getRegName(varDsc->lvArgReg));
1080             }
1081 #endif // DEBUG
1082         }
1083 #ifndef LEGACY_BACKEND
1084         else
1085         {
1086             // For the RyuJIT backend, we need to mark these as being on the stack,
1087             // as this is not done elsewhere in the case that canEnreg returns false.
1088             varDsc->lvOnFrame = true;
1089         }
1090 #endif // !LEGACY_BACKEND
1091
1092         /* Update the total argument size, count and varDsc */
1093
1094         compArgSize += TARGET_POINTER_SIZE;
1095
1096         varDscInfo->varNum++;
1097         varDscInfo->varDsc++;
1098
1099 #if defined(_TARGET_X86_)
1100         varDsc->lvStkOffs = compArgSize;
1101
1102         // Allocate a temp to point at the beginning of the args
1103
1104         lvaVarargsBaseOfStkArgs                  = lvaGrabTemp(false DEBUGARG("Varargs BaseOfStkArgs"));
1105         lvaTable[lvaVarargsBaseOfStkArgs].lvType = TYP_I_IMPL;
1106
1107 #endif // _TARGET_X86_
1108     }
1109 }
1110
1111 /*****************************************************************************/
1112 void Compiler::lvaInitVarDsc(LclVarDsc*              varDsc,
1113                              unsigned                varNum,
1114                              CorInfoType             corInfoType,
1115                              CORINFO_CLASS_HANDLE    typeHnd,
1116                              CORINFO_ARG_LIST_HANDLE varList,
1117                              CORINFO_SIG_INFO*       varSig)
1118 {
1119     noway_assert(varDsc == &lvaTable[varNum]);
1120
1121     switch (corInfoType)
1122     {
1123         // Mark types that looks like a pointer for doing shadow-copying of
1124         // parameters if we have an unsafe buffer.
1125         // Note that this does not handle structs with pointer fields. Instead,
1126         // we rely on using the assign-groups/equivalence-groups in
1127         // gsFindVulnerableParams() to determine if a buffer-struct contains a
1128         // pointer. We could do better by having the EE determine this for us.
1129         // Note that we want to keep buffers without pointers at lower memory
1130         // addresses than buffers with pointers.
1131         case CORINFO_TYPE_PTR:
1132         case CORINFO_TYPE_BYREF:
1133         case CORINFO_TYPE_CLASS:
1134         case CORINFO_TYPE_STRING:
1135         case CORINFO_TYPE_VAR:
1136         case CORINFO_TYPE_REFANY:
1137             varDsc->lvIsPtr = 1;
1138             break;
1139         default:
1140             break;
1141     }
1142
1143     var_types type = JITtype2varType(corInfoType);
1144     if (varTypeIsFloating(type))
1145     {
1146         compFloatingPointUsed = true;
1147     }
1148
1149     if (tiVerificationNeeded)
1150     {
1151         varDsc->lvVerTypeInfo = verParseArgSigToTypeInfo(varSig, varList);
1152     }
1153
1154     if (tiVerificationNeeded)
1155     {
1156         if (varDsc->lvIsParam)
1157         {
1158             // For an incoming ValueType we better be able to have the full type information
1159             // so that we can layout the parameter offsets correctly
1160
1161             if (varTypeIsStruct(type) && varDsc->lvVerTypeInfo.IsDead())
1162             {
1163                 BADCODE("invalid ValueType parameter");
1164             }
1165
1166             // For an incoming reference type we need to verify that the actual type is
1167             // a reference type and not a valuetype.
1168
1169             if (type == TYP_REF &&
1170                 !(varDsc->lvVerTypeInfo.IsType(TI_REF) || varDsc->lvVerTypeInfo.IsUnboxedGenericTypeVar()))
1171             {
1172                 BADCODE("parameter type mismatch");
1173             }
1174         }
1175
1176         // Disallow byrefs to byref like objects (ArgTypeHandle)
1177         // techncally we could get away with just not setting them
1178         if (varDsc->lvVerTypeInfo.IsByRef() && verIsByRefLike(DereferenceByRef(varDsc->lvVerTypeInfo)))
1179         {
1180             varDsc->lvVerTypeInfo = typeInfo();
1181         }
1182
1183         // we don't want the EE to assert in lvaSetStruct on bad sigs, so change
1184         // the JIT type to avoid even trying to call back
1185         if (varTypeIsStruct(type) && varDsc->lvVerTypeInfo.IsDead())
1186         {
1187             type = TYP_VOID;
1188         }
1189     }
1190
1191     if (typeHnd)
1192     {
1193         unsigned cFlags = info.compCompHnd->getClassAttribs(typeHnd);
1194
1195         // We can get typeHnds for primitive types, these are value types which only contain
1196         // a primitive. We will need the typeHnd to distinguish them, so we store it here.
1197         if ((cFlags & CORINFO_FLG_VALUECLASS) && !varTypeIsStruct(type))
1198         {
1199             if (tiVerificationNeeded == false)
1200             {
1201                 // printf("This is a struct that the JIT will treat as a primitive\n");
1202                 varDsc->lvVerTypeInfo = verMakeTypeInfo(typeHnd);
1203             }
1204         }
1205
1206         varDsc->lvOverlappingFields = StructHasOverlappingFields(cFlags);
1207     }
1208
1209     if (varTypeIsGC(type))
1210     {
1211         varDsc->lvStructGcCount = 1;
1212     }
1213
1214     // Set the lvType (before this point it is TYP_UNDEF).
1215     if ((varTypeIsStruct(type)))
1216     {
1217         lvaSetStruct(varNum, typeHnd, typeHnd != nullptr, !tiVerificationNeeded);
1218     }
1219     else
1220     {
1221         varDsc->lvType = type;
1222     }
1223
1224 #if OPT_BOOL_OPS
1225     if (type == TYP_BOOL)
1226     {
1227         varDsc->lvIsBoolean = true;
1228     }
1229 #endif
1230
1231 #ifdef DEBUG
1232     varDsc->lvStkOffs = BAD_STK_OFFS;
1233 #endif
1234 }
1235
1236 /*****************************************************************************
1237  * Returns our internal varNum for a given IL variable.
1238  * Asserts assume it is called after lvaTable[] has been set up.
1239  */
1240
1241 unsigned Compiler::compMapILvarNum(unsigned ILvarNum)
1242 {
1243     noway_assert(ILvarNum < info.compILlocalsCount || ILvarNum > unsigned(ICorDebugInfo::UNKNOWN_ILNUM));
1244
1245     unsigned varNum;
1246
1247     if (ILvarNum == (unsigned)ICorDebugInfo::VARARGS_HND_ILNUM)
1248     {
1249         // The varargs cookie is the last argument in lvaTable[]
1250         noway_assert(info.compIsVarArgs);
1251
1252         varNum = lvaVarargsHandleArg;
1253         noway_assert(lvaTable[varNum].lvIsParam);
1254     }
1255     else if (ILvarNum == (unsigned)ICorDebugInfo::RETBUF_ILNUM)
1256     {
1257         noway_assert(info.compRetBuffArg != BAD_VAR_NUM);
1258         varNum = info.compRetBuffArg;
1259     }
1260     else if (ILvarNum == (unsigned)ICorDebugInfo::TYPECTXT_ILNUM)
1261     {
1262         noway_assert(info.compTypeCtxtArg >= 0);
1263         varNum = unsigned(info.compTypeCtxtArg);
1264     }
1265     else if (ILvarNum < info.compILargsCount)
1266     {
1267         // Parameter
1268         varNum = compMapILargNum(ILvarNum);
1269         noway_assert(lvaTable[varNum].lvIsParam);
1270     }
1271     else if (ILvarNum < info.compILlocalsCount)
1272     {
1273         // Local variable
1274         unsigned lclNum = ILvarNum - info.compILargsCount;
1275         varNum          = info.compArgsCount + lclNum;
1276         noway_assert(!lvaTable[varNum].lvIsParam);
1277     }
1278     else
1279     {
1280         unreached();
1281     }
1282
1283     noway_assert(varNum < info.compLocalsCount);
1284     return varNum;
1285 }
1286
1287 /*****************************************************************************
1288  * Returns the IL variable number given our internal varNum.
1289  * Special return values are VARG_ILNUM, RETBUF_ILNUM, TYPECTXT_ILNUM.
1290  *
1291  * Returns UNKNOWN_ILNUM if it can't be mapped.
1292  */
1293
1294 unsigned Compiler::compMap2ILvarNum(unsigned varNum)
1295 {
1296     if (compIsForInlining())
1297     {
1298         return impInlineInfo->InlinerCompiler->compMap2ILvarNum(varNum);
1299     }
1300
1301     noway_assert(varNum < lvaCount);
1302
1303     if (varNum == info.compRetBuffArg)
1304     {
1305         return (unsigned)ICorDebugInfo::RETBUF_ILNUM;
1306     }
1307
1308     // Is this a varargs function?
1309     if (info.compIsVarArgs && varNum == lvaVarargsHandleArg)
1310     {
1311         return (unsigned)ICorDebugInfo::VARARGS_HND_ILNUM;
1312     }
1313
1314     // We create an extra argument for the type context parameter
1315     // needed for shared generic code.
1316     if ((info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE) && varNum == (unsigned)info.compTypeCtxtArg)
1317     {
1318         return (unsigned)ICorDebugInfo::TYPECTXT_ILNUM;
1319     }
1320
1321     // Now mutate varNum to remove extra parameters from the count.
1322     if ((info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE) && varNum > (unsigned)info.compTypeCtxtArg)
1323     {
1324         varNum--;
1325     }
1326
1327     if (info.compIsVarArgs && varNum > lvaVarargsHandleArg)
1328     {
1329         varNum--;
1330     }
1331
1332     /* Is there a hidden argument for the return buffer.
1333        Note that this code works because if the RetBuffArg is not present,
1334        compRetBuffArg will be BAD_VAR_NUM */
1335     if (info.compRetBuffArg != BAD_VAR_NUM && varNum > info.compRetBuffArg)
1336     {
1337         varNum--;
1338     }
1339
1340     if (varNum >= info.compLocalsCount)
1341     {
1342         return (unsigned)ICorDebugInfo::UNKNOWN_ILNUM; // Cannot be mapped
1343     }
1344
1345     return varNum;
1346 }
1347
1348 /*****************************************************************************
1349  * Returns true if variable "varNum" may be address-exposed.
1350  */
1351
1352 bool Compiler::lvaVarAddrExposed(unsigned varNum)
1353 {
1354     noway_assert(varNum < lvaCount);
1355     LclVarDsc* varDsc = &lvaTable[varNum];
1356
1357     return varDsc->lvAddrExposed;
1358 }
1359
1360 /*****************************************************************************
1361  * Returns true iff variable "varNum" should not be enregistered (or one of several reasons).
1362  */
1363
1364 bool Compiler::lvaVarDoNotEnregister(unsigned varNum)
1365 {
1366     noway_assert(varNum < lvaCount);
1367     LclVarDsc* varDsc = &lvaTable[varNum];
1368
1369     return varDsc->lvDoNotEnregister;
1370 }
1371
1372 /*****************************************************************************
1373  * Returns the handle to the class of the local variable varNum
1374  */
1375
1376 CORINFO_CLASS_HANDLE Compiler::lvaGetStruct(unsigned varNum)
1377 {
1378     noway_assert(varNum < lvaCount);
1379     LclVarDsc* varDsc = &lvaTable[varNum];
1380
1381     return varDsc->lvVerTypeInfo.GetClassHandleForValueClass();
1382 }
1383
1384 /*****************************************************************************
1385  *
1386  *  Compare function passed to qsort() by Compiler::lvaCanPromoteStructVar().
1387  */
1388
1389 /* static */
1390 int __cdecl Compiler::lvaFieldOffsetCmp(const void* field1, const void* field2)
1391 {
1392     lvaStructFieldInfo* pFieldInfo1 = (lvaStructFieldInfo*)field1;
1393     lvaStructFieldInfo* pFieldInfo2 = (lvaStructFieldInfo*)field2;
1394
1395     if (pFieldInfo1->fldOffset == pFieldInfo2->fldOffset)
1396     {
1397         return 0;
1398     }
1399     else
1400     {
1401         return (pFieldInfo1->fldOffset > pFieldInfo2->fldOffset) ? +1 : -1;
1402     }
1403 }
1404
1405 /*****************************************************************************
1406  * Is this type promotable? */
1407
1408 void Compiler::lvaCanPromoteStructType(CORINFO_CLASS_HANDLE    typeHnd,
1409                                        lvaStructPromotionInfo* StructPromotionInfo,
1410                                        bool                    sortFields)
1411 {
1412     assert(eeIsValueClass(typeHnd));
1413
1414     if (typeHnd != StructPromotionInfo->typeHnd)
1415     {
1416         // sizeof(double) represents the size of the largest primitive type that we can struct promote
1417         // In the future this may be changing to XMM_REGSIZE_BYTES
1418         const int MaxOffset = MAX_NumOfFieldsInPromotableStruct * sizeof(double); // must be a compile time constant
1419
1420         assert((BYTE)MaxOffset == MaxOffset); // because lvaStructFieldInfo.fldOffset is byte-sized
1421         assert((BYTE)MAX_NumOfFieldsInPromotableStruct ==
1422                MAX_NumOfFieldsInPromotableStruct); // because lvaStructFieldInfo.fieldCnt is byte-sized
1423
1424         bool requiresScratchVar = false;
1425         bool containsHoles      = false;
1426         bool customLayout       = false;
1427         bool containsGCpointers = false;
1428
1429         StructPromotionInfo->typeHnd    = typeHnd;
1430         StructPromotionInfo->canPromote = false;
1431
1432         unsigned structSize = info.compCompHnd->getClassSize(typeHnd);
1433         if (structSize >= MaxOffset)
1434         {
1435             return; // struct is too large
1436         }
1437
1438         unsigned fieldCnt = info.compCompHnd->getClassNumInstanceFields(typeHnd);
1439         if (fieldCnt == 0 || fieldCnt > MAX_NumOfFieldsInPromotableStruct)
1440         {
1441             return; // struct must have between 1 and MAX_NumOfFieldsInPromotableStruct fields
1442         }
1443
1444         StructPromotionInfo->fieldCnt = (BYTE)fieldCnt;
1445         DWORD typeFlags               = info.compCompHnd->getClassAttribs(typeHnd);
1446
1447         bool treatAsOverlapping = StructHasOverlappingFields(typeFlags);
1448
1449 #if 1 // TODO-Cleanup: Consider removing this entire #if block in the future
1450
1451 // This method has two callers. The one in Importer.cpp passes sortFields == false
1452 // and the other passes sortFields == true.
1453 // This is a workaround that leaves the inlining behavior the same as before while still
1454 // performing extra struct promotions when compiling the method.
1455 //
1456 // The x86 legacy back-end can't handle the more general RyuJIT struct promotion (notably structs
1457 // with holes), in genPushArgList(), so in that case always check for custom layout.
1458 #if FEATURE_FIXED_OUT_ARGS || !defined(LEGACY_BACKEND)
1459         if (!sortFields) // the condition "!sortFields" really means "we are inlining"
1460 #endif
1461         {
1462             treatAsOverlapping = StructHasCustomLayout(typeFlags);
1463         }
1464 #endif
1465
1466         if (treatAsOverlapping)
1467         {
1468             return;
1469         }
1470
1471         // Don't struct promote if we have an CUSTOMLAYOUT flag on an HFA type
1472         if (StructHasCustomLayout(typeFlags) && IsHfa(typeHnd))
1473         {
1474             return;
1475         }
1476
1477 #ifdef _TARGET_ARM_
1478         // On ARM, we have a requirement on the struct alignment; see below.
1479         unsigned structAlignment =
1480             roundUp(info.compCompHnd->getClassAlignmentRequirement(typeHnd), TARGET_POINTER_SIZE);
1481 #endif // _TARGET_ARM
1482
1483         bool isHole[MaxOffset]; // isHole[] is initialized to true for every valid offset in the struct and false for
1484                                 // the rest
1485         unsigned i;             // then as we process the fields we clear the isHole[] values that the field spans.
1486         for (i = 0; i < MaxOffset; i++)
1487         {
1488             isHole[i] = (i < structSize) ? true : false;
1489         }
1490
1491         for (BYTE ordinal = 0; ordinal < fieldCnt; ++ordinal)
1492         {
1493             lvaStructFieldInfo* pFieldInfo = &StructPromotionInfo->fields[ordinal];
1494             pFieldInfo->fldHnd             = info.compCompHnd->getFieldInClass(typeHnd, ordinal);
1495             unsigned fldOffset             = info.compCompHnd->getFieldOffset(pFieldInfo->fldHnd);
1496
1497             // The fldOffset value should never be larger than our structSize.
1498             if (fldOffset >= structSize)
1499             {
1500                 noway_assert(false);
1501                 return;
1502             }
1503
1504             pFieldInfo->fldOffset  = (BYTE)fldOffset;
1505             pFieldInfo->fldOrdinal = ordinal;
1506             CorInfoType corType    = info.compCompHnd->getFieldType(pFieldInfo->fldHnd, &pFieldInfo->fldTypeHnd);
1507             var_types   varType    = JITtype2varType(corType);
1508             pFieldInfo->fldType    = varType;
1509             pFieldInfo->fldSize    = genTypeSize(varType);
1510
1511             if (varTypeIsGC(varType))
1512             {
1513                 containsGCpointers = true;
1514             }
1515
1516             if (pFieldInfo->fldSize == 0)
1517             {
1518                 // Non-primitive struct field. Don't promote.
1519                 return;
1520             }
1521
1522             if ((pFieldInfo->fldOffset % pFieldInfo->fldSize) != 0)
1523             {
1524                 // The code in Compiler::genPushArgList that reconstitutes
1525                 // struct values on the stack from promoted fields expects
1526                 // those fields to be at their natural alignment.
1527                 return;
1528             }
1529
1530             // The end offset for this field should never be larger than our structSize.
1531             noway_assert(fldOffset + pFieldInfo->fldSize <= structSize);
1532
1533             for (i = 0; i < pFieldInfo->fldSize; i++)
1534             {
1535                 isHole[fldOffset + i] = false;
1536             }
1537
1538 #ifdef _TARGET_ARM_
1539             // On ARM, for struct types that don't use explicit layout, the alignment of the struct is
1540             // at least the max alignment of its fields.  We take advantage of this invariant in struct promotion,
1541             // so verify it here.
1542             if (pFieldInfo->fldSize > structAlignment)
1543             {
1544                 // Don't promote vars whose struct types violates the invariant.  (Alignment == size for primitives.)
1545                 return;
1546             }
1547             // If we have any small fields we will allocate a single PromotedStructScratch local var for the method.
1548             // This is a stack area that we use to assemble the small fields in order to place them in a register
1549             // argument.
1550             //
1551             if (pFieldInfo->fldSize < TARGET_POINTER_SIZE)
1552             {
1553                 requiresScratchVar = true;
1554             }
1555 #endif // _TARGET_ARM_
1556         }
1557
1558         // If we saw any GC pointer fields above then the CORINFO_FLG_CONTAINS_GC_PTR has to be set!
1559         noway_assert((containsGCpointers == false) || ((typeFlags & CORINFO_FLG_CONTAINS_GC_PTR) != 0));
1560
1561         // If we have "Custom Layout" then we might have an explicit Size attribute
1562         // Managed C++ uses this for its structs, such C++ types will not contain GC pointers.
1563         //
1564         // The current VM implementation also incorrectly sets the CORINFO_FLG_CUSTOMLAYOUT
1565         // whenever a managed value class contains any GC pointers.
1566         // (See the comment for VMFLAG_NOT_TIGHTLY_PACKED in class.h)
1567         //
1568         // It is important to struct promote managed value classes that have GC pointers
1569         // So we compute the correct value for "CustomLayout" here
1570         //
1571         if (StructHasCustomLayout(typeFlags) && ((typeFlags & CORINFO_FLG_CONTAINS_GC_PTR) == 0))
1572         {
1573             customLayout = true;
1574         }
1575
1576         // Check if this promoted struct contains any holes
1577         //
1578         for (i = 0; i < structSize; i++)
1579         {
1580             if (isHole[i])
1581             {
1582                 containsHoles = true;
1583                 break;
1584             }
1585         }
1586
1587         // Cool, this struct is promotable.
1588         StructPromotionInfo->canPromote         = true;
1589         StructPromotionInfo->requiresScratchVar = requiresScratchVar;
1590         StructPromotionInfo->containsHoles      = containsHoles;
1591         StructPromotionInfo->customLayout       = customLayout;
1592
1593         if (sortFields)
1594         {
1595             // Sort the fields according to the increasing order of the field offset.
1596             // This is needed because the fields need to be pushed on stack (when referenced
1597             // as a struct) in order.
1598             qsort(StructPromotionInfo->fields, StructPromotionInfo->fieldCnt, sizeof(*StructPromotionInfo->fields),
1599                   lvaFieldOffsetCmp);
1600         }
1601     }
1602     else
1603     {
1604         // Asking for the same type of struct as the last time.
1605         // Nothing need to be done.
1606         // Fall through ...
1607     }
1608 }
1609
1610 /*****************************************************************************
1611  * Is this struct type local variable promotable? */
1612
1613 void Compiler::lvaCanPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo)
1614 {
1615     noway_assert(lclNum < lvaCount);
1616
1617     LclVarDsc* varDsc = &lvaTable[lclNum];
1618
1619     noway_assert(varTypeIsStruct(varDsc));
1620     noway_assert(!varDsc->lvPromoted); // Don't ask again :)
1621
1622 #ifdef FEATURE_SIMD
1623     // If this lclVar is used in a SIMD intrinsic, then we don't want to struct promote it.
1624     // Note, however, that SIMD lclVars that are NOT used in a SIMD intrinsic may be
1625     // profitably promoted.
1626     if (varDsc->lvIsUsedInSIMDIntrinsic())
1627     {
1628         StructPromotionInfo->canPromote = false;
1629         return;
1630     }
1631
1632 #endif
1633
1634     // TODO-PERF - Allow struct promotion for HFA register arguments
1635
1636     // Explicitly check for HFA reg args and reject them for promotion here.
1637     // Promoting HFA args will fire an assert in lvaAssignFrameOffsets
1638     // when the HFA reg arg is struct promoted.
1639     //
1640     if (varDsc->lvIsHfaRegArg())
1641     {
1642         StructPromotionInfo->canPromote = false;
1643         return;
1644     }
1645
1646     CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle();
1647     lvaCanPromoteStructType(typeHnd, StructPromotionInfo, true);
1648 }
1649
1650 /*****************************************************************************
1651  * Promote a struct type local */
1652
1653 void Compiler::lvaPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo)
1654 {
1655     LclVarDsc* varDsc = &lvaTable[lclNum];
1656
1657     // We should never see a reg-sized non-field-addressed struct here.
1658     noway_assert(!varDsc->lvRegStruct);
1659
1660     noway_assert(StructPromotionInfo->canPromote);
1661     noway_assert(StructPromotionInfo->typeHnd == varDsc->lvVerTypeInfo.GetClassHandle());
1662
1663     varDsc->lvFieldCnt      = StructPromotionInfo->fieldCnt;
1664     varDsc->lvFieldLclStart = lvaCount;
1665     varDsc->lvPromoted      = true;
1666     varDsc->lvContainsHoles = StructPromotionInfo->containsHoles;
1667     varDsc->lvCustomLayout  = StructPromotionInfo->customLayout;
1668
1669 #ifdef DEBUG
1670     // Don't change the source to a TYP_BLK either.
1671     varDsc->lvKeepType = 1;
1672 #endif
1673
1674 #ifdef DEBUG
1675     if (verbose)
1676     {
1677         printf("\nPromoting struct local V%02u (%s):", lclNum, eeGetClassName(StructPromotionInfo->typeHnd));
1678     }
1679 #endif
1680
1681     for (unsigned index = 0; index < StructPromotionInfo->fieldCnt; ++index)
1682     {
1683         lvaStructFieldInfo* pFieldInfo = &StructPromotionInfo->fields[index];
1684
1685         if (varTypeIsFloating(pFieldInfo->fldType))
1686         {
1687             lvaTable[lclNum].lvContainsFloatingFields = 1;
1688             // Whenever we promote a struct that contains a floating point field
1689             // it's possible we transition from a method that originally only had integer
1690             // local vars to start having FP.  We have to communicate this through this flag
1691             // since LSRA later on will use this flag to determine whether or not to track FP register sets.
1692             compFloatingPointUsed = true;
1693         }
1694
1695 // Now grab the temp for the field local.
1696
1697 #ifdef DEBUG
1698         char  buf[200];
1699         char* bufp = &buf[0];
1700
1701         sprintf_s(bufp, sizeof(buf), "%s V%02u.%s (fldOffset=0x%x)", "field", lclNum,
1702                   eeGetFieldName(pFieldInfo->fldHnd), pFieldInfo->fldOffset);
1703
1704         if (index > 0)
1705         {
1706             noway_assert(pFieldInfo->fldOffset > (pFieldInfo - 1)->fldOffset);
1707         }
1708 #endif
1709
1710         unsigned varNum = lvaGrabTemp(false DEBUGARG(bufp)); // Lifetime of field locals might span multiple BBs, so
1711                                                              // they are long lifetime temps.
1712
1713         LclVarDsc* fieldVarDsc       = &lvaTable[varNum];
1714         fieldVarDsc->lvType          = pFieldInfo->fldType;
1715         fieldVarDsc->lvExactSize     = pFieldInfo->fldSize;
1716         fieldVarDsc->lvIsStructField = true;
1717         fieldVarDsc->lvFldOffset     = pFieldInfo->fldOffset;
1718         fieldVarDsc->lvFldOrdinal    = pFieldInfo->fldOrdinal;
1719         fieldVarDsc->lvParentLcl     = lclNum;
1720         fieldVarDsc->lvIsParam       = varDsc->lvIsParam;
1721 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1722         // Do we have a parameter that can be enregistered?
1723         //
1724         if (varDsc->lvIsRegArg)
1725         {
1726             fieldVarDsc->lvIsRegArg = true;
1727             fieldVarDsc->lvArgReg   = varDsc->lvArgReg;
1728             fieldVarDsc->setPrefReg(varDsc->lvArgReg, this); // Set the preferred register
1729
1730             lvaMarkRefsWeight = BB_UNITY_WEIGHT;            // incRefCnts can use this compiler global variable
1731             fieldVarDsc->incRefCnts(BB_UNITY_WEIGHT, this); // increment the ref count for prolog initialization
1732         }
1733 #endif
1734
1735 #ifdef DEBUG
1736         // This temporary should not be converted to a double in stress mode,
1737         // because we introduce assigns to it after the stress conversion
1738         fieldVarDsc->lvKeepType = 1;
1739 #endif
1740     }
1741 }
1742
1743 #if !defined(LEGACY_BACKEND) && !defined(_TARGET_64BIT_)
1744 //------------------------------------------------------------------------
1745 // lvaPromoteLongVars: "Struct promote" all register candidate longs as if they are structs of two ints.
1746 //
1747 // Arguments:
1748 //    None.
1749 //
1750 // Return Value:
1751 //    None.
1752 //
1753 void Compiler::lvaPromoteLongVars()
1754 {
1755     if ((opts.compFlags & CLFLG_REGVAR) == 0)
1756     {
1757         return;
1758     }
1759     // The lvaTable might grow as we grab temps. Make a local copy here.
1760     unsigned startLvaCount = lvaCount;
1761     for (unsigned lclNum = 0; lclNum < startLvaCount; lclNum++)
1762     {
1763         LclVarDsc* varDsc = &lvaTable[lclNum];
1764         if (!varTypeIsLong(varDsc) || varDsc->lvDoNotEnregister || varDsc->lvIsMultiRegArgOrRet() ||
1765             (varDsc->lvRefCnt == 0) || varDsc->lvIsStructField)
1766         {
1767             continue;
1768         }
1769
1770         varDsc->lvFieldCnt      = 2;
1771         varDsc->lvFieldLclStart = lvaCount;
1772         varDsc->lvPromoted      = true;
1773         varDsc->lvContainsHoles = false;
1774
1775 #ifdef DEBUG
1776         if (verbose)
1777         {
1778             printf("\nPromoting long local V%02u:", lclNum);
1779         }
1780 #endif
1781
1782         bool isParam = varDsc->lvIsParam;
1783
1784         for (unsigned index = 0; index < 2; ++index)
1785         {
1786             // Grab the temp for the field local.
1787             CLANG_FORMAT_COMMENT_ANCHOR;
1788
1789 #ifdef DEBUG
1790             char  buf[200];
1791             char* bufp = &buf[0];
1792
1793             sprintf_s(bufp, sizeof(buf), "%s V%02u.%s (fldOffset=0x%x)", "field", lclNum, index == 0 ? "lo" : "hi",
1794                       index * 4);
1795 #endif
1796             unsigned varNum = lvaGrabTemp(false DEBUGARG(bufp)); // Lifetime of field locals might span multiple BBs, so
1797                                                                  // they are long lifetime temps.
1798
1799             LclVarDsc* fieldVarDsc       = &lvaTable[varNum];
1800             fieldVarDsc->lvType          = TYP_INT;
1801             fieldVarDsc->lvExactSize     = genTypeSize(TYP_INT);
1802             fieldVarDsc->lvIsStructField = true;
1803             fieldVarDsc->lvFldOffset     = (unsigned char)(index * genTypeSize(TYP_INT));
1804             fieldVarDsc->lvFldOrdinal    = (unsigned char)index;
1805             fieldVarDsc->lvParentLcl     = lclNum;
1806             fieldVarDsc->lvIsParam       = isParam;
1807         }
1808     }
1809
1810 #ifdef DEBUG
1811     if (verbose)
1812     {
1813         printf("\nlvaTable after lvaPromoteLongVars\n");
1814         lvaTableDump();
1815     }
1816 #endif // DEBUG
1817 }
1818 #endif // !defined(LEGACY_BACKEND) && !defined(_TARGET_64BIT_)
1819
1820 /*****************************************************************************
1821  * Given a fldOffset in a promoted struct var, return the index of the local
1822    that represents this field.
1823 */
1824
1825 unsigned Compiler::lvaGetFieldLocal(LclVarDsc* varDsc, unsigned int fldOffset)
1826 {
1827     noway_assert(varTypeIsStruct(varDsc));
1828     noway_assert(varDsc->lvPromoted);
1829
1830     for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
1831     {
1832         noway_assert(lvaTable[i].lvIsStructField);
1833         noway_assert(lvaTable[i].lvParentLcl == (unsigned)(varDsc - lvaTable));
1834         if (lvaTable[i].lvFldOffset == fldOffset)
1835         {
1836             return i;
1837         }
1838     }
1839
1840     // This is the not-found error return path, the caller should check for BAD_VAR_NUM
1841     return BAD_VAR_NUM;
1842 }
1843
1844 /*****************************************************************************
1845  *
1846  *  Set the local var "varNum" as address-exposed.
1847  *  If this is a promoted struct, label it's fields the same way.
1848  */
1849
1850 void Compiler::lvaSetVarAddrExposed(unsigned varNum)
1851 {
1852     noway_assert(varNum < lvaCount);
1853
1854     LclVarDsc* varDsc = &lvaTable[varNum];
1855
1856     varDsc->lvAddrExposed = 1;
1857
1858     if (varDsc->lvPromoted)
1859     {
1860         noway_assert(varTypeIsStruct(varDsc));
1861
1862         for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
1863         {
1864             noway_assert(lvaTable[i].lvIsStructField);
1865             lvaTable[i].lvAddrExposed = 1; // Make field local as address-exposed.
1866             lvaSetVarDoNotEnregister(i DEBUGARG(DNER_AddrExposed));
1867         }
1868     }
1869
1870     lvaSetVarDoNotEnregister(varNum DEBUGARG(DNER_AddrExposed));
1871 }
1872
1873 /*****************************************************************************
1874  *
1875  *  Record that the local var "varNum" should not be enregistered (for one of several reasons.)
1876  */
1877
1878 void Compiler::lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregisterReason reason))
1879 {
1880     noway_assert(varNum < lvaCount);
1881     LclVarDsc* varDsc         = &lvaTable[varNum];
1882     varDsc->lvDoNotEnregister = 1;
1883
1884 #ifdef DEBUG
1885     if (verbose)
1886     {
1887         printf("\nLocal V%02u should not be enregistered because: ", varNum);
1888     }
1889     switch (reason)
1890     {
1891         case DNER_AddrExposed:
1892             JITDUMP("it is address exposed\n");
1893             assert(varDsc->lvAddrExposed);
1894             break;
1895         case DNER_IsStruct:
1896             JITDUMP("it is a struct\n");
1897             assert(varTypeIsStruct(varDsc));
1898             break;
1899         case DNER_BlockOp:
1900             JITDUMP("written in a block op\n");
1901             varDsc->lvLclBlockOpAddr = 1;
1902             break;
1903         case DNER_LocalField:
1904             JITDUMP("was accessed as a local field\n");
1905             varDsc->lvLclFieldExpr = 1;
1906             break;
1907         case DNER_VMNeedsStackAddr:
1908             JITDUMP("needs stack addr\n");
1909             varDsc->lvVMNeedsStackAddr = 1;
1910             break;
1911         case DNER_LiveInOutOfHandler:
1912             JITDUMP("live in/out of a handler\n");
1913             varDsc->lvLiveInOutOfHndlr = 1;
1914             break;
1915         case DNER_LiveAcrossUnmanagedCall:
1916             JITDUMP("live across unmanaged call\n");
1917             varDsc->lvLiveAcrossUCall = 1;
1918             break;
1919 #ifdef JIT32_GCENCODER
1920         case DNER_PinningRef:
1921             JITDUMP("pinning ref\n");
1922             assert(varDsc->lvPinned);
1923             break;
1924 #endif
1925         default:
1926             unreached();
1927             break;
1928     }
1929 #endif
1930 }
1931
1932 // Returns true if this local var is a multireg struct
1933 bool Compiler::lvaIsMultiregStruct(LclVarDsc* varDsc)
1934 {
1935     if (varDsc->TypeGet() == TYP_STRUCT)
1936     {
1937         CORINFO_CLASS_HANDLE clsHnd = varDsc->lvVerTypeInfo.GetClassHandleForValueClass();
1938         structPassingKind    howToPassStruct;
1939
1940         var_types type = getArgTypeForStruct(clsHnd, &howToPassStruct, varDsc->lvExactSize);
1941
1942         if (howToPassStruct == SPK_ByValueAsHfa)
1943         {
1944             assert(type = TYP_STRUCT);
1945             return true;
1946         }
1947
1948 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) || defined(_TARGET_ARM64_)
1949         if (howToPassStruct == SPK_ByValue)
1950         {
1951             assert(type = TYP_STRUCT);
1952             return true;
1953         }
1954 #endif
1955     }
1956     return false;
1957 }
1958
1959 /*****************************************************************************
1960  * Set the lvClass for a local variable of a struct type */
1961
1962 void Compiler::lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool unsafeValueClsCheck, bool setTypeInfo)
1963 {
1964     noway_assert(varNum < lvaCount);
1965
1966     LclVarDsc* varDsc = &lvaTable[varNum];
1967     if (setTypeInfo)
1968     {
1969         varDsc->lvVerTypeInfo = typeInfo(TI_STRUCT, typeHnd);
1970     }
1971
1972     // Set the type and associated info if we haven't already set it.
1973     var_types structType = varDsc->lvType;
1974     if (varDsc->lvType == TYP_UNDEF)
1975     {
1976         varDsc->lvType = TYP_STRUCT;
1977     }
1978     if (varDsc->lvExactSize == 0)
1979     {
1980         varDsc->lvExactSize = info.compCompHnd->getClassSize(typeHnd);
1981
1982         size_t lvSize = varDsc->lvSize();
1983         assert((lvSize % sizeof(void*)) ==
1984                0); // The struct needs to be a multiple of sizeof(void*) bytes for getClassGClayout() to be valid.
1985         varDsc->lvGcLayout = (BYTE*)compGetMemA((lvSize / sizeof(void*)) * sizeof(BYTE), CMK_LvaTable);
1986         unsigned  numGCVars;
1987         var_types simdBaseType = TYP_UNKNOWN;
1988         varDsc->lvType         = impNormStructType(typeHnd, varDsc->lvGcLayout, &numGCVars, &simdBaseType);
1989
1990         // We only save the count of GC vars in a struct up to 7.
1991         if (numGCVars >= 8)
1992         {
1993             numGCVars = 7;
1994         }
1995         varDsc->lvStructGcCount = numGCVars;
1996 #if FEATURE_SIMD
1997         if (simdBaseType != TYP_UNKNOWN)
1998         {
1999             assert(varTypeIsSIMD(varDsc));
2000             varDsc->lvSIMDType = true;
2001             varDsc->lvBaseType = simdBaseType;
2002         }
2003 #endif // FEATURE_SIMD
2004 #ifdef FEATURE_HFA
2005         // for structs that are small enough, we check and set lvIsHfa and lvHfaTypeIsFloat
2006         if (varDsc->lvExactSize <= MAX_PASS_MULTIREG_BYTES)
2007         {
2008             var_types hfaType = GetHfaType(typeHnd); // set to float or double if it is an HFA, otherwise TYP_UNDEF
2009             if (varTypeIsFloating(hfaType))
2010             {
2011                 varDsc->_lvIsHfa = true;
2012                 varDsc->lvSetHfaTypeIsFloat(hfaType == TYP_FLOAT);
2013
2014                 // hfa variables can never contain GC pointers
2015                 assert(varDsc->lvStructGcCount == 0);
2016                 // The size of this struct should be evenly divisible by 4 or 8
2017                 assert((varDsc->lvExactSize % genTypeSize(hfaType)) == 0);
2018                 // The number of elements in the HFA should fit into our MAX_ARG_REG_COUNT limit
2019                 assert((varDsc->lvExactSize / genTypeSize(hfaType)) <= MAX_ARG_REG_COUNT);
2020             }
2021         }
2022 #endif // FEATURE_HFA
2023     }
2024     else
2025     {
2026         assert(varDsc->lvExactSize != 0);
2027 #if FEATURE_SIMD
2028         assert(!varTypeIsSIMD(varDsc) || (varDsc->lvBaseType != TYP_UNKNOWN));
2029 #endif // FEATURE_SIMD
2030     }
2031
2032 #ifndef _TARGET_64BIT_
2033     bool fDoubleAlignHint = FALSE;
2034 #ifdef _TARGET_X86_
2035     fDoubleAlignHint = TRUE;
2036 #endif
2037
2038     if (info.compCompHnd->getClassAlignmentRequirement(typeHnd, fDoubleAlignHint) == 8)
2039     {
2040 #ifdef DEBUG
2041         if (verbose)
2042         {
2043             printf("Marking struct in V%02i with double align flag\n", varNum);
2044         }
2045 #endif
2046         varDsc->lvStructDoubleAlign = 1;
2047     }
2048 #endif // not _TARGET_64BIT_
2049
2050     unsigned classAttribs = info.compCompHnd->getClassAttribs(typeHnd);
2051
2052     varDsc->lvOverlappingFields = StructHasOverlappingFields(classAttribs);
2053
2054     // Check whether this local is an unsafe value type and requires GS cookie protection.
2055     // GS checks require the stack to be re-ordered, which can't be done with EnC.
2056     if (unsafeValueClsCheck && (classAttribs & CORINFO_FLG_UNSAFE_VALUECLASS) && !opts.compDbgEnC)
2057     {
2058         setNeedsGSSecurityCookie();
2059         compGSReorderStackLayout = true;
2060         varDsc->lvIsUnsafeBuffer = true;
2061     }
2062 }
2063
2064 /*****************************************************************************
2065  * Returns the array of BYTEs containing the GC layout information
2066  */
2067
2068 BYTE* Compiler::lvaGetGcLayout(unsigned varNum)
2069 {
2070     noway_assert(varTypeIsStruct(lvaTable[varNum].lvType) && (lvaTable[varNum].lvExactSize >= TARGET_POINTER_SIZE));
2071
2072     return lvaTable[varNum].lvGcLayout;
2073 }
2074
2075 /*****************************************************************************
2076  * Return the number of bytes needed for a local variable
2077  */
2078
2079 unsigned Compiler::lvaLclSize(unsigned varNum)
2080 {
2081     noway_assert(varNum < lvaCount);
2082
2083     var_types varType = lvaTable[varNum].TypeGet();
2084
2085     switch (varType)
2086     {
2087         case TYP_STRUCT:
2088         case TYP_BLK:
2089             return lvaTable[varNum].lvSize();
2090
2091         case TYP_LCLBLK:
2092 #if FEATURE_FIXED_OUT_ARGS
2093             noway_assert(lvaOutgoingArgSpaceSize >= 0);
2094             noway_assert(varNum == lvaOutgoingArgSpaceVar);
2095             return lvaOutgoingArgSpaceSize;
2096
2097 #else // FEATURE_FIXED_OUT_ARGS
2098             assert(!"Unknown size");
2099             NO_WAY("Target doesn't support TYP_LCLBLK");
2100
2101             // Keep prefast happy
2102             __fallthrough;
2103
2104 #endif // FEATURE_FIXED_OUT_ARGS
2105
2106         default: // This must be a primitive var. Fall out of switch statement
2107             break;
2108     }
2109 #ifdef _TARGET_64BIT_
2110     // We only need this Quirk for _TARGET_64BIT_
2111     if (lvaTable[varNum].lvQuirkToLong)
2112     {
2113         noway_assert(lvaTable[varNum].lvAddrExposed);
2114         return genTypeStSz(TYP_LONG) * sizeof(int); // return 8  (2 * 4)
2115     }
2116 #endif
2117     return genTypeStSz(varType) * sizeof(int);
2118 }
2119
2120 //
2121 // Return the exact width of local variable "varNum" -- the number of bytes
2122 // you'd need to copy in order to overwrite the value.
2123 //
2124 unsigned Compiler::lvaLclExactSize(unsigned varNum)
2125 {
2126     noway_assert(varNum < lvaCount);
2127
2128     var_types varType = lvaTable[varNum].TypeGet();
2129
2130     switch (varType)
2131     {
2132         case TYP_STRUCT:
2133         case TYP_BLK:
2134             return lvaTable[varNum].lvExactSize;
2135
2136         case TYP_LCLBLK:
2137 #if FEATURE_FIXED_OUT_ARGS
2138             noway_assert(lvaOutgoingArgSpaceSize >= 0);
2139             noway_assert(varNum == lvaOutgoingArgSpaceVar);
2140             return lvaOutgoingArgSpaceSize;
2141
2142 #else // FEATURE_FIXED_OUT_ARGS
2143             assert(!"Unknown size");
2144             NO_WAY("Target doesn't support TYP_LCLBLK");
2145
2146             // Keep prefast happy
2147             __fallthrough;
2148
2149 #endif // FEATURE_FIXED_OUT_ARGS
2150
2151         default: // This must be a primitive var. Fall out of switch statement
2152             break;
2153     }
2154
2155     return genTypeSize(varType);
2156 }
2157
2158 // getBBWeight -- get the normalized weight of this block
2159 unsigned BasicBlock::getBBWeight(Compiler* comp)
2160 {
2161     if (this->bbWeight == 0)
2162     {
2163         return 0;
2164     }
2165     else
2166     {
2167         unsigned calledWeight = comp->fgCalledWeight;
2168         if (calledWeight == 0)
2169         {
2170             calledWeight = comp->fgFirstBB->bbWeight;
2171             if (calledWeight == 0)
2172             {
2173                 calledWeight = BB_UNITY_WEIGHT;
2174             }
2175         }
2176         if (this->bbWeight < (BB_MAX_WEIGHT / BB_UNITY_WEIGHT))
2177         {
2178             return max(1, (((this->bbWeight * BB_UNITY_WEIGHT) + (calledWeight / 2)) / calledWeight));
2179         }
2180         else
2181         {
2182             return (unsigned)((((double)this->bbWeight * (double)BB_UNITY_WEIGHT) / (double)calledWeight) + 0.5);
2183         }
2184     }
2185 }
2186
2187 /*****************************************************************************
2188  *
2189  *  Callback used by the tree walker to call lvaDecRefCnts
2190  */
2191 Compiler::fgWalkResult Compiler::lvaDecRefCntsCB(GenTreePtr* pTree, fgWalkData* data)
2192 {
2193     data->compiler->lvaDecRefCnts(*pTree);
2194     return WALK_CONTINUE;
2195 }
2196
2197 // Decrement the ref counts for all locals contained in the tree and its children.
2198 void Compiler::lvaRecursiveDecRefCounts(GenTreePtr tree)
2199 {
2200     assert(lvaLocalVarRefCounted);
2201
2202     // We could just use the recursive walker for all cases but that is a
2203     // fairly heavyweight thing to spin up when we're usually just handling a leaf.
2204     if (tree->OperIsLeaf())
2205     {
2206         if (tree->OperIsLocal())
2207         {
2208             lvaDecRefCnts(tree);
2209         }
2210     }
2211     else
2212     {
2213         fgWalkTreePre(&tree, Compiler::lvaDecRefCntsCB, (void*)this, true);
2214     }
2215 }
2216
2217 // Increment the ref counts for all locals contained in the tree and its children.
2218 void Compiler::lvaRecursiveIncRefCounts(GenTreePtr tree)
2219 {
2220     assert(lvaLocalVarRefCounted);
2221
2222     // We could just use the recursive walker for all cases but that is a
2223     // fairly heavyweight thing to spin up when we're usually just handling a leaf.
2224     if (tree->OperIsLeaf())
2225     {
2226         if (tree->OperIsLocal())
2227         {
2228             lvaIncRefCnts(tree);
2229         }
2230     }
2231     else
2232     {
2233         fgWalkTreePre(&tree, Compiler::lvaIncRefCntsCB, (void*)this, true);
2234     }
2235 }
2236
2237 /*****************************************************************************
2238  *
2239  *  Helper passed to the tree walker to decrement the refCnts for
2240  *  all local variables in an expression
2241  */
2242 void Compiler::lvaDecRefCnts(GenTreePtr tree)
2243 {
2244     assert(compCurBB != nullptr);
2245     lvaDecRefCnts(compCurBB, tree);
2246 }
2247
2248 void Compiler::lvaDecRefCnts(BasicBlock* block, GenTreePtr tree)
2249 {
2250     assert(block != nullptr);
2251     assert(tree != nullptr);
2252
2253     unsigned   lclNum;
2254     LclVarDsc* varDsc;
2255
2256     noway_assert(lvaRefCountingStarted || lvaLocalVarRefCounted);
2257
2258     if ((tree->gtOper == GT_CALL) && (tree->gtFlags & GTF_CALL_UNMANAGED))
2259     {
2260         assert((!opts.ShouldUsePInvokeHelpers()) || (info.compLvFrameListRoot == BAD_VAR_NUM));
2261         if (!opts.ShouldUsePInvokeHelpers())
2262         {
2263             /* Get the special variable descriptor */
2264
2265             lclNum = info.compLvFrameListRoot;
2266
2267             noway_assert(lclNum <= lvaCount);
2268             varDsc = lvaTable + lclNum;
2269
2270             /* Decrement the reference counts twice */
2271
2272             varDsc->decRefCnts(block->getBBWeight(this), this);
2273             varDsc->decRefCnts(block->getBBWeight(this), this);
2274         }
2275     }
2276     else
2277     {
2278         /* This must be a local variable */
2279
2280         noway_assert(tree->OperIsLocal());
2281
2282         /* Get the variable descriptor */
2283
2284         lclNum = tree->gtLclVarCommon.gtLclNum;
2285
2286         noway_assert(lclNum < lvaCount);
2287         varDsc = lvaTable + lclNum;
2288
2289         /* Decrement its lvRefCnt and lvRefCntWtd */
2290
2291         varDsc->decRefCnts(block->getBBWeight(this), this);
2292     }
2293 }
2294
2295 /*****************************************************************************
2296  *
2297  *  Callback used by the tree walker to call lvaIncRefCnts
2298  */
2299 Compiler::fgWalkResult Compiler::lvaIncRefCntsCB(GenTreePtr* pTree, fgWalkData* data)
2300 {
2301     data->compiler->lvaIncRefCnts(*pTree);
2302     return WALK_CONTINUE;
2303 }
2304
2305 /*****************************************************************************
2306  *
2307  *  Helper passed to the tree walker to increment the refCnts for
2308  *  all local variables in an expression
2309  */
2310 void Compiler::lvaIncRefCnts(GenTreePtr tree)
2311 {
2312     unsigned   lclNum;
2313     LclVarDsc* varDsc;
2314
2315     noway_assert(lvaRefCountingStarted || lvaLocalVarRefCounted);
2316
2317     if ((tree->gtOper == GT_CALL) && (tree->gtFlags & GTF_CALL_UNMANAGED))
2318     {
2319         assert((!opts.ShouldUsePInvokeHelpers()) || (info.compLvFrameListRoot == BAD_VAR_NUM));
2320         if (!opts.ShouldUsePInvokeHelpers())
2321         {
2322             /* Get the special variable descriptor */
2323
2324             lclNum = info.compLvFrameListRoot;
2325
2326             noway_assert(lclNum <= lvaCount);
2327             varDsc = lvaTable + lclNum;
2328
2329             /* Increment the reference counts twice */
2330
2331             varDsc->incRefCnts(compCurBB->getBBWeight(this), this);
2332             varDsc->incRefCnts(compCurBB->getBBWeight(this), this);
2333         }
2334     }
2335     else
2336     {
2337         /* This must be a local variable */
2338
2339         noway_assert(tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD || tree->gtOper == GT_STORE_LCL_VAR ||
2340                      tree->gtOper == GT_STORE_LCL_FLD);
2341
2342         /* Get the variable descriptor */
2343
2344         lclNum = tree->gtLclVarCommon.gtLclNum;
2345
2346         noway_assert(lclNum < lvaCount);
2347         varDsc = lvaTable + lclNum;
2348
2349         /* Increment its lvRefCnt and lvRefCntWtd */
2350
2351         varDsc->incRefCnts(compCurBB->getBBWeight(this), this);
2352     }
2353 }
2354
2355 /*****************************************************************************
2356  *
2357  *  Compare function passed to qsort() by Compiler::lclVars.lvaSortByRefCount().
2358  *  when generating SMALL_CODE.
2359  *    Return positive if dsc2 has a higher ref count
2360  *    Return negative if dsc1 has a higher ref count
2361  *    Return zero     if the ref counts are the same
2362  *    lvPrefReg is only used to break ties
2363  */
2364
2365 /* static */
2366 int __cdecl Compiler::RefCntCmp(const void* op1, const void* op2)
2367 {
2368     LclVarDsc* dsc1 = *(LclVarDsc**)op1;
2369     LclVarDsc* dsc2 = *(LclVarDsc**)op2;
2370
2371     /* Make sure we preference tracked variables over untracked variables */
2372
2373     if (dsc1->lvTracked != dsc2->lvTracked)
2374     {
2375         return (dsc2->lvTracked) ? +1 : -1;
2376     }
2377
2378     unsigned weight1 = dsc1->lvRefCnt;
2379     unsigned weight2 = dsc2->lvRefCnt;
2380
2381 #if !FEATURE_FP_REGALLOC
2382     /* Force integer candidates to sort above float candidates */
2383
2384     bool isFloat1 = isFloatRegType(dsc1->lvType);
2385     bool isFloat2 = isFloatRegType(dsc2->lvType);
2386
2387     if (isFloat1 != isFloat2)
2388     {
2389         if (weight2 && isFloat1)
2390         {
2391             return +1;
2392         }
2393         if (weight1 && isFloat2)
2394         {
2395             return -1;
2396         }
2397     }
2398 #endif
2399
2400     int diff = weight2 - weight1;
2401
2402     if (diff != 0)
2403     {
2404         return diff;
2405     }
2406
2407     /* The unweighted ref counts were the same */
2408     /* If the weighted ref counts are different then use their difference */
2409     diff = dsc2->lvRefCntWtd - dsc1->lvRefCntWtd;
2410
2411     if (diff != 0)
2412     {
2413         return diff;
2414     }
2415
2416     /* We have equal ref counts and weighted ref counts */
2417
2418     /* Break the tie by: */
2419     /* Increasing the weight by 2   if we have exactly one bit set in lvPrefReg   */
2420     /* Increasing the weight by 1   if we have more than one bit set in lvPrefReg */
2421     /* Increasing the weight by 0.5 if we are a GC type */
2422     /* Increasing the weight by 0.5 if we were enregistered in the previous pass  */
2423
2424     if (weight1)
2425     {
2426         if (dsc1->lvPrefReg)
2427         {
2428             if ((dsc1->lvPrefReg & ~RBM_BYTE_REG_FLAG) && genMaxOneBit((unsigned)dsc1->lvPrefReg))
2429             {
2430                 weight1 += 2 * BB_UNITY_WEIGHT;
2431             }
2432             else
2433             {
2434                 weight1 += 1 * BB_UNITY_WEIGHT;
2435             }
2436         }
2437         if (varTypeIsGC(dsc1->TypeGet()))
2438         {
2439             weight1 += BB_UNITY_WEIGHT / 2;
2440         }
2441
2442         if (dsc1->lvRegister)
2443         {
2444             weight1 += BB_UNITY_WEIGHT / 2;
2445         }
2446     }
2447
2448     if (weight2)
2449     {
2450         if (dsc2->lvPrefReg)
2451         {
2452             if ((dsc2->lvPrefReg & ~RBM_BYTE_REG_FLAG) && genMaxOneBit((unsigned)dsc2->lvPrefReg))
2453             {
2454                 weight2 += 2 * BB_UNITY_WEIGHT;
2455             }
2456             else
2457             {
2458                 weight2 += 1 * BB_UNITY_WEIGHT;
2459             }
2460         }
2461         if (varTypeIsGC(dsc2->TypeGet()))
2462         {
2463             weight1 += BB_UNITY_WEIGHT / 2;
2464         }
2465
2466         if (dsc2->lvRegister)
2467         {
2468             weight2 += BB_UNITY_WEIGHT / 2;
2469         }
2470     }
2471
2472     diff = weight2 - weight1;
2473
2474     if (diff != 0)
2475     {
2476         return diff;
2477     }
2478
2479     /* To achieve a Stable Sort we use the LclNum (by way of the pointer address) */
2480
2481     if (dsc1 < dsc2)
2482     {
2483         return -1;
2484     }
2485     if (dsc1 > dsc2)
2486     {
2487         return +1;
2488     }
2489
2490     return 0;
2491 }
2492
2493 /*****************************************************************************
2494  *
2495  *  Compare function passed to qsort() by Compiler::lclVars.lvaSortByRefCount().
2496  *  when not generating SMALL_CODE.
2497  *    Return positive if dsc2 has a higher weighted ref count
2498  *    Return negative if dsc1 has a higher weighted ref count
2499  *    Return zero     if the ref counts are the same
2500  */
2501
2502 /* static */
2503 int __cdecl Compiler::WtdRefCntCmp(const void* op1, const void* op2)
2504 {
2505     LclVarDsc* dsc1 = *(LclVarDsc**)op1;
2506     LclVarDsc* dsc2 = *(LclVarDsc**)op2;
2507
2508     /* Make sure we preference tracked variables over untracked variables */
2509
2510     if (dsc1->lvTracked != dsc2->lvTracked)
2511     {
2512         return (dsc2->lvTracked) ? +1 : -1;
2513     }
2514
2515     unsigned weight1 = dsc1->lvRefCntWtd;
2516     unsigned weight2 = dsc2->lvRefCntWtd;
2517
2518 #if !FEATURE_FP_REGALLOC
2519     /* Force integer candidates to sort above float candidates */
2520
2521     bool isFloat1 = isFloatRegType(dsc1->lvType);
2522     bool isFloat2 = isFloatRegType(dsc2->lvType);
2523
2524     if (isFloat1 != isFloat2)
2525     {
2526         if (weight2 && isFloat1)
2527         {
2528             return +1;
2529         }
2530         if (weight1 && isFloat2)
2531         {
2532             return -1;
2533         }
2534     }
2535 #endif
2536
2537     /* Increase the weight by 2 if we have exactly one bit set in lvPrefReg */
2538     /* Increase the weight by 1 if we have more than one bit set in lvPrefReg */
2539
2540     if (weight1 && dsc1->lvPrefReg)
2541     {
2542         if ((dsc1->lvPrefReg & ~RBM_BYTE_REG_FLAG) && genMaxOneBit((unsigned)dsc1->lvPrefReg))
2543         {
2544             weight1 += 2 * BB_UNITY_WEIGHT;
2545         }
2546         else
2547         {
2548             weight1 += 1 * BB_UNITY_WEIGHT;
2549         }
2550     }
2551
2552     if (weight2 && dsc2->lvPrefReg)
2553     {
2554         if ((dsc2->lvPrefReg & ~RBM_BYTE_REG_FLAG) && genMaxOneBit((unsigned)dsc2->lvPrefReg))
2555         {
2556             weight2 += 2 * BB_UNITY_WEIGHT;
2557         }
2558         else
2559         {
2560             weight2 += 1 * BB_UNITY_WEIGHT;
2561         }
2562     }
2563
2564     if (weight2 > weight1)
2565     {
2566         return 1;
2567     }
2568     else if (weight2 < weight1)
2569     {
2570         return -1;
2571     }
2572
2573     // Otherwise, we have equal weighted ref counts.
2574
2575     /* If the unweighted ref counts are different then use their difference */
2576     int diff = (int)dsc2->lvRefCnt - (int)dsc1->lvRefCnt;
2577
2578     if (diff != 0)
2579     {
2580         return diff;
2581     }
2582
2583     /* If one is a GC type and the other is not the GC type wins */
2584     if (varTypeIsGC(dsc1->TypeGet()) != varTypeIsGC(dsc2->TypeGet()))
2585     {
2586         if (varTypeIsGC(dsc1->TypeGet()))
2587         {
2588             diff = -1;
2589         }
2590         else
2591         {
2592             diff = +1;
2593         }
2594
2595         return diff;
2596     }
2597
2598     /* If one was enregistered in the previous pass then it wins */
2599     if (dsc1->lvRegister != dsc2->lvRegister)
2600     {
2601         if (dsc1->lvRegister)
2602         {
2603             diff = -1;
2604         }
2605         else
2606         {
2607             diff = +1;
2608         }
2609
2610         return diff;
2611     }
2612
2613     /* We have a tie! */
2614
2615     /* To achieve a Stable Sort we use the LclNum (by way of the pointer address) */
2616
2617     if (dsc1 < dsc2)
2618     {
2619         return -1;
2620     }
2621     if (dsc1 > dsc2)
2622     {
2623         return +1;
2624     }
2625
2626     return 0;
2627 }
2628
2629 /*****************************************************************************
2630  *
2631  *  Sort the local variable table by refcount and assign tracking indices.
2632  */
2633
2634 void Compiler::lvaSortOnly()
2635 {
2636     /* Now sort the variable table by ref-count */
2637
2638     qsort(lvaRefSorted, lvaCount, sizeof(*lvaRefSorted), (compCodeOpt() == SMALL_CODE) ? RefCntCmp : WtdRefCntCmp);
2639
2640     lvaSortAgain = false;
2641
2642     lvaDumpRefCounts();
2643 }
2644
2645 void Compiler::lvaDumpRefCounts()
2646 {
2647 #ifdef DEBUG
2648
2649     if (verbose && lvaCount)
2650     {
2651         printf("refCnt table for '%s':\n", info.compMethodName);
2652
2653         for (unsigned lclNum = 0; lclNum < lvaCount; lclNum++)
2654         {
2655             unsigned refCnt = lvaRefSorted[lclNum]->lvRefCnt;
2656             if (refCnt == 0)
2657             {
2658                 break;
2659             }
2660             unsigned refCntWtd = lvaRefSorted[lclNum]->lvRefCntWtd;
2661
2662             printf("   ");
2663             gtDispLclVar((unsigned)(lvaRefSorted[lclNum] - lvaTable));
2664             printf(" [%6s]: refCnt = %4u, refCntWtd = %6s", varTypeName(lvaRefSorted[lclNum]->TypeGet()), refCnt,
2665                    refCntWtd2str(refCntWtd));
2666
2667             regMaskSmall pref = lvaRefSorted[lclNum]->lvPrefReg;
2668             if (pref)
2669             {
2670                 printf(" pref ");
2671                 dspRegMask(pref);
2672             }
2673             printf("\n");
2674         }
2675
2676         printf("\n");
2677     }
2678
2679 #endif
2680 }
2681
2682 /*****************************************************************************
2683  *
2684  *  Sort the local variable table by refcount and assign tracking indices.
2685  */
2686
2687 void Compiler::lvaSortByRefCount()
2688 {
2689     lvaTrackedCount             = 0;
2690     lvaTrackedCountInSizeTUnits = 0;
2691
2692 #ifdef DEBUG
2693     VarSetOps::AssignNoCopy(this, lvaTrackedVars, VarSetOps::MakeEmpty(this));
2694 #endif
2695
2696     if (lvaCount == 0)
2697     {
2698         return;
2699     }
2700
2701     unsigned   lclNum;
2702     LclVarDsc* varDsc;
2703
2704     LclVarDsc** refTab;
2705
2706     /* We'll sort the variables by ref count - allocate the sorted table */
2707
2708     lvaRefSorted = refTab = new (this, CMK_LvaTable) LclVarDsc*[lvaCount];
2709
2710     /* Fill in the table used for sorting */
2711
2712     for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
2713     {
2714         /* Append this variable to the table for sorting */
2715
2716         *refTab++ = varDsc;
2717
2718         /* If we have JMP, all arguments must have a location
2719          * even if we don't use them inside the method */
2720
2721         if (compJmpOpUsed && varDsc->lvIsParam)
2722         {
2723             /* ...except when we have varargs and the argument is
2724               passed on the stack.  In that case, it's important
2725               for the ref count to be zero, so that we don't attempt
2726               to track them for GC info (which is not possible since we
2727               don't know their offset in the stack).  See the assert at the
2728               end of raMarkStkVars and bug #28949 for more info. */
2729
2730             if (!raIsVarargsStackArg(lclNum))
2731             {
2732                 varDsc->incRefCnts(1, this);
2733             }
2734         }
2735
2736         /* For now assume we'll be able to track all locals */
2737
2738         varDsc->lvTracked = 1;
2739
2740         /* If the ref count is zero */
2741         if (varDsc->lvRefCnt == 0)
2742         {
2743             /* Zero ref count, make this untracked */
2744             varDsc->lvTracked   = 0;
2745             varDsc->lvRefCntWtd = 0;
2746         }
2747
2748 #if !defined(_TARGET_64BIT_) && !defined(LEGACY_BACKEND)
2749         if (varTypeIsLong(varDsc) && varDsc->lvPromoted)
2750         {
2751             varDsc->lvTracked = 0;
2752         }
2753 #endif // !defined(_TARGET_64BIT_) && !defined(LEGACY_BACKEND)
2754
2755         // Variables that are address-exposed, and all struct locals, are never enregistered, or tracked.
2756         // (The struct may be promoted, and its field variables enregistered/tracked, or the VM may "normalize"
2757         // its type so that its not seen by the JIT as a struct.)
2758         // Pinned variables may not be tracked (a condition of the GCInfo representation)
2759         // or enregistered, on x86 -- it is believed that we can enregister pinned (more properly, "pinning")
2760         // references when using the general GC encoding.
2761         if (varDsc->lvAddrExposed)
2762         {
2763             varDsc->lvTracked = 0;
2764             assert(varDsc->lvType != TYP_STRUCT ||
2765                    varDsc->lvDoNotEnregister); // For structs, should have set this when we set lvAddrExposed.
2766         }
2767         else if (varTypeIsStruct(varDsc))
2768         {
2769             // Promoted structs will never be considered for enregistration anyway,
2770             // and the DoNotEnregister flag was used to indicate whether promotion was
2771             // independent or dependent.
2772             if (varDsc->lvPromoted)
2773             {
2774                 varDsc->lvTracked = 0;
2775             }
2776             else if ((varDsc->lvType == TYP_STRUCT) && !varDsc->lvRegStruct)
2777             {
2778                 lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_IsStruct));
2779             }
2780         }
2781         else if (varDsc->lvIsStructField && (lvaGetParentPromotionType(lclNum) != PROMOTION_TYPE_INDEPENDENT))
2782         {
2783             // SSA must exclude struct fields that are not independently promoted
2784             // as dependent fields could be assigned using a CopyBlock
2785             // resulting in a single node causing multiple SSA definitions
2786             // which isn't currently supported by SSA
2787             //
2788             // TODO-CQ:  Consider using lvLclBlockOpAddr and only marking these LclVars
2789             // untracked when a blockOp is used to assign the struct.
2790             //
2791             varDsc->lvTracked = 0; // so, don't mark as tracked
2792         }
2793         else if (varDsc->lvPinned)
2794         {
2795             varDsc->lvTracked = 0;
2796 #ifdef JIT32_GCENCODER
2797             lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_PinningRef));
2798 #endif
2799         }
2800
2801         //  Are we not optimizing and we have exception handlers?
2802         //   if so mark all args and locals "do not enregister".
2803         //
2804         if (opts.MinOpts() && compHndBBtabCount > 0)
2805         {
2806             lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LiveInOutOfHandler));
2807             continue;
2808         }
2809
2810         var_types type = genActualType(varDsc->TypeGet());
2811
2812         switch (type)
2813         {
2814 #if CPU_HAS_FP_SUPPORT
2815             case TYP_FLOAT:
2816             case TYP_DOUBLE:
2817 #endif
2818             case TYP_INT:
2819             case TYP_LONG:
2820             case TYP_REF:
2821             case TYP_BYREF:
2822 #ifdef FEATURE_SIMD
2823             case TYP_SIMD8:
2824             case TYP_SIMD12:
2825             case TYP_SIMD16:
2826             case TYP_SIMD32:
2827 #endif // FEATURE_SIMD
2828             case TYP_STRUCT:
2829                 break;
2830
2831             case TYP_UNDEF:
2832             case TYP_UNKNOWN:
2833                 noway_assert(!"lvType not set correctly");
2834                 varDsc->lvType = TYP_INT;
2835
2836                 __fallthrough;
2837
2838             default:
2839                 varDsc->lvTracked = 0;
2840         }
2841     }
2842
2843     /* Now sort the variable table by ref-count */
2844
2845     lvaSortOnly();
2846
2847     /* Decide which variables will be worth tracking */
2848
2849     if (lvaCount > lclMAX_TRACKED)
2850     {
2851         /* Mark all variables past the first 'lclMAX_TRACKED' as untracked */
2852
2853         for (lclNum = lclMAX_TRACKED; lclNum < lvaCount; lclNum++)
2854         {
2855             lvaRefSorted[lclNum]->lvTracked = 0;
2856         }
2857     }
2858
2859 #ifdef DEBUG
2860     // Re-Initialize to -1 for safety in debug build.
2861     memset(lvaTrackedToVarNum, -1, sizeof(lvaTrackedToVarNum));
2862 #endif
2863
2864     /* Assign indices to all the variables we've decided to track */
2865
2866     for (lclNum = 0; lclNum < min(lvaCount, lclMAX_TRACKED); lclNum++)
2867     {
2868         varDsc = lvaRefSorted[lclNum];
2869         if (varDsc->lvTracked)
2870         {
2871             noway_assert(varDsc->lvRefCnt > 0);
2872
2873             /* This variable will be tracked - assign it an index */
2874
2875             lvaTrackedToVarNum[lvaTrackedCount] = (unsigned)(varDsc - lvaTable); // The type of varDsc and lvaTable
2876             // is LclVarDsc. Subtraction will give us
2877             // the index.
2878             varDsc->lvVarIndex = lvaTrackedCount++;
2879         }
2880     }
2881
2882     // We have a new epoch, and also cache the tracked var count in terms of size_t's sufficient to hold that many bits.
2883     lvaCurEpoch++;
2884     lvaTrackedCountInSizeTUnits = unsigned(roundUp(lvaTrackedCount, sizeof(size_t) * 8)) / unsigned(sizeof(size_t) * 8);
2885
2886 #ifdef DEBUG
2887     VarSetOps::AssignNoCopy(this, lvaTrackedVars, VarSetOps::MakeFull(this));
2888 #endif
2889 }
2890
2891 #if ASSERTION_PROP
2892 /*****************************************************************************
2893  *
2894  *  This is called by lvaMarkLclRefs to disqualify a variable from being
2895  *  considered by optAddCopies()
2896  */
2897 void LclVarDsc::lvaDisqualifyVar()
2898 {
2899     this->lvDisqualify = true;
2900     this->lvSingleDef  = false;
2901     this->lvDefStmt    = nullptr;
2902 }
2903 #endif // ASSERTION_PROP
2904
2905 #ifndef LEGACY_BACKEND
2906 /**********************************************************************************
2907 * Get type of a variable when passed as an argument.
2908 */
2909 var_types LclVarDsc::lvaArgType()
2910 {
2911     var_types type = TypeGet();
2912
2913 #ifdef _TARGET_AMD64_
2914     if (type == TYP_STRUCT)
2915     {
2916         switch (lvExactSize)
2917         {
2918             case 1:
2919                 type = TYP_BYTE;
2920                 break;
2921             case 2:
2922                 type = TYP_SHORT;
2923                 break;
2924             case 4:
2925                 type = TYP_INT;
2926                 break;
2927             case 8:
2928                 switch (*lvGcLayout)
2929                 {
2930                     case TYPE_GC_NONE:
2931                         type = TYP_I_IMPL;
2932                         break;
2933
2934                     case TYPE_GC_REF:
2935                         type = TYP_REF;
2936                         break;
2937
2938                     case TYPE_GC_BYREF:
2939                         type = TYP_BYREF;
2940                         break;
2941
2942                     default:
2943                         unreached();
2944                 }
2945                 break;
2946
2947             default:
2948                 type = TYP_BYREF;
2949                 break;
2950         }
2951     }
2952 #elif defined(_TARGET_X86_)
2953 // Nothing to do; use the type as is.
2954 #else
2955     NYI("lvaArgType");
2956 #endif //_TARGET_AMD64_
2957
2958     return type;
2959 }
2960 #endif // !LEGACY_BACKEND
2961
2962 /*****************************************************************************
2963  *
2964  *  This is called by lvaMarkLclRefsCallback() to do variable ref marking
2965  */
2966
2967 void Compiler::lvaMarkLclRefs(GenTreePtr tree)
2968 {
2969     /* Is this a call to unmanaged code ? */
2970     if (tree->gtOper == GT_CALL && tree->gtFlags & GTF_CALL_UNMANAGED)
2971     {
2972         assert((!opts.ShouldUsePInvokeHelpers()) || (info.compLvFrameListRoot == BAD_VAR_NUM));
2973         if (!opts.ShouldUsePInvokeHelpers())
2974         {
2975             /* Get the special variable descriptor */
2976
2977             unsigned lclNum = info.compLvFrameListRoot;
2978
2979             noway_assert(lclNum <= lvaCount);
2980             LclVarDsc* varDsc = lvaTable + lclNum;
2981
2982             /* Increment the ref counts twice */
2983             varDsc->incRefCnts(lvaMarkRefsWeight, this);
2984             varDsc->incRefCnts(lvaMarkRefsWeight, this);
2985         }
2986     }
2987
2988     /* Is this an assigment? */
2989
2990     if (tree->OperKind() & GTK_ASGOP)
2991     {
2992         GenTreePtr op1 = tree->gtOp.gtOp1;
2993         GenTreePtr op2 = tree->gtOp.gtOp2;
2994
2995         /* Set target register for RHS local if assignment is of a "small" type */
2996
2997         if (varTypeIsByte(tree->gtType))
2998         {
2999             unsigned   lclNum;
3000             LclVarDsc* varDsc = nullptr;
3001
3002             /* GT_CHS is special it doesn't have a valid op2 */
3003             if (tree->gtOper == GT_CHS)
3004             {
3005                 if (op1->gtOper == GT_LCL_VAR)
3006                 {
3007                     lclNum = op1->gtLclVarCommon.gtLclNum;
3008                     noway_assert(lclNum < lvaCount);
3009                     varDsc = &lvaTable[lclNum];
3010                 }
3011             }
3012             else
3013             {
3014                 if (op2->gtOper == GT_LCL_VAR)
3015                 {
3016                     lclNum = op2->gtLclVarCommon.gtLclNum;
3017                     noway_assert(lclNum < lvaCount);
3018                     varDsc = &lvaTable[lclNum];
3019                 }
3020             }
3021 #if CPU_HAS_BYTE_REGS
3022             if (varDsc)
3023                 varDsc->addPrefReg(RBM_BYTE_REG_FLAG, this);
3024 #endif
3025         }
3026
3027 #if OPT_BOOL_OPS
3028
3029         /* Is this an assignment to a local variable? */
3030
3031         if (op1->gtOper == GT_LCL_VAR && op2->gtType != TYP_BOOL)
3032         {
3033             /* Only simple assignments allowed for booleans */
3034
3035             if (tree->gtOper != GT_ASG)
3036             {
3037                 goto NOT_BOOL;
3038             }
3039
3040             /* Is the RHS clearly a boolean value? */
3041
3042             switch (op2->gtOper)
3043             {
3044                 unsigned lclNum;
3045
3046                 case GT_CNS_INT:
3047
3048                     if (op2->gtIntCon.gtIconVal == 0)
3049                     {
3050                         break;
3051                     }
3052                     if (op2->gtIntCon.gtIconVal == 1)
3053                     {
3054                         break;
3055                     }
3056
3057                     // Not 0 or 1, fall through ....
3058                     __fallthrough;
3059
3060                 default:
3061
3062                     if (op2->OperIsCompare())
3063                     {
3064                         break;
3065                     }
3066
3067                 NOT_BOOL:
3068
3069                     lclNum = op1->gtLclVarCommon.gtLclNum;
3070                     noway_assert(lclNum < lvaCount);
3071
3072                     lvaTable[lclNum].lvIsBoolean = false;
3073                     break;
3074             }
3075         }
3076 #endif
3077     }
3078
3079 #if FANCY_ARRAY_OPT
3080
3081     /* Special case: assignment node */
3082
3083     if (tree->gtOper == GT_ASG)
3084     {
3085         if (tree->gtType == TYP_INT)
3086         {
3087             unsigned   lclNum1;
3088             LclVarDsc* varDsc1;
3089
3090             GenTreePtr op1 = tree->gtOp.gtOp1;
3091
3092             if (op1->gtOper != GT_LCL_VAR)
3093                 return;
3094
3095             lclNum1 = op1->gtLclVarCommon.gtLclNum;
3096             noway_assert(lclNum1 < lvaCount);
3097             varDsc1 = lvaTable + lclNum1;
3098
3099             if (varDsc1->lvAssignOne)
3100                 varDsc1->lvAssignTwo = true;
3101             else
3102                 varDsc1->lvAssignOne = true;
3103         }
3104
3105         return;
3106     }
3107
3108 #endif
3109
3110 #ifdef _TARGET_XARCH_
3111     /* Special case: integer shift node by a variable amount */
3112
3113     if (tree->OperIsShiftOrRotate())
3114     {
3115         if (tree->gtType == TYP_INT)
3116         {
3117             GenTreePtr op2 = tree->gtOp.gtOp2;
3118
3119             if (op2->gtOper == GT_LCL_VAR)
3120             {
3121                 unsigned lclNum = op2->gtLclVarCommon.gtLclNum;
3122                 noway_assert(lclNum < lvaCount);
3123                 lvaTable[lclNum].setPrefReg(REG_ECX, this);
3124             }
3125         }
3126
3127         return;
3128     }
3129 #endif
3130
3131     if ((tree->gtOper != GT_LCL_VAR) && (tree->gtOper != GT_LCL_FLD))
3132     {
3133         return;
3134     }
3135
3136     /* This must be a local variable reference */
3137
3138     noway_assert((tree->gtOper == GT_LCL_VAR) || (tree->gtOper == GT_LCL_FLD));
3139     unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
3140
3141     noway_assert(lclNum < lvaCount);
3142     LclVarDsc* varDsc = lvaTable + lclNum;
3143
3144     /* Increment the reference counts */
3145
3146     varDsc->incRefCnts(lvaMarkRefsWeight, this);
3147
3148     if (lvaVarAddrExposed(lclNum))
3149     {
3150         varDsc->lvIsBoolean = false;
3151     }
3152
3153     if (tree->gtOper == GT_LCL_FLD)
3154     {
3155 #if ASSERTION_PROP
3156         // variables that have uses inside a GT_LCL_FLD
3157         // cause problems, so we will disqualify them here
3158         varDsc->lvaDisqualifyVar();
3159 #endif // ASSERTION_PROP
3160         return;
3161     }
3162
3163 #if ASSERTION_PROP
3164     /* Exclude the normal entry block */
3165     if (fgDomsComputed && (lvaMarkRefsCurBlock->bbNum != 1) && lvaMarkRefsCurBlock->bbIDom != nullptr)
3166     {
3167         // If any entry block except the normal entry block dominates the block, then mark the local with the
3168         // lvVolatileHint flag.
3169
3170         if (BlockSetOps::MayBeUninit(lvaMarkRefsCurBlock->bbDoms))
3171         {
3172             // Lazy init (If a block is not dominated by any other block, we'll redo this every time, but it'll be fast)
3173             BlockSetOps::AssignNoCopy(this, lvaMarkRefsCurBlock->bbDoms, fgGetDominatorSet(lvaMarkRefsCurBlock));
3174             BlockSetOps::RemoveElemD(this, lvaMarkRefsCurBlock->bbDoms, fgFirstBB->bbNum);
3175         }
3176         assert(fgEnterBlksSetValid);
3177         if (!BlockSetOps::IsEmptyIntersection(this, lvaMarkRefsCurBlock->bbDoms, fgEnterBlks))
3178         {
3179             varDsc->lvVolatileHint = 1;
3180         }
3181     }
3182
3183     /* Record if the variable has a single def or not */
3184
3185     if (!varDsc->lvDisqualify) // If this variable is already disqualified we can skip this
3186     {
3187         if (tree->gtFlags & GTF_VAR_DEF) // Is this is a def of our variable
3188         {
3189             /*
3190                If we have one of these cases:
3191                    1.    We have already seen a definition (i.e lvSingleDef is true)
3192                    2. or info.CompInitMem is true (thus this would be the second definition)
3193                    3. or we have an assignment inside QMARK-COLON trees
3194                    4. or we have an update form of assignment (i.e. +=, -=, *=)
3195                Then we must disqualify this variable for use in optAddCopies()
3196
3197                Note that all parameters start out with lvSingleDef set to true
3198             */
3199             if ((varDsc->lvSingleDef == true) || (info.compInitMem == true) || (tree->gtFlags & GTF_COLON_COND) ||
3200                 (tree->gtFlags & GTF_VAR_USEASG))
3201             {
3202                 varDsc->lvaDisqualifyVar();
3203             }
3204             else
3205             {
3206                 varDsc->lvSingleDef = true;
3207                 varDsc->lvDefStmt   = lvaMarkRefsCurStmt;
3208             }
3209         }
3210         else // otherwise this is a ref of our variable
3211         {
3212             if (BlockSetOps::MayBeUninit(varDsc->lvRefBlks))
3213             {
3214                 // Lazy initialization
3215                 BlockSetOps::AssignNoCopy(this, varDsc->lvRefBlks, BlockSetOps::MakeEmpty(this));
3216             }
3217             BlockSetOps::AddElemD(this, varDsc->lvRefBlks, lvaMarkRefsCurBlock->bbNum);
3218         }
3219     }
3220 #endif // ASSERTION_PROP
3221
3222     bool allowStructs = false;
3223 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
3224     // On System V the type of the var could be a struct type.
3225     allowStructs = varTypeIsStruct(varDsc);
3226 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
3227
3228     /* Variables must be used as the same type throughout the method */
3229     noway_assert(tiVerificationNeeded || varDsc->lvType == TYP_UNDEF || tree->gtType == TYP_UNKNOWN || allowStructs ||
3230                  genActualType(varDsc->TypeGet()) == genActualType(tree->gtType) ||
3231                  (tree->gtType == TYP_BYREF && varDsc->TypeGet() == TYP_I_IMPL) ||
3232                  (tree->gtType == TYP_I_IMPL && varDsc->TypeGet() == TYP_BYREF) || (tree->gtFlags & GTF_VAR_CAST) ||
3233                  varTypeIsFloating(varDsc->TypeGet()) && varTypeIsFloating(tree->gtType));
3234
3235     /* Remember the type of the reference */
3236
3237     if (tree->gtType == TYP_UNKNOWN || varDsc->lvType == TYP_UNDEF)
3238     {
3239         varDsc->lvType = tree->gtType;
3240         noway_assert(genActualType(varDsc->TypeGet()) == tree->gtType); // no truncation
3241     }
3242
3243 #ifdef DEBUG
3244     if (tree->gtFlags & GTF_VAR_CAST)
3245     {
3246         // it should never be bigger than the variable slot
3247
3248         // Trees don't store the full information about structs
3249         // so we can't check them.
3250         if (tree->TypeGet() != TYP_STRUCT)
3251         {
3252             unsigned treeSize = genTypeSize(tree->TypeGet());
3253             unsigned varSize  = genTypeSize(varDsc->TypeGet());
3254             if (varDsc->TypeGet() == TYP_STRUCT)
3255             {
3256                 varSize = varDsc->lvSize();
3257             }
3258
3259             assert(treeSize <= varSize);
3260         }
3261     }
3262 #endif
3263 }
3264
3265 /*****************************************************************************
3266  *
3267  *  Helper passed to Compiler::fgWalkTreePre() to do variable ref marking.
3268  */
3269
3270 /* static */
3271 Compiler::fgWalkResult Compiler::lvaMarkLclRefsCallback(GenTreePtr* pTree, fgWalkData* data)
3272 {
3273     data->compiler->lvaMarkLclRefs(*pTree);
3274
3275     return WALK_CONTINUE;
3276 }
3277
3278 /*****************************************************************************
3279  *
3280  *  Update the local variable reference counts for one basic block
3281  */
3282
3283 void Compiler::lvaMarkLocalVars(BasicBlock* block)
3284 {
3285 #if ASSERTION_PROP
3286     lvaMarkRefsCurBlock = block;
3287 #endif
3288     lvaMarkRefsWeight = block->getBBWeight(this);
3289
3290 #ifdef DEBUG
3291     if (verbose)
3292     {
3293         printf("\n*** marking local variables in block BB%02u (weight=%s)\n", block->bbNum,
3294                refCntWtd2str(lvaMarkRefsWeight));
3295     }
3296 #endif
3297
3298     for (GenTreePtr tree = block->FirstNonPhiDef(); tree; tree = tree->gtNext)
3299     {
3300         noway_assert(tree->gtOper == GT_STMT);
3301
3302 #if ASSERTION_PROP
3303         lvaMarkRefsCurStmt = tree;
3304 #endif
3305
3306 #ifdef DEBUG
3307         if (verbose)
3308         {
3309             gtDispTree(tree);
3310         }
3311 #endif
3312
3313         fgWalkTreePre(&tree->gtStmt.gtStmtExpr, Compiler::lvaMarkLclRefsCallback, (void*)this, false);
3314     }
3315 }
3316
3317 /*****************************************************************************
3318  *
3319  *  Create the local variable table and compute local variable reference
3320  *  counts.
3321  */
3322
3323 void Compiler::lvaMarkLocalVars()
3324 {
3325
3326 #ifdef DEBUG
3327     if (verbose)
3328     {
3329         printf("\n*************** In lvaMarkLocalVars()");
3330     }
3331 #endif
3332
3333     /* If there is a call to an unmanaged target, we already grabbed a
3334        local slot for the current thread control block.
3335      */
3336
3337     if (info.compCallUnmanaged != 0)
3338     {
3339         assert((!opts.ShouldUsePInvokeHelpers()) || (info.compLvFrameListRoot == BAD_VAR_NUM));
3340         if (!opts.ShouldUsePInvokeHelpers())
3341         {
3342             noway_assert(info.compLvFrameListRoot >= info.compLocalsCount && info.compLvFrameListRoot < lvaCount);
3343
3344             lvaTable[info.compLvFrameListRoot].lvType = TYP_I_IMPL;
3345
3346             /* Set the refCnt, it is used in the prolog and return block(s) */
3347
3348             lvaTable[info.compLvFrameListRoot].lvRefCnt    = 2;
3349             lvaTable[info.compLvFrameListRoot].lvRefCntWtd = 2 * BB_UNITY_WEIGHT;
3350         }
3351     }
3352
3353     lvaAllocOutgoingArgSpace();
3354
3355 #if !FEATURE_EH_FUNCLETS
3356
3357     // Grab space for exception handling
3358
3359     if (ehNeedsShadowSPslots())
3360     {
3361         // The first slot is reserved for ICodeManager::FixContext(ppEndRegion)
3362         // ie. the offset of the end-of-last-executed-filter
3363         unsigned slotsNeeded = 1;
3364
3365         unsigned handlerNestingLevel = ehMaxHndNestingCount;
3366
3367         if (opts.compDbgEnC && (handlerNestingLevel < (unsigned)MAX_EnC_HANDLER_NESTING_LEVEL))
3368             handlerNestingLevel = (unsigned)MAX_EnC_HANDLER_NESTING_LEVEL;
3369
3370         slotsNeeded += handlerNestingLevel;
3371
3372         // For a filter (which can be active at the same time as a catch/finally handler)
3373         slotsNeeded++;
3374         // For zero-termination of the shadow-Stack-pointer chain
3375         slotsNeeded++;
3376
3377         lvaShadowSPslotsVar           = lvaGrabTempWithImplicitUse(false DEBUGARG("lvaShadowSPslotsVar"));
3378         LclVarDsc* shadowSPslotsVar   = &lvaTable[lvaShadowSPslotsVar];
3379         shadowSPslotsVar->lvType      = TYP_BLK;
3380         shadowSPslotsVar->lvExactSize = (slotsNeeded * TARGET_POINTER_SIZE);
3381     }
3382
3383 #endif // !FEATURE_EH_FUNCLETS
3384
3385 #if FEATURE_EH_FUNCLETS
3386     if (ehNeedsPSPSym())
3387     {
3388         lvaPSPSym            = lvaGrabTempWithImplicitUse(false DEBUGARG("PSPSym"));
3389         LclVarDsc* lclPSPSym = &lvaTable[lvaPSPSym];
3390         lclPSPSym->lvType    = TYP_I_IMPL;
3391     }
3392 #endif // FEATURE_EH_FUNCLETS
3393
3394     if (compLocallocUsed)
3395     {
3396         lvaLocAllocSPvar         = lvaGrabTempWithImplicitUse(false DEBUGARG("LocAllocSPvar"));
3397         LclVarDsc* locAllocSPvar = &lvaTable[lvaLocAllocSPvar];
3398         locAllocSPvar->lvType    = TYP_I_IMPL;
3399     }
3400
3401     BasicBlock* block;
3402
3403 #ifndef DEBUG
3404     // Assign slot numbers to all variables.
3405     // If compiler generated local variables, slot numbers will be
3406     // invalid (out of range of info.compVarScopes).
3407
3408     // Also have to check if variable was not reallocated to another
3409     // slot in which case we have to register the original slot #.
3410
3411     // We don't need to do this for IL, but this keeps lvSlotNum consistent.
3412
3413     if (opts.compScopeInfo && (info.compVarScopesCount > 0))
3414 #endif
3415     {
3416         unsigned   lclNum;
3417         LclVarDsc* varDsc;
3418
3419         for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
3420         {
3421             varDsc->lvSlotNum = lclNum;
3422         }
3423     }
3424
3425     /* Mark all local variable references */
3426
3427     lvaRefCountingStarted = true;
3428     for (block = fgFirstBB; block; block = block->bbNext)
3429     {
3430         lvaMarkLocalVars(block);
3431     }
3432
3433     /*  For incoming register arguments, if there are references in the body
3434      *  then we will have to copy them to the final home in the prolog
3435      *  This counts as an extra reference with a weight of 2
3436      */
3437
3438     unsigned   lclNum;
3439     LclVarDsc* varDsc;
3440
3441     for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
3442     {
3443         if (lclNum >= info.compArgsCount)
3444         {
3445             break; // early exit for loop
3446         }
3447
3448         if ((varDsc->lvIsRegArg) && (varDsc->lvRefCnt > 0))
3449         {
3450             // Fix 388376 ARM JitStress WP7
3451             varDsc->incRefCnts(BB_UNITY_WEIGHT, this);
3452             varDsc->incRefCnts(BB_UNITY_WEIGHT, this);
3453         }
3454     }
3455
3456 #if ASSERTION_PROP
3457     if (!opts.MinOpts() && !opts.compDbgCode)
3458     {
3459         // Note: optAddCopies() depends on lvaRefBlks, which is set in lvaMarkLocalVars(BasicBlock*), called above.
3460         optAddCopies();
3461     }
3462 #endif
3463
3464     if (lvaKeepAliveAndReportThis() && lvaTable[0].lvRefCnt == 0)
3465     {
3466         lvaTable[0].lvRefCnt = 1;
3467         // This isn't strictly needed as we will make a copy of the param-type-arg
3468         // in the prolog. However, this ensures that the LclVarDsc corresponding to
3469         // info.compTypeCtxtArg is valid.
3470     }
3471     else if (lvaReportParamTypeArg() && lvaTable[info.compTypeCtxtArg].lvRefCnt == 0)
3472     {
3473         lvaTable[info.compTypeCtxtArg].lvRefCnt = 1;
3474     }
3475
3476     lvaLocalVarRefCounted = true;
3477     lvaRefCountingStarted = false;
3478
3479     lvaSortByRefCount();
3480 }
3481
3482 void Compiler::lvaAllocOutgoingArgSpace()
3483 {
3484 #if FEATURE_FIXED_OUT_ARGS
3485
3486     // Setup the outgoing argument region, in case we end up using it later
3487
3488     if (lvaOutgoingArgSpaceVar == BAD_VAR_NUM)
3489     {
3490         lvaOutgoingArgSpaceVar = lvaGrabTemp(false DEBUGARG("OutgoingArgSpace"));
3491
3492         lvaTable[lvaOutgoingArgSpaceVar].lvType = TYP_LCLBLK;
3493
3494         /* Set the refCnts */
3495
3496         lvaTable[lvaOutgoingArgSpaceVar].lvRefCnt    = 1;
3497         lvaTable[lvaOutgoingArgSpaceVar].lvRefCntWtd = BB_UNITY_WEIGHT;
3498
3499         if (lvaOutgoingArgSpaceSize == 0)
3500         {
3501             if (compUsesThrowHelper || compIsProfilerHookNeeded())
3502             {
3503                 // Need to make sure the MIN_ARG_AREA_FOR_CALL space is added to the frame if:
3504                 // 1. there are calls to THROW_HEPLPER methods.
3505                 // 2. we are generating profiling Enter/Leave/TailCall hooks. This will ensure
3506                 //    that even methods without any calls will have outgoing arg area space allocated.
3507                 //
3508                 // An example for these two cases is Windows Amd64, where the ABI requires to have 4 slots for
3509                 // the outgoing arg space if the method makes any calls.
3510                 lvaOutgoingArgSpaceSize = MIN_ARG_AREA_FOR_CALL;
3511             }
3512         }
3513     }
3514
3515     noway_assert(lvaOutgoingArgSpaceVar >= info.compLocalsCount && lvaOutgoingArgSpaceVar < lvaCount);
3516
3517 #endif // FEATURE_FIXED_OUT_ARGS
3518 }
3519
3520 inline void Compiler::lvaIncrementFrameSize(unsigned size)
3521 {
3522     if (size > MAX_FrameSize || compLclFrameSize + size > MAX_FrameSize)
3523     {
3524         BADCODE("Frame size overflow");
3525     }
3526
3527     compLclFrameSize += size;
3528 }
3529
3530 /****************************************************************************
3531 *
3532 *  Return true if absolute offsets of temps are larger than vars, or in other
3533 *  words, did we allocate temps before of after vars.  The /GS buffer overrun
3534 *  checks want temps to be at low stack addresses than buffers
3535 */
3536 bool Compiler::lvaTempsHaveLargerOffsetThanVars()
3537 {
3538 #ifdef _TARGET_ARM_
3539     // We never want to place the temps with larger offsets for ARM
3540     return false;
3541 #else
3542     if (compGSReorderStackLayout)
3543     {
3544         return codeGen->isFramePointerUsed();
3545     }
3546     else
3547     {
3548         return true;
3549     }
3550 #endif
3551 }
3552
3553 /****************************************************************************
3554 *
3555 *  Return an upper bound estimate for the size of the compiler spill temps
3556 *
3557 */
3558 unsigned Compiler::lvaGetMaxSpillTempSize()
3559 {
3560     unsigned result = 0;
3561
3562 #ifndef LEGACY_BACKEND
3563     if (lvaDoneFrameLayout >= REGALLOC_FRAME_LAYOUT)
3564     {
3565         result = tmpSize;
3566     }
3567     else
3568     {
3569         result = MAX_SPILL_TEMP_SIZE;
3570     }
3571 #else // LEGACY_BACKEND
3572     if (lvaDoneFrameLayout >= FINAL_FRAME_LAYOUT)
3573     {
3574         result = tmpSize;
3575     }
3576     else
3577     {
3578         if (lvaDoneFrameLayout >= REGALLOC_FRAME_LAYOUT)
3579         {
3580             unsigned maxTmpSize = sizeof(double) + sizeof(int);
3581
3582             maxTmpSize += (tmpDoubleSpillMax * sizeof(double)) + (tmpIntSpillMax * sizeof(int));
3583
3584             result = maxTmpSize;
3585         }
3586         else
3587         {
3588             result = MAX_SPILL_TEMP_SIZE;
3589         }
3590 #ifdef DEBUG
3591         // When StressRegs is >=1, there can  be a bunch of spills that are not
3592         // predicted by the predictor (see logic in rsPickReg).  It is very hard
3593         // to teach the predictor about the behavior of rsPickReg for StressRegs >= 1,
3594         // so instead let's make MaxTmpSize large enough so that we won't be wrong.
3595
3596         if (codeGen->regSet.rsStressRegs() >= 1)
3597         {
3598             result += (REG_TMP_ORDER_COUNT * REGSIZE_BYTES);
3599         }
3600 #endif // DEBUG
3601     }
3602 #endif // LEGACY_BACKEND
3603     return result;
3604 }
3605
3606 // clang-format off
3607 /*****************************************************************************
3608  *
3609  *  Compute stack frame offsets for arguments, locals and optionally temps.
3610  *
3611  *  The frame is laid out as follows for x86:
3612  *
3613  *              ESP frames                
3614  *
3615  *      |                       |         
3616  *      |-----------------------|         
3617  *      |       incoming        |         
3618  *      |       arguments       |         
3619  *      |-----------------------| <---- Virtual '0'         
3620  *      |    return address     |         
3621  *      +=======================+
3622  *      |Callee saved registers |         
3623  *      |-----------------------|         
3624  *      |       Temps           |         
3625  *      |-----------------------|         
3626  *      |       Variables       |         
3627  *      |-----------------------| <---- Ambient ESP
3628  *      |   Arguments for the   |         
3629  *      ~    next function      ~ 
3630  *      |                       |         
3631  *      |       |               |         
3632  *      |       | Stack grows   |         
3633  *              | downward                
3634  *              V                         
3635  *
3636  *
3637  *              EBP frames
3638  *
3639  *      |                       |
3640  *      |-----------------------|
3641  *      |       incoming        |
3642  *      |       arguments       |
3643  *      |-----------------------| <---- Virtual '0'         
3644  *      |    return address     |         
3645  *      +=======================+
3646  *      |    incoming EBP       |
3647  *      |-----------------------| <---- EBP
3648  *      |Callee saved registers |         
3649  *      |-----------------------|         
3650  *      |   security object     |
3651  *      |-----------------------|
3652  *      |     ParamTypeArg      |
3653  *      |-----------------------|
3654  *      |  Last-executed-filter |
3655  *      |-----------------------|
3656  *      |                       |
3657  *      ~      Shadow SPs       ~
3658  *      |                       |
3659  *      |-----------------------|
3660  *      |                       |
3661  *      ~      Variables        ~
3662  *      |                       |
3663  *      ~-----------------------|
3664  *      |       Temps           |
3665  *      |-----------------------|
3666  *      |       localloc        |
3667  *      |-----------------------| <---- Ambient ESP
3668  *      |   Arguments for the   |
3669  *      |    next function      ~
3670  *      |                       |
3671  *      |       |               |
3672  *      |       | Stack grows   |
3673  *              | downward
3674  *              V
3675  *
3676  *
3677  *  The frame is laid out as follows for x64:
3678  *
3679  *              RSP frames                
3680  *      |                       |         
3681  *      |-----------------------|         
3682  *      |       incoming        |         
3683  *      |       arguments       |         
3684  *      |-----------------------|         
3685  *      |   4 fixed incoming    |         
3686  *      |    argument slots     |         
3687  *      |-----------------------| <---- Caller's SP & Virtual '0'
3688  *      |    return address     |         
3689  *      +=======================+
3690  *      | Callee saved Int regs |  
3691  *      -------------------------
3692  *      |        Padding        | <---- this padding (0 or 8 bytes) is to ensure flt registers are saved at a mem location aligned at 16-bytes
3693  *      |                       |       so that we can save 128-bit callee saved xmm regs using performant "movaps" instruction instead of "movups"
3694  *      -------------------------
3695  *      | Callee saved Flt regs | <----- entire 128-bits of callee saved xmm registers are stored here
3696  *      |-----------------------|         
3697  *      |         Temps         |         
3698  *      |-----------------------|         
3699  *      |       Variables       |         
3700  *      |-----------------------|
3701  *      |   Arguments for the   |         
3702  *      ~    next function      ~ 
3703  *      |                       |         
3704  *      |-----------------------|         
3705  *      |   4 fixed outgoing    |         
3706  *      |    argument slots     |         
3707  *      |-----------------------| <---- Ambient RSP
3708  *      |       |               |         
3709  *      ~       | Stack grows   ~         
3710  *      |       | downward      |         
3711  *              V                         
3712  *
3713  *
3714  *              RBP frames
3715  *      |                       |
3716  *      |-----------------------|
3717  *      |       incoming        |
3718  *      |       arguments       |
3719  *      |-----------------------|         
3720  *      |   4 fixed incoming    |         
3721  *      |    argument slots     |         
3722  *      |-----------------------| <---- Caller's SP & Virtual '0'
3723  *      |    return address     |         
3724  *      +=======================+
3725  *      | Callee saved Int regs |         
3726  *      -------------------------
3727  *      |        Padding        | 
3728  *      -------------------------
3729  *      | Callee saved Flt regs | 
3730  *      |-----------------------|         
3731  *      |   security object     |
3732  *      |-----------------------|
3733  *      |     ParamTypeArg      |
3734  *      |-----------------------|
3735  *      |                       |
3736  *      |                       | 
3737  *      ~       Variables       ~
3738  *      |                       | 
3739  *      |                       |
3740  *      |-----------------------|
3741  *      |        Temps          |
3742  *      |-----------------------| 
3743  *      |                       |
3744  *      ~       localloc        ~   // not in frames with EH
3745  *      |                       |
3746  *      |-----------------------|
3747  *      |        PSPSym         |   // only in frames with EH (thus no localloc)
3748  *      |                       |
3749  *      |-----------------------| <---- RBP in localloc frames (max 240 bytes from Initial-SP)
3750  *      |   Arguments for the   |         
3751  *      ~    next function      ~ 
3752  *      |                       |         
3753  *      |-----------------------| 
3754  *      |   4 fixed outgoing    |         
3755  *      |    argument slots     |         
3756  *      |-----------------------| <---- Ambient RSP (before localloc, this is Initial-SP)
3757  *      |       |               |         
3758  *      ~       | Stack grows   ~         
3759  *      |       | downward      |         
3760  *              V
3761  *
3762  *
3763  *  The frame is laid out as follows for ARM (this is a general picture; details may differ for different conditions):
3764  *
3765  *              SP frames                
3766  *      |                       |         
3767  *      |-----------------------|         
3768  *      |       incoming        |         
3769  *      |       arguments       |         
3770  *      +=======================+ <---- Caller's SP
3771  *      |  Pre-spill registers  |         
3772  *      |-----------------------| <---- Virtual '0'
3773  *      |Callee saved registers |         
3774  *      |-----------------------|         
3775  *      ~ possible double align ~
3776  *      |-----------------------|
3777  *      |   security object     |
3778  *      |-----------------------|
3779  *      |     ParamTypeArg      |
3780  *      |-----------------------|
3781  *      |  possible GS cookie   |
3782  *      |-----------------------|
3783  *      |       Variables       |
3784  *      |-----------------------|
3785  *      |  possible GS cookie   |
3786  *      |-----------------------|
3787  *      |        Temps          |
3788  *      |-----------------------|
3789  *      |   Stub Argument Var   |
3790  *      |-----------------------|
3791  *      |Inlined PInvoke Frame V|
3792  *      |-----------------------|
3793  *      ~ possible double align ~
3794  *      |-----------------------|
3795  *      |   Arguments for the   |         
3796  *      ~    next function      ~ 
3797  *      |                       |         
3798  *      |-----------------------| <---- Ambient SP
3799  *      |       |               |         
3800  *      ~       | Stack grows   ~         
3801  *      |       | downward      |         
3802  *              V
3803  *
3804  *
3805  *              FP / R11 frames
3806  *      |                       |
3807  *      |-----------------------|
3808  *      |       incoming        |
3809  *      |       arguments       |
3810  *      +=======================+ <---- Caller's SP
3811  *      |  Pre-spill registers  |         
3812  *      |-----------------------| <---- Virtual '0'
3813  *      |Callee saved registers |         
3814  *      |-----------------------|         
3815  *      |        PSPSym         |   // Only for frames with EH, which means FP-based frames
3816  *      |-----------------------|
3817  *      ~ possible double align ~
3818  *      |-----------------------|
3819  *      |   security object     |
3820  *      |-----------------------|
3821  *      |     ParamTypeArg      |
3822  *      |-----------------------|
3823  *      |  possible GS cookie   |
3824  *      |-----------------------|
3825  *      |       Variables       |
3826  *      |-----------------------|
3827  *      |  possible GS cookie   |
3828  *      |-----------------------|
3829  *      |        Temps          |
3830  *      |-----------------------|
3831  *      |   Stub Argument Var   |
3832  *      |-----------------------|
3833  *      |Inlined PInvoke Frame V|
3834  *      |-----------------------|
3835  *      ~ possible double align ~
3836  *      |-----------------------|
3837  *      |       localloc        |
3838  *      |-----------------------|
3839  *      |   Arguments for the   |         
3840  *      ~    next function      ~ 
3841  *      |                       |         
3842  *      |-----------------------| <---- Ambient SP
3843  *      |       |               |         
3844  *      ~       | Stack grows   ~         
3845  *      |       | downward      |         
3846  *              V
3847  *
3848  *
3849  *  The frame is laid out as follows for ARM64 (this is a general picture; details may differ for different conditions):
3850  *  TODO-ARM64-NYI: this is preliminary (copied from ARM and modified), and needs to be reviewed.
3851  *  NOTE: SP must be 16-byte aligned, so there may be alignment slots in the frame.
3852  *  We will often save and establish a frame pointer to create better ETW stack walks.
3853  *
3854  *              SP frames                
3855  *      |                       |         
3856  *      |-----------------------|         
3857  *      |       incoming        |         
3858  *      |       arguments       |         
3859  *      +=======================+ <---- Caller's SP
3860  *      |         homed         | // this is only needed if reg argument need to be homed, e.g., for varargs
3861  *      |   register arguments  |         
3862  *      |-----------------------| <---- Virtual '0'
3863  *      |Callee saved registers |
3864  *      |   except fp/lr        |         
3865  *      |-----------------------|
3866  *      |   security object     |
3867  *      |-----------------------|
3868  *      |     ParamTypeArg      |
3869  *      |-----------------------|
3870  *      |  possible GS cookie   |
3871  *      |-----------------------|
3872  *      |       Variables       |
3873  *      |-----------------------|
3874  *      |  possible GS cookie   |
3875  *      |-----------------------|
3876  *      |        Temps          |
3877  *      |-----------------------|
3878  *      |   Stub Argument Var   |
3879  *      |-----------------------|
3880  *      |Inlined PInvoke Frame V|
3881  *      |-----------------------|
3882  *      |      Saved LR         |
3883  *      |-----------------------|
3884  *      |      Saved FP         | <---- Frame pointer
3885  *      |-----------------------|         
3886  *      |  Stack arguments for  |
3887  *      |   the next function   |
3888  *      |-----------------------| <---- SP
3889  *      |       |               |         
3890  *      ~       | Stack grows   ~         
3891  *      |       | downward      |         
3892  *              V
3893  *
3894  *
3895  *              FP (R29 / x29) frames
3896  *      |                       |
3897  *      |-----------------------|
3898  *      |       incoming        |
3899  *      |       arguments       |
3900  *      +=======================+ <---- Caller's SP
3901  *      |     optional homed    | // this is only needed if reg argument need to be homed, e.g., for varargs
3902  *      |   register arguments  |         
3903  *      |-----------------------| <---- Virtual '0'         
3904  *      |Callee saved registers |
3905  *      |   except fp/lr        |         
3906  *      |-----------------------|
3907  *      |        PSPSym         | // Only for frames with EH, which requires FP-based frames
3908  *      |-----------------------|
3909  *      |   security object     |
3910  *      |-----------------------|
3911  *      |     ParamTypeArg      |
3912  *      |-----------------------|
3913  *      |  possible GS cookie   |
3914  *      |-----------------------|
3915  *      |       Variables       |
3916  *      |-----------------------|
3917  *      |  possible GS cookie   |
3918  *      |-----------------------|
3919  *      |        Temps          |
3920  *      |-----------------------|
3921  *      |   Stub Argument Var   |
3922  *      |-----------------------|
3923  *      |Inlined PInvoke Frame V|
3924  *      |-----------------------|
3925  *      |      Saved LR         |
3926  *      |-----------------------|
3927  *      |      Saved FP         | <---- Frame pointer
3928  *      |-----------------------|
3929  *      ~       localloc        ~
3930  *      |-----------------------|
3931  *      |  Stack arguments for  |
3932  *      |   the next function   |
3933  *      |-----------------------| <---- Ambient SP
3934  *      |       |               |         
3935  *      ~       | Stack grows   ~         
3936  *      |       | downward      |         
3937  *              V
3938  *
3939  *
3940  *  Doing this all in one pass is 'hard'.  So instead we do it in 2 basic passes:
3941  *    1. Assign all the offsets relative to the Virtual '0'. Offsets above (the
3942  *      incoming arguments) are positive. Offsets below (everything else) are
3943  *      negative.  This pass also calcuates the total frame size (between Caller's
3944  *      SP/return address and the Ambient SP).
3945  *    2. Figure out where to place the frame pointer, and then adjust the offsets
3946  *      as needed for the final stack size and whether the offset is frame pointer
3947  *      relative or stack pointer relative.
3948  *
3949  */
3950 // clang-format on
3951
3952 void Compiler::lvaAssignFrameOffsets(FrameLayoutState curState)
3953 {
3954     noway_assert(lvaDoneFrameLayout < curState);
3955
3956     lvaDoneFrameLayout = curState;
3957
3958 #ifdef DEBUG
3959     if (verbose)
3960     {
3961
3962         printf("*************** In lvaAssignFrameOffsets");
3963         if (curState == INITIAL_FRAME_LAYOUT)
3964         {
3965             printf("(INITIAL_FRAME_LAYOUT)");
3966         }
3967         else if (curState == PRE_REGALLOC_FRAME_LAYOUT)
3968         {
3969             printf("(PRE_REGALLOC_FRAME_LAYOUT)");
3970         }
3971         else if (curState == REGALLOC_FRAME_LAYOUT)
3972         {
3973             printf("(REGALLOC_FRAME_LAYOUT)");
3974         }
3975         else if (curState == TENTATIVE_FRAME_LAYOUT)
3976         {
3977             printf("(TENTATIVE_FRAME_LAYOUT)");
3978         }
3979         else if (curState == FINAL_FRAME_LAYOUT)
3980         {
3981             printf("(FINAL_FRAME_LAYOUT)");
3982         }
3983         else
3984         {
3985             printf("(UNKNOWN)");
3986             unreached();
3987         }
3988         printf("\n");
3989     }
3990 #endif
3991
3992 #if FEATURE_FIXED_OUT_ARGS
3993     assert(lvaOutgoingArgSpaceVar != BAD_VAR_NUM);
3994 #endif // FEATURE_FIXED_OUT_ARGS
3995
3996     /*-------------------------------------------------------------------------
3997      *
3998      * First process the arguments.
3999      *
4000      *-------------------------------------------------------------------------
4001      */
4002
4003     lvaAssignVirtualFrameOffsetsToArgs();
4004
4005     /*-------------------------------------------------------------------------
4006      *
4007      * Now compute stack offsets for any variables that don't live in registers
4008      *
4009      *-------------------------------------------------------------------------
4010      */
4011
4012     lvaAssignVirtualFrameOffsetsToLocals();
4013
4014     lvaAlignFrame();
4015
4016     /*-------------------------------------------------------------------------
4017      *
4018      * Now patch the offsets
4019      *
4020      *-------------------------------------------------------------------------
4021      */
4022
4023     lvaFixVirtualFrameOffsets();
4024
4025     // Modify the stack offset for fields of promoted structs.
4026     lvaAssignFrameOffsetsToPromotedStructs();
4027
4028     /*-------------------------------------------------------------------------
4029      *
4030      * Finalize
4031      *
4032      *-------------------------------------------------------------------------
4033      */
4034
4035     // If it's not the final frame layout, then it's just an estimate. This means
4036     // we're allowed to once again write to these variables, even if we've read
4037     // from them to make tentative code generation or frame layout decisions.
4038     if (curState < FINAL_FRAME_LAYOUT)
4039     {
4040         codeGen->resetFramePointerUsedWritePhase();
4041     }
4042 }
4043
4044 /*****************************************************************************
4045  *  lvaFixVirtualFrameOffsets() : Now that everything has a virtual offset,
4046  *  determine the final value for the frame pointer (if needed) and then
4047  *  adjust all the offsets appropriately.
4048  *
4049  *  This routine fixes virtual offset to be relative to frame pointer or SP
4050  *  based on whether varDsc->lvFramePointerBased is true or false respectively.
4051  */
4052 void Compiler::lvaFixVirtualFrameOffsets()
4053 {
4054     LclVarDsc* varDsc;
4055
4056 #if FEATURE_EH_FUNCLETS && defined(_TARGET_AMD64_)
4057     if (ehNeedsPSPSym())
4058     {
4059         // We need to fix the offset of the PSPSym so there is no padding between it and the outgoing argument space.
4060         // Without this code, lvaAlignFrame might have put the padding lower than the PSPSym, which would be between
4061         // the PSPSym and the outgoing argument space.
4062         assert(lvaPSPSym != BAD_VAR_NUM);
4063         varDsc = &lvaTable[lvaPSPSym];
4064         assert(varDsc->lvFramePointerBased); // We always access it RBP-relative.
4065         assert(!varDsc->lvMustInit);         // It is never "must init".
4066         varDsc->lvStkOffs = codeGen->genCallerSPtoInitialSPdelta() + lvaLclSize(lvaOutgoingArgSpaceVar);
4067     }
4068 #endif
4069
4070     // The delta to be added to virtual offset to adjust it relative to frame pointer or SP
4071     int delta = 0;
4072
4073 #ifdef _TARGET_XARCH_
4074     delta += REGSIZE_BYTES; // pushed PC (return address) for x86/x64
4075
4076     if (codeGen->doubleAlignOrFramePointerUsed())
4077     {
4078         delta += REGSIZE_BYTES; // pushed EBP (frame pointer)
4079     }
4080 #endif
4081
4082     if (!codeGen->isFramePointerUsed())
4083     {
4084         // pushed registers, return address, and padding
4085         delta += codeGen->genTotalFrameSize();
4086     }
4087 #if defined(_TARGET_ARM_)
4088     else
4089     {
4090         // We set FP to be after LR, FP
4091         delta += 2 * REGSIZE_BYTES;
4092     }
4093 #elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
4094     else
4095     {
4096         // FP is used.
4097         delta += codeGen->genTotalFrameSize() - codeGen->genSPtoFPdelta();
4098     }
4099 #endif //_TARGET_AMD64_
4100
4101     unsigned lclNum;
4102     for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
4103     {
4104         bool doAssignStkOffs = true;
4105
4106         // Can't be relative to EBP unless we have an EBP
4107         noway_assert(!varDsc->lvFramePointerBased || codeGen->doubleAlignOrFramePointerUsed());
4108
4109         // Is this a non-param promoted struct field?
4110         //   if so then set doAssignStkOffs to false.
4111         //
4112         if (varDsc->lvIsStructField && !varDsc->lvIsParam)
4113         {
4114             LclVarDsc*       parentvarDsc  = &lvaTable[varDsc->lvParentLcl];
4115             lvaPromotionType promotionType = lvaGetPromotionType(parentvarDsc);
4116
4117             if (promotionType == PROMOTION_TYPE_DEPENDENT)
4118             {
4119                 doAssignStkOffs = false; // Assigned later in lvaAssignFrameOffsetsToPromotedStructs()
4120             }
4121         }
4122
4123         if (!varDsc->lvOnFrame)
4124         {
4125             if (!varDsc->lvIsParam
4126 #if !defined(_TARGET_AMD64_)
4127                 || (varDsc->lvIsRegArg
4128 #if defined(_TARGET_ARM_) && defined(PROFILING_SUPPORTED)
4129                     && compIsProfilerHookNeeded() &&
4130                     !lvaIsPreSpilled(lclNum, codeGen->regSet.rsMaskPreSpillRegs(false)) // We need assign stack offsets
4131                                                                                         // for prespilled arguments
4132 #endif
4133                     )
4134 #endif // !defined(_TARGET_AMD64_)
4135                     )
4136             {
4137                 doAssignStkOffs = false; // Not on frame or an incomming stack arg
4138             }
4139         }
4140
4141         if (doAssignStkOffs)
4142         {
4143             varDsc->lvStkOffs += delta;
4144
4145 #if DOUBLE_ALIGN
4146             if (genDoubleAlign() && !codeGen->isFramePointerUsed())
4147             {
4148                 if (varDsc->lvFramePointerBased)
4149                 {
4150                     varDsc->lvStkOffs -= delta;
4151
4152                     // We need to re-adjust the offsets of the parameters so they are EBP
4153                     // relative rather than stack/frame pointer relative
4154
4155                     varDsc->lvStkOffs += (2 * sizeof(void*)); // return address and pushed EBP
4156
4157                     noway_assert(varDsc->lvStkOffs >= FIRST_ARG_STACK_OFFS);
4158                 }
4159             }
4160 #endif
4161             // On System V environments the stkOffs could be 0 for params passed in registers.
4162             assert(codeGen->isFramePointerUsed() ||
4163                    varDsc->lvStkOffs >= 0); // Only EBP relative references can have negative offsets
4164         }
4165     }
4166
4167     assert(tmpAllFree());
4168     for (TempDsc* temp = tmpListBeg(); temp != nullptr; temp = tmpListNxt(temp))
4169     {
4170         temp->tdAdjustTempOffs(delta);
4171     }
4172
4173     lvaCachedGenericContextArgOffs += delta;
4174
4175 #if FEATURE_FIXED_OUT_ARGS
4176
4177     if (lvaOutgoingArgSpaceVar != BAD_VAR_NUM)
4178     {
4179         varDsc                      = &lvaTable[lvaOutgoingArgSpaceVar];
4180         varDsc->lvStkOffs           = 0;
4181         varDsc->lvFramePointerBased = false;
4182         varDsc->lvMustInit          = false;
4183     }
4184
4185 #endif // FEATURE_FIXED_OUT_ARGS
4186 }
4187
4188 #ifdef _TARGET_ARM_
4189 bool Compiler::lvaIsPreSpilled(unsigned lclNum, regMaskTP preSpillMask)
4190 {
4191     const LclVarDsc& desc = lvaTable[lclNum];
4192     return desc.lvIsRegArg && (preSpillMask & genRegMask(desc.lvArgReg));
4193 }
4194 #endif // _TARGET_ARM_
4195
4196 #ifndef LEGACY_BACKEND
4197 /*****************************************************************************
4198  *  lvaUpdateArgsWithInitialReg() : For each argument variable descriptor, update
4199  *  its current register with the initial register as assigned by LSRA.
4200  */
4201 void Compiler::lvaUpdateArgsWithInitialReg()
4202 {
4203     if (!compLSRADone)
4204     {
4205         return;
4206     }
4207
4208     for (unsigned lclNum = 0; lclNum < info.compArgsCount; lclNum++)
4209     {
4210         LclVarDsc* varDsc = lvaTable + lclNum;
4211
4212         if (varDsc->lvPromotedStruct())
4213         {
4214             noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
4215
4216             unsigned fieldVarNum = varDsc->lvFieldLclStart;
4217             varDsc               = lvaTable + fieldVarNum;
4218         }
4219
4220         noway_assert(varDsc->lvIsParam);
4221
4222         if (varDsc->lvIsRegCandidate())
4223         {
4224             if (varTypeIsMultiReg(varDsc))
4225             {
4226                 regPairNo initialRegPair = varDsc->lvArgInitRegPair;
4227                 varDsc->lvRegNum         = genRegPairLo(initialRegPair);
4228                 varDsc->lvOtherReg       = genRegPairHi(initialRegPair);
4229             }
4230             else
4231             {
4232                 varDsc->lvRegNum = varDsc->lvArgInitReg;
4233             }
4234         }
4235     }
4236 }
4237 #endif // !LEGACY_BACKEND
4238
4239 /*****************************************************************************
4240  *  lvaAssignVirtualFrameOffsetsToArgs() : Assign virtual stack offsets to the
4241  *  arguments, and implicit arguments (this ptr, return buffer, generics,
4242  *  and varargs).
4243  */
4244 void Compiler::lvaAssignVirtualFrameOffsetsToArgs()
4245 {
4246     unsigned lclNum  = 0;
4247     int      argOffs = 0;
4248 #ifdef UNIX_AMD64_ABI
4249     int callerArgOffset = 0;
4250 #endif // UNIX_AMD64_ABI
4251
4252     /*
4253         Assign stack offsets to arguments (in reverse order of passing).
4254
4255         This means that if we pass arguments left->right, we start at
4256         the end of the list and work backwards, for right->left we start
4257         with the first argument and move forward.
4258
4259         This is all relative to our Virtual '0'
4260      */
4261
4262     if (Target::g_tgtArgOrder == Target::ARG_ORDER_L2R)
4263     {
4264         argOffs = compArgSize;
4265     }
4266
4267     /* Update the argOffs to reflect arguments that are passed in registers */
4268
4269     noway_assert(codeGen->intRegState.rsCalleeRegArgCount <= MAX_REG_ARG);
4270     noway_assert(compArgSize >= codeGen->intRegState.rsCalleeRegArgCount * sizeof(void*));
4271
4272 #ifdef _TARGET_X86_
4273     argOffs -= codeGen->intRegState.rsCalleeRegArgCount * sizeof(void*);
4274 #endif
4275
4276 #ifndef LEGACY_BACKEND
4277     // Update the arg initial register locations.
4278     lvaUpdateArgsWithInitialReg();
4279 #endif // !LEGACY_BACKEND
4280
4281     /* Is there a "this" argument? */
4282
4283     if (!info.compIsStatic)
4284     {
4285         noway_assert(lclNum == info.compThisArg);
4286 #ifndef _TARGET_X86_
4287         argOffs =
4288             lvaAssignVirtualFrameOffsetToArg(lclNum, REGSIZE_BYTES, argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4289 #endif // _TARGET_X86_
4290         lclNum++;
4291     }
4292
4293     /* if we have a hidden buffer parameter, that comes here */
4294
4295     if (info.compRetBuffArg != BAD_VAR_NUM)
4296     {
4297         noway_assert(lclNum == info.compRetBuffArg);
4298         noway_assert(lvaTable[lclNum].lvIsRegArg);
4299 #ifndef _TARGET_X86_
4300         argOffs =
4301             lvaAssignVirtualFrameOffsetToArg(lclNum, REGSIZE_BYTES, argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4302 #endif // _TARGET_X86_
4303         lclNum++;
4304     }
4305
4306 #if USER_ARGS_COME_LAST
4307
4308     //@GENERICS: extra argument for instantiation info
4309     if (info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE)
4310     {
4311         noway_assert(lclNum == (unsigned)info.compTypeCtxtArg);
4312         argOffs = lvaAssignVirtualFrameOffsetToArg(lclNum++, sizeof(void*),
4313                                                    argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4314     }
4315
4316     if (info.compIsVarArgs)
4317     {
4318         argOffs = lvaAssignVirtualFrameOffsetToArg(lclNum++, sizeof(void*),
4319                                                    argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4320     }
4321
4322 #endif // USER_ARGS_COME_LAST
4323
4324     CORINFO_ARG_LIST_HANDLE argLst    = info.compMethodInfo->args.args;
4325     unsigned                argSigLen = info.compMethodInfo->args.numArgs;
4326
4327 #ifdef _TARGET_ARM_
4328     //
4329     // struct_n { int; int; ... n times };
4330     //
4331     // Consider signature:
4332     //
4333     // Foo (float a,double b,float c,double d,float e,double f,float g,double h,
4334     //      float i,double j,float k,double l,struct_3 m) { }
4335     //
4336     // Basically the signature is: (all float regs full, 1 double, struct_3);
4337     //
4338     // The double argument occurs before pre spill in the argument iteration and
4339     // computes an argOffset of 0. struct_3 offset becomes 8. This is wrong.
4340     // Because struct_3 is prespilled and double occurs after prespill.
4341     // The correct offsets are double = 16 (aligned stk), struct_3 = 0..12,
4342     // Offset 12 will be skipped for double alignment of double.
4343     //
4344     // Another example is (struct_2, all float regs full, double, struct_2);
4345     // Here, notice the order is similarly messed up because of 2 pre-spilled
4346     // struct_2.
4347     //
4348     // Succinctly,
4349     // ARG_INDEX(i) > ARG_INDEX(j) DOES NOT IMPLY |ARG_OFFSET(i)| > |ARG_OFFSET(j)|
4350     //
4351     // Therefore, we'll do a two pass offset calculation, one that considers pre-spill
4352     // and the next, stack args.
4353     //
4354
4355     unsigned argLcls = 0;
4356
4357     // Take care of pre spill registers first.
4358     regMaskTP preSpillMask = codeGen->regSet.rsMaskPreSpillRegs(false);
4359     regMaskTP tempMask     = RBM_NONE;
4360     for (unsigned i = 0, preSpillLclNum = lclNum; i < argSigLen; ++i, ++preSpillLclNum)
4361     {
4362         if (lvaIsPreSpilled(preSpillLclNum, preSpillMask))
4363         {
4364             unsigned argSize = eeGetArgSize(argLst, &info.compMethodInfo->args);
4365             argOffs          = lvaAssignVirtualFrameOffsetToArg(preSpillLclNum, argSize, argOffs);
4366             argLcls++;
4367
4368             // Early out if we can. If size is 8 and base reg is 2, then the mask is 0x1100
4369             tempMask |= ((((1 << (roundUp(argSize) / REGSIZE_BYTES))) - 1) << lvaTable[preSpillLclNum].lvArgReg);
4370             if (tempMask == preSpillMask)
4371             {
4372                 // We won't encounter more pre-spilled registers,
4373                 // so don't bother iterating further.
4374                 break;
4375             }
4376         }
4377         argLst = info.compCompHnd->getArgNext(argLst);
4378     }
4379
4380     // Take care of non pre-spilled stack arguments.
4381     argLst = info.compMethodInfo->args.args;
4382     for (unsigned i = 0, stkLclNum = lclNum; i < argSigLen; ++i, ++stkLclNum)
4383     {
4384         if (!lvaIsPreSpilled(stkLclNum, preSpillMask))
4385         {
4386             argOffs =
4387                 lvaAssignVirtualFrameOffsetToArg(stkLclNum, eeGetArgSize(argLst, &info.compMethodInfo->args), argOffs);
4388             argLcls++;
4389         }
4390         argLst = info.compCompHnd->getArgNext(argLst);
4391     }
4392
4393     lclNum += argLcls;
4394 #else // !_TARGET_ARM_
4395     for (unsigned i = 0; i < argSigLen; i++)
4396     {
4397         unsigned argumentSize = eeGetArgSize(argLst, &info.compMethodInfo->args);
4398
4399 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
4400         // On the stack frame the homed arg always takes a full number of slots
4401         // for proper stack alignment. Make sure the real struct size is properly rounded up.
4402         argumentSize = (unsigned)roundUp(argumentSize, TARGET_POINTER_SIZE);
4403 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
4404
4405         argOffs =
4406             lvaAssignVirtualFrameOffsetToArg(lclNum++, argumentSize, argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4407         argLst = info.compCompHnd->getArgNext(argLst);
4408     }
4409 #endif // !_TARGET_ARM_
4410
4411 #if !USER_ARGS_COME_LAST
4412
4413     //@GENERICS: extra argument for instantiation info
4414     if (info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE)
4415     {
4416         noway_assert(lclNum == (unsigned)info.compTypeCtxtArg);
4417         argOffs = lvaAssignVirtualFrameOffsetToArg(lclNum++, sizeof(void*),
4418                                                    argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4419     }
4420
4421     if (info.compIsVarArgs)
4422     {
4423         argOffs = lvaAssignVirtualFrameOffsetToArg(lclNum++, sizeof(void*),
4424                                                    argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4425     }
4426
4427 #endif // USER_ARGS_COME_LAST
4428 }
4429
4430 #ifdef UNIX_AMD64_ABI
4431 //
4432 //  lvaAssignVirtualFrameOffsetToArg() : Assign virtual stack offsets to an
4433 //  individual argument, and return the offset for the next argument.
4434 //  Note: This method only calculates the initial offset of the stack passed/spilled arguments
4435 //  (if any - the RA might decide to spill(home on the stack) register passed arguments, if rarely used.)
4436 //        The final offset is calculated in lvaFixVirtualFrameOffsets method. It accounts for FP existance,
4437 //        ret address slot, stack frame padding, alloca instructions, etc.
4438 //  Note: This is the implementation for UNIX_AMD64 System V platforms.
4439 //
4440 int Compiler::lvaAssignVirtualFrameOffsetToArg(unsigned lclNum,
4441                                                unsigned argSize,
4442                                                int argOffs UNIX_AMD64_ABI_ONLY_ARG(int* callerArgOffset))
4443 {
4444     noway_assert(lclNum < info.compArgsCount);
4445     noway_assert(argSize);
4446
4447     if (Target::g_tgtArgOrder == Target::ARG_ORDER_L2R)
4448     {
4449         argOffs -= argSize;
4450     }
4451
4452     unsigned fieldVarNum = BAD_VAR_NUM;
4453
4454     noway_assert(lclNum < lvaCount);
4455     LclVarDsc* varDsc = lvaTable + lclNum;
4456
4457     if (varDsc->lvPromotedStruct())
4458     {
4459         noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
4460         fieldVarNum = varDsc->lvFieldLclStart;
4461
4462         lvaPromotionType promotionType = lvaGetPromotionType(varDsc);
4463
4464         if (promotionType == PROMOTION_TYPE_INDEPENDENT)
4465         {
4466             lclNum = fieldVarNum;
4467             noway_assert(lclNum < lvaCount);
4468             varDsc = lvaTable + lclNum;
4469             assert(varDsc->lvIsStructField);
4470         }
4471     }
4472
4473     noway_assert(varDsc->lvIsParam);
4474
4475     if (varDsc->lvIsRegArg)
4476     {
4477         // Argument is passed in a register, don't count it
4478         // when updating the current offset on the stack.
4479
4480         if (varDsc->lvOnFrame)
4481         {
4482             // The offset for args needs to be set only for the stack homed arguments for System V.
4483             varDsc->lvStkOffs = argOffs;
4484         }
4485         else
4486         {
4487             varDsc->lvStkOffs = 0;
4488         }
4489     }
4490     else
4491     {
4492         // For Windows AMD64 there are 4 slots for the register passed arguments on the top of the caller's stack.
4493         // This is where they are always homed. So, they can be accessed with positive offset.
4494         // On System V platforms, if the RA decides to home a register passed arg on the stack, it creates a stack
4495         // location on the callee stack (like any other local var.) In such a case, the register passed, stack homed
4496         // arguments are accessed using negative offsets and the stack passed arguments are accessed using positive
4497         // offset (from the caller's stack.)
4498         // For  System V platforms if there is no frame pointer the caller stack parameter offset should include the
4499         // callee allocated space. If frame register is used, the callee allocated space should not be included for
4500         // accessing the caller stack parameters. The last two requirements are met in lvaFixVirtualFrameOffsets
4501         // method, which fixes the offsets, based on frame pointer existence, existence of alloca instructions, ret
4502         // address pushed, ets.
4503
4504         varDsc->lvStkOffs = *callerArgOffset;
4505         // Structs passed on stack could be of size less than TARGET_POINTER_SIZE.
4506         // Make sure they get at least TARGET_POINTER_SIZE on the stack - this is required for alignment.
4507         if (argSize > TARGET_POINTER_SIZE)
4508         {
4509             *callerArgOffset += (int)roundUp(argSize, TARGET_POINTER_SIZE);
4510         }
4511         else
4512         {
4513             *callerArgOffset += TARGET_POINTER_SIZE;
4514         }
4515     }
4516
4517     // For struct promoted parameters we need to set the offsets for both LclVars.
4518     //
4519     // For a dependent promoted struct we also assign the struct fields stack offset
4520     if (varDsc->lvPromotedStruct())
4521     {
4522         lvaPromotionType promotionType = lvaGetPromotionType(varDsc);
4523
4524         if (promotionType == PROMOTION_TYPE_DEPENDENT)
4525         {
4526             noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
4527
4528             assert(fieldVarNum == varDsc->lvFieldLclStart);
4529             lvaTable[fieldVarNum].lvStkOffs = varDsc->lvStkOffs;
4530         }
4531     }
4532     // For an independent promoted struct field we also assign the parent struct stack offset
4533     else if (varDsc->lvIsStructField)
4534     {
4535         noway_assert(varDsc->lvParentLcl < lvaCount);
4536         lvaTable[varDsc->lvParentLcl].lvStkOffs = varDsc->lvStkOffs;
4537     }
4538
4539     if (Target::g_tgtArgOrder == Target::ARG_ORDER_R2L && !varDsc->lvIsRegArg)
4540     {
4541         argOffs += argSize;
4542     }
4543
4544     return argOffs;
4545 }
4546
4547 #else // !UNIX_AMD64_ABI
4548
4549 //
4550 //  lvaAssignVirtualFrameOffsetToArg() : Assign virtual stack offsets to an
4551 //  individual argument, and return the offset for the next argument.
4552 //  Note: This method only calculates the initial offset of the stack passed/spilled arguments
4553 //  (if any - the RA might decide to spill(home on the stack) register passed arguments, if rarely used.)
4554 //        The final offset is calculated in lvaFixVirtualFrameOffsets method. It accounts for FP existance,
4555 //        ret address slot, stack frame padding, alloca instructions, etc.
4556 //  Note: This implementation for all the platforms but UNIX_AMD64 OSs (System V 64 bit.)
4557 int Compiler::lvaAssignVirtualFrameOffsetToArg(unsigned lclNum,
4558                                                unsigned argSize,
4559                                                int argOffs UNIX_AMD64_ABI_ONLY_ARG(int* callerArgOffset))
4560 {
4561     noway_assert(lclNum < info.compArgsCount);
4562     noway_assert(argSize);
4563
4564     if (Target::g_tgtArgOrder == Target::ARG_ORDER_L2R)
4565     {
4566         argOffs -= argSize;
4567     }
4568
4569     unsigned fieldVarNum = BAD_VAR_NUM;
4570
4571     noway_assert(lclNum < lvaCount);
4572     LclVarDsc* varDsc = lvaTable + lclNum;
4573
4574     if (varDsc->lvPromotedStruct())
4575     {
4576         noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
4577         fieldVarNum = varDsc->lvFieldLclStart;
4578
4579         lvaPromotionType promotionType = lvaGetPromotionType(varDsc);
4580
4581         if (promotionType == PROMOTION_TYPE_INDEPENDENT)
4582         {
4583             lclNum = fieldVarNum;
4584             noway_assert(lclNum < lvaCount);
4585             varDsc = lvaTable + lclNum;
4586             assert(varDsc->lvIsStructField);
4587         }
4588     }
4589
4590     noway_assert(varDsc->lvIsParam);
4591
4592     if (varDsc->lvIsRegArg)
4593     {
4594         /* Argument is passed in a register, don't count it
4595          * when updating the current offset on the stack */
4596         CLANG_FORMAT_COMMENT_ANCHOR;
4597
4598 #if !defined(_TARGET_ARMARCH_)
4599 #if DEBUG
4600         // TODO: Remove this noway_assert and replace occurrences of sizeof(void *) with argSize
4601         // Also investigate why we are incrementing argOffs for X86 as this seems incorrect
4602         //
4603         noway_assert(argSize == sizeof(void*));
4604 #endif // DEBUG
4605 #endif
4606
4607 #if defined(_TARGET_X86_)
4608         argOffs += sizeof(void*);
4609 #elif defined(_TARGET_AMD64_)
4610         // Register arguments on AMD64 also takes stack space. (in the backing store)
4611         varDsc->lvStkOffs = argOffs;
4612         argOffs += sizeof(void*);
4613 #elif defined(_TARGET_ARM64_)
4614 // Register arguments on ARM64 only take stack space when they have a frame home.
4615 #elif defined(_TARGET_ARM_)
4616         // On ARM we spill the registers in codeGen->regSet.rsMaskPreSpillRegArg
4617         // in the prolog, so we have to fill in lvStkOffs here
4618         //
4619         regMaskTP regMask = genRegMask(varDsc->lvArgReg);
4620         if (codeGen->regSet.rsMaskPreSpillRegArg & regMask)
4621         {
4622             // Signature: void foo(struct_8, int, struct_4)
4623             // ------- CALLER SP -------
4624             // r3 struct_4
4625             // r2 int - not prespilled, but added for alignment. argOffs should skip this.
4626             // r1 struct_8
4627             // r0 struct_8
4628             // -------------------------
4629             // If we added alignment we need to fix argOffs for all registers above alignment.
4630             if (codeGen->regSet.rsMaskPreSpillAlign != RBM_NONE)
4631             {
4632                 assert(genCountBits(codeGen->regSet.rsMaskPreSpillAlign) == 1);
4633                 // Is register beyond the alignment pos?
4634                 if (regMask > codeGen->regSet.rsMaskPreSpillAlign)
4635                 {
4636                     // Increment argOffs just once for the _first_ register after alignment pos
4637                     // in the prespill mask.
4638                     if (!BitsBetween(codeGen->regSet.rsMaskPreSpillRegArg, regMask,
4639                                      codeGen->regSet.rsMaskPreSpillAlign))
4640                     {
4641                         argOffs += TARGET_POINTER_SIZE;
4642                     }
4643                 }
4644             }
4645
4646             switch (varDsc->lvType)
4647             {
4648                 case TYP_STRUCT:
4649                     if (!varDsc->lvStructDoubleAlign)
4650                     {
4651                         break;
4652                     }
4653                     __fallthrough;
4654
4655                 case TYP_DOUBLE:
4656                 case TYP_LONG:
4657                 {
4658                     //
4659                     // Let's assign offsets to arg1, a double in r2. argOffs has to be 4 not 8.
4660                     //
4661                     // ------- CALLER SP -------
4662                     // r3
4663                     // r2 double   -- argOffs = 4, but it doesn't need to be skipped, because there is no skipping.
4664                     // r1 VACookie -- argOffs = 0
4665                     // -------------------------
4666                     //
4667                     // Consider argOffs as if it accounts for number of prespilled registers before the current
4668                     // register. In the above example, for r2, it is r1 that is prespilled, but since r1 is
4669                     // accounted for by argOffs being 4, there should have been no skipping. Instead, if we didn't
4670                     // assign r1 to any variable, then argOffs would still be 0 which implies it is not accounting
4671                     // for r1, equivalently r1 is skipped.
4672                     //
4673                     // If prevRegsSize is unaccounted for by a corresponding argOffs, we must have skipped a register.
4674                     int prevRegsSize =
4675                         genCountBits(codeGen->regSet.rsMaskPreSpillRegArg & (regMask - 1)) * TARGET_POINTER_SIZE;
4676                     if (argOffs < prevRegsSize)
4677                     {
4678                         // We must align up the argOffset to a multiple of 8 to account for skipped registers.
4679                         argOffs = roundUp(argOffs, 2 * TARGET_POINTER_SIZE);
4680                     }
4681                     // We should've skipped only a single register.
4682                     assert(argOffs == prevRegsSize);
4683                 }
4684                 break;
4685
4686                 default:
4687                     // No alignment of argOffs required
4688                     break;
4689             }
4690             varDsc->lvStkOffs = argOffs;
4691             argOffs += argSize;
4692         }
4693 #else // _TARGET_*
4694 #error Unsupported or unset target architecture
4695 #endif // _TARGET_*
4696     }
4697     else
4698     {
4699 #if defined(_TARGET_ARM_)
4700         // Dev11 Bug 42817: incorrect codegen for DrawFlatCheckBox causes A/V in WinForms
4701         //
4702         // Here we have method with a signature (int a1, struct a2, struct a3, int a4, int a5).
4703         // Struct parameter 'a2' is 16-bytes with no alignment requirements;
4704         //  it uses r1,r2,r3 and [OutArg+0] when passed.
4705         // Struct parameter 'a3' is 16-bytes that is required to be double aligned;
4706         //  the caller skips [OutArg+4] and starts the argument at [OutArg+8].
4707         // Thus the caller generates the correct code to pass the arguments.
4708         // When generating code to receive the arguments we set codeGen->regSet.rsMaskPreSpillRegArg to [r1,r2,r3]
4709         //  and spill these three registers as the first instruction in the prolog.
4710         // Then when we layout the arguments' stack offsets we have an argOffs 0 which
4711         //  points at the location that we spilled r1 into the stack.  For this first
4712         //  struct we take the lvIsRegArg path above with "codeGen->regSet.rsMaskPreSpillRegArg &" matching.
4713         // Next when we calculate the argOffs for the second 16-byte struct we have an argOffs
4714         //  of 16, which appears to be aligned properly so we don't skip a stack slot.
4715         //
4716         // To fix this we must recover the actual OutArg offset by subtracting off the
4717         //  sizeof of the PreSpill register args.
4718         // Then we align this offset to a multiple of 8 and add back the sizeof
4719         //  of the PreSpill register args.
4720         //
4721         // Dev11 Bug 71767: failure of assert(sizeofPreSpillRegArgs <= argOffs)
4722         //
4723         // We have a method with 'this' passed in r0, RetBuf arg in r1, VarArgs cookie
4724         // in r2. The first user arg is a 144 byte struct with double alignment required,
4725         // r3 is skipped, and the struct is passed on the stack. However, 'r3' is added
4726         // to the codeGen->regSet.rsMaskPreSpillRegArg mask by the VarArgs cookie code, since we need to
4727         // home all the potential varargs arguments in registers, even if we don't have
4728         // signature type information for the variadic arguments. However, due to alignment,
4729         // we have skipped a register that doesn't have a corresponding symbol. Make up
4730         // for that by increasing argOffs here.
4731         //
4732
4733         int sizeofPreSpillRegArgs = genCountBits(codeGen->regSet.rsMaskPreSpillRegs(true)) * REGSIZE_BYTES;
4734
4735         if (argOffs < sizeofPreSpillRegArgs)
4736         {
4737             // This can only happen if we skipped the last register spot because current stk arg
4738             // is a struct requiring alignment or a pre-spill alignment was required because the
4739             // first reg arg needed alignment.
4740             //
4741             // Example 1: First Stk Argument requiring alignment in vararg case (same as above comment.)
4742             //            Signature (int a0, int a1, int a2, struct {long} a3, ...)
4743             //
4744             // stk arg    a3             --> argOffs here will be 12 (r0-r2) but pre-spill will be 16.
4745             // ---- Caller SP ----
4746             // r3                        --> Stack slot is skipped in this case.
4747             // r2    int  a2
4748             // r1    int  a1
4749             // r0    int  a0
4750             //
4751             // Example 2: First Reg Argument requiring alignment in no-vararg case.
4752             //            Signature (struct {long} a0, struct {int} a1, int a2, int a3)
4753             //
4754             // stk arg                  --> argOffs here will be 12 {r0-r2} but pre-spill will be 16.
4755             // ---- Caller SP ----
4756             // r3    int             a2 --> pushed (not pre-spilled) for alignment of a0 by lvaInitUserArgs.
4757             // r2    struct { int }  a1
4758             // r0-r1 struct { long } a0
4759             CLANG_FORMAT_COMMENT_ANCHOR;
4760
4761 #ifdef PROFILING_SUPPORTED
4762             // On Arm under profiler, r0-r3 are always prespilled on stack.
4763             // It is possible to have methods that accept only HFAs as parameters e.g. Signature(struct hfa1, struct
4764             // hfa2), in which case hfa1 and hfa2 will be en-registered in co-processor registers and will have an
4765             // argument offset less than size of preSpill.
4766             //
4767             // For this reason the following conditions are asserted when not under profiler.
4768             if (!compIsProfilerHookNeeded())
4769 #endif
4770             {
4771                 bool cond = ((info.compIsVarArgs || opts.compUseSoftFP) &&
4772                              // Does cur stk arg require double alignment?
4773                              ((varDsc->lvType == TYP_STRUCT && varDsc->lvStructDoubleAlign) ||
4774                               (varDsc->lvType == TYP_DOUBLE) || (varDsc->lvType == TYP_LONG))) ||
4775                             // Did first reg arg require alignment?
4776                             (codeGen->regSet.rsMaskPreSpillAlign & genRegMask(REG_ARG_LAST));
4777
4778                 noway_assert(cond);
4779                 noway_assert(sizeofPreSpillRegArgs <=
4780                              argOffs + TARGET_POINTER_SIZE); // at most one register of alignment
4781             }
4782             argOffs = sizeofPreSpillRegArgs;
4783         }
4784
4785         noway_assert(argOffs >= sizeofPreSpillRegArgs);
4786         int argOffsWithoutPreSpillRegArgs = argOffs - sizeofPreSpillRegArgs;
4787
4788         switch (varDsc->lvType)
4789         {
4790             case TYP_STRUCT:
4791                 if (!varDsc->lvStructDoubleAlign)
4792                     break;
4793
4794                 __fallthrough;
4795
4796             case TYP_DOUBLE:
4797             case TYP_LONG:
4798                 // We must align up the argOffset to a multiple of 8
4799                 argOffs = roundUp(argOffsWithoutPreSpillRegArgs, 2 * TARGET_POINTER_SIZE) + sizeofPreSpillRegArgs;
4800                 break;
4801
4802             default:
4803                 // No alignment of argOffs required
4804                 break;
4805         }
4806 #endif // _TARGET_ARM_
4807
4808         varDsc->lvStkOffs = argOffs;
4809     }
4810
4811     // For struct promoted parameters we need to set the offsets for both LclVars.
4812     //
4813     // For a dependent promoted struct we also assign the struct fields stack offset
4814     CLANG_FORMAT_COMMENT_ANCHOR;
4815
4816 #if !defined(_TARGET_64BIT_)
4817     if ((varDsc->TypeGet() == TYP_LONG) && varDsc->lvPromoted)
4818     {
4819         noway_assert(varDsc->lvFieldCnt == 2);
4820         fieldVarNum                         = varDsc->lvFieldLclStart;
4821         lvaTable[fieldVarNum].lvStkOffs     = varDsc->lvStkOffs;
4822         lvaTable[fieldVarNum + 1].lvStkOffs = varDsc->lvStkOffs + genTypeSize(TYP_INT);
4823     }
4824     else
4825 #endif // !defined(_TARGET_64BIT_)
4826         if (varDsc->lvPromotedStruct())
4827     {
4828         lvaPromotionType promotionType = lvaGetPromotionType(varDsc);
4829
4830         if (promotionType == PROMOTION_TYPE_DEPENDENT)
4831         {
4832             noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
4833
4834             assert(fieldVarNum == varDsc->lvFieldLclStart);
4835             lvaTable[fieldVarNum].lvStkOffs = varDsc->lvStkOffs;
4836         }
4837     }
4838     // For an independent promoted struct field we also assign the parent struct stack offset
4839     else if (varDsc->lvIsStructField)
4840     {
4841         noway_assert(varDsc->lvParentLcl < lvaCount);
4842         lvaTable[varDsc->lvParentLcl].lvStkOffs = varDsc->lvStkOffs;
4843     }
4844
4845     if (Target::g_tgtArgOrder == Target::ARG_ORDER_R2L && !varDsc->lvIsRegArg)
4846     {
4847         argOffs += argSize;
4848     }
4849
4850     return argOffs;
4851 }
4852 #endif // !UNIX_AMD64_ABI
4853
4854 /*****************************************************************************
4855  *  lvaAssignVirtualFrameOffsetsToLocals() : Assign virtual stack offsets to
4856  *  locals, temps, and anything else.  These will all be negative offsets
4857  *  (stack grows down) relative to the virtual '0'/return address
4858  */
4859 void Compiler::lvaAssignVirtualFrameOffsetsToLocals()
4860 {
4861     int stkOffs = 0;
4862     // codeGen->isFramePointerUsed is set in regalloc phase. Initialize it to a guess for pre-regalloc layout.
4863     if (lvaDoneFrameLayout <= PRE_REGALLOC_FRAME_LAYOUT)
4864     {
4865         codeGen->setFramePointerUsed(codeGen->isFramePointerRequired());
4866     }
4867
4868 #ifdef _TARGET_XARCH_
4869     // On x86/amd64, the return address has already been pushed by the call instruction in the caller.
4870     stkOffs -= sizeof(void*); // return address;
4871
4872     // TODO-AMD64-CQ: for X64 eventually this should be pushed with all the other
4873     // calleeregs.  When you fix this, you'll also need to fix
4874     // the assert at the bottom of this method
4875     if (codeGen->doubleAlignOrFramePointerUsed())
4876     {
4877         stkOffs -= REGSIZE_BYTES;
4878     }
4879 #endif //_TARGET_XARCH_
4880
4881     int  preSpillSize    = 0;
4882     bool mustDoubleAlign = false;
4883
4884 #ifdef _TARGET_ARM_
4885     mustDoubleAlign = true;
4886     preSpillSize    = genCountBits(codeGen->regSet.rsMaskPreSpillRegs(true)) * REGSIZE_BYTES;
4887 #else // !_TARGET_ARM_
4888 #if DOUBLE_ALIGN
4889     if (genDoubleAlign())
4890     {
4891         mustDoubleAlign = true; // X86 only
4892     }
4893 #endif
4894 #endif // !_TARGET_ARM_
4895
4896 #ifdef _TARGET_ARM64_
4897     // If the frame pointer is used, then we'll save FP/LR at the bottom of the stack.
4898     // Otherwise, we won't store FP, and we'll store LR at the top, with the other callee-save
4899     // registers (if any).
4900
4901     int initialStkOffs = 0;
4902     if (info.compIsVarArgs)
4903     {
4904         // For varargs we always save all of the integer register arguments
4905         // so that they are contiguous with the incoming stack arguments.
4906         initialStkOffs = MAX_REG_ARG * REGSIZE_BYTES;
4907         stkOffs -= initialStkOffs;
4908     }
4909
4910     if (isFramePointerUsed())
4911     {
4912         // Subtract off FP and LR.
4913         assert(compCalleeRegsPushed >= 2);
4914         stkOffs -= (compCalleeRegsPushed - 2) * REGSIZE_BYTES;
4915     }
4916     else
4917     {
4918         stkOffs -= compCalleeRegsPushed * REGSIZE_BYTES;
4919     }
4920
4921 #else  // !_TARGET_ARM64_
4922     stkOffs -= compCalleeRegsPushed * REGSIZE_BYTES;
4923 #endif // !_TARGET_ARM64_
4924
4925     compLclFrameSize = 0;
4926
4927 #ifdef _TARGET_AMD64_
4928     // In case of Amd64 compCalleeRegsPushed includes float regs (Xmm6-xmm15) that
4929     // need to be pushed.  But Amd64 doesn't support push/pop of xmm registers.
4930     // Instead we need to allocate space for them on the stack and save them in prolog.
4931     // Therefore, we consider xmm registers being saved while computing stack offsets
4932     // but space for xmm registers is considered part of compLclFrameSize.
4933     // Notes
4934     //  1) We need to save the entire 128-bits of xmm register to stack, since amd64
4935     //     prolog unwind codes allow encoding of an instruction that stores the entire xmm reg
4936     //     at an offset relative to SP
4937     //  2) We adjust frame size so that SP is aligned at 16-bytes after pushing integer registers.
4938     //     This means while saving the first xmm register to its allocated stack location we might
4939     //     have to skip 8-bytes.  The reason for padding is to use efficient "movaps" to save/restore
4940     //     xmm registers to/from stack to match Jit64 codegen.  Without the aligning on 16-byte
4941     //     boundary we would have to use movups when offset turns out unaligned.  Movaps is more
4942     //     performant than movups.
4943     unsigned calleeFPRegsSavedSize = genCountBits(compCalleeFPRegsSavedMask) * XMM_REGSIZE_BYTES;
4944     if (calleeFPRegsSavedSize > 0 && ((stkOffs % XMM_REGSIZE_BYTES) != 0))
4945     {
4946         // Take care of alignment
4947         int alignPad = (int)AlignmentPad((unsigned)-stkOffs, XMM_REGSIZE_BYTES);
4948         stkOffs -= alignPad;
4949         lvaIncrementFrameSize(alignPad);
4950     }
4951
4952     stkOffs -= calleeFPRegsSavedSize;
4953     lvaIncrementFrameSize(calleeFPRegsSavedSize);
4954
4955     // Quirk for VS debug-launch scenario to work
4956     if (compVSQuirkStackPaddingNeeded > 0)
4957     {
4958 #ifdef DEBUG
4959         if (verbose)
4960         {
4961             printf("\nAdding VS quirk stack padding of %d bytes between save-reg area and locals\n",
4962                    compVSQuirkStackPaddingNeeded);
4963         }
4964 #endif // DEBUG
4965
4966         stkOffs -= compVSQuirkStackPaddingNeeded;
4967         lvaIncrementFrameSize(compVSQuirkStackPaddingNeeded);
4968     }
4969 #endif //_TARGET_AMD64_
4970
4971 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARMARCH_)
4972     if (ehNeedsPSPSym())
4973     {
4974         // On ARM/ARM64, if we need a PSPSym, allocate it first, before anything else, including
4975         // padding (so we can avoid computing the same padding in the funclet
4976         // frame). Note that there is no special padding requirement for the PSPSym.
4977         noway_assert(codeGen->isFramePointerUsed()); // We need an explicit frame pointer
4978         assert(lvaPSPSym != BAD_VAR_NUM);            // We should have created the PSPSym variable
4979         stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaPSPSym, TARGET_POINTER_SIZE, stkOffs);
4980     }
4981 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARMARCH_)
4982
4983     if (mustDoubleAlign)
4984     {
4985         if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
4986         {
4987             // Allocate a pointer sized stack slot, since we may need to double align here
4988             // when lvaDoneFrameLayout == FINAL_FRAME_LAYOUT
4989             //
4990             lvaIncrementFrameSize(TARGET_POINTER_SIZE);
4991             stkOffs -= TARGET_POINTER_SIZE;
4992
4993             // If we have any TYP_LONG, TYP_DOUBLE or double aligned structs
4994             // then we need to allocate a second pointer sized stack slot,
4995             // since we may need to double align that LclVar when we see it
4996             // in the loop below.  We will just always do this so that the
4997             // offsets that we calculate for the stack frame will always
4998             // be greater (or equal) to what they can be in the final layout.
4999             //
5000             lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5001             stkOffs -= TARGET_POINTER_SIZE;
5002         }
5003         else // FINAL_FRAME_LAYOUT
5004         {
5005             if (((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) != 0)
5006             {
5007                 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5008                 stkOffs -= TARGET_POINTER_SIZE;
5009             }
5010             // We should now have a double-aligned (stkOffs+preSpillSize)
5011             noway_assert(((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) == 0);
5012         }
5013     }
5014
5015     if (lvaMonAcquired != BAD_VAR_NUM)
5016     {
5017         // This var must go first, in what is called the 'frame header' for EnC so that it is
5018         // preserved when remapping occurs.  See vm\eetwain.cpp for detailed comment specifying frame
5019         // layout requirements for EnC to work.
5020         stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaMonAcquired, lvaLclSize(lvaMonAcquired), stkOffs);
5021     }
5022
5023     if (opts.compNeedSecurityCheck)
5024     {
5025 #ifdef JIT32_GCENCODER
5026         /* This can't work without an explicit frame, so make sure */
5027         noway_assert(codeGen->isFramePointerUsed());
5028 #endif
5029         stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaSecurityObject, TARGET_POINTER_SIZE, stkOffs);
5030     }
5031
5032     if (compLocallocUsed)
5033     {
5034 #ifdef JIT32_GCENCODER
5035         noway_assert(codeGen->isFramePointerUsed()); // else offsets of locals of frameless methods will be incorrect
5036 #endif
5037         stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaLocAllocSPvar, TARGET_POINTER_SIZE, stkOffs);
5038     }
5039
5040     if (lvaReportParamTypeArg())
5041     {
5042 #ifdef JIT32_GCENCODER
5043         noway_assert(codeGen->isFramePointerUsed());
5044 #endif
5045         // For CORINFO_CALLCONV_PARAMTYPE (if needed)
5046         lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5047         stkOffs -= TARGET_POINTER_SIZE;
5048         lvaCachedGenericContextArgOffs = stkOffs;
5049     }
5050 #ifndef JIT32_GCENCODER
5051     else if (lvaKeepAliveAndReportThis())
5052     {
5053         // When "this" is also used as generic context arg.
5054         lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5055         stkOffs -= TARGET_POINTER_SIZE;
5056         lvaCachedGenericContextArgOffs = stkOffs;
5057     }
5058 #endif
5059
5060 #if !FEATURE_EH_FUNCLETS
5061     /* If we need space for slots for shadow SP, reserve it now */
5062     if (ehNeedsShadowSPslots())
5063     {
5064         noway_assert(codeGen->isFramePointerUsed()); // else offsets of locals of frameless methods will be incorrect
5065         if (!lvaReportParamTypeArg())
5066         {
5067 #ifndef JIT32_GCENCODER
5068             if (!lvaKeepAliveAndReportThis())
5069 #endif
5070             {
5071                 // In order to keep the gc info encoding smaller, the VM assumes that all methods with EH
5072                 // have also saved space for a ParamTypeArg, so we need to do that here
5073                 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5074                 stkOffs -= TARGET_POINTER_SIZE;
5075             }
5076         }
5077         stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaShadowSPslotsVar, lvaLclSize(lvaShadowSPslotsVar), stkOffs);
5078     }
5079 #endif // !FEATURE_EH_FUNCLETS
5080
5081     if (compGSReorderStackLayout)
5082     {
5083         assert(getNeedsGSSecurityCookie());
5084         stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaGSSecurityCookie, lvaLclSize(lvaGSSecurityCookie), stkOffs);
5085     }
5086
5087     /*
5088         If we're supposed to track lifetimes of pointer temps, we'll
5089         assign frame offsets in the following order:
5090
5091             non-pointer local variables (also untracked pointer variables)
5092                 pointer local variables
5093                 pointer temps
5094             non-pointer temps
5095      */
5096
5097     enum Allocation
5098     {
5099         ALLOC_NON_PTRS                 = 0x1, // assign offsets to non-ptr
5100         ALLOC_PTRS                     = 0x2, // Second pass, assign offsets to tracked ptrs
5101         ALLOC_UNSAFE_BUFFERS           = 0x4,
5102         ALLOC_UNSAFE_BUFFERS_WITH_PTRS = 0x8
5103     };
5104     UINT alloc_order[5];
5105
5106     unsigned int cur = 0;
5107
5108     if (compGSReorderStackLayout)
5109     {
5110         noway_assert(getNeedsGSSecurityCookie());
5111
5112         if (codeGen->isFramePointerUsed())
5113         {
5114             alloc_order[cur++] = ALLOC_UNSAFE_BUFFERS;
5115             alloc_order[cur++] = ALLOC_UNSAFE_BUFFERS_WITH_PTRS;
5116         }
5117     }
5118
5119     bool tempsAllocated = false;
5120
5121 #ifdef _TARGET_ARM_
5122     // On ARM, SP based offsets use smaller encoding. Since temps are relatively
5123     // rarer than lcl usage, allocate them farther from SP.
5124     if (!opts.MinOpts() && !compLocallocUsed)
5125 #else
5126     if (lvaTempsHaveLargerOffsetThanVars() && !codeGen->isFramePointerUsed())
5127 #endif
5128     {
5129         // Because we want the temps to have a larger offset than locals
5130         // and we're not using a frame pointer, we have to place the temps
5131         // above the vars.  Otherwise we place them after the vars (at the
5132         // bottom of the frame).
5133         noway_assert(!tempsAllocated);
5134         stkOffs        = lvaAllocateTemps(stkOffs, mustDoubleAlign);
5135         tempsAllocated = true;
5136     }
5137
5138     alloc_order[cur++] = ALLOC_NON_PTRS;
5139
5140     if (opts.compDbgEnC)
5141     {
5142         /* We will use just one pass, and assign offsets to all variables */
5143         alloc_order[cur - 1] |= ALLOC_PTRS;
5144         noway_assert(compGSReorderStackLayout == false);
5145     }
5146     else
5147     {
5148         alloc_order[cur++] = ALLOC_PTRS;
5149     }
5150
5151     if (!codeGen->isFramePointerUsed() && compGSReorderStackLayout)
5152     {
5153         alloc_order[cur++] = ALLOC_UNSAFE_BUFFERS_WITH_PTRS;
5154         alloc_order[cur++] = ALLOC_UNSAFE_BUFFERS;
5155     }
5156
5157     alloc_order[cur] = 0;
5158
5159     noway_assert(cur < sizeof(alloc_order) / sizeof(alloc_order[0]));
5160
5161     // Force first pass to happen
5162     UINT assignMore             = 0xFFFFFFFF;
5163     bool have_LclVarDoubleAlign = false;
5164
5165     for (cur = 0; alloc_order[cur]; cur++)
5166     {
5167         if ((assignMore & alloc_order[cur]) == 0)
5168         {
5169             continue;
5170         }
5171
5172         assignMore = 0;
5173
5174         unsigned   lclNum;
5175         LclVarDsc* varDsc;
5176
5177         for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
5178         {
5179             /* Ignore field locals of the promotion type PROMOTION_TYPE_FIELD_DEPENDENT.
5180                In other words, we will not calculate the "base" address of the struct local if
5181                the promotion type is PROMOTION_TYPE_FIELD_DEPENDENT.
5182             */
5183             if (lvaIsFieldOfDependentlyPromotedStruct(varDsc))
5184             {
5185                 continue;
5186             }
5187
5188 #if FEATURE_FIXED_OUT_ARGS
5189             // The scratch mem is used for the outgoing arguments, and it must be absolutely last
5190             if (lclNum == lvaOutgoingArgSpaceVar)
5191             {
5192                 continue;
5193             }
5194 #endif
5195
5196             bool allocateOnFrame = varDsc->lvOnFrame;
5197
5198             if (varDsc->lvRegister && (lvaDoneFrameLayout == REGALLOC_FRAME_LAYOUT) &&
5199                 ((varDsc->TypeGet() != TYP_LONG) || (varDsc->lvOtherReg != REG_STK)))
5200             {
5201                 allocateOnFrame = false;
5202             }
5203
5204             /* Ignore variables that are not on the stack frame */
5205
5206             if (!allocateOnFrame)
5207             {
5208                 /* For EnC, all variables have to be allocated space on the
5209                    stack, even though they may actually be enregistered. This
5210                    way, the frame layout can be directly inferred from the
5211                    locals-sig.
5212                  */
5213
5214                 if (!opts.compDbgEnC)
5215                 {
5216                     continue;
5217                 }
5218                 else if (lclNum >= info.compLocalsCount)
5219                 { // ignore temps for EnC
5220                     continue;
5221                 }
5222             }
5223             else if (lvaGSSecurityCookie == lclNum && getNeedsGSSecurityCookie())
5224             {
5225                 continue; // This is allocated outside of this loop.
5226             }
5227
5228             // These need to be located as the very first variables (highest memory address)
5229             // and so they have already been assigned an offset
5230             if (
5231 #if FEATURE_EH_FUNCLETS
5232                 lclNum == lvaPSPSym ||
5233 #else
5234                 lclNum == lvaShadowSPslotsVar ||
5235 #endif // FEATURE_EH_FUNCLETS
5236                 lclNum == lvaLocAllocSPvar || lclNum == lvaSecurityObject)
5237             {
5238                 assert(varDsc->lvStkOffs != BAD_STK_OFFS);
5239                 continue;
5240             }
5241
5242             if (lclNum == lvaMonAcquired)
5243             {
5244                 continue;
5245             }
5246
5247             // This should be low on the stack. Hence, it will be assigned later.
5248             if (lclNum == lvaStubArgumentVar)
5249             {
5250 #ifdef JIT32_GCENCODER
5251                 noway_assert(codeGen->isFramePointerUsed());
5252 #endif
5253                 continue;
5254             }
5255
5256             // This should be low on the stack. Hence, it will be assigned later.
5257             if (lclNum == lvaInlinedPInvokeFrameVar)
5258             {
5259                 noway_assert(codeGen->isFramePointerUsed());
5260                 continue;
5261             }
5262
5263             if (varDsc->lvIsParam)
5264             {
5265 #if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI)
5266
5267                 // On Windows AMD64 we can use the caller-reserved stack area that is already setup
5268                 assert(varDsc->lvStkOffs != BAD_STK_OFFS);
5269                 continue;
5270
5271 #else // !_TARGET_AMD64_
5272
5273                 //  A register argument that is not enregistered ends up as
5274                 //  a local variable which will need stack frame space.
5275                 //
5276                 if (!varDsc->lvIsRegArg)
5277                 {
5278                     continue;
5279                 }
5280
5281 #ifdef _TARGET_ARM64_
5282                 if (info.compIsVarArgs)
5283                 {
5284                     // Stack offset to varargs (parameters) should point to home area which will be preallocated.
5285                     varDsc->lvStkOffs =
5286                         -initialStkOffs + genMapIntRegNumToRegArgNum(varDsc->GetArgReg()) * REGSIZE_BYTES;
5287                     continue;
5288                 }
5289 #endif
5290
5291 #ifdef _TARGET_ARM_
5292                 // On ARM we spill the registers in codeGen->regSet.rsMaskPreSpillRegArg
5293                 // in the prolog, thus they don't need stack frame space.
5294                 //
5295                 if ((codeGen->regSet.rsMaskPreSpillRegs(false) & genRegMask(varDsc->lvArgReg)) != 0)
5296                 {
5297                     assert(varDsc->lvStkOffs != BAD_STK_OFFS);
5298                     continue;
5299                 }
5300 #endif
5301
5302 #endif // !_TARGET_AMD64_
5303             }
5304
5305             /* Make sure the type is appropriate */
5306
5307             if (varDsc->lvIsUnsafeBuffer && compGSReorderStackLayout)
5308             {
5309                 if (varDsc->lvIsPtr)
5310                 {
5311                     if ((alloc_order[cur] & ALLOC_UNSAFE_BUFFERS_WITH_PTRS) == 0)
5312                     {
5313                         assignMore |= ALLOC_UNSAFE_BUFFERS_WITH_PTRS;
5314                         continue;
5315                     }
5316                 }
5317                 else
5318                 {
5319                     if ((alloc_order[cur] & ALLOC_UNSAFE_BUFFERS) == 0)
5320                     {
5321                         assignMore |= ALLOC_UNSAFE_BUFFERS;
5322                         continue;
5323                     }
5324                 }
5325             }
5326             else if (varTypeIsGC(varDsc->TypeGet()) && varDsc->lvTracked)
5327             {
5328                 if ((alloc_order[cur] & ALLOC_PTRS) == 0)
5329                 {
5330                     assignMore |= ALLOC_PTRS;
5331                     continue;
5332                 }
5333             }
5334             else
5335             {
5336                 if ((alloc_order[cur] & ALLOC_NON_PTRS) == 0)
5337                 {
5338                     assignMore |= ALLOC_NON_PTRS;
5339                     continue;
5340                 }
5341             }
5342
5343             /* Need to align the offset? */
5344
5345             if (mustDoubleAlign && (varDsc->lvType == TYP_DOUBLE // Align doubles for ARM and x86
5346 #ifdef _TARGET_ARM_
5347                                     || varDsc->lvType == TYP_LONG // Align longs for ARM
5348 #endif
5349 #ifndef _TARGET_64BIT_
5350                                     || varDsc->lvStructDoubleAlign // Align when lvStructDoubleAlign is true
5351 #endif                                                             // !_TARGET_64BIT_
5352                                     ))
5353             {
5354                 noway_assert((compLclFrameSize % TARGET_POINTER_SIZE) == 0);
5355
5356                 if ((lvaDoneFrameLayout != FINAL_FRAME_LAYOUT) && !have_LclVarDoubleAlign)
5357                 {
5358                     // If this is the first TYP_LONG, TYP_DOUBLE or double aligned struct
5359                     // then we have seen in this loop then we allocate a pointer sized
5360                     // stack slot since we may need to double align this LclVar
5361                     // when lvaDoneFrameLayout == FINAL_FRAME_LAYOUT
5362                     //
5363                     lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5364                     stkOffs -= TARGET_POINTER_SIZE;
5365                 }
5366                 else
5367                 {
5368                     if (((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) != 0)
5369                     {
5370                         lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5371                         stkOffs -= TARGET_POINTER_SIZE;
5372                     }
5373
5374                     // We should now have a double-aligned (stkOffs+preSpillSize)
5375                     noway_assert(((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) == 0);
5376                 }
5377
5378                 // Remember that we had to double align a LclVar
5379                 have_LclVarDoubleAlign = true;
5380             }
5381
5382             // Reserve the stack space for this variable
5383             stkOffs = lvaAllocLocalAndSetVirtualOffset(lclNum, lvaLclSize(lclNum), stkOffs);
5384 #ifdef _TARGET_ARM64_
5385             // If we have an incoming register argument that has a struct promoted field
5386             // then we need to copy the lvStkOff (the stack home) from the reg arg to the field lclvar
5387             //
5388             if (varDsc->lvIsRegArg && varDsc->lvPromotedStruct())
5389             {
5390                 noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
5391
5392                 unsigned fieldVarNum            = varDsc->lvFieldLclStart;
5393                 lvaTable[fieldVarNum].lvStkOffs = varDsc->lvStkOffs;
5394             }
5395 #endif
5396         }
5397     }
5398
5399     if (getNeedsGSSecurityCookie() && !compGSReorderStackLayout)
5400     {
5401         // LOCALLOC used, but we have no unsafe buffer.  Allocated cookie last, close to localloc buffer.
5402         stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaGSSecurityCookie, lvaLclSize(lvaGSSecurityCookie), stkOffs);
5403     }
5404
5405     if (tempsAllocated == false)
5406     {
5407         /*-------------------------------------------------------------------------
5408          *
5409          * Now the temps
5410          *
5411          *-------------------------------------------------------------------------
5412          */
5413         stkOffs = lvaAllocateTemps(stkOffs, mustDoubleAlign);
5414     }
5415
5416     /*-------------------------------------------------------------------------
5417      *
5418      * Now do some final stuff
5419      *
5420      *-------------------------------------------------------------------------
5421      */
5422
5423     // lvaInlinedPInvokeFrameVar and lvaStubArgumentVar need to be assigned last
5424     // Important: The stack walker depends on lvaStubArgumentVar immediately
5425     // following lvaInlinedPInvokeFrameVar in the frame.
5426
5427     if (lvaStubArgumentVar != BAD_VAR_NUM)
5428     {
5429 #ifdef JIT32_GCENCODER
5430         noway_assert(codeGen->isFramePointerUsed());
5431 #endif
5432         stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaStubArgumentVar, lvaLclSize(lvaStubArgumentVar), stkOffs);
5433     }
5434
5435     if (lvaInlinedPInvokeFrameVar != BAD_VAR_NUM)
5436     {
5437         noway_assert(codeGen->isFramePointerUsed());
5438         stkOffs =
5439             lvaAllocLocalAndSetVirtualOffset(lvaInlinedPInvokeFrameVar, lvaLclSize(lvaInlinedPInvokeFrameVar), stkOffs);
5440     }
5441
5442     if (mustDoubleAlign)
5443     {
5444         if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
5445         {
5446             // Allocate a pointer sized stack slot, since we may need to double align here
5447             // when lvaDoneFrameLayout == FINAL_FRAME_LAYOUT
5448             //
5449             lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5450             stkOffs -= TARGET_POINTER_SIZE;
5451
5452             if (have_LclVarDoubleAlign)
5453             {
5454                 // If we have any TYP_LONG, TYP_DOUBLE or double aligned structs
5455                 // the we need to allocate a second pointer sized stack slot,
5456                 // since we may need to double align the last LclVar that we saw
5457                 // in the loop above. We do this so that the offsets that we
5458                 // calculate for the stack frame are always greater than they will
5459                 // be in the final layout.
5460                 //
5461                 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5462                 stkOffs -= TARGET_POINTER_SIZE;
5463             }
5464         }
5465         else // FINAL_FRAME_LAYOUT
5466         {
5467             if (((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) != 0)
5468             {
5469                 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5470                 stkOffs -= TARGET_POINTER_SIZE;
5471             }
5472             // We should now have a double-aligned (stkOffs+preSpillSize)
5473             noway_assert(((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) == 0);
5474         }
5475     }
5476
5477 #if FEATURE_EH_FUNCLETS && defined(_TARGET_AMD64_)
5478     if (ehNeedsPSPSym())
5479     {
5480         // On AMD64, if we need a PSPSym, allocate it last, immediately above the outgoing argument
5481         // space. Any padding will be higher on the stack than this
5482         // (including the padding added by lvaAlignFrame()).
5483         noway_assert(codeGen->isFramePointerUsed()); // We need an explicit frame pointer
5484         assert(lvaPSPSym != BAD_VAR_NUM);            // We should have created the PSPSym variable
5485         stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaPSPSym, TARGET_POINTER_SIZE, stkOffs);
5486     }
5487 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_AMD64_)
5488
5489 #ifdef _TARGET_ARM64_
5490     if (isFramePointerUsed())
5491     {
5492         // Create space for saving FP and LR.
5493         stkOffs -= 2 * REGSIZE_BYTES;
5494     }
5495 #endif // _TARGET_ARM64_
5496
5497 #if FEATURE_FIXED_OUT_ARGS
5498     if (lvaOutgoingArgSpaceSize > 0)
5499     {
5500 #if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI) // No 4 slots for outgoing params on System V.
5501         noway_assert(lvaOutgoingArgSpaceSize >= (4 * sizeof(void*)));
5502 #endif
5503         noway_assert((lvaOutgoingArgSpaceSize % sizeof(void*)) == 0);
5504
5505         // Give it a value so we can avoid asserts in CHK builds.
5506         // Since this will always use an SP relative offset of zero
5507         // at the end of lvaFixVirtualFrameOffsets, it will be set to absolute '0'
5508
5509         stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaOutgoingArgSpaceVar, lvaLclSize(lvaOutgoingArgSpaceVar), stkOffs);
5510     }
5511 #endif // FEATURE_FIXED_OUT_ARGS
5512
5513     // compLclFrameSize equals our negated virtual stack offset minus the pushed registers and return address
5514     // and the pushed frame pointer register which for some strange reason isn't part of 'compCalleeRegsPushed'.
5515     int pushedCount = compCalleeRegsPushed;
5516
5517 #ifdef _TARGET_ARM64_
5518     if (info.compIsVarArgs)
5519     {
5520         pushedCount += MAX_REG_ARG;
5521     }
5522 #endif
5523
5524 #ifdef _TARGET_XARCH_
5525     if (codeGen->doubleAlignOrFramePointerUsed())
5526     {
5527         pushedCount += 1; // pushed EBP (frame pointer)
5528     }
5529     pushedCount += 1; // pushed PC (return address)
5530 #endif
5531
5532     noway_assert(compLclFrameSize == (unsigned)-(stkOffs + (pushedCount * (int)sizeof(void*))));
5533 }
5534
5535 int Compiler::lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, int stkOffs)
5536 {
5537     noway_assert(lclNum != BAD_VAR_NUM);
5538
5539 #ifdef _TARGET_64BIT_
5540     // Before final frame layout, assume the worst case, that every >=8 byte local will need
5541     // maximum padding to be aligned. This is because we generate code based on the stack offset
5542     // computed during tentative frame layout. These offsets cannot get bigger during final
5543     // frame layout, as that would possibly require different code generation (for example,
5544     // using a 4-byte offset instead of a 1-byte offset in an instruction). The offsets can get
5545     // smaller. It is possible there is different alignment at the point locals are allocated
5546     // between tentative and final frame layout which would introduce padding between locals
5547     // and thus increase the offset (from the stack pointer) of one of the locals. Hence the
5548     // need to assume the worst alignment before final frame layout.
5549     // We could probably improve this by sorting all the objects by alignment,
5550     // such that all 8 byte objects are together, 4 byte objects are together, etc., which
5551     // would require at most one alignment padding per group.
5552     //
5553     // TYP_SIMD structs locals have alignment preference given by getSIMDTypeAlignment() for
5554     // better performance.
5555     if ((size >= 8) && ((lvaDoneFrameLayout != FINAL_FRAME_LAYOUT) || ((stkOffs % 8) != 0)
5556 #if defined(FEATURE_SIMD) && ALIGN_SIMD_TYPES
5557                         || lclVarIsSIMDType(lclNum)
5558 #endif
5559                             ))
5560     {
5561         // Note that stack offsets are negative
5562         assert(stkOffs < 0);
5563
5564         // alignment padding
5565         unsigned pad = 0;
5566 #if defined(FEATURE_SIMD) && ALIGN_SIMD_TYPES
5567         if (lclVarIsSIMDType(lclNum) && !lvaIsImplicitByRefLocal(lclNum))
5568         {
5569             int alignment = getSIMDTypeAlignment(lvaTable[lclNum].lvType);
5570
5571             if (stkOffs % alignment != 0)
5572             {
5573                 if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
5574                 {
5575                     pad = alignment - 1;
5576                     // Note that all the objects will probably be misaligned, but we'll fix that in final layout.
5577                 }
5578                 else
5579                 {
5580                     pad = alignment + (stkOffs % alignment); // +1 to +(alignment-1) bytes
5581                 }
5582             }
5583         }
5584         else
5585 #endif // FEATURE_SIMD && ALIGN_SIMD_TYPES
5586         {
5587             if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
5588             {
5589                 pad = 7;
5590                 // Note that all the objects will probably be misaligned, but we'll fix that in final layout.
5591             }
5592             else
5593             {
5594                 pad = 8 + (stkOffs % 8); // +1 to +7 bytes
5595             }
5596         }
5597         // Will the pad ever be anything except 4? Do we put smaller-than-4-sized objects on the stack?
5598         lvaIncrementFrameSize(pad);
5599         stkOffs -= pad;
5600
5601 #ifdef DEBUG
5602         if (verbose)
5603         {
5604             printf("Pad ");
5605             gtDispLclVar(lclNum, /*pad*/ false);
5606             printf(", size=%d, stkOffs=%c0x%x, pad=%d\n", size, stkOffs < 0 ? '-' : '+',
5607                    stkOffs < 0 ? -stkOffs : stkOffs, pad);
5608         }
5609 #endif
5610     }
5611 #endif // _TARGET_64BIT_
5612
5613     /* Reserve space on the stack by bumping the frame size */
5614
5615     lvaIncrementFrameSize(size);
5616     stkOffs -= size;
5617     lvaTable[lclNum].lvStkOffs = stkOffs;
5618
5619 #ifdef DEBUG
5620     if (verbose)
5621     {
5622         printf("Assign ");
5623         gtDispLclVar(lclNum, /*pad*/ false);
5624         printf(", size=%d, stkOffs=%c0x%x\n", size, stkOffs < 0 ? '-' : '+', stkOffs < 0 ? -stkOffs : stkOffs);
5625     }
5626 #endif
5627
5628     return stkOffs;
5629 }
5630
5631 #ifdef _TARGET_AMD64_
5632 /*****************************************************************************
5633  *  lvaIsCalleeSavedIntRegCountEven() :  returns true if the number of integer registers
5634  *  pushed onto stack is even including RBP if used as frame pointer
5635  *
5636  *  Note that this excludes return address (PC) pushed by caller.  To know whether
5637  *  the SP offset after pushing integer registers is aligned, we need to take
5638  *  negation of this routine.
5639  */
5640 bool Compiler::lvaIsCalleeSavedIntRegCountEven()
5641 {
5642     unsigned regsPushed = compCalleeRegsPushed + (codeGen->isFramePointerUsed() ? 1 : 0);
5643     return (regsPushed % (16 / REGSIZE_BYTES)) == 0;
5644 }
5645 #endif //_TARGET_AMD64_
5646
5647 /*****************************************************************************
5648  *  lvaAlignFrame() :  After allocating everything on the frame, reserve any
5649  *  extra space needed to keep the frame aligned
5650  */
5651 void Compiler::lvaAlignFrame()
5652 {
5653 #if defined(_TARGET_AMD64_)
5654
5655     // Leaf frames do not need full alignment, but the unwind info is smaller if we
5656     // are at least 8 byte aligned (and we assert as much)
5657     if ((compLclFrameSize % 8) != 0)
5658     {
5659         lvaIncrementFrameSize(8 - (compLclFrameSize % 8));
5660     }
5661     else if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
5662     {
5663         // If we are not doing final layout, we don't know the exact value of compLclFrameSize
5664         // and thus do not know how much we will need to add in order to be aligned.
5665         // We add 8 so compLclFrameSize is still a multiple of 8.
5666         lvaIncrementFrameSize(8);
5667     }
5668     assert((compLclFrameSize % 8) == 0);
5669
5670     // Ensure that the stack is always 16-byte aligned by grabbing an unused QWORD
5671     // if needed, but off by 8 because of the return value.
5672     // And don't forget that compCalleeRegsPused does *not* include RBP if we are
5673     // using it as the frame pointer.
5674     //
5675     bool regPushedCountAligned = lvaIsCalleeSavedIntRegCountEven();
5676     bool lclFrameSizeAligned   = (compLclFrameSize % 16) == 0;
5677
5678     // If this isn't the final frame layout, assume we have to push an extra QWORD
5679     // Just so the offsets are true upper limits.
5680     CLANG_FORMAT_COMMENT_ANCHOR;
5681
5682 #ifdef UNIX_AMD64_ABI
5683     // The compNeedToAlignFrame flag  is indicating if there is a need to align the frame.
5684     // On AMD64-Windows, if there are calls, 4 slots for the outgoing ars are allocated, except for
5685     // FastTailCall. This slots makes the frame size non-zero, so alignment logic will be called.
5686     // On AMD64-Unix, there are no such slots. There is a possibility to have calls in the method with frame size of 0.
5687     // The frame alignment logic won't kick in. This flags takes care of the AMD64-Unix case by remembering that there
5688     // are calls and making sure the frame alignment logic is executed.
5689     bool stackNeedsAlignment = (compLclFrameSize != 0 || opts.compNeedToAlignFrame);
5690 #else  // !UNIX_AMD64_ABI
5691     bool stackNeedsAlignment = compLclFrameSize != 0;
5692 #endif // !UNIX_AMD64_ABI
5693     if ((!codeGen->isFramePointerUsed() && (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)) ||
5694         (stackNeedsAlignment && (regPushedCountAligned == lclFrameSizeAligned)))
5695     {
5696         lvaIncrementFrameSize(REGSIZE_BYTES);
5697     }
5698
5699 #elif defined(_TARGET_ARM64_)
5700
5701     // The stack on ARM64 must be 16 byte aligned.
5702
5703     // First, align up to 8.
5704     if ((compLclFrameSize % 8) != 0)
5705     {
5706         lvaIncrementFrameSize(8 - (compLclFrameSize % 8));
5707     }
5708     else if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
5709     {
5710         // If we are not doing final layout, we don't know the exact value of compLclFrameSize
5711         // and thus do not know how much we will need to add in order to be aligned.
5712         // We add 8 so compLclFrameSize is still a multiple of 8.
5713         lvaIncrementFrameSize(8);
5714     }
5715     assert((compLclFrameSize % 8) == 0);
5716
5717     // Ensure that the stack is always 16-byte aligned by grabbing an unused QWORD
5718     // if needed.
5719     bool regPushedCountAligned = (compCalleeRegsPushed % (16 / REGSIZE_BYTES)) == 0;
5720     bool lclFrameSizeAligned   = (compLclFrameSize % 16) == 0;
5721
5722     // If this isn't the final frame layout, assume we have to push an extra QWORD
5723     // Just so the offsets are true upper limits.
5724     if ((lvaDoneFrameLayout != FINAL_FRAME_LAYOUT) || (regPushedCountAligned != lclFrameSizeAligned))
5725     {
5726         lvaIncrementFrameSize(REGSIZE_BYTES);
5727     }
5728
5729 #elif defined(_TARGET_ARM_)
5730
5731     // Ensure that stack offsets will be double-aligned by grabbing an unused DWORD if needed.
5732     //
5733     bool lclFrameSizeAligned   = (compLclFrameSize % sizeof(double)) == 0;
5734     bool regPushedCountAligned = ((compCalleeRegsPushed + genCountBits(codeGen->regSet.rsMaskPreSpillRegs(true))) %
5735                                   (sizeof(double) / sizeof(void*))) == 0;
5736
5737     if (regPushedCountAligned != lclFrameSizeAligned)
5738     {
5739         lvaIncrementFrameSize(sizeof(void*));
5740     }
5741
5742 #elif defined(_TARGET_X86_)
5743
5744     if (genDoubleAlign())
5745     {
5746         // Double Frame Alignement for x86 is handled in Compiler::lvaAssignVirtualFrameOffsetsToLocals()
5747
5748         if (compLclFrameSize == 0)
5749         {
5750             // This can only happen with JitStress=1 or JitDoubleAlign=2
5751             lvaIncrementFrameSize(sizeof(void*));
5752         }
5753     }
5754
5755 #else
5756     NYI("TARGET specific lvaAlignFrame");
5757 #endif // !_TARGET_AMD64_
5758 }
5759
5760 /*****************************************************************************
5761  *  lvaAssignFrameOffsetsToPromotedStructs() :  Assign offsets to fields
5762  *  within a promoted struct (worker for lvaAssignFrameOffsets).
5763  */
5764 void Compiler::lvaAssignFrameOffsetsToPromotedStructs()
5765 {
5766     LclVarDsc* varDsc = lvaTable;
5767     for (unsigned lclNum = 0; lclNum < lvaCount; lclNum++, varDsc++)
5768     {
5769         // For promoted struct fields that are params, we will
5770         // assign their offsets in lvaAssignVirtualFrameOffsetToArg().
5771         // This is not true for the System V systems since there is no
5772         // outgoing args space. Assign the dependently promoted fields properly.
5773         //
5774         if (varDsc->lvIsStructField
5775 #ifndef UNIX_AMD64_ABI
5776             // For System V platforms there is no outgoing args space.
5777             // A register passed struct arg is homed on the stack in a separate local var.
5778             // The offset of these structs is already calculated in lvaAssignVirtualFrameOffsetToArg methos.
5779             // Make sure the code below is not executed for these structs and the offset is not changed.
5780             && !varDsc->lvIsParam
5781 #endif // UNIX_AMD64_ABI
5782             )
5783         {
5784             LclVarDsc*       parentvarDsc  = &lvaTable[varDsc->lvParentLcl];
5785             lvaPromotionType promotionType = lvaGetPromotionType(parentvarDsc);
5786
5787             if (promotionType == PROMOTION_TYPE_INDEPENDENT)
5788             {
5789                 // The stack offset for these field locals must have been calculated
5790                 // by the normal frame offset assignment.
5791                 continue;
5792             }
5793             else
5794             {
5795                 noway_assert(promotionType == PROMOTION_TYPE_DEPENDENT);
5796                 noway_assert(varDsc->lvOnFrame);
5797                 varDsc->lvStkOffs = parentvarDsc->lvStkOffs + varDsc->lvFldOffset;
5798             }
5799         }
5800     }
5801 }
5802
5803 /*****************************************************************************
5804  *  lvaAllocateTemps() :  Assign virtual offsets to temps (always negative).
5805  */
5806 int Compiler::lvaAllocateTemps(int stkOffs, bool mustDoubleAlign)
5807 {
5808     unsigned spillTempSize = 0;
5809
5810     if (lvaDoneFrameLayout == FINAL_FRAME_LAYOUT)
5811     {
5812         int preSpillSize = 0;
5813 #ifdef _TARGET_ARM_
5814         preSpillSize = genCountBits(codeGen->regSet.rsMaskPreSpillRegs(true)) * TARGET_POINTER_SIZE;
5815 #endif
5816         bool assignDone;
5817         bool assignNptr;
5818         bool assignPtrs = true;
5819
5820         /* Allocate temps */
5821
5822         if (TRACK_GC_TEMP_LIFETIMES)
5823         {
5824             /* first pointers, then non-pointers in second pass */
5825             assignNptr = false;
5826             assignDone = false;
5827         }
5828         else
5829         {
5830             /* Pointers and non-pointers together in single pass */
5831             assignNptr = true;
5832             assignDone = true;
5833         }
5834
5835         assert(tmpAllFree());
5836
5837     AGAIN2:
5838
5839         for (TempDsc* temp = tmpListBeg(); temp != nullptr; temp = tmpListNxt(temp))
5840         {
5841             var_types tempType = temp->tdTempType();
5842             unsigned  size;
5843
5844             /* Make sure the type is appropriate */
5845
5846             if (!assignPtrs && varTypeIsGC(tempType))
5847             {
5848                 continue;
5849             }
5850             if (!assignNptr && !varTypeIsGC(tempType))
5851             {
5852                 continue;
5853             }
5854
5855             size = temp->tdTempSize();
5856
5857             /* Figure out and record the stack offset of the temp */
5858
5859             /* Need to align the offset? */
5860             CLANG_FORMAT_COMMENT_ANCHOR;
5861
5862 #ifdef _TARGET_64BIT_
5863             if (varTypeIsGC(tempType) && ((stkOffs % TARGET_POINTER_SIZE) != 0))
5864             {
5865                 // Calculate 'pad' as the number of bytes to align up 'stkOffs' to be a multiple of TARGET_POINTER_SIZE
5866                 // In practice this is really just a fancy way of writing 4. (as all stack locations are at least 4-byte
5867                 // aligned). Note stkOffs is always negative, so (stkOffs % TARGET_POINTER_SIZE) yields a negative
5868                 // value.
5869                 //
5870                 int alignPad = (int)AlignmentPad((unsigned)-stkOffs, TARGET_POINTER_SIZE);
5871
5872                 spillTempSize += alignPad;
5873                 lvaIncrementFrameSize(alignPad);
5874                 stkOffs -= alignPad;
5875
5876                 noway_assert((stkOffs % TARGET_POINTER_SIZE) == 0);
5877             }
5878 #endif
5879
5880             if (mustDoubleAlign && (tempType == TYP_DOUBLE)) // Align doubles for x86 and ARM
5881             {
5882                 noway_assert((compLclFrameSize % TARGET_POINTER_SIZE) == 0);
5883
5884                 if (((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) != 0)
5885                 {
5886                     spillTempSize += TARGET_POINTER_SIZE;
5887                     lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5888                     stkOffs -= TARGET_POINTER_SIZE;
5889                 }
5890                 // We should now have a double-aligned (stkOffs+preSpillSize)
5891                 noway_assert(((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) == 0);
5892             }
5893
5894             spillTempSize += size;
5895             lvaIncrementFrameSize(size);
5896             stkOffs -= size;
5897             temp->tdSetTempOffs(stkOffs);
5898         }
5899 #ifdef _TARGET_ARM_
5900         // Only required for the ARM platform that we have an accurate estimate for the spillTempSize
5901         noway_assert(spillTempSize <= lvaGetMaxSpillTempSize());
5902 #endif
5903
5904         /* If we've only assigned some temps, go back and do the rest now */
5905
5906         if (!assignDone)
5907         {
5908             assignNptr = !assignNptr;
5909             assignPtrs = !assignPtrs;
5910             assignDone = true;
5911
5912             goto AGAIN2;
5913         }
5914     }
5915     else // We haven't run codegen, so there are no Spill temps yet!
5916     {
5917         unsigned size = lvaGetMaxSpillTempSize();
5918
5919         lvaIncrementFrameSize(size);
5920         stkOffs -= size;
5921     }
5922
5923     return stkOffs;
5924 }
5925
5926 #ifdef DEBUG
5927
5928 /*****************************************************************************
5929  *
5930  *  Dump the register a local is in right now.
5931  *  For non-LSRA, this will be the register it is always in. For LSRA, it's only the current
5932  *  location, since the location changes and it is updated throughout code generation based on
5933  *  LSRA register assignments.
5934  */
5935
5936 void Compiler::lvaDumpRegLocation(unsigned lclNum)
5937 {
5938     LclVarDsc* varDsc = lvaTable + lclNum;
5939     var_types  type   = varDsc->TypeGet();
5940
5941 #if FEATURE_STACK_FP_X87
5942     if (varTypeIsFloating(type))
5943     {
5944         printf("fpu stack   ");
5945     }
5946     else
5947 #endif
5948         if (isRegPairType(type))
5949     {
5950         if (!doLSRA())
5951         {
5952             noway_assert(varDsc->lvRegNum != REG_STK);
5953         }
5954         if (doLSRA() && varDsc->lvRegNum == REG_STK)
5955         {
5956             /* Hi-only enregistered long */
5957             int offset = varDsc->lvStkOffs;
5958             printf("%-3s:[%1s0x%02X]",
5959                    getRegName(varDsc->lvOtherReg), // hi32
5960                    (offset < 0 ? "-" : "+"), (offset < 0 ? -offset : offset));
5961         }
5962         else if (varDsc->lvOtherReg != REG_STK)
5963         {
5964             /* Fully enregistered long */
5965             printf("%3s:%-3s    ",
5966                    getRegName(varDsc->lvOtherReg), // hi32
5967                    getRegName(varDsc->lvRegNum));  // lo32
5968         }
5969         else
5970         {
5971             /* Partially enregistered long */
5972             int offset = varDsc->lvStkOffs + 4;
5973             printf("[%1s0x%02X]:%-3s", (offset < 0 ? "-" : "+"), (offset < 0 ? -offset : offset),
5974                    getRegName(varDsc->lvRegNum)); // lo32
5975         }
5976     }
5977 #ifdef _TARGET_ARM_
5978     else if (varDsc->TypeGet() == TYP_DOUBLE)
5979     {
5980         printf("%3s:%-3s    ", getRegName(varDsc->lvRegNum), getRegName(varDsc->lvOtherReg));
5981     }
5982 #endif
5983     else
5984     {
5985         printf("%3s        ", getRegName(varDsc->lvRegNum));
5986     }
5987 }
5988
5989 /*****************************************************************************
5990  *
5991  *  Dump the frame location assigned to a local.
5992  *  For non-LSRA, this will only be valid if there is no assigned register.
5993  *  For LSRA, it's the home location, even though the variable doesn't always live
5994  *  in its home location.
5995  */
5996
5997 void Compiler::lvaDumpFrameLocation(unsigned lclNum)
5998 {
5999     int       offset;
6000     regNumber baseReg;
6001
6002 #ifdef _TARGET_ARM_
6003     offset = lvaFrameAddress(lclNum, compLocallocUsed, &baseReg, 0);
6004 #else
6005     bool EBPbased;
6006     offset  = lvaFrameAddress(lclNum, &EBPbased);
6007     baseReg = EBPbased ? REG_FPBASE : REG_SPBASE;
6008 #endif
6009
6010     printf("[%2s%1s0x%02X]  ", getRegName(baseReg), (offset < 0 ? "-" : "+"), (offset < 0 ? -offset : offset));
6011 }
6012
6013 /*****************************************************************************
6014  *
6015  *  dump a single lvaTable entry
6016  */
6017
6018 void Compiler::lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t refCntWtdWidth)
6019 {
6020     LclVarDsc* varDsc = lvaTable + lclNum;
6021     var_types  type   = varDsc->TypeGet();
6022
6023     if (curState == INITIAL_FRAME_LAYOUT)
6024     {
6025         printf(";  ");
6026         gtDispLclVar(lclNum);
6027
6028         printf(" %7s ", varTypeName(type));
6029         if (genTypeSize(type) == 0)
6030         {
6031             printf("(%2d) ", lvaLclSize(lclNum));
6032         }
6033     }
6034     else
6035     {
6036         if (varDsc->lvRefCnt == 0)
6037         {
6038             // Print this with a special indicator that the variable is unused. Even though the
6039             // variable itself is unused, it might be a struct that is promoted, so seeing it
6040             // can be useful when looking at the promoted struct fields. It's also weird to see
6041             // missing var numbers if these aren't printed.
6042             printf(";* ");
6043         }
6044         else
6045 #if FEATURE_FIXED_OUT_ARGS
6046             if ((lclNum == lvaOutgoingArgSpaceVar) && (lvaLclSize(lclNum) == 0))
6047         {
6048             // Similar to above; print this anyway.
6049             printf(";# ");
6050         }
6051         else
6052 #endif
6053         {
6054             printf(";  ");
6055         }
6056
6057         gtDispLclVar(lclNum);
6058
6059         printf("[V%02u", lclNum);
6060         if (varDsc->lvTracked)
6061         {
6062             printf(",T%02u]", varDsc->lvVarIndex);
6063         }
6064         else
6065         {
6066             printf("    ]");
6067         }
6068
6069         printf(" (%3u,%*s)", varDsc->lvRefCnt, (int)refCntWtdWidth, refCntWtd2str(varDsc->lvRefCntWtd));
6070
6071         printf(" %7s ", varTypeName(type));
6072         if (genTypeSize(type) == 0)
6073         {
6074             printf("(%2d) ", lvaLclSize(lclNum));
6075         }
6076         else
6077         {
6078             printf(" ->  ");
6079         }
6080
6081         // The register or stack location field is 11 characters wide.
6082         if (varDsc->lvRefCnt == 0)
6083         {
6084             printf("zero-ref   ");
6085         }
6086         else if (varDsc->lvRegister != 0)
6087         {
6088             // It's always a register, and always in the same register.
6089             lvaDumpRegLocation(lclNum);
6090         }
6091         else if (varDsc->lvOnFrame == 0)
6092         {
6093             printf("registers  ");
6094         }
6095         else
6096         {
6097             // For RyuJIT backend, it might be in a register part of the time, but it will definitely have a stack home
6098             // location. Otherwise, it's always on the stack.
6099             if (lvaDoneFrameLayout != NO_FRAME_LAYOUT)
6100             {
6101                 lvaDumpFrameLocation(lclNum);
6102             }
6103         }
6104     }
6105
6106     if (varDsc->lvIsHfaRegArg())
6107     {
6108         if (varDsc->lvHfaTypeIsFloat())
6109         {
6110             printf(" (enregistered HFA: float) ");
6111         }
6112         else
6113         {
6114             printf(" (enregistered HFA: double)");
6115         }
6116     }
6117
6118     if (varDsc->lvDoNotEnregister)
6119     {
6120         printf(" do-not-enreg[");
6121         if (varDsc->lvAddrExposed)
6122         {
6123             printf("X");
6124         }
6125         if (varTypeIsStruct(varDsc))
6126         {
6127             printf("S");
6128         }
6129         if (varDsc->lvVMNeedsStackAddr)
6130         {
6131             printf("V");
6132         }
6133         if (varDsc->lvLiveInOutOfHndlr)
6134         {
6135             printf("H");
6136         }
6137         if (varDsc->lvLclFieldExpr)
6138         {
6139             printf("F");
6140         }
6141         if (varDsc->lvLclBlockOpAddr)
6142         {
6143             printf("B");
6144         }
6145         if (varDsc->lvLiveAcrossUCall)
6146         {
6147             printf("U");
6148         }
6149         if (varDsc->lvIsMultiRegArg)
6150         {
6151             printf("A");
6152         }
6153         if (varDsc->lvIsMultiRegRet)
6154         {
6155             printf("R");
6156         }
6157 #ifdef JIT32_GCENCODER
6158         if (varDsc->lvPinned)
6159             printf("P");
6160 #endif // JIT32_GCENCODER
6161         printf("]");
6162     }
6163
6164     if (varDsc->lvIsMultiRegArg)
6165     {
6166         printf(" multireg-arg");
6167     }
6168     if (varDsc->lvIsMultiRegRet)
6169     {
6170         printf(" multireg-ret");
6171     }
6172     if (varDsc->lvMustInit)
6173     {
6174         printf(" must-init");
6175     }
6176     if (varDsc->lvAddrExposed)
6177     {
6178         printf(" addr-exposed");
6179     }
6180     if (varDsc->lvHasLdAddrOp)
6181     {
6182         printf(" ld-addr-op");
6183     }
6184     if (varDsc->lvVerTypeInfo.IsThisPtr())
6185     {
6186         printf(" this");
6187     }
6188     if (varDsc->lvPinned)
6189     {
6190         printf(" pinned");
6191     }
6192     if (varDsc->lvRefAssign)
6193     {
6194         printf(" ref-asgn");
6195     }
6196     if (varDsc->lvStackByref)
6197     {
6198         printf(" stack-byref");
6199     }
6200 #ifndef _TARGET_64BIT_
6201     if (varDsc->lvStructDoubleAlign)
6202         printf(" double-align");
6203 #endif // !_TARGET_64BIT_
6204     if (varDsc->lvOverlappingFields)
6205     {
6206         printf(" overlapping-fields");
6207     }
6208
6209     if (compGSReorderStackLayout && !varDsc->lvRegister)
6210     {
6211         if (varDsc->lvIsPtr)
6212         {
6213             printf(" ptr");
6214         }
6215         if (varDsc->lvIsUnsafeBuffer)
6216         {
6217             printf(" unsafe-buffer");
6218         }
6219     }
6220     if (varDsc->lvIsStructField)
6221     {
6222         LclVarDsc* parentvarDsc = &lvaTable[varDsc->lvParentLcl];
6223 #if !defined(_TARGET_64BIT_)
6224         if (varTypeIsLong(parentvarDsc))
6225         {
6226             bool isLo = (lclNum == parentvarDsc->lvFieldLclStart);
6227             printf(" V%02u.%s(offs=0x%02x)", varDsc->lvParentLcl, isLo ? "lo" : "hi", isLo ? 0 : genTypeSize(TYP_INT));
6228         }
6229         else
6230 #endif // !defined(_TARGET_64BIT_)
6231         {
6232             CORINFO_CLASS_HANDLE typeHnd = parentvarDsc->lvVerTypeInfo.GetClassHandle();
6233             CORINFO_FIELD_HANDLE fldHnd  = info.compCompHnd->getFieldInClass(typeHnd, varDsc->lvFldOrdinal);
6234
6235             printf(" V%02u.%s(offs=0x%02x)", varDsc->lvParentLcl, eeGetFieldName(fldHnd), varDsc->lvFldOffset);
6236
6237             lvaPromotionType promotionType = lvaGetPromotionType(parentvarDsc);
6238             // We should never have lvIsStructField set if it is a reg-sized non-field-addressed struct.
6239             assert(!varDsc->lvRegStruct);
6240             switch (promotionType)
6241             {
6242                 case PROMOTION_TYPE_NONE:
6243                     printf(" P-NONE");
6244                     break;
6245                 case PROMOTION_TYPE_DEPENDENT:
6246                     printf(" P-DEP");
6247                     break;
6248                 case PROMOTION_TYPE_INDEPENDENT:
6249                     printf(" P-INDEP");
6250                     break;
6251             }
6252         }
6253     }
6254
6255     printf("\n");
6256 }
6257
6258 /*****************************************************************************
6259 *
6260 *  dump the lvaTable
6261 */
6262
6263 void Compiler::lvaTableDump(FrameLayoutState curState)
6264 {
6265     if (curState == NO_FRAME_LAYOUT)
6266     {
6267         curState = lvaDoneFrameLayout;
6268         if (curState == NO_FRAME_LAYOUT)
6269         {
6270             // Still no layout? Could be a bug, but just display the initial layout
6271             curState = INITIAL_FRAME_LAYOUT;
6272         }
6273     }
6274
6275     if (curState == INITIAL_FRAME_LAYOUT)
6276     {
6277         printf("; Initial");
6278     }
6279     else if (curState == PRE_REGALLOC_FRAME_LAYOUT)
6280     {
6281         printf("; Pre-RegAlloc");
6282     }
6283     else if (curState == REGALLOC_FRAME_LAYOUT)
6284     {
6285         printf("; RegAlloc");
6286     }
6287     else if (curState == TENTATIVE_FRAME_LAYOUT)
6288     {
6289         printf("; Tentative");
6290     }
6291     else if (curState == FINAL_FRAME_LAYOUT)
6292     {
6293         printf("; Final");
6294     }
6295     else
6296     {
6297         printf("UNKNOWN FrameLayoutState!");
6298         unreached();
6299     }
6300
6301     printf(" local variable assignments\n");
6302     printf(";\n");
6303
6304     unsigned   lclNum;
6305     LclVarDsc* varDsc;
6306
6307     // Figure out some sizes, to help line things up
6308
6309     size_t refCntWtdWidth = 6; // Use 6 as the minimum width
6310
6311     if (curState != INITIAL_FRAME_LAYOUT) // don't need this info for INITIAL_FRAME_LAYOUT
6312     {
6313         for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
6314         {
6315             size_t width = strlen(refCntWtd2str(varDsc->lvRefCntWtd));
6316             if (width > refCntWtdWidth)
6317             {
6318                 refCntWtdWidth = width;
6319             }
6320         }
6321     }
6322
6323     // Do the actual output
6324
6325     for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
6326     {
6327         lvaDumpEntry(lclNum, curState, refCntWtdWidth);
6328     }
6329
6330     //-------------------------------------------------------------------------
6331     // Display the code-gen temps
6332
6333     assert(tmpAllFree());
6334     for (TempDsc* temp = tmpListBeg(); temp != nullptr; temp = tmpListNxt(temp))
6335     {
6336         printf(";  TEMP_%02u %26s%*s%7s  -> ", -temp->tdTempNum(), " ", refCntWtdWidth, " ",
6337                varTypeName(temp->tdTempType()));
6338         int offset = temp->tdTempOffs();
6339         printf(" [%2s%1s0x%02X]\n", isFramePointerUsed() ? STR_FPBASE : STR_SPBASE, (offset < 0 ? "-" : "+"),
6340                (offset < 0 ? -offset : offset));
6341     }
6342
6343     if (curState >= TENTATIVE_FRAME_LAYOUT)
6344     {
6345         printf(";\n");
6346         printf("; Lcl frame size = %d\n", compLclFrameSize);
6347     }
6348 }
6349 #endif // DEBUG
6350
6351 /*****************************************************************************
6352  *
6353  *  Conservatively estimate the layout of the stack frame.
6354  *
6355  *  This function is only used before final frame layout. It conservatively estimates the
6356  *  number of callee-saved registers that must be saved, then calls lvaAssignFrameOffsets().
6357  *  To do final frame layout, the callee-saved registers are known precisely, so
6358  *  lvaAssignFrameOffsets() is called directly.
6359  *
6360  *  Returns the (conservative, that is, overly large) estimated size of the frame,
6361  *  including the callee-saved registers. This is only used by the emitter during code
6362  *  generation when estimating the size of the offset of instructions accessing temps,
6363  *  and only if temps have a larger offset than variables.
6364  */
6365
6366 unsigned Compiler::lvaFrameSize(FrameLayoutState curState)
6367 {
6368     assert(curState < FINAL_FRAME_LAYOUT);
6369
6370     unsigned result;
6371
6372     /* Layout the stack frame conservatively.
6373        Assume all callee-saved registers are spilled to stack */
6374
6375     compCalleeRegsPushed = CNT_CALLEE_SAVED;
6376
6377 #if defined(_TARGET_ARMARCH_)
6378     if (compFloatingPointUsed)
6379         compCalleeRegsPushed += CNT_CALLEE_SAVED_FLOAT;
6380
6381     compCalleeRegsPushed++; // we always push LR.  See genPushCalleeSavedRegisters
6382 #elif defined(_TARGET_AMD64_)
6383     if (compFloatingPointUsed)
6384     {
6385         compCalleeFPRegsSavedMask = RBM_FLT_CALLEE_SAVED;
6386     }
6387     else
6388     {
6389         compCalleeFPRegsSavedMask = RBM_NONE;
6390     }
6391 #endif
6392
6393 #if DOUBLE_ALIGN
6394     if (genDoubleAlign())
6395     {
6396         // X86 only - account for extra 4-byte pad that may be created by "and  esp, -8"  instruction
6397         compCalleeRegsPushed++;
6398     }
6399 #endif
6400
6401 #ifdef _TARGET_XARCH_
6402     // Since FP/EBP is included in the SAVED_REG_MAXSZ we need to
6403     // subtract 1 register if codeGen->isFramePointerUsed() is true.
6404     if (codeGen->isFramePointerUsed())
6405     {
6406         compCalleeRegsPushed--;
6407     }
6408 #endif
6409
6410     lvaAssignFrameOffsets(curState);
6411
6412     unsigned calleeSavedRegMaxSz = CALLEE_SAVED_REG_MAXSZ;
6413 #if defined(_TARGET_ARMARCH_)
6414     if (compFloatingPointUsed)
6415     {
6416         calleeSavedRegMaxSz += CALLEE_SAVED_FLOAT_MAXSZ;
6417     }
6418     calleeSavedRegMaxSz += REGSIZE_BYTES; // we always push LR.  See genPushCalleeSavedRegisters
6419 #endif
6420
6421     result = compLclFrameSize + calleeSavedRegMaxSz;
6422     return result;
6423 }
6424
6425 //------------------------------------------------------------------------
6426 // lvaGetSPRelativeOffset: Given a variable, return the offset of that
6427 // variable in the frame from the stack pointer. This number will be positive,
6428 // since the stack pointer must be at a lower address than everything on the
6429 // stack.
6430 //
6431 // This can't be called for localloc functions, since the stack pointer
6432 // varies, and thus there is no fixed offset to a variable from the stack pointer.
6433 //
6434 // Arguments:
6435 //    varNum - the variable number
6436 //
6437 // Return Value:
6438 //    The offset.
6439
6440 int Compiler::lvaGetSPRelativeOffset(unsigned varNum)
6441 {
6442     assert(!compLocallocUsed);
6443     assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
6444     assert(varNum < lvaCount);
6445     const LclVarDsc* varDsc = lvaTable + varNum;
6446     assert(varDsc->lvOnFrame);
6447     int spRelativeOffset;
6448
6449     if (varDsc->lvFramePointerBased)
6450     {
6451         // The stack offset is relative to the frame pointer, so convert it to be
6452         // relative to the stack pointer (which makes no sense for localloc functions).
6453         spRelativeOffset = varDsc->lvStkOffs + codeGen->genSPtoFPdelta();
6454     }
6455     else
6456     {
6457         spRelativeOffset = varDsc->lvStkOffs;
6458     }
6459
6460     assert(spRelativeOffset >= 0);
6461     return spRelativeOffset;
6462 }
6463
6464 /*****************************************************************************
6465  *
6466  *  Return the caller-SP-relative stack offset of a local/parameter.
6467  *  Requires the local to be on the stack and frame layout to be complete.
6468  */
6469
6470 int Compiler::lvaGetCallerSPRelativeOffset(unsigned varNum)
6471 {
6472     assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
6473     assert(varNum < lvaCount);
6474     LclVarDsc* varDsc = lvaTable + varNum;
6475     assert(varDsc->lvOnFrame);
6476
6477     return lvaToCallerSPRelativeOffset(varDsc->lvStkOffs, varDsc->lvFramePointerBased);
6478 }
6479
6480 int Compiler::lvaToCallerSPRelativeOffset(int offset, bool isFpBased)
6481 {
6482     assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
6483
6484     if (isFpBased)
6485     {
6486         offset += codeGen->genCallerSPtoFPdelta();
6487     }
6488     else
6489     {
6490         offset += codeGen->genCallerSPtoInitialSPdelta();
6491     }
6492
6493     return offset;
6494 }
6495
6496 /*****************************************************************************
6497  *
6498  *  Return the Initial-SP-relative stack offset of a local/parameter.
6499  *  Requires the local to be on the stack and frame layout to be complete.
6500  */
6501
6502 int Compiler::lvaGetInitialSPRelativeOffset(unsigned varNum)
6503 {
6504     assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
6505     assert(varNum < lvaCount);
6506     LclVarDsc* varDsc = lvaTable + varNum;
6507     assert(varDsc->lvOnFrame);
6508
6509     return lvaToInitialSPRelativeOffset(varDsc->lvStkOffs, varDsc->lvFramePointerBased);
6510 }
6511
6512 // Given a local variable offset, and whether that offset is frame-pointer based, return its offset from Initial-SP.
6513 // This is used, for example, to figure out the offset of the frame pointer from Initial-SP.
6514 int Compiler::lvaToInitialSPRelativeOffset(unsigned offset, bool isFpBased)
6515 {
6516     assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
6517 #ifdef _TARGET_AMD64_
6518     if (isFpBased)
6519     {
6520         // Currently, the frame starts by pushing ebp, ebp points to the saved ebp
6521         // (so we have ebp pointer chaining). Add the fixed-size frame size plus the
6522         // size of the callee-saved regs (not including ebp itself) to find Initial-SP.
6523
6524         assert(codeGen->isFramePointerUsed());
6525         offset += codeGen->genSPtoFPdelta();
6526     }
6527     else
6528     {
6529         // The offset is correct already!
6530     }
6531 #else  // !_TARGET_AMD64_
6532     NYI("lvaToInitialSPRelativeOffset");
6533 #endif // !_TARGET_AMD64_
6534
6535     return offset;
6536 }
6537
6538 /*****************************************************************************/
6539
6540 #ifdef DEBUG
6541 /*****************************************************************************
6542  *  Pick a padding size at "random" for the local.
6543  *  0 means that it should not be converted to a GT_LCL_FLD
6544  */
6545
6546 static unsigned LCL_FLD_PADDING(unsigned lclNum)
6547 {
6548     // Convert every 2nd variable
6549     if (lclNum % 2)
6550     {
6551         return 0;
6552     }
6553
6554     // Pick a padding size at "random"
6555     unsigned size = lclNum % 7;
6556
6557     return size;
6558 }
6559
6560 /*****************************************************************************
6561  *
6562  *  Callback for fgWalkAllTreesPre()
6563  *  Convert as many GT_LCL_VAR's to GT_LCL_FLD's
6564  */
6565
6566 /* static */
6567 /*
6568     The stress mode does 2 passes.
6569
6570     In the first pass we will mark the locals where we CAN't apply the stress mode.
6571     In the second pass we will do the appropiate morphing wherever we've not determined we can't do it.
6572 */
6573 Compiler::fgWalkResult Compiler::lvaStressLclFldCB(GenTreePtr* pTree, fgWalkData* data)
6574 {
6575     GenTreePtr tree = *pTree;
6576     genTreeOps oper = tree->OperGet();
6577     GenTreePtr lcl;
6578
6579     switch (oper)
6580     {
6581         case GT_LCL_VAR:
6582             lcl = tree;
6583             break;
6584
6585         case GT_ADDR:
6586             if (tree->gtOp.gtOp1->gtOper != GT_LCL_VAR)
6587             {
6588                 return WALK_CONTINUE;
6589             }
6590             lcl = tree->gtOp.gtOp1;
6591             break;
6592
6593         default:
6594             return WALK_CONTINUE;
6595     }
6596
6597     Compiler* pComp      = ((lvaStressLclFldArgs*)data->pCallbackData)->m_pCompiler;
6598     bool      bFirstPass = ((lvaStressLclFldArgs*)data->pCallbackData)->m_bFirstPass;
6599     noway_assert(lcl->gtOper == GT_LCL_VAR);
6600     unsigned   lclNum = lcl->gtLclVarCommon.gtLclNum;
6601     var_types  type   = lcl->TypeGet();
6602     LclVarDsc* varDsc = &pComp->lvaTable[lclNum];
6603
6604     if (varDsc->lvNoLclFldStress)
6605     {
6606         // Already determined we can't do anything for this var
6607         return WALK_SKIP_SUBTREES;
6608     }
6609
6610     if (bFirstPass)
6611     {
6612         // Ignore arguments and temps
6613         if (varDsc->lvIsParam || lclNum >= pComp->info.compLocalsCount)
6614         {
6615             varDsc->lvNoLclFldStress = true;
6616             return WALK_SKIP_SUBTREES;
6617         }
6618
6619         // Fix for lcl_fld stress mode
6620         if (varDsc->lvKeepType)
6621         {
6622             varDsc->lvNoLclFldStress = true;
6623             return WALK_SKIP_SUBTREES;
6624         }
6625
6626         // Can't have GC ptrs in TYP_BLK.
6627         if (!varTypeIsArithmetic(type))
6628         {
6629             varDsc->lvNoLclFldStress = true;
6630             return WALK_SKIP_SUBTREES;
6631         }
6632
6633         // Weed out "small" types like TYP_BYTE as we don't mark the GT_LCL_VAR
6634         // node with the accurate small type. If we bash lvaTable[].lvType,
6635         // then there will be no indication that it was ever a small type.
6636         var_types varType = varDsc->TypeGet();
6637         if (varType != TYP_BLK && genTypeSize(varType) != genTypeSize(genActualType(varType)))
6638         {
6639             varDsc->lvNoLclFldStress = true;
6640             return WALK_SKIP_SUBTREES;
6641         }
6642
6643         // Offset some of the local variable by a "random" non-zero amount
6644         unsigned padding = LCL_FLD_PADDING(lclNum);
6645         if (padding == 0)
6646         {
6647             varDsc->lvNoLclFldStress = true;
6648             return WALK_SKIP_SUBTREES;
6649         }
6650     }
6651     else
6652     {
6653         // Do the morphing
6654         noway_assert(varDsc->lvType == lcl->gtType || varDsc->lvType == TYP_BLK);
6655         var_types varType = varDsc->TypeGet();
6656
6657         // Calculate padding
6658         unsigned padding = LCL_FLD_PADDING(lclNum);
6659
6660         // Change the variable to a TYP_BLK
6661         if (varType != TYP_BLK)
6662         {
6663             varDsc->lvExactSize = (unsigned)(roundUp(padding + pComp->lvaLclSize(lclNum)));
6664             varDsc->lvType      = TYP_BLK;
6665             pComp->lvaSetVarAddrExposed(lclNum);
6666         }
6667
6668         tree->gtFlags |= GTF_GLOB_REF;
6669
6670         /* Now morph the tree appropriately */
6671         if (oper == GT_LCL_VAR)
6672         {
6673             /* Change lclVar(lclNum) to lclFld(lclNum,padding) */
6674
6675             tree->ChangeOper(GT_LCL_FLD);
6676             tree->gtLclFld.gtLclOffs = padding;
6677         }
6678         else
6679         {
6680             /* Change addr(lclVar) to addr(lclVar)+padding */
6681
6682             noway_assert(oper == GT_ADDR);
6683             GenTreePtr newAddr = new (pComp, GT_NONE) GenTreeOp(*tree->AsOp());
6684
6685             tree->ChangeOper(GT_ADD);
6686             tree->gtOp.gtOp1 = newAddr;
6687             tree->gtOp.gtOp2 = pComp->gtNewIconNode(padding);
6688
6689             lcl->gtType = TYP_BLK;
6690         }
6691     }
6692
6693     return WALK_SKIP_SUBTREES;
6694 }
6695
6696 /*****************************************************************************/
6697
6698 void Compiler::lvaStressLclFld()
6699 {
6700     if (!compStressCompile(STRESS_LCL_FLDS, 5))
6701     {
6702         return;
6703     }
6704
6705     lvaStressLclFldArgs Args;
6706     Args.m_pCompiler  = this;
6707     Args.m_bFirstPass = true;
6708
6709     // Do First pass
6710     fgWalkAllTreesPre(lvaStressLclFldCB, &Args);
6711
6712     // Second pass
6713     Args.m_bFirstPass = false;
6714     fgWalkAllTreesPre(lvaStressLclFldCB, &Args);
6715 }
6716
6717 #endif // DEBUG
6718
6719 /*****************************************************************************
6720  *
6721  *  A little routine that displays a local variable bitset.
6722  *  'set' is mask of variables that have to be displayed
6723  *  'allVars' is the complete set of interesting variables (blank space is
6724  *    inserted if its corresponding bit is not in 'set').
6725  */
6726
6727 #ifdef DEBUG
6728 void Compiler::lvaDispVarSet(VARSET_VALARG_TP set)
6729 {
6730     VARSET_TP VARSET_INIT_NOCOPY(allVars, VarSetOps::MakeEmpty(this));
6731     lvaDispVarSet(set, allVars);
6732 }
6733
6734 void Compiler::lvaDispVarSet(VARSET_VALARG_TP set, VARSET_VALARG_TP allVars)
6735 {
6736     printf("{");
6737
6738     bool needSpace = false;
6739
6740     for (unsigned index = 0; index < lvaTrackedCount; index++)
6741     {
6742         if (VarSetOps::IsMember(this, set, index))
6743         {
6744             unsigned   lclNum;
6745             LclVarDsc* varDsc;
6746
6747             /* Look for the matching variable */
6748
6749             for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
6750             {
6751                 if ((varDsc->lvVarIndex == index) && varDsc->lvTracked)
6752                 {
6753                     break;
6754                 }
6755             }
6756
6757             if (needSpace)
6758             {
6759                 printf(" ");
6760             }
6761             else
6762             {
6763                 needSpace = true;
6764             }
6765
6766             printf("V%02u", lclNum);
6767         }
6768         else if (VarSetOps::IsMember(this, allVars, index))
6769         {
6770             if (needSpace)
6771             {
6772                 printf(" ");
6773             }
6774             else
6775             {
6776                 needSpace = true;
6777             }
6778
6779             printf("   ");
6780         }
6781     }
6782
6783     printf("}");
6784 }
6785
6786 #endif // DEBUG