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