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