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.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XX The variables to be used by the code generator. XX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
22 #include "register_arg_convention.h"
24 /*****************************************************************************/
29 unsigned Compiler::s_lvaDoubleAlignedProcsCount = 0;
33 /*****************************************************************************/
35 void Compiler::lvaInit()
37 /* We haven't allocated stack variables yet */
38 lvaRefCountingStarted = false;
39 lvaLocalVarRefCounted = false;
41 lvaSortAgain = false; // false: We don't need to call lvaSortOnly()
42 lvaTrackedFixed = false; // false: We can still add new tracked variables
44 lvaDoneFrameLayout = NO_FRAME_LAYOUT;
45 #if !FEATURE_EH_FUNCLETS
46 lvaShadowSPslotsVar = BAD_VAR_NUM;
47 #endif // !FEATURE_EH_FUNCLETS
48 lvaInlinedPInvokeFrameVar = BAD_VAR_NUM;
49 lvaReversePInvokeFrameVar = BAD_VAR_NUM;
50 #if FEATURE_FIXED_OUT_ARGS
51 lvaPInvokeFrameRegSaveVar = BAD_VAR_NUM;
52 lvaOutgoingArgSpaceVar = BAD_VAR_NUM;
53 #endif // FEATURE_FIXED_OUT_ARGS
55 lvaPromotedStructAssemblyScratchVar = BAD_VAR_NUM;
56 #endif // _TARGET_ARM_
57 lvaLocAllocSPvar = BAD_VAR_NUM;
58 lvaNewObjArrayArgs = BAD_VAR_NUM;
59 lvaGSSecurityCookie = BAD_VAR_NUM;
61 lvaVarargsBaseOfStkArgs = BAD_VAR_NUM;
62 #endif // _TARGET_X86_
63 lvaVarargsHandleArg = BAD_VAR_NUM;
64 lvaSecurityObject = BAD_VAR_NUM;
65 lvaStubArgumentVar = BAD_VAR_NUM;
66 lvaArg0Var = BAD_VAR_NUM;
67 lvaMonAcquired = BAD_VAR_NUM;
69 lvaInlineeReturnSpillTemp = BAD_VAR_NUM;
71 gsShadowVarInfo = nullptr;
72 #if FEATURE_EH_FUNCLETS
73 lvaPSPSym = BAD_VAR_NUM;
76 lvaSIMDInitTempVarNum = BAD_VAR_NUM;
77 #endif // FEATURE_SIMD
79 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
80 lvaFirstStackIncomingArgNum = BAD_VAR_NUM;
81 #endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
84 /*****************************************************************************/
86 void Compiler::lvaInitTypeRef()
89 /* x86 args look something like this:
90 [this ptr] [hidden return buffer] [declared arguments]* [generic context] [var arg cookie]
92 x64 is closer to the native ABI:
93 [this ptr] [hidden return buffer] [generic context] [var arg cookie] [declared arguments]*
94 (Note: prior to .NET Framework 4.5.1 for Windows 8.1 (but not .NET Framework 4.5.1 "downlevel"),
95 the "hidden return buffer" came before the "this ptr". Now, the "this ptr" comes first. This
96 is different from the C++ order, where the "hidden return buffer" always comes first.)
98 ARM and ARM64 are the same as the current x64 convention:
99 [this ptr] [hidden return buffer] [generic context] [var arg cookie] [declared arguments]*
102 The var arg cookie and generic context are swapped with respect to the user arguments
105 /* Set compArgsCount and compLocalsCount */
107 info.compArgsCount = info.compMethodInfo->args.numArgs;
109 // Is there a 'this' pointer
111 if (!info.compIsStatic)
113 info.compArgsCount++;
117 info.compThisArg = BAD_VAR_NUM;
120 info.compILargsCount = info.compArgsCount;
123 if (featureSIMD && (info.compRetNativeType == TYP_STRUCT))
125 var_types structType = impNormStructType(info.compMethodInfo->args.retTypeClass);
126 info.compRetType = structType;
128 #endif // FEATURE_SIMD
130 // Are we returning a struct using a return buffer argument?
132 const bool hasRetBuffArg = impMethodInfo_hasRetBuffArg(info.compMethodInfo);
134 // Possibly change the compRetNativeType from TYP_STRUCT to a "primitive" type
135 // when we are returning a struct by value and it fits in one register
137 if (!hasRetBuffArg && varTypeIsStruct(info.compRetNativeType))
139 CORINFO_CLASS_HANDLE retClsHnd = info.compMethodInfo->args.retTypeClass;
141 Compiler::structPassingKind howToReturnStruct;
142 var_types returnType = getReturnTypeForStruct(retClsHnd, &howToReturnStruct);
144 if (howToReturnStruct == SPK_PrimitiveType)
146 assert(returnType != TYP_UNKNOWN);
147 assert(returnType != TYP_STRUCT);
149 info.compRetNativeType = returnType;
151 // ToDo: Refactor this common code sequence into its own method as it is used 4+ times
152 if ((returnType == TYP_LONG) && (compLongUsed == false))
156 else if (((returnType == TYP_FLOAT) || (returnType == TYP_DOUBLE)) && (compFloatingPointUsed == false))
158 compFloatingPointUsed = true;
163 // Do we have a RetBuffArg?
167 info.compArgsCount++;
171 info.compRetBuffArg = BAD_VAR_NUM;
174 /* There is a 'hidden' cookie pushed last when the
175 calling convention is varargs */
177 if (info.compIsVarArgs)
179 info.compArgsCount++;
182 // Is there an extra parameter used to pass instantiation info to
183 // shared generic methods and shared generic struct instance methods?
184 if (info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE)
186 info.compArgsCount++;
190 info.compTypeCtxtArg = BAD_VAR_NUM;
193 lvaCount = info.compLocalsCount = info.compArgsCount + info.compMethodInfo->locals.numArgs;
195 info.compILlocalsCount = info.compILargsCount + info.compMethodInfo->locals.numArgs;
197 /* Now allocate the variable descriptor table */
199 if (compIsForInlining())
201 lvaTable = impInlineInfo->InlinerCompiler->lvaTable;
202 lvaCount = impInlineInfo->InlinerCompiler->lvaCount;
203 lvaTableCnt = impInlineInfo->InlinerCompiler->lvaTableCnt;
205 // No more stuff needs to be done.
209 lvaTableCnt = lvaCount * 2;
211 if (lvaTableCnt < 16)
216 lvaTable = (LclVarDsc*)compGetMemArray(lvaTableCnt, sizeof(*lvaTable), CMK_LvaTable);
217 size_t tableSize = lvaTableCnt * sizeof(*lvaTable);
218 memset(lvaTable, 0, tableSize);
219 for (unsigned i = 0; i < lvaTableCnt; i++)
221 new (&lvaTable[i], jitstd::placement_t()) LclVarDsc(this); // call the constructor.
224 //-------------------------------------------------------------------------
225 // Count the arguments and initialize the respective lvaTable[] entries
227 // First the implicit arguments
228 //-------------------------------------------------------------------------
230 InitVarDscInfo varDscInfo;
231 varDscInfo.Init(lvaTable, hasRetBuffArg);
233 lvaInitArgs(&varDscInfo);
235 //-------------------------------------------------------------------------
236 // Finally the local variables
237 //-------------------------------------------------------------------------
239 unsigned varNum = varDscInfo.varNum;
240 LclVarDsc* varDsc = varDscInfo.varDsc;
241 CORINFO_ARG_LIST_HANDLE localsSig = info.compMethodInfo->locals.args;
243 for (unsigned i = 0; i < info.compMethodInfo->locals.numArgs;
244 i++, varNum++, varDsc++, localsSig = info.compCompHnd->getArgNext(localsSig))
246 CORINFO_CLASS_HANDLE typeHnd;
247 CorInfoTypeWithMod corInfoType =
248 info.compCompHnd->getArgType(&info.compMethodInfo->locals, localsSig, &typeHnd);
249 lvaInitVarDsc(varDsc, varNum, strip(corInfoType), typeHnd, localsSig, &info.compMethodInfo->locals);
251 varDsc->lvPinned = ((corInfoType & CORINFO_TYPE_MOD_PINNED) != 0);
252 varDsc->lvOnFrame = true; // The final home for this local variable might be our local stack frame
255 if ( // If there already exist unsafe buffers, don't mark more structs as unsafe
256 // as that will cause them to be placed along with the real unsafe buffers,
257 // unnecessarily exposing them to overruns. This can affect GS tests which
258 // intentionally do buffer-overruns.
259 !getNeedsGSSecurityCookie() &&
260 // GS checks require the stack to be re-ordered, which can't be done with EnC
261 !opts.compDbgEnC && compStressCompile(STRESS_UNSAFE_BUFFER_CHECKS, 25))
263 setNeedsGSSecurityCookie();
264 compGSReorderStackLayout = true;
266 for (unsigned i = 0; i < lvaCount; i++)
268 if ((lvaTable[i].lvType == TYP_STRUCT) && compStressCompile(STRESS_GENERIC_VARN, 60))
270 lvaTable[i].lvIsUnsafeBuffer = true;
275 if (getNeedsGSSecurityCookie())
277 // Ensure that there will be at least one stack variable since
278 // we require that the GSCookie does not have a 0 stack offset.
279 unsigned dummy = lvaGrabTempWithImplicitUse(false DEBUGARG("GSCookie dummy"));
280 lvaTable[dummy].lvType = TYP_INT;
286 lvaTableDump(INITIAL_FRAME_LAYOUT);
291 /*****************************************************************************/
292 void Compiler::lvaInitArgs(InitVarDscInfo* varDscInfo)
296 #if defined(_TARGET_ARM_) && defined(PROFILING_SUPPORTED)
297 // Prespill all argument regs on to stack in case of Arm when under profiler.
298 if (compIsProfilerHookNeeded())
300 codeGen->regSet.rsMaskPreSpillRegArg |= RBM_ARG_REGS;
304 //----------------------------------------------------------------------
306 /* Is there a "this" pointer ? */
307 lvaInitThisPtr(varDscInfo);
309 /* If we have a hidden return-buffer parameter, that comes here */
310 lvaInitRetBuffArg(varDscInfo);
312 //======================================================================
314 #if USER_ARGS_COME_LAST
315 //@GENERICS: final instantiation-info argument for shared generic methods
316 // and shared generic struct instance methods
317 lvaInitGenericsCtxt(varDscInfo);
319 /* If the method is varargs, process the varargs cookie */
320 lvaInitVarArgsHandle(varDscInfo);
323 //-------------------------------------------------------------------------
324 // Now walk the function signature for the explicit user arguments
325 //-------------------------------------------------------------------------
326 lvaInitUserArgs(varDscInfo);
328 #if !USER_ARGS_COME_LAST
329 //@GENERICS: final instantiation-info argument for shared generic methods
330 // and shared generic struct instance methods
331 lvaInitGenericsCtxt(varDscInfo);
333 /* If the method is varargs, process the varargs cookie */
334 lvaInitVarArgsHandle(varDscInfo);
337 //----------------------------------------------------------------------
339 // We have set info.compArgsCount in compCompile()
340 noway_assert(varDscInfo->varNum == info.compArgsCount);
341 assert(varDscInfo->intRegArgNum <= MAX_REG_ARG);
343 codeGen->intRegState.rsCalleeRegArgCount = varDscInfo->intRegArgNum;
344 #if !FEATURE_STACK_FP_X87
345 codeGen->floatRegState.rsCalleeRegArgCount = varDscInfo->floatRegArgNum;
346 #endif // FEATURE_STACK_FP_X87
348 // The total argument size must be aligned.
349 noway_assert((compArgSize % sizeof(void*)) == 0);
352 /* We can not pass more than 2^16 dwords as arguments as the "ret"
353 instruction can only pop 2^16 arguments. Could be handled correctly
354 but it will be very difficult for fully interruptible code */
356 if (compArgSize != (size_t)(unsigned short)compArgSize)
357 NO_WAY("Too many arguments for the \"ret\" instruction to pop");
361 /*****************************************************************************/
362 void Compiler::lvaInitThisPtr(InitVarDscInfo* varDscInfo)
364 LclVarDsc* varDsc = varDscInfo->varDsc;
365 if (!info.compIsStatic)
367 varDsc->lvIsParam = 1;
369 varDsc->lvSingleDef = 1;
374 lvaArg0Var = info.compThisArg = varDscInfo->varNum;
375 noway_assert(info.compThisArg == 0);
377 if (eeIsValueClass(info.compClassHnd))
379 varDsc->lvType = TYP_BYREF;
383 var_types simdBaseType = TYP_UNKNOWN;
384 var_types type = impNormStructType(info.compClassHnd, nullptr, nullptr, &simdBaseType);
385 if (simdBaseType != TYP_UNKNOWN)
387 assert(varTypeIsSIMD(type));
388 varDsc->lvSIMDType = true;
389 varDsc->lvBaseType = simdBaseType;
392 #endif // FEATURE_SIMD
396 varDsc->lvType = TYP_REF;
399 if (tiVerificationNeeded)
401 varDsc->lvVerTypeInfo = verMakeTypeInfo(info.compClassHnd);
403 if (varDsc->lvVerTypeInfo.IsValueClass())
405 varDsc->lvVerTypeInfo.MakeByRef();
410 varDsc->lvVerTypeInfo = typeInfo();
413 // Mark the 'this' pointer for the method
414 varDsc->lvVerTypeInfo.SetIsThisPtr();
416 varDsc->lvIsRegArg = 1;
417 noway_assert(varDscInfo->intRegArgNum == 0);
419 varDsc->lvArgReg = genMapRegArgNumToRegNum(varDscInfo->allocRegArg(TYP_INT), varDsc->TypeGet());
420 #if FEATURE_MULTIREG_ARGS
421 varDsc->lvOtherArgReg = REG_NA;
423 varDsc->setPrefReg(varDsc->lvArgReg, this);
424 varDsc->lvOnFrame = true; // The final home for this incoming register might be our local stack frame
429 printf("'this' passed in register %s\n", getRegName(varDsc->lvArgReg));
432 compArgSize += TARGET_POINTER_SIZE;
434 varDscInfo->varNum++;
435 varDscInfo->varDsc++;
439 /*****************************************************************************/
440 void Compiler::lvaInitRetBuffArg(InitVarDscInfo* varDscInfo)
442 LclVarDsc* varDsc = varDscInfo->varDsc;
443 bool hasRetBuffArg = impMethodInfo_hasRetBuffArg(info.compMethodInfo);
445 // These two should always match
446 noway_assert(hasRetBuffArg == varDscInfo->hasRetBufArg);
450 info.compRetBuffArg = varDscInfo->varNum;
451 varDsc->lvType = TYP_BYREF;
452 varDsc->lvIsParam = 1;
453 varDsc->lvIsRegArg = 1;
455 varDsc->lvSingleDef = 1;
457 if (hasFixedRetBuffReg())
459 varDsc->lvArgReg = theFixedRetBuffReg();
463 unsigned retBuffArgNum = varDscInfo->allocRegArg(TYP_INT);
464 varDsc->lvArgReg = genMapIntRegArgNumToRegNum(retBuffArgNum);
467 #if FEATURE_MULTIREG__ARGS
468 varDsc->lvOtherArgReg = REG_NA;
470 varDsc->setPrefReg(varDsc->lvArgReg, this);
471 varDsc->lvOnFrame = true; // The final home for this incoming register might be our local stack frame
473 info.compRetBuffDefStack = 0;
474 if (info.compRetType == TYP_STRUCT)
476 CORINFO_SIG_INFO sigInfo;
477 info.compCompHnd->getMethodSig(info.compMethodHnd, &sigInfo);
478 assert(JITtype2varType(sigInfo.retType) == info.compRetType); // Else shouldn't have a ret buff.
480 info.compRetBuffDefStack =
481 (info.compCompHnd->isStructRequiringStackAllocRetBuf(sigInfo.retTypeClass) == TRUE);
482 if (info.compRetBuffDefStack)
484 // If we're assured that the ret buff argument points into a callers stack, we will type it as
486 // (native int/unmanaged pointer) so that it's not tracked as a GC ref.
487 varDsc->lvType = TYP_I_IMPL;
490 assert(isValidIntArgReg(varDsc->lvArgReg));
495 printf("'__retBuf' passed in register %s\n", getRegName(varDsc->lvArgReg));
499 /* Update the total argument size, count and varDsc */
501 compArgSize += TARGET_POINTER_SIZE;
502 varDscInfo->varNum++;
503 varDscInfo->varDsc++;
507 /*****************************************************************************/
508 void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo)
510 //-------------------------------------------------------------------------
511 // Walk the function signature for the explicit arguments
512 //-------------------------------------------------------------------------
514 #if defined(_TARGET_X86_)
515 // Only (some of) the implicit args are enregistered for varargs
516 varDscInfo->maxIntRegArgNum = info.compIsVarArgs ? varDscInfo->intRegArgNum : MAX_REG_ARG;
517 #elif defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI)
518 // On System V type environment the float registers are not indexed together with the int ones.
519 varDscInfo->floatRegArgNum = varDscInfo->intRegArgNum;
522 CORINFO_ARG_LIST_HANDLE argLst = info.compMethodInfo->args.args;
524 const unsigned argSigLen = info.compMethodInfo->args.numArgs;
526 regMaskTP doubleAlignMask = RBM_NONE;
527 for (unsigned i = 0; i < argSigLen;
528 i++, varDscInfo->varNum++, varDscInfo->varDsc++, argLst = info.compCompHnd->getArgNext(argLst))
530 LclVarDsc* varDsc = varDscInfo->varDsc;
531 CORINFO_CLASS_HANDLE typeHnd = nullptr;
533 CorInfoTypeWithMod corInfoType = info.compCompHnd->getArgType(&info.compMethodInfo->args, argLst, &typeHnd);
534 varDsc->lvIsParam = 1;
536 varDsc->lvSingleDef = 1;
539 lvaInitVarDsc(varDsc, varDscInfo->varNum, strip(corInfoType), typeHnd, argLst, &info.compMethodInfo->args);
541 // For ARM, ARM64, and AMD64 varargs, all arguments go in integer registers
542 var_types argType = mangleVarArgsType(varDsc->TypeGet());
543 var_types origArgType = argType;
544 // ARM softfp calling convention should affect only the floating point arguments.
545 // Otherwise there appear too many surplus pre-spills and other memory operations
546 // with the associated locations .
547 bool isSoftFPPreSpill = opts.compUseSoftFP && varTypeIsFloating(varDsc->TypeGet());
548 unsigned argSize = eeGetArgSize(argLst, &info.compMethodInfo->args);
549 unsigned cSlots = argSize / TARGET_POINTER_SIZE; // the total number of slots of this argument
550 bool isHfaArg = false;
551 var_types hfaType = TYP_UNDEF;
553 // Methods that use VarArg or SoftFP cannot have HFA arguments
554 if (!info.compIsVarArgs && !opts.compUseSoftFP)
556 // If the argType is a struct, then check if it is an HFA
557 if (varTypeIsStruct(argType))
559 hfaType = GetHfaType(typeHnd); // set to float or double if it is an HFA, otherwise TYP_UNDEF
560 isHfaArg = varTypeIsFloating(hfaType);
565 // We have an HFA argument, so from here on out treat the type as a float or double.
566 // The orginal struct type is available by using origArgType
567 // We also update the cSlots to be the number of float/double fields in the HFA
569 cSlots = varDsc->lvHfaSlots();
571 // The number of slots that must be enregistered if we are to consider this argument enregistered.
572 // This is normally the same as cSlots, since we normally either enregister the entire object,
573 // or none of it. For structs on ARM, however, we only need to enregister a single slot to consider
574 // it enregistered, as long as we can split the rest onto the stack.
575 unsigned cSlotsToEnregister = cSlots;
578 // On ARM we pass the first 4 words of integer arguments and non-HFA structs in registers.
579 // But we pre-spill user arguments in varargs methods and structs.
582 bool preSpill = info.compIsVarArgs || isSoftFPPreSpill;
587 assert(varDsc->lvSize() == argSize);
588 cAlign = varDsc->lvStructDoubleAlign ? 2 : 1;
590 // HFA arguments go on the stack frame. They don't get spilled in the prolog like struct
591 // arguments passed in the integer registers but get homed immediately after the prolog.
594 cSlotsToEnregister = 1; // HFAs must be totally enregistered or not, but other structs can be split.
609 if (isRegParamType(argType))
611 compArgSize += varDscInfo->alignReg(argType, cAlign) * REGSIZE_BYTES;
614 if (argType == TYP_STRUCT)
616 // Are we going to split the struct between registers and stack? We can do that as long as
617 // no floating-point arguments have been put on the stack.
619 // From the ARM Procedure Call Standard:
620 // Rule C.5: "If the NCRN is less than r4 **and** the NSAA is equal to the SP,"
621 // then split the argument between registers and stack. Implication: if something
622 // has already been spilled to the stack, then anything that would normally be
623 // split between the core registers and the stack will be put on the stack.
624 // Anything that follows will also be on the stack. However, if something from
625 // floating point regs has been spilled to the stack, we can still use r0-r3 until they are full.
627 if (varDscInfo->canEnreg(TYP_INT, 1) && // The beginning of the struct can go in a register
628 !varDscInfo->canEnreg(TYP_INT, cSlots) && // The end of the struct can't fit in a register
629 varDscInfo->existAnyFloatStackArgs()) // There's at least one stack-based FP arg already
631 varDscInfo->setAllRegArgUsed(TYP_INT); // Prevent all future use of integer registers
632 preSpill = false; // This struct won't be prespilled, since it will go on the stack
638 for (unsigned ix = 0; ix < cSlots; ix++)
640 if (!varDscInfo->canEnreg(TYP_INT, ix + 1))
644 regMaskTP regMask = genMapArgNumToRegMask(varDscInfo->regArgNum(TYP_INT) + ix, TYP_INT);
647 doubleAlignMask |= regMask;
649 codeGen->regSet.rsMaskPreSpillRegArg |= regMask;
654 varDsc->lvOnFrame = true; // The final home for this incoming register might be our local stack frame
657 #else // !_TARGET_ARM_
658 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
659 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
660 if (varTypeIsStruct(argType))
662 assert(typeHnd != nullptr);
663 eeGetSystemVAmd64PassStructInRegisterDescriptor(typeHnd, &structDesc);
664 if (structDesc.passedInRegisters)
666 unsigned intRegCount = 0;
667 unsigned floatRegCount = 0;
669 for (unsigned int i = 0; i < structDesc.eightByteCount; i++)
671 if (structDesc.IsIntegralSlot(i))
675 else if (structDesc.IsSseSlot(i))
681 assert(false && "Invalid eightbyte classification type.");
686 if (intRegCount != 0 && !varDscInfo->canEnreg(TYP_INT, intRegCount))
688 structDesc.passedInRegisters = false; // No register to enregister the eightbytes.
691 if (floatRegCount != 0 && !varDscInfo->canEnreg(TYP_FLOAT, floatRegCount))
693 structDesc.passedInRegisters = false; // No register to enregister the eightbytes.
697 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
699 // The final home for this incoming register might be our local stack frame.
700 // For System V platforms the final home will always be on the local stack frame.
701 varDsc->lvOnFrame = true;
703 #endif // !_TARGET_ARM_
705 bool canPassArgInRegisters = false;
707 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
708 if (varTypeIsStruct(argType))
710 canPassArgInRegisters = structDesc.passedInRegisters;
713 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
715 canPassArgInRegisters = varDscInfo->canEnreg(argType, cSlotsToEnregister);
718 if (canPassArgInRegisters)
720 /* Another register argument */
722 // Allocate the registers we need. allocRegArg() returns the first argument register number of the set.
723 // For non-HFA structs, we still "try" to enregister the whole thing; it will just max out if splitting
724 // to the stack happens.
725 unsigned firstAllocatedRegArgNum = 0;
727 #if FEATURE_MULTIREG_ARGS
728 varDsc->lvOtherArgReg = REG_NA;
729 #endif // FEATURE_MULTIREG_ARGS
731 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
732 unsigned secondAllocatedRegArgNum = 0;
733 var_types firstEightByteType = TYP_UNDEF;
734 var_types secondEightByteType = TYP_UNDEF;
736 if (varTypeIsStruct(argType))
738 if (structDesc.eightByteCount >= 1)
740 firstEightByteType = GetEightByteType(structDesc, 0);
741 firstAllocatedRegArgNum = varDscInfo->allocRegArg(firstEightByteType, 1);
745 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
747 firstAllocatedRegArgNum = varDscInfo->allocRegArg(argType, cSlots);
752 // We need to save the fact that this HFA is enregistered
753 varDsc->lvSetIsHfa();
754 varDsc->lvSetIsHfaRegArg();
755 varDsc->SetHfaType(hfaType);
756 varDsc->lvIsMultiRegArg = (varDsc->lvHfaSlots() > 1);
759 varDsc->lvIsRegArg = 1;
761 #if FEATURE_MULTIREG_ARGS
762 if (varTypeIsStruct(argType))
764 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
765 varDsc->lvArgReg = genMapRegArgNumToRegNum(firstAllocatedRegArgNum, firstEightByteType);
767 // If there is a second eightbyte, get a register for it too and map the arg to the reg number.
768 if (structDesc.eightByteCount >= 2)
770 secondEightByteType = GetEightByteType(structDesc, 1);
771 secondAllocatedRegArgNum = varDscInfo->allocRegArg(secondEightByteType, 1);
774 if (secondEightByteType != TYP_UNDEF)
776 varDsc->lvOtherArgReg = genMapRegArgNumToRegNum(secondAllocatedRegArgNum, secondEightByteType);
777 varDsc->addPrefReg(genRegMask(varDsc->lvOtherArgReg), this);
779 #else // ARM32 or ARM64
780 varDsc->lvArgReg = genMapRegArgNumToRegNum(firstAllocatedRegArgNum, TYP_I_IMPL);
781 #ifdef _TARGET_ARM64_
784 varDsc->lvOtherArgReg = genMapRegArgNumToRegNum(firstAllocatedRegArgNum + 1, TYP_I_IMPL);
785 varDsc->addPrefReg(genRegMask(varDsc->lvOtherArgReg), this);
787 #endif // _TARGET_ARM64_
788 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
791 #endif // FEATURE_MULTIREG_ARGS
793 varDsc->lvArgReg = genMapRegArgNumToRegNum(firstAllocatedRegArgNum, argType);
796 varDsc->setPrefReg(varDsc->lvArgReg, this);
799 if (varDsc->TypeGet() == TYP_LONG)
801 varDsc->lvOtherReg = genMapRegArgNumToRegNum(firstAllocatedRegArgNum + 1, TYP_INT);
802 varDsc->addPrefReg(genRegMask(varDsc->lvOtherReg), this);
804 #endif // _TARGET_ARM_
809 printf("Arg #%u passed in register(s) ", varDscInfo->varNum);
810 bool isFloat = false;
811 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
812 // In case of one eightbyte struct the type is already normalized earlier.
813 // The varTypeIsFloating(argType) is good for this case.
814 if (varTypeIsStruct(argType) && (structDesc.eightByteCount >= 1))
816 isFloat = varTypeIsFloating(firstEightByteType);
819 #else // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
821 isFloat = varTypeIsFloating(argType);
823 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
825 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
826 if (varTypeIsStruct(argType))
828 // Print both registers, just to be clear
829 if (firstEightByteType == TYP_UNDEF)
831 printf("firstEightByte: <not used>");
835 printf("firstEightByte: %s",
836 getRegName(genMapRegArgNumToRegNum(firstAllocatedRegArgNum, firstEightByteType),
840 if (secondEightByteType == TYP_UNDEF)
842 printf(", secondEightByte: <not used>");
846 printf(", secondEightByte: %s",
847 getRegName(genMapRegArgNumToRegNum(secondAllocatedRegArgNum, secondEightByteType),
848 varTypeIsFloating(secondEightByteType)));
852 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
854 unsigned regArgNum = genMapRegNumToRegArgNum(varDsc->lvArgReg, argType);
856 for (unsigned ix = 0; ix < cSlots; ix++, regArgNum++)
863 if (!isFloat && (regArgNum >= varDscInfo->maxIntRegArgNum)) // a struct has been split between
864 // registers and stack
866 printf(" stack slots:%d", cSlots - ix);
873 // Print register size prefix
874 if (argType == TYP_DOUBLE)
876 // Print both registers, just to be clear
877 printf("%s/%s", getRegName(genMapRegArgNumToRegNum(regArgNum, argType), isFloat),
878 getRegName(genMapRegArgNumToRegNum(regArgNum + 1, argType), isFloat));
880 // doubles take 2 slots
881 assert(ix + 1 < cSlots);
887 printf("%s", getRegName(genMapRegArgNumToRegNum(regArgNum, argType), isFloat));
891 #endif // _TARGET_ARM_
893 printf("%s", getRegName(genMapRegArgNumToRegNum(regArgNum, argType), isFloat));
900 } // end if (canPassArgInRegisters)
903 #if defined(_TARGET_ARM_)
905 varDscInfo->setAllRegArgUsed(argType);
906 if (varTypeIsFloating(argType))
908 varDscInfo->setAnyFloatStackArgs();
911 #elif defined(_TARGET_ARM64_)
913 // If we needed to use the stack in order to pass this argument then
914 // record the fact that we have used up any remaining registers of this 'type'
915 // This prevents any 'backfilling' from occuring on ARM64
917 varDscInfo->setAllRegArgUsed(argType);
919 #endif // _TARGET_XXX_
922 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
923 // The arg size is returning the number of bytes of the argument. For a struct it could return a size not a
924 // multiple of TARGET_POINTER_SIZE. The stack allocated space should always be multiple of TARGET_POINTER_SIZE,
926 compArgSize += (unsigned)roundUp(argSize, TARGET_POINTER_SIZE);
927 #else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
928 compArgSize += argSize;
929 #endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
930 if (info.compIsVarArgs || isHfaArg || isSoftFPPreSpill)
932 #if defined(_TARGET_X86_)
933 varDsc->lvStkOffs = compArgSize;
934 #else // !_TARGET_X86_
935 // TODO-CQ: We shouldn't have to go as far as to declare these
936 // address-exposed -- DoNotEnregister should suffice.
937 lvaSetVarAddrExposed(varDscInfo->varNum);
938 #endif // !_TARGET_X86_
940 } // for each user arg
943 if (doubleAlignMask != RBM_NONE)
945 assert(RBM_ARG_REGS == 0xF);
946 assert((doubleAlignMask & RBM_ARG_REGS) == doubleAlignMask);
947 if (doubleAlignMask != RBM_NONE && doubleAlignMask != RBM_ARG_REGS)
949 // doubleAlignMask can only be 0011 and/or 1100 as 'double aligned types' can
950 // begin at r0 or r2.
951 assert(doubleAlignMask == 0x3 || doubleAlignMask == 0xC /* || 0xF is if'ed out */);
953 // Now if doubleAlignMask is 0011 i.e., {r0,r1} and we prespill r2 or r3
954 // but not both, then the stack would be misaligned for r0. So spill both
957 // ; +0 --- caller SP double aligned ----
960 // ; -c r0 r0 <-- misaligned.
961 // ; callee saved regs
962 if (doubleAlignMask == 0x3 && doubleAlignMask != codeGen->regSet.rsMaskPreSpillRegArg)
964 codeGen->regSet.rsMaskPreSpillAlign =
965 (~codeGen->regSet.rsMaskPreSpillRegArg & ~doubleAlignMask) & RBM_ARG_REGS;
969 #endif // _TARGET_ARM_
972 /*****************************************************************************/
973 void Compiler::lvaInitGenericsCtxt(InitVarDscInfo* varDscInfo)
975 //@GENERICS: final instantiation-info argument for shared generic methods
976 // and shared generic struct instance methods
977 if (info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE)
979 info.compTypeCtxtArg = varDscInfo->varNum;
981 LclVarDsc* varDsc = varDscInfo->varDsc;
982 varDsc->lvIsParam = 1;
984 varDsc->lvSingleDef = 1;
987 varDsc->lvType = TYP_I_IMPL;
989 if (varDscInfo->canEnreg(TYP_I_IMPL))
991 /* Another register argument */
993 varDsc->lvIsRegArg = 1;
994 varDsc->lvArgReg = genMapRegArgNumToRegNum(varDscInfo->regArgNum(TYP_INT), varDsc->TypeGet());
995 #if FEATURE_MULTIREG_ARGS
996 varDsc->lvOtherArgReg = REG_NA;
998 varDsc->setPrefReg(varDsc->lvArgReg, this);
999 varDsc->lvOnFrame = true; // The final home for this incoming register might be our local stack frame
1001 varDscInfo->intRegArgNum++;
1006 printf("'GenCtxt' passed in register %s\n", getRegName(varDsc->lvArgReg));
1010 #ifndef LEGACY_BACKEND
1013 // For the RyuJIT backend, we need to mark these as being on the stack,
1014 // as this is not done elsewhere in the case that canEnreg returns false.
1015 varDsc->lvOnFrame = true;
1017 #endif // !LEGACY_BACKEND
1019 compArgSize += TARGET_POINTER_SIZE;
1021 #if defined(_TARGET_X86_)
1022 if (info.compIsVarArgs)
1023 varDsc->lvStkOffs = compArgSize;
1024 #endif // _TARGET_X86_
1026 varDscInfo->varNum++;
1027 varDscInfo->varDsc++;
1031 /*****************************************************************************/
1032 void Compiler::lvaInitVarArgsHandle(InitVarDscInfo* varDscInfo)
1034 if (info.compIsVarArgs)
1036 lvaVarargsHandleArg = varDscInfo->varNum;
1038 LclVarDsc* varDsc = varDscInfo->varDsc;
1039 varDsc->lvType = TYP_I_IMPL;
1040 varDsc->lvIsParam = 1;
1041 // Make sure this lives in the stack -- address may be reported to the VM.
1042 // TODO-CQ: This should probably be:
1043 // lvaSetVarDoNotEnregister(varDscInfo->varNum DEBUGARG(DNER_VMNeedsStackAddr));
1044 // But that causes problems, so, for expedience, I switched back to this heavyweight
1045 // hammer. But I think it should be possible to switch; it may just work now
1046 // that other problems are fixed.
1047 lvaSetVarAddrExposed(varDscInfo->varNum);
1050 varDsc->lvSingleDef = 1;
1053 if (varDscInfo->canEnreg(TYP_I_IMPL))
1055 /* Another register argument */
1057 unsigned varArgHndArgNum = varDscInfo->allocRegArg(TYP_I_IMPL);
1059 varDsc->lvIsRegArg = 1;
1060 varDsc->lvArgReg = genMapRegArgNumToRegNum(varArgHndArgNum, TYP_I_IMPL);
1061 #if FEATURE_MULTIREG__ARGS
1062 varDsc->lvOtherArgReg = REG_NA;
1064 varDsc->setPrefReg(varDsc->lvArgReg, this);
1065 varDsc->lvOnFrame = true; // The final home for this incoming register might be our local stack frame
1067 // This has to be spilled right in front of the real arguments and we have
1068 // to pre-spill all the argument registers explicitly because we only have
1069 // have symbols for the declared ones, not any potential variadic ones.
1070 for (unsigned ix = varArgHndArgNum; ix < ArrLen(intArgMasks); ix++)
1072 codeGen->regSet.rsMaskPreSpillRegArg |= intArgMasks[ix];
1074 #endif // _TARGET_ARM_
1079 printf("'VarArgHnd' passed in register %s\n", getRegName(varDsc->lvArgReg));
1083 #ifndef LEGACY_BACKEND
1086 // For the RyuJIT backend, we need to mark these as being on the stack,
1087 // as this is not done elsewhere in the case that canEnreg returns false.
1088 varDsc->lvOnFrame = true;
1090 #endif // !LEGACY_BACKEND
1092 /* Update the total argument size, count and varDsc */
1094 compArgSize += TARGET_POINTER_SIZE;
1096 varDscInfo->varNum++;
1097 varDscInfo->varDsc++;
1099 #if defined(_TARGET_X86_)
1100 varDsc->lvStkOffs = compArgSize;
1102 // Allocate a temp to point at the beginning of the args
1104 lvaVarargsBaseOfStkArgs = lvaGrabTemp(false DEBUGARG("Varargs BaseOfStkArgs"));
1105 lvaTable[lvaVarargsBaseOfStkArgs].lvType = TYP_I_IMPL;
1107 #endif // _TARGET_X86_
1111 /*****************************************************************************/
1112 void Compiler::lvaInitVarDsc(LclVarDsc* varDsc,
1114 CorInfoType corInfoType,
1115 CORINFO_CLASS_HANDLE typeHnd,
1116 CORINFO_ARG_LIST_HANDLE varList,
1117 CORINFO_SIG_INFO* varSig)
1119 noway_assert(varDsc == &lvaTable[varNum]);
1121 switch (corInfoType)
1123 // Mark types that looks like a pointer for doing shadow-copying of
1124 // parameters if we have an unsafe buffer.
1125 // Note that this does not handle structs with pointer fields. Instead,
1126 // we rely on using the assign-groups/equivalence-groups in
1127 // gsFindVulnerableParams() to determine if a buffer-struct contains a
1128 // pointer. We could do better by having the EE determine this for us.
1129 // Note that we want to keep buffers without pointers at lower memory
1130 // addresses than buffers with pointers.
1131 case CORINFO_TYPE_PTR:
1132 case CORINFO_TYPE_BYREF:
1133 case CORINFO_TYPE_CLASS:
1134 case CORINFO_TYPE_STRING:
1135 case CORINFO_TYPE_VAR:
1136 case CORINFO_TYPE_REFANY:
1137 varDsc->lvIsPtr = 1;
1143 var_types type = JITtype2varType(corInfoType);
1144 if (varTypeIsFloating(type))
1146 compFloatingPointUsed = true;
1149 if (tiVerificationNeeded)
1151 varDsc->lvVerTypeInfo = verParseArgSigToTypeInfo(varSig, varList);
1154 if (tiVerificationNeeded)
1156 if (varDsc->lvIsParam)
1158 // For an incoming ValueType we better be able to have the full type information
1159 // so that we can layout the parameter offsets correctly
1161 if (varTypeIsStruct(type) && varDsc->lvVerTypeInfo.IsDead())
1163 BADCODE("invalid ValueType parameter");
1166 // For an incoming reference type we need to verify that the actual type is
1167 // a reference type and not a valuetype.
1169 if (type == TYP_REF &&
1170 !(varDsc->lvVerTypeInfo.IsType(TI_REF) || varDsc->lvVerTypeInfo.IsUnboxedGenericTypeVar()))
1172 BADCODE("parameter type mismatch");
1176 // Disallow byrefs to byref like objects (ArgTypeHandle)
1177 // techncally we could get away with just not setting them
1178 if (varDsc->lvVerTypeInfo.IsByRef() && verIsByRefLike(DereferenceByRef(varDsc->lvVerTypeInfo)))
1180 varDsc->lvVerTypeInfo = typeInfo();
1183 // we don't want the EE to assert in lvaSetStruct on bad sigs, so change
1184 // the JIT type to avoid even trying to call back
1185 if (varTypeIsStruct(type) && varDsc->lvVerTypeInfo.IsDead())
1193 unsigned cFlags = info.compCompHnd->getClassAttribs(typeHnd);
1195 // We can get typeHnds for primitive types, these are value types which only contain
1196 // a primitive. We will need the typeHnd to distinguish them, so we store it here.
1197 if ((cFlags & CORINFO_FLG_VALUECLASS) && !varTypeIsStruct(type))
1199 if (tiVerificationNeeded == false)
1201 // printf("This is a struct that the JIT will treat as a primitive\n");
1202 varDsc->lvVerTypeInfo = verMakeTypeInfo(typeHnd);
1206 varDsc->lvOverlappingFields = StructHasOverlappingFields(cFlags);
1209 if (varTypeIsGC(type))
1211 varDsc->lvStructGcCount = 1;
1214 // Set the lvType (before this point it is TYP_UNDEF).
1215 if ((varTypeIsStruct(type)))
1217 lvaSetStruct(varNum, typeHnd, typeHnd != nullptr, !tiVerificationNeeded);
1221 varDsc->lvType = type;
1225 if (type == TYP_BOOL)
1227 varDsc->lvIsBoolean = true;
1232 varDsc->lvStkOffs = BAD_STK_OFFS;
1236 /*****************************************************************************
1237 * Returns our internal varNum for a given IL variable.
1238 * Asserts assume it is called after lvaTable[] has been set up.
1241 unsigned Compiler::compMapILvarNum(unsigned ILvarNum)
1243 noway_assert(ILvarNum < info.compILlocalsCount || ILvarNum > unsigned(ICorDebugInfo::UNKNOWN_ILNUM));
1247 if (ILvarNum == (unsigned)ICorDebugInfo::VARARGS_HND_ILNUM)
1249 // The varargs cookie is the last argument in lvaTable[]
1250 noway_assert(info.compIsVarArgs);
1252 varNum = lvaVarargsHandleArg;
1253 noway_assert(lvaTable[varNum].lvIsParam);
1255 else if (ILvarNum == (unsigned)ICorDebugInfo::RETBUF_ILNUM)
1257 noway_assert(info.compRetBuffArg != BAD_VAR_NUM);
1258 varNum = info.compRetBuffArg;
1260 else if (ILvarNum == (unsigned)ICorDebugInfo::TYPECTXT_ILNUM)
1262 noway_assert(info.compTypeCtxtArg >= 0);
1263 varNum = unsigned(info.compTypeCtxtArg);
1265 else if (ILvarNum < info.compILargsCount)
1268 varNum = compMapILargNum(ILvarNum);
1269 noway_assert(lvaTable[varNum].lvIsParam);
1271 else if (ILvarNum < info.compILlocalsCount)
1274 unsigned lclNum = ILvarNum - info.compILargsCount;
1275 varNum = info.compArgsCount + lclNum;
1276 noway_assert(!lvaTable[varNum].lvIsParam);
1283 noway_assert(varNum < info.compLocalsCount);
1287 /*****************************************************************************
1288 * Returns the IL variable number given our internal varNum.
1289 * Special return values are VARG_ILNUM, RETBUF_ILNUM, TYPECTXT_ILNUM.
1291 * Returns UNKNOWN_ILNUM if it can't be mapped.
1294 unsigned Compiler::compMap2ILvarNum(unsigned varNum)
1296 if (compIsForInlining())
1298 return impInlineInfo->InlinerCompiler->compMap2ILvarNum(varNum);
1301 noway_assert(varNum < lvaCount);
1303 if (varNum == info.compRetBuffArg)
1305 return (unsigned)ICorDebugInfo::RETBUF_ILNUM;
1308 // Is this a varargs function?
1309 if (info.compIsVarArgs && varNum == lvaVarargsHandleArg)
1311 return (unsigned)ICorDebugInfo::VARARGS_HND_ILNUM;
1314 // We create an extra argument for the type context parameter
1315 // needed for shared generic code.
1316 if ((info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE) && varNum == (unsigned)info.compTypeCtxtArg)
1318 return (unsigned)ICorDebugInfo::TYPECTXT_ILNUM;
1321 // Now mutate varNum to remove extra parameters from the count.
1322 if ((info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE) && varNum > (unsigned)info.compTypeCtxtArg)
1327 if (info.compIsVarArgs && varNum > lvaVarargsHandleArg)
1332 /* Is there a hidden argument for the return buffer.
1333 Note that this code works because if the RetBuffArg is not present,
1334 compRetBuffArg will be BAD_VAR_NUM */
1335 if (info.compRetBuffArg != BAD_VAR_NUM && varNum > info.compRetBuffArg)
1340 if (varNum >= info.compLocalsCount)
1342 return (unsigned)ICorDebugInfo::UNKNOWN_ILNUM; // Cannot be mapped
1348 /*****************************************************************************
1349 * Returns true if variable "varNum" may be address-exposed.
1352 bool Compiler::lvaVarAddrExposed(unsigned varNum)
1354 noway_assert(varNum < lvaCount);
1355 LclVarDsc* varDsc = &lvaTable[varNum];
1357 return varDsc->lvAddrExposed;
1360 /*****************************************************************************
1361 * Returns true iff variable "varNum" should not be enregistered (or one of several reasons).
1364 bool Compiler::lvaVarDoNotEnregister(unsigned varNum)
1366 noway_assert(varNum < lvaCount);
1367 LclVarDsc* varDsc = &lvaTable[varNum];
1369 return varDsc->lvDoNotEnregister;
1372 /*****************************************************************************
1373 * Returns the handle to the class of the local variable varNum
1376 CORINFO_CLASS_HANDLE Compiler::lvaGetStruct(unsigned varNum)
1378 noway_assert(varNum < lvaCount);
1379 LclVarDsc* varDsc = &lvaTable[varNum];
1381 return varDsc->lvVerTypeInfo.GetClassHandleForValueClass();
1384 /*****************************************************************************
1386 * Compare function passed to qsort() by Compiler::lvaCanPromoteStructVar().
1390 int __cdecl Compiler::lvaFieldOffsetCmp(const void* field1, const void* field2)
1392 lvaStructFieldInfo* pFieldInfo1 = (lvaStructFieldInfo*)field1;
1393 lvaStructFieldInfo* pFieldInfo2 = (lvaStructFieldInfo*)field2;
1395 if (pFieldInfo1->fldOffset == pFieldInfo2->fldOffset)
1401 return (pFieldInfo1->fldOffset > pFieldInfo2->fldOffset) ? +1 : -1;
1405 /*****************************************************************************
1406 * Is this type promotable? */
1408 void Compiler::lvaCanPromoteStructType(CORINFO_CLASS_HANDLE typeHnd,
1409 lvaStructPromotionInfo* StructPromotionInfo,
1412 assert(eeIsValueClass(typeHnd));
1414 if (typeHnd != StructPromotionInfo->typeHnd)
1416 // sizeof(double) represents the size of the largest primitive type that we can struct promote
1417 // In the future this may be changing to XMM_REGSIZE_BYTES
1418 const int MaxOffset = MAX_NumOfFieldsInPromotableStruct * sizeof(double); // must be a compile time constant
1420 assert((BYTE)MaxOffset == MaxOffset); // because lvaStructFieldInfo.fldOffset is byte-sized
1421 assert((BYTE)MAX_NumOfFieldsInPromotableStruct ==
1422 MAX_NumOfFieldsInPromotableStruct); // because lvaStructFieldInfo.fieldCnt is byte-sized
1424 bool requiresScratchVar = false;
1425 bool containsHoles = false;
1426 bool customLayout = false;
1427 bool containsGCpointers = false;
1429 StructPromotionInfo->typeHnd = typeHnd;
1430 StructPromotionInfo->canPromote = false;
1432 unsigned structSize = info.compCompHnd->getClassSize(typeHnd);
1433 if (structSize >= MaxOffset)
1435 return; // struct is too large
1438 unsigned fieldCnt = info.compCompHnd->getClassNumInstanceFields(typeHnd);
1439 if (fieldCnt == 0 || fieldCnt > MAX_NumOfFieldsInPromotableStruct)
1441 return; // struct must have between 1 and MAX_NumOfFieldsInPromotableStruct fields
1444 StructPromotionInfo->fieldCnt = (BYTE)fieldCnt;
1445 DWORD typeFlags = info.compCompHnd->getClassAttribs(typeHnd);
1447 bool treatAsOverlapping = StructHasOverlappingFields(typeFlags);
1449 #if 1 // TODO-Cleanup: Consider removing this entire #if block in the future
1451 // This method has two callers. The one in Importer.cpp passes sortFields == false
1452 // and the other passes sortFields == true.
1453 // This is a workaround that leaves the inlining behavior the same as before while still
1454 // performing extra struct promotions when compiling the method.
1456 // The x86 legacy back-end can't handle the more general RyuJIT struct promotion (notably structs
1457 // with holes), in genPushArgList(), so in that case always check for custom layout.
1458 #if FEATURE_FIXED_OUT_ARGS || !defined(LEGACY_BACKEND)
1459 if (!sortFields) // the condition "!sortFields" really means "we are inlining"
1462 treatAsOverlapping = StructHasCustomLayout(typeFlags);
1466 if (treatAsOverlapping)
1471 // Don't struct promote if we have an CUSTOMLAYOUT flag on an HFA type
1472 if (StructHasCustomLayout(typeFlags) && IsHfa(typeHnd))
1478 // On ARM, we have a requirement on the struct alignment; see below.
1479 unsigned structAlignment =
1480 roundUp(info.compCompHnd->getClassAlignmentRequirement(typeHnd), TARGET_POINTER_SIZE);
1481 #endif // _TARGET_ARM
1483 bool isHole[MaxOffset]; // isHole[] is initialized to true for every valid offset in the struct and false for
1485 unsigned i; // then as we process the fields we clear the isHole[] values that the field spans.
1486 for (i = 0; i < MaxOffset; i++)
1488 isHole[i] = (i < structSize) ? true : false;
1491 for (BYTE ordinal = 0; ordinal < fieldCnt; ++ordinal)
1493 lvaStructFieldInfo* pFieldInfo = &StructPromotionInfo->fields[ordinal];
1494 pFieldInfo->fldHnd = info.compCompHnd->getFieldInClass(typeHnd, ordinal);
1495 unsigned fldOffset = info.compCompHnd->getFieldOffset(pFieldInfo->fldHnd);
1497 // The fldOffset value should never be larger than our structSize.
1498 if (fldOffset >= structSize)
1500 noway_assert(false);
1504 pFieldInfo->fldOffset = (BYTE)fldOffset;
1505 pFieldInfo->fldOrdinal = ordinal;
1506 CorInfoType corType = info.compCompHnd->getFieldType(pFieldInfo->fldHnd, &pFieldInfo->fldTypeHnd);
1507 var_types varType = JITtype2varType(corType);
1508 pFieldInfo->fldType = varType;
1509 pFieldInfo->fldSize = genTypeSize(varType);
1511 if (varTypeIsGC(varType))
1513 containsGCpointers = true;
1516 if (pFieldInfo->fldSize == 0)
1518 // Non-primitive struct field. Don't promote.
1522 if ((pFieldInfo->fldOffset % pFieldInfo->fldSize) != 0)
1524 // The code in Compiler::genPushArgList that reconstitutes
1525 // struct values on the stack from promoted fields expects
1526 // those fields to be at their natural alignment.
1530 // The end offset for this field should never be larger than our structSize.
1531 noway_assert(fldOffset + pFieldInfo->fldSize <= structSize);
1533 for (i = 0; i < pFieldInfo->fldSize; i++)
1535 isHole[fldOffset + i] = false;
1539 // On ARM, for struct types that don't use explicit layout, the alignment of the struct is
1540 // at least the max alignment of its fields. We take advantage of this invariant in struct promotion,
1541 // so verify it here.
1542 if (pFieldInfo->fldSize > structAlignment)
1544 // Don't promote vars whose struct types violates the invariant. (Alignment == size for primitives.)
1547 // If we have any small fields we will allocate a single PromotedStructScratch local var for the method.
1548 // This is a stack area that we use to assemble the small fields in order to place them in a register
1551 if (pFieldInfo->fldSize < TARGET_POINTER_SIZE)
1553 requiresScratchVar = true;
1555 #endif // _TARGET_ARM_
1558 // If we saw any GC pointer fields above then the CORINFO_FLG_CONTAINS_GC_PTR has to be set!
1559 noway_assert((containsGCpointers == false) || ((typeFlags & CORINFO_FLG_CONTAINS_GC_PTR) != 0));
1561 // If we have "Custom Layout" then we might have an explicit Size attribute
1562 // Managed C++ uses this for its structs, such C++ types will not contain GC pointers.
1564 // The current VM implementation also incorrectly sets the CORINFO_FLG_CUSTOMLAYOUT
1565 // whenever a managed value class contains any GC pointers.
1566 // (See the comment for VMFLAG_NOT_TIGHTLY_PACKED in class.h)
1568 // It is important to struct promote managed value classes that have GC pointers
1569 // So we compute the correct value for "CustomLayout" here
1571 if (StructHasCustomLayout(typeFlags) && ((typeFlags & CORINFO_FLG_CONTAINS_GC_PTR) == 0))
1573 customLayout = true;
1576 // Check if this promoted struct contains any holes
1578 for (i = 0; i < structSize; i++)
1582 containsHoles = true;
1587 // Cool, this struct is promotable.
1588 StructPromotionInfo->canPromote = true;
1589 StructPromotionInfo->requiresScratchVar = requiresScratchVar;
1590 StructPromotionInfo->containsHoles = containsHoles;
1591 StructPromotionInfo->customLayout = customLayout;
1595 // Sort the fields according to the increasing order of the field offset.
1596 // This is needed because the fields need to be pushed on stack (when referenced
1597 // as a struct) in order.
1598 qsort(StructPromotionInfo->fields, StructPromotionInfo->fieldCnt, sizeof(*StructPromotionInfo->fields),
1604 // Asking for the same type of struct as the last time.
1605 // Nothing need to be done.
1610 /*****************************************************************************
1611 * Is this struct type local variable promotable? */
1613 void Compiler::lvaCanPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo)
1615 noway_assert(lclNum < lvaCount);
1617 LclVarDsc* varDsc = &lvaTable[lclNum];
1619 noway_assert(varTypeIsStruct(varDsc));
1620 noway_assert(!varDsc->lvPromoted); // Don't ask again :)
1623 // If this lclVar is used in a SIMD intrinsic, then we don't want to struct promote it.
1624 // Note, however, that SIMD lclVars that are NOT used in a SIMD intrinsic may be
1625 // profitably promoted.
1626 if (varDsc->lvIsUsedInSIMDIntrinsic())
1628 StructPromotionInfo->canPromote = false;
1634 // TODO-PERF - Allow struct promotion for HFA register arguments
1636 // Explicitly check for HFA reg args and reject them for promotion here.
1637 // Promoting HFA args will fire an assert in lvaAssignFrameOffsets
1638 // when the HFA reg arg is struct promoted.
1640 if (varDsc->lvIsHfaRegArg())
1642 StructPromotionInfo->canPromote = false;
1646 CORINFO_CLASS_HANDLE typeHnd = varDsc->lvVerTypeInfo.GetClassHandle();
1647 lvaCanPromoteStructType(typeHnd, StructPromotionInfo, true);
1650 /*****************************************************************************
1651 * Promote a struct type local */
1653 void Compiler::lvaPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo)
1655 LclVarDsc* varDsc = &lvaTable[lclNum];
1657 // We should never see a reg-sized non-field-addressed struct here.
1658 noway_assert(!varDsc->lvRegStruct);
1660 noway_assert(StructPromotionInfo->canPromote);
1661 noway_assert(StructPromotionInfo->typeHnd == varDsc->lvVerTypeInfo.GetClassHandle());
1663 varDsc->lvFieldCnt = StructPromotionInfo->fieldCnt;
1664 varDsc->lvFieldLclStart = lvaCount;
1665 varDsc->lvPromoted = true;
1666 varDsc->lvContainsHoles = StructPromotionInfo->containsHoles;
1667 varDsc->lvCustomLayout = StructPromotionInfo->customLayout;
1670 // Don't change the source to a TYP_BLK either.
1671 varDsc->lvKeepType = 1;
1677 printf("\nPromoting struct local V%02u (%s):", lclNum, eeGetClassName(StructPromotionInfo->typeHnd));
1681 for (unsigned index = 0; index < StructPromotionInfo->fieldCnt; ++index)
1683 lvaStructFieldInfo* pFieldInfo = &StructPromotionInfo->fields[index];
1685 if (varTypeIsFloating(pFieldInfo->fldType))
1687 lvaTable[lclNum].lvContainsFloatingFields = 1;
1688 // Whenever we promote a struct that contains a floating point field
1689 // it's possible we transition from a method that originally only had integer
1690 // local vars to start having FP. We have to communicate this through this flag
1691 // since LSRA later on will use this flag to determine whether or not to track FP register sets.
1692 compFloatingPointUsed = true;
1695 // Now grab the temp for the field local.
1699 char* bufp = &buf[0];
1701 sprintf_s(bufp, sizeof(buf), "%s V%02u.%s (fldOffset=0x%x)", "field", lclNum,
1702 eeGetFieldName(pFieldInfo->fldHnd), pFieldInfo->fldOffset);
1706 noway_assert(pFieldInfo->fldOffset > (pFieldInfo - 1)->fldOffset);
1710 unsigned varNum = lvaGrabTemp(false DEBUGARG(bufp)); // Lifetime of field locals might span multiple BBs, so
1711 // they are long lifetime temps.
1713 LclVarDsc* fieldVarDsc = &lvaTable[varNum];
1714 fieldVarDsc->lvType = pFieldInfo->fldType;
1715 fieldVarDsc->lvExactSize = pFieldInfo->fldSize;
1716 fieldVarDsc->lvIsStructField = true;
1717 fieldVarDsc->lvFldOffset = pFieldInfo->fldOffset;
1718 fieldVarDsc->lvFldOrdinal = pFieldInfo->fldOrdinal;
1719 fieldVarDsc->lvParentLcl = lclNum;
1720 fieldVarDsc->lvIsParam = varDsc->lvIsParam;
1721 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1722 // Do we have a parameter that can be enregistered?
1724 if (varDsc->lvIsRegArg)
1726 fieldVarDsc->lvIsRegArg = true;
1727 fieldVarDsc->lvArgReg = varDsc->lvArgReg;
1728 fieldVarDsc->setPrefReg(varDsc->lvArgReg, this); // Set the preferred register
1730 lvaMarkRefsWeight = BB_UNITY_WEIGHT; // incRefCnts can use this compiler global variable
1731 fieldVarDsc->incRefCnts(BB_UNITY_WEIGHT, this); // increment the ref count for prolog initialization
1736 // This temporary should not be converted to a double in stress mode,
1737 // because we introduce assigns to it after the stress conversion
1738 fieldVarDsc->lvKeepType = 1;
1743 #if !defined(LEGACY_BACKEND) && !defined(_TARGET_64BIT_)
1744 //------------------------------------------------------------------------
1745 // lvaPromoteLongVars: "Struct promote" all register candidate longs as if they are structs of two ints.
1753 void Compiler::lvaPromoteLongVars()
1755 if ((opts.compFlags & CLFLG_REGVAR) == 0)
1759 // The lvaTable might grow as we grab temps. Make a local copy here.
1760 unsigned startLvaCount = lvaCount;
1761 for (unsigned lclNum = 0; lclNum < startLvaCount; lclNum++)
1763 LclVarDsc* varDsc = &lvaTable[lclNum];
1764 if (!varTypeIsLong(varDsc) || varDsc->lvDoNotEnregister || varDsc->lvIsMultiRegArgOrRet() ||
1765 (varDsc->lvRefCnt == 0) || varDsc->lvIsStructField)
1770 varDsc->lvFieldCnt = 2;
1771 varDsc->lvFieldLclStart = lvaCount;
1772 varDsc->lvPromoted = true;
1773 varDsc->lvContainsHoles = false;
1778 printf("\nPromoting long local V%02u:", lclNum);
1782 bool isParam = varDsc->lvIsParam;
1784 for (unsigned index = 0; index < 2; ++index)
1786 // Grab the temp for the field local.
1787 CLANG_FORMAT_COMMENT_ANCHOR;
1791 char* bufp = &buf[0];
1793 sprintf_s(bufp, sizeof(buf), "%s V%02u.%s (fldOffset=0x%x)", "field", lclNum, index == 0 ? "lo" : "hi",
1796 unsigned varNum = lvaGrabTemp(false DEBUGARG(bufp)); // Lifetime of field locals might span multiple BBs, so
1797 // they are long lifetime temps.
1799 LclVarDsc* fieldVarDsc = &lvaTable[varNum];
1800 fieldVarDsc->lvType = TYP_INT;
1801 fieldVarDsc->lvExactSize = genTypeSize(TYP_INT);
1802 fieldVarDsc->lvIsStructField = true;
1803 fieldVarDsc->lvFldOffset = (unsigned char)(index * genTypeSize(TYP_INT));
1804 fieldVarDsc->lvFldOrdinal = (unsigned char)index;
1805 fieldVarDsc->lvParentLcl = lclNum;
1806 fieldVarDsc->lvIsParam = isParam;
1813 printf("\nlvaTable after lvaPromoteLongVars\n");
1818 #endif // !defined(LEGACY_BACKEND) && !defined(_TARGET_64BIT_)
1820 /*****************************************************************************
1821 * Given a fldOffset in a promoted struct var, return the index of the local
1822 that represents this field.
1825 unsigned Compiler::lvaGetFieldLocal(LclVarDsc* varDsc, unsigned int fldOffset)
1827 noway_assert(varTypeIsStruct(varDsc));
1828 noway_assert(varDsc->lvPromoted);
1830 for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
1832 noway_assert(lvaTable[i].lvIsStructField);
1833 noway_assert(lvaTable[i].lvParentLcl == (unsigned)(varDsc - lvaTable));
1834 if (lvaTable[i].lvFldOffset == fldOffset)
1840 // This is the not-found error return path, the caller should check for BAD_VAR_NUM
1844 /*****************************************************************************
1846 * Set the local var "varNum" as address-exposed.
1847 * If this is a promoted struct, label it's fields the same way.
1850 void Compiler::lvaSetVarAddrExposed(unsigned varNum)
1852 noway_assert(varNum < lvaCount);
1854 LclVarDsc* varDsc = &lvaTable[varNum];
1856 varDsc->lvAddrExposed = 1;
1858 if (varDsc->lvPromoted)
1860 noway_assert(varTypeIsStruct(varDsc));
1862 for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
1864 noway_assert(lvaTable[i].lvIsStructField);
1865 lvaTable[i].lvAddrExposed = 1; // Make field local as address-exposed.
1866 lvaSetVarDoNotEnregister(i DEBUGARG(DNER_AddrExposed));
1870 lvaSetVarDoNotEnregister(varNum DEBUGARG(DNER_AddrExposed));
1873 /*****************************************************************************
1875 * Record that the local var "varNum" should not be enregistered (for one of several reasons.)
1878 void Compiler::lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregisterReason reason))
1880 noway_assert(varNum < lvaCount);
1881 LclVarDsc* varDsc = &lvaTable[varNum];
1882 varDsc->lvDoNotEnregister = 1;
1887 printf("\nLocal V%02u should not be enregistered because: ", varNum);
1891 case DNER_AddrExposed:
1892 JITDUMP("it is address exposed\n");
1893 assert(varDsc->lvAddrExposed);
1896 JITDUMP("it is a struct\n");
1897 assert(varTypeIsStruct(varDsc));
1900 JITDUMP("written in a block op\n");
1901 varDsc->lvLclBlockOpAddr = 1;
1903 case DNER_LocalField:
1904 JITDUMP("was accessed as a local field\n");
1905 varDsc->lvLclFieldExpr = 1;
1907 case DNER_VMNeedsStackAddr:
1908 JITDUMP("needs stack addr\n");
1909 varDsc->lvVMNeedsStackAddr = 1;
1911 case DNER_LiveInOutOfHandler:
1912 JITDUMP("live in/out of a handler\n");
1913 varDsc->lvLiveInOutOfHndlr = 1;
1915 case DNER_LiveAcrossUnmanagedCall:
1916 JITDUMP("live across unmanaged call\n");
1917 varDsc->lvLiveAcrossUCall = 1;
1919 #ifdef JIT32_GCENCODER
1920 case DNER_PinningRef:
1921 JITDUMP("pinning ref\n");
1922 assert(varDsc->lvPinned);
1932 // Returns true if this local var is a multireg struct
1933 bool Compiler::lvaIsMultiregStruct(LclVarDsc* varDsc)
1935 if (varDsc->TypeGet() == TYP_STRUCT)
1937 CORINFO_CLASS_HANDLE clsHnd = varDsc->lvVerTypeInfo.GetClassHandleForValueClass();
1938 structPassingKind howToPassStruct;
1940 var_types type = getArgTypeForStruct(clsHnd, &howToPassStruct, varDsc->lvExactSize);
1942 if (howToPassStruct == SPK_ByValueAsHfa)
1944 assert(type = TYP_STRUCT);
1948 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) || defined(_TARGET_ARM64_)
1949 if (howToPassStruct == SPK_ByValue)
1951 assert(type = TYP_STRUCT);
1959 /*****************************************************************************
1960 * Set the lvClass for a local variable of a struct type */
1962 void Compiler::lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool unsafeValueClsCheck, bool setTypeInfo)
1964 noway_assert(varNum < lvaCount);
1966 LclVarDsc* varDsc = &lvaTable[varNum];
1969 varDsc->lvVerTypeInfo = typeInfo(TI_STRUCT, typeHnd);
1972 // Set the type and associated info if we haven't already set it.
1973 var_types structType = varDsc->lvType;
1974 if (varDsc->lvType == TYP_UNDEF)
1976 varDsc->lvType = TYP_STRUCT;
1978 if (varDsc->lvExactSize == 0)
1980 varDsc->lvExactSize = info.compCompHnd->getClassSize(typeHnd);
1982 size_t lvSize = varDsc->lvSize();
1983 assert((lvSize % sizeof(void*)) ==
1984 0); // The struct needs to be a multiple of sizeof(void*) bytes for getClassGClayout() to be valid.
1985 varDsc->lvGcLayout = (BYTE*)compGetMemA((lvSize / sizeof(void*)) * sizeof(BYTE), CMK_LvaTable);
1987 var_types simdBaseType = TYP_UNKNOWN;
1988 varDsc->lvType = impNormStructType(typeHnd, varDsc->lvGcLayout, &numGCVars, &simdBaseType);
1990 // We only save the count of GC vars in a struct up to 7.
1995 varDsc->lvStructGcCount = numGCVars;
1997 if (simdBaseType != TYP_UNKNOWN)
1999 assert(varTypeIsSIMD(varDsc));
2000 varDsc->lvSIMDType = true;
2001 varDsc->lvBaseType = simdBaseType;
2003 #endif // FEATURE_SIMD
2005 // for structs that are small enough, we check and set lvIsHfa and lvHfaTypeIsFloat
2006 if (varDsc->lvExactSize <= MAX_PASS_MULTIREG_BYTES)
2008 var_types hfaType = GetHfaType(typeHnd); // set to float or double if it is an HFA, otherwise TYP_UNDEF
2009 if (varTypeIsFloating(hfaType))
2011 varDsc->_lvIsHfa = true;
2012 varDsc->lvSetHfaTypeIsFloat(hfaType == TYP_FLOAT);
2014 // hfa variables can never contain GC pointers
2015 assert(varDsc->lvStructGcCount == 0);
2016 // The size of this struct should be evenly divisible by 4 or 8
2017 assert((varDsc->lvExactSize % genTypeSize(hfaType)) == 0);
2018 // The number of elements in the HFA should fit into our MAX_ARG_REG_COUNT limit
2019 assert((varDsc->lvExactSize / genTypeSize(hfaType)) <= MAX_ARG_REG_COUNT);
2022 #endif // FEATURE_HFA
2026 assert(varDsc->lvExactSize != 0);
2028 assert(!varTypeIsSIMD(varDsc) || (varDsc->lvBaseType != TYP_UNKNOWN));
2029 #endif // FEATURE_SIMD
2032 #ifndef _TARGET_64BIT_
2033 bool fDoubleAlignHint = FALSE;
2035 fDoubleAlignHint = TRUE;
2038 if (info.compCompHnd->getClassAlignmentRequirement(typeHnd, fDoubleAlignHint) == 8)
2043 printf("Marking struct in V%02i with double align flag\n", varNum);
2046 varDsc->lvStructDoubleAlign = 1;
2048 #endif // not _TARGET_64BIT_
2050 unsigned classAttribs = info.compCompHnd->getClassAttribs(typeHnd);
2052 varDsc->lvOverlappingFields = StructHasOverlappingFields(classAttribs);
2054 // Check whether this local is an unsafe value type and requires GS cookie protection.
2055 // GS checks require the stack to be re-ordered, which can't be done with EnC.
2056 if (unsafeValueClsCheck && (classAttribs & CORINFO_FLG_UNSAFE_VALUECLASS) && !opts.compDbgEnC)
2058 setNeedsGSSecurityCookie();
2059 compGSReorderStackLayout = true;
2060 varDsc->lvIsUnsafeBuffer = true;
2064 /*****************************************************************************
2065 * Returns the array of BYTEs containing the GC layout information
2068 BYTE* Compiler::lvaGetGcLayout(unsigned varNum)
2070 noway_assert(varTypeIsStruct(lvaTable[varNum].lvType) && (lvaTable[varNum].lvExactSize >= TARGET_POINTER_SIZE));
2072 return lvaTable[varNum].lvGcLayout;
2075 /*****************************************************************************
2076 * Return the number of bytes needed for a local variable
2079 unsigned Compiler::lvaLclSize(unsigned varNum)
2081 noway_assert(varNum < lvaCount);
2083 var_types varType = lvaTable[varNum].TypeGet();
2089 return lvaTable[varNum].lvSize();
2092 #if FEATURE_FIXED_OUT_ARGS
2093 noway_assert(lvaOutgoingArgSpaceSize >= 0);
2094 noway_assert(varNum == lvaOutgoingArgSpaceVar);
2095 return lvaOutgoingArgSpaceSize;
2097 #else // FEATURE_FIXED_OUT_ARGS
2098 assert(!"Unknown size");
2099 NO_WAY("Target doesn't support TYP_LCLBLK");
2101 // Keep prefast happy
2104 #endif // FEATURE_FIXED_OUT_ARGS
2106 default: // This must be a primitive var. Fall out of switch statement
2109 #ifdef _TARGET_64BIT_
2110 // We only need this Quirk for _TARGET_64BIT_
2111 if (lvaTable[varNum].lvQuirkToLong)
2113 noway_assert(lvaTable[varNum].lvAddrExposed);
2114 return genTypeStSz(TYP_LONG) * sizeof(int); // return 8 (2 * 4)
2117 return genTypeStSz(varType) * sizeof(int);
2121 // Return the exact width of local variable "varNum" -- the number of bytes
2122 // you'd need to copy in order to overwrite the value.
2124 unsigned Compiler::lvaLclExactSize(unsigned varNum)
2126 noway_assert(varNum < lvaCount);
2128 var_types varType = lvaTable[varNum].TypeGet();
2134 return lvaTable[varNum].lvExactSize;
2137 #if FEATURE_FIXED_OUT_ARGS
2138 noway_assert(lvaOutgoingArgSpaceSize >= 0);
2139 noway_assert(varNum == lvaOutgoingArgSpaceVar);
2140 return lvaOutgoingArgSpaceSize;
2142 #else // FEATURE_FIXED_OUT_ARGS
2143 assert(!"Unknown size");
2144 NO_WAY("Target doesn't support TYP_LCLBLK");
2146 // Keep prefast happy
2149 #endif // FEATURE_FIXED_OUT_ARGS
2151 default: // This must be a primitive var. Fall out of switch statement
2155 return genTypeSize(varType);
2158 // getBBWeight -- get the normalized weight of this block
2159 unsigned BasicBlock::getBBWeight(Compiler* comp)
2161 if (this->bbWeight == 0)
2167 unsigned calledWeight = comp->fgCalledWeight;
2168 if (calledWeight == 0)
2170 calledWeight = comp->fgFirstBB->bbWeight;
2171 if (calledWeight == 0)
2173 calledWeight = BB_UNITY_WEIGHT;
2176 if (this->bbWeight < (BB_MAX_WEIGHT / BB_UNITY_WEIGHT))
2178 return max(1, (((this->bbWeight * BB_UNITY_WEIGHT) + (calledWeight / 2)) / calledWeight));
2182 return (unsigned)((((double)this->bbWeight * (double)BB_UNITY_WEIGHT) / (double)calledWeight) + 0.5);
2187 /*****************************************************************************
2189 * Callback used by the tree walker to call lvaDecRefCnts
2191 Compiler::fgWalkResult Compiler::lvaDecRefCntsCB(GenTreePtr* pTree, fgWalkData* data)
2193 data->compiler->lvaDecRefCnts(*pTree);
2194 return WALK_CONTINUE;
2197 // Decrement the ref counts for all locals contained in the tree and its children.
2198 void Compiler::lvaRecursiveDecRefCounts(GenTreePtr tree)
2200 assert(lvaLocalVarRefCounted);
2202 // We could just use the recursive walker for all cases but that is a
2203 // fairly heavyweight thing to spin up when we're usually just handling a leaf.
2204 if (tree->OperIsLeaf())
2206 if (tree->OperIsLocal())
2208 lvaDecRefCnts(tree);
2213 fgWalkTreePre(&tree, Compiler::lvaDecRefCntsCB, (void*)this, true);
2217 // Increment the ref counts for all locals contained in the tree and its children.
2218 void Compiler::lvaRecursiveIncRefCounts(GenTreePtr tree)
2220 assert(lvaLocalVarRefCounted);
2222 // We could just use the recursive walker for all cases but that is a
2223 // fairly heavyweight thing to spin up when we're usually just handling a leaf.
2224 if (tree->OperIsLeaf())
2226 if (tree->OperIsLocal())
2228 lvaIncRefCnts(tree);
2233 fgWalkTreePre(&tree, Compiler::lvaIncRefCntsCB, (void*)this, true);
2237 /*****************************************************************************
2239 * Helper passed to the tree walker to decrement the refCnts for
2240 * all local variables in an expression
2242 void Compiler::lvaDecRefCnts(GenTreePtr tree)
2244 assert(compCurBB != nullptr);
2245 lvaDecRefCnts(compCurBB, tree);
2248 void Compiler::lvaDecRefCnts(BasicBlock* block, GenTreePtr tree)
2250 assert(block != nullptr);
2251 assert(tree != nullptr);
2256 noway_assert(lvaRefCountingStarted || lvaLocalVarRefCounted);
2258 if ((tree->gtOper == GT_CALL) && (tree->gtFlags & GTF_CALL_UNMANAGED))
2260 assert((!opts.ShouldUsePInvokeHelpers()) || (info.compLvFrameListRoot == BAD_VAR_NUM));
2261 if (!opts.ShouldUsePInvokeHelpers())
2263 /* Get the special variable descriptor */
2265 lclNum = info.compLvFrameListRoot;
2267 noway_assert(lclNum <= lvaCount);
2268 varDsc = lvaTable + lclNum;
2270 /* Decrement the reference counts twice */
2272 varDsc->decRefCnts(block->getBBWeight(this), this);
2273 varDsc->decRefCnts(block->getBBWeight(this), this);
2278 /* This must be a local variable */
2280 noway_assert(tree->OperIsLocal());
2282 /* Get the variable descriptor */
2284 lclNum = tree->gtLclVarCommon.gtLclNum;
2286 noway_assert(lclNum < lvaCount);
2287 varDsc = lvaTable + lclNum;
2289 /* Decrement its lvRefCnt and lvRefCntWtd */
2291 varDsc->decRefCnts(block->getBBWeight(this), this);
2295 /*****************************************************************************
2297 * Callback used by the tree walker to call lvaIncRefCnts
2299 Compiler::fgWalkResult Compiler::lvaIncRefCntsCB(GenTreePtr* pTree, fgWalkData* data)
2301 data->compiler->lvaIncRefCnts(*pTree);
2302 return WALK_CONTINUE;
2305 /*****************************************************************************
2307 * Helper passed to the tree walker to increment the refCnts for
2308 * all local variables in an expression
2310 void Compiler::lvaIncRefCnts(GenTreePtr tree)
2315 noway_assert(lvaRefCountingStarted || lvaLocalVarRefCounted);
2317 if ((tree->gtOper == GT_CALL) && (tree->gtFlags & GTF_CALL_UNMANAGED))
2319 assert((!opts.ShouldUsePInvokeHelpers()) || (info.compLvFrameListRoot == BAD_VAR_NUM));
2320 if (!opts.ShouldUsePInvokeHelpers())
2322 /* Get the special variable descriptor */
2324 lclNum = info.compLvFrameListRoot;
2326 noway_assert(lclNum <= lvaCount);
2327 varDsc = lvaTable + lclNum;
2329 /* Increment the reference counts twice */
2331 varDsc->incRefCnts(compCurBB->getBBWeight(this), this);
2332 varDsc->incRefCnts(compCurBB->getBBWeight(this), this);
2337 /* This must be a local variable */
2339 noway_assert(tree->gtOper == GT_LCL_VAR || tree->gtOper == GT_LCL_FLD || tree->gtOper == GT_STORE_LCL_VAR ||
2340 tree->gtOper == GT_STORE_LCL_FLD);
2342 /* Get the variable descriptor */
2344 lclNum = tree->gtLclVarCommon.gtLclNum;
2346 noway_assert(lclNum < lvaCount);
2347 varDsc = lvaTable + lclNum;
2349 /* Increment its lvRefCnt and lvRefCntWtd */
2351 varDsc->incRefCnts(compCurBB->getBBWeight(this), this);
2355 /*****************************************************************************
2357 * Compare function passed to qsort() by Compiler::lclVars.lvaSortByRefCount().
2358 * when generating SMALL_CODE.
2359 * Return positive if dsc2 has a higher ref count
2360 * Return negative if dsc1 has a higher ref count
2361 * Return zero if the ref counts are the same
2362 * lvPrefReg is only used to break ties
2366 int __cdecl Compiler::RefCntCmp(const void* op1, const void* op2)
2368 LclVarDsc* dsc1 = *(LclVarDsc**)op1;
2369 LclVarDsc* dsc2 = *(LclVarDsc**)op2;
2371 /* Make sure we preference tracked variables over untracked variables */
2373 if (dsc1->lvTracked != dsc2->lvTracked)
2375 return (dsc2->lvTracked) ? +1 : -1;
2378 unsigned weight1 = dsc1->lvRefCnt;
2379 unsigned weight2 = dsc2->lvRefCnt;
2381 #if !FEATURE_FP_REGALLOC
2382 /* Force integer candidates to sort above float candidates */
2384 bool isFloat1 = isFloatRegType(dsc1->lvType);
2385 bool isFloat2 = isFloatRegType(dsc2->lvType);
2387 if (isFloat1 != isFloat2)
2389 if (weight2 && isFloat1)
2393 if (weight1 && isFloat2)
2400 int diff = weight2 - weight1;
2407 /* The unweighted ref counts were the same */
2408 /* If the weighted ref counts are different then use their difference */
2409 diff = dsc2->lvRefCntWtd - dsc1->lvRefCntWtd;
2416 /* We have equal ref counts and weighted ref counts */
2418 /* Break the tie by: */
2419 /* Increasing the weight by 2 if we have exactly one bit set in lvPrefReg */
2420 /* Increasing the weight by 1 if we have more than one bit set in lvPrefReg */
2421 /* Increasing the weight by 0.5 if we are a GC type */
2422 /* Increasing the weight by 0.5 if we were enregistered in the previous pass */
2426 if (dsc1->lvPrefReg)
2428 if ((dsc1->lvPrefReg & ~RBM_BYTE_REG_FLAG) && genMaxOneBit((unsigned)dsc1->lvPrefReg))
2430 weight1 += 2 * BB_UNITY_WEIGHT;
2434 weight1 += 1 * BB_UNITY_WEIGHT;
2437 if (varTypeIsGC(dsc1->TypeGet()))
2439 weight1 += BB_UNITY_WEIGHT / 2;
2442 if (dsc1->lvRegister)
2444 weight1 += BB_UNITY_WEIGHT / 2;
2450 if (dsc2->lvPrefReg)
2452 if ((dsc2->lvPrefReg & ~RBM_BYTE_REG_FLAG) && genMaxOneBit((unsigned)dsc2->lvPrefReg))
2454 weight2 += 2 * BB_UNITY_WEIGHT;
2458 weight2 += 1 * BB_UNITY_WEIGHT;
2461 if (varTypeIsGC(dsc2->TypeGet()))
2463 weight1 += BB_UNITY_WEIGHT / 2;
2466 if (dsc2->lvRegister)
2468 weight2 += BB_UNITY_WEIGHT / 2;
2472 diff = weight2 - weight1;
2479 /* To achieve a Stable Sort we use the LclNum (by way of the pointer address) */
2493 /*****************************************************************************
2495 * Compare function passed to qsort() by Compiler::lclVars.lvaSortByRefCount().
2496 * when not generating SMALL_CODE.
2497 * Return positive if dsc2 has a higher weighted ref count
2498 * Return negative if dsc1 has a higher weighted ref count
2499 * Return zero if the ref counts are the same
2503 int __cdecl Compiler::WtdRefCntCmp(const void* op1, const void* op2)
2505 LclVarDsc* dsc1 = *(LclVarDsc**)op1;
2506 LclVarDsc* dsc2 = *(LclVarDsc**)op2;
2508 /* Make sure we preference tracked variables over untracked variables */
2510 if (dsc1->lvTracked != dsc2->lvTracked)
2512 return (dsc2->lvTracked) ? +1 : -1;
2515 unsigned weight1 = dsc1->lvRefCntWtd;
2516 unsigned weight2 = dsc2->lvRefCntWtd;
2518 #if !FEATURE_FP_REGALLOC
2519 /* Force integer candidates to sort above float candidates */
2521 bool isFloat1 = isFloatRegType(dsc1->lvType);
2522 bool isFloat2 = isFloatRegType(dsc2->lvType);
2524 if (isFloat1 != isFloat2)
2526 if (weight2 && isFloat1)
2530 if (weight1 && isFloat2)
2537 /* Increase the weight by 2 if we have exactly one bit set in lvPrefReg */
2538 /* Increase the weight by 1 if we have more than one bit set in lvPrefReg */
2540 if (weight1 && dsc1->lvPrefReg)
2542 if ((dsc1->lvPrefReg & ~RBM_BYTE_REG_FLAG) && genMaxOneBit((unsigned)dsc1->lvPrefReg))
2544 weight1 += 2 * BB_UNITY_WEIGHT;
2548 weight1 += 1 * BB_UNITY_WEIGHT;
2552 if (weight2 && dsc2->lvPrefReg)
2554 if ((dsc2->lvPrefReg & ~RBM_BYTE_REG_FLAG) && genMaxOneBit((unsigned)dsc2->lvPrefReg))
2556 weight2 += 2 * BB_UNITY_WEIGHT;
2560 weight2 += 1 * BB_UNITY_WEIGHT;
2564 if (weight2 > weight1)
2568 else if (weight2 < weight1)
2573 // Otherwise, we have equal weighted ref counts.
2575 /* If the unweighted ref counts are different then use their difference */
2576 int diff = (int)dsc2->lvRefCnt - (int)dsc1->lvRefCnt;
2583 /* If one is a GC type and the other is not the GC type wins */
2584 if (varTypeIsGC(dsc1->TypeGet()) != varTypeIsGC(dsc2->TypeGet()))
2586 if (varTypeIsGC(dsc1->TypeGet()))
2598 /* If one was enregistered in the previous pass then it wins */
2599 if (dsc1->lvRegister != dsc2->lvRegister)
2601 if (dsc1->lvRegister)
2613 /* We have a tie! */
2615 /* To achieve a Stable Sort we use the LclNum (by way of the pointer address) */
2629 /*****************************************************************************
2631 * Sort the local variable table by refcount and assign tracking indices.
2634 void Compiler::lvaSortOnly()
2636 /* Now sort the variable table by ref-count */
2638 qsort(lvaRefSorted, lvaCount, sizeof(*lvaRefSorted), (compCodeOpt() == SMALL_CODE) ? RefCntCmp : WtdRefCntCmp);
2640 lvaSortAgain = false;
2645 void Compiler::lvaDumpRefCounts()
2649 if (verbose && lvaCount)
2651 printf("refCnt table for '%s':\n", info.compMethodName);
2653 for (unsigned lclNum = 0; lclNum < lvaCount; lclNum++)
2655 unsigned refCnt = lvaRefSorted[lclNum]->lvRefCnt;
2660 unsigned refCntWtd = lvaRefSorted[lclNum]->lvRefCntWtd;
2663 gtDispLclVar((unsigned)(lvaRefSorted[lclNum] - lvaTable));
2664 printf(" [%6s]: refCnt = %4u, refCntWtd = %6s", varTypeName(lvaRefSorted[lclNum]->TypeGet()), refCnt,
2665 refCntWtd2str(refCntWtd));
2667 regMaskSmall pref = lvaRefSorted[lclNum]->lvPrefReg;
2682 /*****************************************************************************
2684 * Sort the local variable table by refcount and assign tracking indices.
2687 void Compiler::lvaSortByRefCount()
2689 lvaTrackedCount = 0;
2690 lvaTrackedCountInSizeTUnits = 0;
2693 VarSetOps::AssignNoCopy(this, lvaTrackedVars, VarSetOps::MakeEmpty(this));
2706 /* We'll sort the variables by ref count - allocate the sorted table */
2708 lvaRefSorted = refTab = new (this, CMK_LvaTable) LclVarDsc*[lvaCount];
2710 /* Fill in the table used for sorting */
2712 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
2714 /* Append this variable to the table for sorting */
2718 /* If we have JMP, all arguments must have a location
2719 * even if we don't use them inside the method */
2721 if (compJmpOpUsed && varDsc->lvIsParam)
2723 /* ...except when we have varargs and the argument is
2724 passed on the stack. In that case, it's important
2725 for the ref count to be zero, so that we don't attempt
2726 to track them for GC info (which is not possible since we
2727 don't know their offset in the stack). See the assert at the
2728 end of raMarkStkVars and bug #28949 for more info. */
2730 if (!raIsVarargsStackArg(lclNum))
2732 varDsc->incRefCnts(1, this);
2736 /* For now assume we'll be able to track all locals */
2738 varDsc->lvTracked = 1;
2740 /* If the ref count is zero */
2741 if (varDsc->lvRefCnt == 0)
2743 /* Zero ref count, make this untracked */
2744 varDsc->lvTracked = 0;
2745 varDsc->lvRefCntWtd = 0;
2748 #if !defined(_TARGET_64BIT_) && !defined(LEGACY_BACKEND)
2749 if (varTypeIsLong(varDsc) && varDsc->lvPromoted)
2751 varDsc->lvTracked = 0;
2753 #endif // !defined(_TARGET_64BIT_) && !defined(LEGACY_BACKEND)
2755 // Variables that are address-exposed, and all struct locals, are never enregistered, or tracked.
2756 // (The struct may be promoted, and its field variables enregistered/tracked, or the VM may "normalize"
2757 // its type so that its not seen by the JIT as a struct.)
2758 // Pinned variables may not be tracked (a condition of the GCInfo representation)
2759 // or enregistered, on x86 -- it is believed that we can enregister pinned (more properly, "pinning")
2760 // references when using the general GC encoding.
2761 if (varDsc->lvAddrExposed)
2763 varDsc->lvTracked = 0;
2764 assert(varDsc->lvType != TYP_STRUCT ||
2765 varDsc->lvDoNotEnregister); // For structs, should have set this when we set lvAddrExposed.
2767 else if (varTypeIsStruct(varDsc))
2769 // Promoted structs will never be considered for enregistration anyway,
2770 // and the DoNotEnregister flag was used to indicate whether promotion was
2771 // independent or dependent.
2772 if (varDsc->lvPromoted)
2774 varDsc->lvTracked = 0;
2776 else if ((varDsc->lvType == TYP_STRUCT) && !varDsc->lvRegStruct)
2778 lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_IsStruct));
2781 else if (varDsc->lvIsStructField && (lvaGetParentPromotionType(lclNum) != PROMOTION_TYPE_INDEPENDENT))
2783 // SSA must exclude struct fields that are not independently promoted
2784 // as dependent fields could be assigned using a CopyBlock
2785 // resulting in a single node causing multiple SSA definitions
2786 // which isn't currently supported by SSA
2788 // TODO-CQ: Consider using lvLclBlockOpAddr and only marking these LclVars
2789 // untracked when a blockOp is used to assign the struct.
2791 varDsc->lvTracked = 0; // so, don't mark as tracked
2793 else if (varDsc->lvPinned)
2795 varDsc->lvTracked = 0;
2796 #ifdef JIT32_GCENCODER
2797 lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_PinningRef));
2801 // Are we not optimizing and we have exception handlers?
2802 // if so mark all args and locals "do not enregister".
2804 if (opts.MinOpts() && compHndBBtabCount > 0)
2806 lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LiveInOutOfHandler));
2810 var_types type = genActualType(varDsc->TypeGet());
2814 #if CPU_HAS_FP_SUPPORT
2827 #endif // FEATURE_SIMD
2833 noway_assert(!"lvType not set correctly");
2834 varDsc->lvType = TYP_INT;
2839 varDsc->lvTracked = 0;
2843 /* Now sort the variable table by ref-count */
2847 /* Decide which variables will be worth tracking */
2849 if (lvaCount > lclMAX_TRACKED)
2851 /* Mark all variables past the first 'lclMAX_TRACKED' as untracked */
2853 for (lclNum = lclMAX_TRACKED; lclNum < lvaCount; lclNum++)
2855 lvaRefSorted[lclNum]->lvTracked = 0;
2860 // Re-Initialize to -1 for safety in debug build.
2861 memset(lvaTrackedToVarNum, -1, sizeof(lvaTrackedToVarNum));
2864 /* Assign indices to all the variables we've decided to track */
2866 for (lclNum = 0; lclNum < min(lvaCount, lclMAX_TRACKED); lclNum++)
2868 varDsc = lvaRefSorted[lclNum];
2869 if (varDsc->lvTracked)
2871 noway_assert(varDsc->lvRefCnt > 0);
2873 /* This variable will be tracked - assign it an index */
2875 lvaTrackedToVarNum[lvaTrackedCount] = (unsigned)(varDsc - lvaTable); // The type of varDsc and lvaTable
2876 // is LclVarDsc. Subtraction will give us
2878 varDsc->lvVarIndex = lvaTrackedCount++;
2882 // We have a new epoch, and also cache the tracked var count in terms of size_t's sufficient to hold that many bits.
2884 lvaTrackedCountInSizeTUnits = unsigned(roundUp(lvaTrackedCount, sizeof(size_t) * 8)) / unsigned(sizeof(size_t) * 8);
2887 VarSetOps::AssignNoCopy(this, lvaTrackedVars, VarSetOps::MakeFull(this));
2892 /*****************************************************************************
2894 * This is called by lvaMarkLclRefs to disqualify a variable from being
2895 * considered by optAddCopies()
2897 void LclVarDsc::lvaDisqualifyVar()
2899 this->lvDisqualify = true;
2900 this->lvSingleDef = false;
2901 this->lvDefStmt = nullptr;
2903 #endif // ASSERTION_PROP
2905 #ifndef LEGACY_BACKEND
2906 /**********************************************************************************
2907 * Get type of a variable when passed as an argument.
2909 var_types LclVarDsc::lvaArgType()
2911 var_types type = TypeGet();
2913 #ifdef _TARGET_AMD64_
2914 if (type == TYP_STRUCT)
2916 switch (lvExactSize)
2928 switch (*lvGcLayout)
2952 #elif defined(_TARGET_X86_)
2953 // Nothing to do; use the type as is.
2956 #endif //_TARGET_AMD64_
2960 #endif // !LEGACY_BACKEND
2962 /*****************************************************************************
2964 * This is called by lvaMarkLclRefsCallback() to do variable ref marking
2967 void Compiler::lvaMarkLclRefs(GenTreePtr tree)
2969 /* Is this a call to unmanaged code ? */
2970 if (tree->gtOper == GT_CALL && tree->gtFlags & GTF_CALL_UNMANAGED)
2972 assert((!opts.ShouldUsePInvokeHelpers()) || (info.compLvFrameListRoot == BAD_VAR_NUM));
2973 if (!opts.ShouldUsePInvokeHelpers())
2975 /* Get the special variable descriptor */
2977 unsigned lclNum = info.compLvFrameListRoot;
2979 noway_assert(lclNum <= lvaCount);
2980 LclVarDsc* varDsc = lvaTable + lclNum;
2982 /* Increment the ref counts twice */
2983 varDsc->incRefCnts(lvaMarkRefsWeight, this);
2984 varDsc->incRefCnts(lvaMarkRefsWeight, this);
2988 /* Is this an assigment? */
2990 if (tree->OperKind() & GTK_ASGOP)
2992 GenTreePtr op1 = tree->gtOp.gtOp1;
2993 GenTreePtr op2 = tree->gtOp.gtOp2;
2995 /* Set target register for RHS local if assignment is of a "small" type */
2997 if (varTypeIsByte(tree->gtType))
3000 LclVarDsc* varDsc = nullptr;
3002 /* GT_CHS is special it doesn't have a valid op2 */
3003 if (tree->gtOper == GT_CHS)
3005 if (op1->gtOper == GT_LCL_VAR)
3007 lclNum = op1->gtLclVarCommon.gtLclNum;
3008 noway_assert(lclNum < lvaCount);
3009 varDsc = &lvaTable[lclNum];
3014 if (op2->gtOper == GT_LCL_VAR)
3016 lclNum = op2->gtLclVarCommon.gtLclNum;
3017 noway_assert(lclNum < lvaCount);
3018 varDsc = &lvaTable[lclNum];
3021 #if CPU_HAS_BYTE_REGS
3023 varDsc->addPrefReg(RBM_BYTE_REG_FLAG, this);
3029 /* Is this an assignment to a local variable? */
3031 if (op1->gtOper == GT_LCL_VAR && op2->gtType != TYP_BOOL)
3033 /* Only simple assignments allowed for booleans */
3035 if (tree->gtOper != GT_ASG)
3040 /* Is the RHS clearly a boolean value? */
3042 switch (op2->gtOper)
3048 if (op2->gtIntCon.gtIconVal == 0)
3052 if (op2->gtIntCon.gtIconVal == 1)
3057 // Not 0 or 1, fall through ....
3062 if (op2->OperIsCompare())
3069 lclNum = op1->gtLclVarCommon.gtLclNum;
3070 noway_assert(lclNum < lvaCount);
3072 lvaTable[lclNum].lvIsBoolean = false;
3081 /* Special case: assignment node */
3083 if (tree->gtOper == GT_ASG)
3085 if (tree->gtType == TYP_INT)
3090 GenTreePtr op1 = tree->gtOp.gtOp1;
3092 if (op1->gtOper != GT_LCL_VAR)
3095 lclNum1 = op1->gtLclVarCommon.gtLclNum;
3096 noway_assert(lclNum1 < lvaCount);
3097 varDsc1 = lvaTable + lclNum1;
3099 if (varDsc1->lvAssignOne)
3100 varDsc1->lvAssignTwo = true;
3102 varDsc1->lvAssignOne = true;
3110 #ifdef _TARGET_XARCH_
3111 /* Special case: integer shift node by a variable amount */
3113 if (tree->OperIsShiftOrRotate())
3115 if (tree->gtType == TYP_INT)
3117 GenTreePtr op2 = tree->gtOp.gtOp2;
3119 if (op2->gtOper == GT_LCL_VAR)
3121 unsigned lclNum = op2->gtLclVarCommon.gtLclNum;
3122 noway_assert(lclNum < lvaCount);
3123 lvaTable[lclNum].setPrefReg(REG_ECX, this);
3131 if ((tree->gtOper != GT_LCL_VAR) && (tree->gtOper != GT_LCL_FLD))
3136 /* This must be a local variable reference */
3138 noway_assert((tree->gtOper == GT_LCL_VAR) || (tree->gtOper == GT_LCL_FLD));
3139 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
3141 noway_assert(lclNum < lvaCount);
3142 LclVarDsc* varDsc = lvaTable + lclNum;
3144 /* Increment the reference counts */
3146 varDsc->incRefCnts(lvaMarkRefsWeight, this);
3148 if (lvaVarAddrExposed(lclNum))
3150 varDsc->lvIsBoolean = false;
3153 if (tree->gtOper == GT_LCL_FLD)
3156 // variables that have uses inside a GT_LCL_FLD
3157 // cause problems, so we will disqualify them here
3158 varDsc->lvaDisqualifyVar();
3159 #endif // ASSERTION_PROP
3164 /* Exclude the normal entry block */
3165 if (fgDomsComputed && (lvaMarkRefsCurBlock->bbNum != 1) && lvaMarkRefsCurBlock->bbIDom != nullptr)
3167 // If any entry block except the normal entry block dominates the block, then mark the local with the
3168 // lvVolatileHint flag.
3170 if (BlockSetOps::MayBeUninit(lvaMarkRefsCurBlock->bbDoms))
3172 // Lazy init (If a block is not dominated by any other block, we'll redo this every time, but it'll be fast)
3173 BlockSetOps::AssignNoCopy(this, lvaMarkRefsCurBlock->bbDoms, fgGetDominatorSet(lvaMarkRefsCurBlock));
3174 BlockSetOps::RemoveElemD(this, lvaMarkRefsCurBlock->bbDoms, fgFirstBB->bbNum);
3176 assert(fgEnterBlksSetValid);
3177 if (!BlockSetOps::IsEmptyIntersection(this, lvaMarkRefsCurBlock->bbDoms, fgEnterBlks))
3179 varDsc->lvVolatileHint = 1;
3183 /* Record if the variable has a single def or not */
3185 if (!varDsc->lvDisqualify) // If this variable is already disqualified we can skip this
3187 if (tree->gtFlags & GTF_VAR_DEF) // Is this is a def of our variable
3190 If we have one of these cases:
3191 1. We have already seen a definition (i.e lvSingleDef is true)
3192 2. or info.CompInitMem is true (thus this would be the second definition)
3193 3. or we have an assignment inside QMARK-COLON trees
3194 4. or we have an update form of assignment (i.e. +=, -=, *=)
3195 Then we must disqualify this variable for use in optAddCopies()
3197 Note that all parameters start out with lvSingleDef set to true
3199 if ((varDsc->lvSingleDef == true) || (info.compInitMem == true) || (tree->gtFlags & GTF_COLON_COND) ||
3200 (tree->gtFlags & GTF_VAR_USEASG))
3202 varDsc->lvaDisqualifyVar();
3206 varDsc->lvSingleDef = true;
3207 varDsc->lvDefStmt = lvaMarkRefsCurStmt;
3210 else // otherwise this is a ref of our variable
3212 if (BlockSetOps::MayBeUninit(varDsc->lvRefBlks))
3214 // Lazy initialization
3215 BlockSetOps::AssignNoCopy(this, varDsc->lvRefBlks, BlockSetOps::MakeEmpty(this));
3217 BlockSetOps::AddElemD(this, varDsc->lvRefBlks, lvaMarkRefsCurBlock->bbNum);
3220 #endif // ASSERTION_PROP
3222 bool allowStructs = false;
3223 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
3224 // On System V the type of the var could be a struct type.
3225 allowStructs = varTypeIsStruct(varDsc);
3226 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
3228 /* Variables must be used as the same type throughout the method */
3229 noway_assert(tiVerificationNeeded || varDsc->lvType == TYP_UNDEF || tree->gtType == TYP_UNKNOWN || allowStructs ||
3230 genActualType(varDsc->TypeGet()) == genActualType(tree->gtType) ||
3231 (tree->gtType == TYP_BYREF && varDsc->TypeGet() == TYP_I_IMPL) ||
3232 (tree->gtType == TYP_I_IMPL && varDsc->TypeGet() == TYP_BYREF) || (tree->gtFlags & GTF_VAR_CAST) ||
3233 varTypeIsFloating(varDsc->TypeGet()) && varTypeIsFloating(tree->gtType));
3235 /* Remember the type of the reference */
3237 if (tree->gtType == TYP_UNKNOWN || varDsc->lvType == TYP_UNDEF)
3239 varDsc->lvType = tree->gtType;
3240 noway_assert(genActualType(varDsc->TypeGet()) == tree->gtType); // no truncation
3244 if (tree->gtFlags & GTF_VAR_CAST)
3246 // it should never be bigger than the variable slot
3248 // Trees don't store the full information about structs
3249 // so we can't check them.
3250 if (tree->TypeGet() != TYP_STRUCT)
3252 unsigned treeSize = genTypeSize(tree->TypeGet());
3253 unsigned varSize = genTypeSize(varDsc->TypeGet());
3254 if (varDsc->TypeGet() == TYP_STRUCT)
3256 varSize = varDsc->lvSize();
3259 assert(treeSize <= varSize);
3265 /*****************************************************************************
3267 * Helper passed to Compiler::fgWalkTreePre() to do variable ref marking.
3271 Compiler::fgWalkResult Compiler::lvaMarkLclRefsCallback(GenTreePtr* pTree, fgWalkData* data)
3273 data->compiler->lvaMarkLclRefs(*pTree);
3275 return WALK_CONTINUE;
3278 /*****************************************************************************
3280 * Update the local variable reference counts for one basic block
3283 void Compiler::lvaMarkLocalVars(BasicBlock* block)
3286 lvaMarkRefsCurBlock = block;
3288 lvaMarkRefsWeight = block->getBBWeight(this);
3293 printf("\n*** marking local variables in block BB%02u (weight=%s)\n", block->bbNum,
3294 refCntWtd2str(lvaMarkRefsWeight));
3298 for (GenTreePtr tree = block->FirstNonPhiDef(); tree; tree = tree->gtNext)
3300 noway_assert(tree->gtOper == GT_STMT);
3303 lvaMarkRefsCurStmt = tree;
3313 fgWalkTreePre(&tree->gtStmt.gtStmtExpr, Compiler::lvaMarkLclRefsCallback, (void*)this, false);
3317 /*****************************************************************************
3319 * Create the local variable table and compute local variable reference
3323 void Compiler::lvaMarkLocalVars()
3329 printf("\n*************** In lvaMarkLocalVars()");
3333 /* If there is a call to an unmanaged target, we already grabbed a
3334 local slot for the current thread control block.
3337 if (info.compCallUnmanaged != 0)
3339 assert((!opts.ShouldUsePInvokeHelpers()) || (info.compLvFrameListRoot == BAD_VAR_NUM));
3340 if (!opts.ShouldUsePInvokeHelpers())
3342 noway_assert(info.compLvFrameListRoot >= info.compLocalsCount && info.compLvFrameListRoot < lvaCount);
3344 lvaTable[info.compLvFrameListRoot].lvType = TYP_I_IMPL;
3346 /* Set the refCnt, it is used in the prolog and return block(s) */
3348 lvaTable[info.compLvFrameListRoot].lvRefCnt = 2;
3349 lvaTable[info.compLvFrameListRoot].lvRefCntWtd = 2 * BB_UNITY_WEIGHT;
3353 lvaAllocOutgoingArgSpace();
3355 #if !FEATURE_EH_FUNCLETS
3357 // Grab space for exception handling
3359 if (ehNeedsShadowSPslots())
3361 // The first slot is reserved for ICodeManager::FixContext(ppEndRegion)
3362 // ie. the offset of the end-of-last-executed-filter
3363 unsigned slotsNeeded = 1;
3365 unsigned handlerNestingLevel = ehMaxHndNestingCount;
3367 if (opts.compDbgEnC && (handlerNestingLevel < (unsigned)MAX_EnC_HANDLER_NESTING_LEVEL))
3368 handlerNestingLevel = (unsigned)MAX_EnC_HANDLER_NESTING_LEVEL;
3370 slotsNeeded += handlerNestingLevel;
3372 // For a filter (which can be active at the same time as a catch/finally handler)
3374 // For zero-termination of the shadow-Stack-pointer chain
3377 lvaShadowSPslotsVar = lvaGrabTempWithImplicitUse(false DEBUGARG("lvaShadowSPslotsVar"));
3378 LclVarDsc* shadowSPslotsVar = &lvaTable[lvaShadowSPslotsVar];
3379 shadowSPslotsVar->lvType = TYP_BLK;
3380 shadowSPslotsVar->lvExactSize = (slotsNeeded * TARGET_POINTER_SIZE);
3383 #endif // !FEATURE_EH_FUNCLETS
3385 #if FEATURE_EH_FUNCLETS
3386 if (ehNeedsPSPSym())
3388 lvaPSPSym = lvaGrabTempWithImplicitUse(false DEBUGARG("PSPSym"));
3389 LclVarDsc* lclPSPSym = &lvaTable[lvaPSPSym];
3390 lclPSPSym->lvType = TYP_I_IMPL;
3392 #endif // FEATURE_EH_FUNCLETS
3394 if (compLocallocUsed)
3396 lvaLocAllocSPvar = lvaGrabTempWithImplicitUse(false DEBUGARG("LocAllocSPvar"));
3397 LclVarDsc* locAllocSPvar = &lvaTable[lvaLocAllocSPvar];
3398 locAllocSPvar->lvType = TYP_I_IMPL;
3404 // Assign slot numbers to all variables.
3405 // If compiler generated local variables, slot numbers will be
3406 // invalid (out of range of info.compVarScopes).
3408 // Also have to check if variable was not reallocated to another
3409 // slot in which case we have to register the original slot #.
3411 // We don't need to do this for IL, but this keeps lvSlotNum consistent.
3413 if (opts.compScopeInfo && (info.compVarScopesCount > 0))
3419 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
3421 varDsc->lvSlotNum = lclNum;
3425 /* Mark all local variable references */
3427 lvaRefCountingStarted = true;
3428 for (block = fgFirstBB; block; block = block->bbNext)
3430 lvaMarkLocalVars(block);
3433 /* For incoming register arguments, if there are references in the body
3434 * then we will have to copy them to the final home in the prolog
3435 * This counts as an extra reference with a weight of 2
3441 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
3443 if (lclNum >= info.compArgsCount)
3445 break; // early exit for loop
3448 if ((varDsc->lvIsRegArg) && (varDsc->lvRefCnt > 0))
3450 // Fix 388376 ARM JitStress WP7
3451 varDsc->incRefCnts(BB_UNITY_WEIGHT, this);
3452 varDsc->incRefCnts(BB_UNITY_WEIGHT, this);
3457 if (!opts.MinOpts() && !opts.compDbgCode)
3459 // Note: optAddCopies() depends on lvaRefBlks, which is set in lvaMarkLocalVars(BasicBlock*), called above.
3464 if (lvaKeepAliveAndReportThis() && lvaTable[0].lvRefCnt == 0)
3466 lvaTable[0].lvRefCnt = 1;
3467 // This isn't strictly needed as we will make a copy of the param-type-arg
3468 // in the prolog. However, this ensures that the LclVarDsc corresponding to
3469 // info.compTypeCtxtArg is valid.
3471 else if (lvaReportParamTypeArg() && lvaTable[info.compTypeCtxtArg].lvRefCnt == 0)
3473 lvaTable[info.compTypeCtxtArg].lvRefCnt = 1;
3476 lvaLocalVarRefCounted = true;
3477 lvaRefCountingStarted = false;
3479 lvaSortByRefCount();
3482 void Compiler::lvaAllocOutgoingArgSpace()
3484 #if FEATURE_FIXED_OUT_ARGS
3486 // Setup the outgoing argument region, in case we end up using it later
3488 if (lvaOutgoingArgSpaceVar == BAD_VAR_NUM)
3490 lvaOutgoingArgSpaceVar = lvaGrabTemp(false DEBUGARG("OutgoingArgSpace"));
3492 lvaTable[lvaOutgoingArgSpaceVar].lvType = TYP_LCLBLK;
3494 /* Set the refCnts */
3496 lvaTable[lvaOutgoingArgSpaceVar].lvRefCnt = 1;
3497 lvaTable[lvaOutgoingArgSpaceVar].lvRefCntWtd = BB_UNITY_WEIGHT;
3499 if (lvaOutgoingArgSpaceSize == 0)
3501 if (compUsesThrowHelper || compIsProfilerHookNeeded())
3503 // Need to make sure the MIN_ARG_AREA_FOR_CALL space is added to the frame if:
3504 // 1. there are calls to THROW_HEPLPER methods.
3505 // 2. we are generating profiling Enter/Leave/TailCall hooks. This will ensure
3506 // that even methods without any calls will have outgoing arg area space allocated.
3508 // An example for these two cases is Windows Amd64, where the ABI requires to have 4 slots for
3509 // the outgoing arg space if the method makes any calls.
3510 lvaOutgoingArgSpaceSize = MIN_ARG_AREA_FOR_CALL;
3515 noway_assert(lvaOutgoingArgSpaceVar >= info.compLocalsCount && lvaOutgoingArgSpaceVar < lvaCount);
3517 #endif // FEATURE_FIXED_OUT_ARGS
3520 inline void Compiler::lvaIncrementFrameSize(unsigned size)
3522 if (size > MAX_FrameSize || compLclFrameSize + size > MAX_FrameSize)
3524 BADCODE("Frame size overflow");
3527 compLclFrameSize += size;
3530 /****************************************************************************
3532 * Return true if absolute offsets of temps are larger than vars, or in other
3533 * words, did we allocate temps before of after vars. The /GS buffer overrun
3534 * checks want temps to be at low stack addresses than buffers
3536 bool Compiler::lvaTempsHaveLargerOffsetThanVars()
3539 // We never want to place the temps with larger offsets for ARM
3542 if (compGSReorderStackLayout)
3544 return codeGen->isFramePointerUsed();
3553 /****************************************************************************
3555 * Return an upper bound estimate for the size of the compiler spill temps
3558 unsigned Compiler::lvaGetMaxSpillTempSize()
3560 unsigned result = 0;
3562 #ifndef LEGACY_BACKEND
3563 if (lvaDoneFrameLayout >= REGALLOC_FRAME_LAYOUT)
3569 result = MAX_SPILL_TEMP_SIZE;
3571 #else // LEGACY_BACKEND
3572 if (lvaDoneFrameLayout >= FINAL_FRAME_LAYOUT)
3578 if (lvaDoneFrameLayout >= REGALLOC_FRAME_LAYOUT)
3580 unsigned maxTmpSize = sizeof(double) + sizeof(int);
3582 maxTmpSize += (tmpDoubleSpillMax * sizeof(double)) + (tmpIntSpillMax * sizeof(int));
3584 result = maxTmpSize;
3588 result = MAX_SPILL_TEMP_SIZE;
3591 // When StressRegs is >=1, there can be a bunch of spills that are not
3592 // predicted by the predictor (see logic in rsPickReg). It is very hard
3593 // to teach the predictor about the behavior of rsPickReg for StressRegs >= 1,
3594 // so instead let's make MaxTmpSize large enough so that we won't be wrong.
3596 if (codeGen->regSet.rsStressRegs() >= 1)
3598 result += (REG_TMP_ORDER_COUNT * REGSIZE_BYTES);
3602 #endif // LEGACY_BACKEND
3607 /*****************************************************************************
3609 * Compute stack frame offsets for arguments, locals and optionally temps.
3611 * The frame is laid out as follows for x86:
3616 * |-----------------------|
3619 * |-----------------------| <---- Virtual '0'
3620 * | return address |
3621 * +=======================+
3622 * |Callee saved registers |
3623 * |-----------------------|
3625 * |-----------------------|
3627 * |-----------------------| <---- Ambient ESP
3628 * | Arguments for the |
3640 * |-----------------------|
3643 * |-----------------------| <---- Virtual '0'
3644 * | return address |
3645 * +=======================+
3647 * |-----------------------| <---- EBP
3648 * |Callee saved registers |
3649 * |-----------------------|
3650 * | security object |
3651 * |-----------------------|
3653 * |-----------------------|
3654 * | Last-executed-filter |
3655 * |-----------------------|
3659 * |-----------------------|
3663 * ~-----------------------|
3665 * |-----------------------|
3667 * |-----------------------| <---- Ambient ESP
3668 * | Arguments for the |
3677 * The frame is laid out as follows for x64:
3681 * |-----------------------|
3684 * |-----------------------|
3685 * | 4 fixed incoming |
3686 * | argument slots |
3687 * |-----------------------| <---- Caller's SP & Virtual '0'
3688 * | return address |
3689 * +=======================+
3690 * | Callee saved Int regs |
3691 * -------------------------
3692 * | Padding | <---- this padding (0 or 8 bytes) is to ensure flt registers are saved at a mem location aligned at 16-bytes
3693 * | | so that we can save 128-bit callee saved xmm regs using performant "movaps" instruction instead of "movups"
3694 * -------------------------
3695 * | Callee saved Flt regs | <----- entire 128-bits of callee saved xmm registers are stored here
3696 * |-----------------------|
3698 * |-----------------------|
3700 * |-----------------------|
3701 * | Arguments for the |
3704 * |-----------------------|
3705 * | 4 fixed outgoing |
3706 * | argument slots |
3707 * |-----------------------| <---- Ambient RSP
3716 * |-----------------------|
3719 * |-----------------------|
3720 * | 4 fixed incoming |
3721 * | argument slots |
3722 * |-----------------------| <---- Caller's SP & Virtual '0'
3723 * | return address |
3724 * +=======================+
3725 * | Callee saved Int regs |
3726 * -------------------------
3728 * -------------------------
3729 * | Callee saved Flt regs |
3730 * |-----------------------|
3731 * | security object |
3732 * |-----------------------|
3734 * |-----------------------|
3740 * |-----------------------|
3742 * |-----------------------|
3744 * ~ localloc ~ // not in frames with EH
3746 * |-----------------------|
3747 * | PSPSym | // only in frames with EH (thus no localloc)
3749 * |-----------------------| <---- RBP in localloc frames (max 240 bytes from Initial-SP)
3750 * | Arguments for the |
3753 * |-----------------------|
3754 * | 4 fixed outgoing |
3755 * | argument slots |
3756 * |-----------------------| <---- Ambient RSP (before localloc, this is Initial-SP)
3763 * The frame is laid out as follows for ARM (this is a general picture; details may differ for different conditions):
3767 * |-----------------------|
3770 * +=======================+ <---- Caller's SP
3771 * | Pre-spill registers |
3772 * |-----------------------| <---- Virtual '0'
3773 * |Callee saved registers |
3774 * |-----------------------|
3775 * ~ possible double align ~
3776 * |-----------------------|
3777 * | security object |
3778 * |-----------------------|
3780 * |-----------------------|
3781 * | possible GS cookie |
3782 * |-----------------------|
3784 * |-----------------------|
3785 * | possible GS cookie |
3786 * |-----------------------|
3788 * |-----------------------|
3789 * | Stub Argument Var |
3790 * |-----------------------|
3791 * |Inlined PInvoke Frame V|
3792 * |-----------------------|
3793 * ~ possible double align ~
3794 * |-----------------------|
3795 * | Arguments for the |
3798 * |-----------------------| <---- Ambient SP
3807 * |-----------------------|
3810 * +=======================+ <---- Caller's SP
3811 * | Pre-spill registers |
3812 * |-----------------------| <---- Virtual '0'
3813 * |Callee saved registers |
3814 * |-----------------------|
3815 * | PSPSym | // Only for frames with EH, which means FP-based frames
3816 * |-----------------------|
3817 * ~ possible double align ~
3818 * |-----------------------|
3819 * | security object |
3820 * |-----------------------|
3822 * |-----------------------|
3823 * | possible GS cookie |
3824 * |-----------------------|
3826 * |-----------------------|
3827 * | possible GS cookie |
3828 * |-----------------------|
3830 * |-----------------------|
3831 * | Stub Argument Var |
3832 * |-----------------------|
3833 * |Inlined PInvoke Frame V|
3834 * |-----------------------|
3835 * ~ possible double align ~
3836 * |-----------------------|
3838 * |-----------------------|
3839 * | Arguments for the |
3842 * |-----------------------| <---- Ambient SP
3849 * The frame is laid out as follows for ARM64 (this is a general picture; details may differ for different conditions):
3850 * TODO-ARM64-NYI: this is preliminary (copied from ARM and modified), and needs to be reviewed.
3851 * NOTE: SP must be 16-byte aligned, so there may be alignment slots in the frame.
3852 * We will often save and establish a frame pointer to create better ETW stack walks.
3856 * |-----------------------|
3859 * +=======================+ <---- Caller's SP
3860 * | homed | // this is only needed if reg argument need to be homed, e.g., for varargs
3861 * | register arguments |
3862 * |-----------------------| <---- Virtual '0'
3863 * |Callee saved registers |
3865 * |-----------------------|
3866 * | security object |
3867 * |-----------------------|
3869 * |-----------------------|
3870 * | possible GS cookie |
3871 * |-----------------------|
3873 * |-----------------------|
3874 * | possible GS cookie |
3875 * |-----------------------|
3877 * |-----------------------|
3878 * | Stub Argument Var |
3879 * |-----------------------|
3880 * |Inlined PInvoke Frame V|
3881 * |-----------------------|
3883 * |-----------------------|
3884 * | Saved FP | <---- Frame pointer
3885 * |-----------------------|
3886 * | Stack arguments for |
3887 * | the next function |
3888 * |-----------------------| <---- SP
3895 * FP (R29 / x29) frames
3897 * |-----------------------|
3900 * +=======================+ <---- Caller's SP
3901 * | optional homed | // this is only needed if reg argument need to be homed, e.g., for varargs
3902 * | register arguments |
3903 * |-----------------------| <---- Virtual '0'
3904 * |Callee saved registers |
3906 * |-----------------------|
3907 * | PSPSym | // Only for frames with EH, which requires FP-based frames
3908 * |-----------------------|
3909 * | security object |
3910 * |-----------------------|
3912 * |-----------------------|
3913 * | possible GS cookie |
3914 * |-----------------------|
3916 * |-----------------------|
3917 * | possible GS cookie |
3918 * |-----------------------|
3920 * |-----------------------|
3921 * | Stub Argument Var |
3922 * |-----------------------|
3923 * |Inlined PInvoke Frame V|
3924 * |-----------------------|
3926 * |-----------------------|
3927 * | Saved FP | <---- Frame pointer
3928 * |-----------------------|
3930 * |-----------------------|
3931 * | Stack arguments for |
3932 * | the next function |
3933 * |-----------------------| <---- Ambient SP
3940 * Doing this all in one pass is 'hard'. So instead we do it in 2 basic passes:
3941 * 1. Assign all the offsets relative to the Virtual '0'. Offsets above (the
3942 * incoming arguments) are positive. Offsets below (everything else) are
3943 * negative. This pass also calcuates the total frame size (between Caller's
3944 * SP/return address and the Ambient SP).
3945 * 2. Figure out where to place the frame pointer, and then adjust the offsets
3946 * as needed for the final stack size and whether the offset is frame pointer
3947 * relative or stack pointer relative.
3952 void Compiler::lvaAssignFrameOffsets(FrameLayoutState curState)
3954 noway_assert(lvaDoneFrameLayout < curState);
3956 lvaDoneFrameLayout = curState;
3962 printf("*************** In lvaAssignFrameOffsets");
3963 if (curState == INITIAL_FRAME_LAYOUT)
3965 printf("(INITIAL_FRAME_LAYOUT)");
3967 else if (curState == PRE_REGALLOC_FRAME_LAYOUT)
3969 printf("(PRE_REGALLOC_FRAME_LAYOUT)");
3971 else if (curState == REGALLOC_FRAME_LAYOUT)
3973 printf("(REGALLOC_FRAME_LAYOUT)");
3975 else if (curState == TENTATIVE_FRAME_LAYOUT)
3977 printf("(TENTATIVE_FRAME_LAYOUT)");
3979 else if (curState == FINAL_FRAME_LAYOUT)
3981 printf("(FINAL_FRAME_LAYOUT)");
3985 printf("(UNKNOWN)");
3992 #if FEATURE_FIXED_OUT_ARGS
3993 assert(lvaOutgoingArgSpaceVar != BAD_VAR_NUM);
3994 #endif // FEATURE_FIXED_OUT_ARGS
3996 /*-------------------------------------------------------------------------
3998 * First process the arguments.
4000 *-------------------------------------------------------------------------
4003 lvaAssignVirtualFrameOffsetsToArgs();
4005 /*-------------------------------------------------------------------------
4007 * Now compute stack offsets for any variables that don't live in registers
4009 *-------------------------------------------------------------------------
4012 lvaAssignVirtualFrameOffsetsToLocals();
4016 /*-------------------------------------------------------------------------
4018 * Now patch the offsets
4020 *-------------------------------------------------------------------------
4023 lvaFixVirtualFrameOffsets();
4025 // Modify the stack offset for fields of promoted structs.
4026 lvaAssignFrameOffsetsToPromotedStructs();
4028 /*-------------------------------------------------------------------------
4032 *-------------------------------------------------------------------------
4035 // If it's not the final frame layout, then it's just an estimate. This means
4036 // we're allowed to once again write to these variables, even if we've read
4037 // from them to make tentative code generation or frame layout decisions.
4038 if (curState < FINAL_FRAME_LAYOUT)
4040 codeGen->resetFramePointerUsedWritePhase();
4044 /*****************************************************************************
4045 * lvaFixVirtualFrameOffsets() : Now that everything has a virtual offset,
4046 * determine the final value for the frame pointer (if needed) and then
4047 * adjust all the offsets appropriately.
4049 * This routine fixes virtual offset to be relative to frame pointer or SP
4050 * based on whether varDsc->lvFramePointerBased is true or false respectively.
4052 void Compiler::lvaFixVirtualFrameOffsets()
4056 #if FEATURE_EH_FUNCLETS && defined(_TARGET_AMD64_)
4057 if (ehNeedsPSPSym())
4059 // We need to fix the offset of the PSPSym so there is no padding between it and the outgoing argument space.
4060 // Without this code, lvaAlignFrame might have put the padding lower than the PSPSym, which would be between
4061 // the PSPSym and the outgoing argument space.
4062 assert(lvaPSPSym != BAD_VAR_NUM);
4063 varDsc = &lvaTable[lvaPSPSym];
4064 assert(varDsc->lvFramePointerBased); // We always access it RBP-relative.
4065 assert(!varDsc->lvMustInit); // It is never "must init".
4066 varDsc->lvStkOffs = codeGen->genCallerSPtoInitialSPdelta() + lvaLclSize(lvaOutgoingArgSpaceVar);
4070 // The delta to be added to virtual offset to adjust it relative to frame pointer or SP
4073 #ifdef _TARGET_XARCH_
4074 delta += REGSIZE_BYTES; // pushed PC (return address) for x86/x64
4076 if (codeGen->doubleAlignOrFramePointerUsed())
4078 delta += REGSIZE_BYTES; // pushed EBP (frame pointer)
4082 if (!codeGen->isFramePointerUsed())
4084 // pushed registers, return address, and padding
4085 delta += codeGen->genTotalFrameSize();
4087 #if defined(_TARGET_ARM_)
4090 // We set FP to be after LR, FP
4091 delta += 2 * REGSIZE_BYTES;
4093 #elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
4097 delta += codeGen->genTotalFrameSize() - codeGen->genSPtoFPdelta();
4099 #endif //_TARGET_AMD64_
4102 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
4104 bool doAssignStkOffs = true;
4106 // Can't be relative to EBP unless we have an EBP
4107 noway_assert(!varDsc->lvFramePointerBased || codeGen->doubleAlignOrFramePointerUsed());
4109 // Is this a non-param promoted struct field?
4110 // if so then set doAssignStkOffs to false.
4112 if (varDsc->lvIsStructField && !varDsc->lvIsParam)
4114 LclVarDsc* parentvarDsc = &lvaTable[varDsc->lvParentLcl];
4115 lvaPromotionType promotionType = lvaGetPromotionType(parentvarDsc);
4117 if (promotionType == PROMOTION_TYPE_DEPENDENT)
4119 doAssignStkOffs = false; // Assigned later in lvaAssignFrameOffsetsToPromotedStructs()
4123 if (!varDsc->lvOnFrame)
4125 if (!varDsc->lvIsParam
4126 #if !defined(_TARGET_AMD64_)
4127 || (varDsc->lvIsRegArg
4128 #if defined(_TARGET_ARM_) && defined(PROFILING_SUPPORTED)
4129 && compIsProfilerHookNeeded() &&
4130 !lvaIsPreSpilled(lclNum, codeGen->regSet.rsMaskPreSpillRegs(false)) // We need assign stack offsets
4131 // for prespilled arguments
4134 #endif // !defined(_TARGET_AMD64_)
4137 doAssignStkOffs = false; // Not on frame or an incomming stack arg
4141 if (doAssignStkOffs)
4143 varDsc->lvStkOffs += delta;
4146 if (genDoubleAlign() && !codeGen->isFramePointerUsed())
4148 if (varDsc->lvFramePointerBased)
4150 varDsc->lvStkOffs -= delta;
4152 // We need to re-adjust the offsets of the parameters so they are EBP
4153 // relative rather than stack/frame pointer relative
4155 varDsc->lvStkOffs += (2 * sizeof(void*)); // return address and pushed EBP
4157 noway_assert(varDsc->lvStkOffs >= FIRST_ARG_STACK_OFFS);
4161 // On System V environments the stkOffs could be 0 for params passed in registers.
4162 assert(codeGen->isFramePointerUsed() ||
4163 varDsc->lvStkOffs >= 0); // Only EBP relative references can have negative offsets
4167 assert(tmpAllFree());
4168 for (TempDsc* temp = tmpListBeg(); temp != nullptr; temp = tmpListNxt(temp))
4170 temp->tdAdjustTempOffs(delta);
4173 lvaCachedGenericContextArgOffs += delta;
4175 #if FEATURE_FIXED_OUT_ARGS
4177 if (lvaOutgoingArgSpaceVar != BAD_VAR_NUM)
4179 varDsc = &lvaTable[lvaOutgoingArgSpaceVar];
4180 varDsc->lvStkOffs = 0;
4181 varDsc->lvFramePointerBased = false;
4182 varDsc->lvMustInit = false;
4185 #endif // FEATURE_FIXED_OUT_ARGS
4189 bool Compiler::lvaIsPreSpilled(unsigned lclNum, regMaskTP preSpillMask)
4191 const LclVarDsc& desc = lvaTable[lclNum];
4192 return desc.lvIsRegArg && (preSpillMask & genRegMask(desc.lvArgReg));
4194 #endif // _TARGET_ARM_
4196 #ifndef LEGACY_BACKEND
4197 /*****************************************************************************
4198 * lvaUpdateArgsWithInitialReg() : For each argument variable descriptor, update
4199 * its current register with the initial register as assigned by LSRA.
4201 void Compiler::lvaUpdateArgsWithInitialReg()
4208 for (unsigned lclNum = 0; lclNum < info.compArgsCount; lclNum++)
4210 LclVarDsc* varDsc = lvaTable + lclNum;
4212 if (varDsc->lvPromotedStruct())
4214 noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
4216 unsigned fieldVarNum = varDsc->lvFieldLclStart;
4217 varDsc = lvaTable + fieldVarNum;
4220 noway_assert(varDsc->lvIsParam);
4222 if (varDsc->lvIsRegCandidate())
4224 if (varTypeIsMultiReg(varDsc))
4226 regPairNo initialRegPair = varDsc->lvArgInitRegPair;
4227 varDsc->lvRegNum = genRegPairLo(initialRegPair);
4228 varDsc->lvOtherReg = genRegPairHi(initialRegPair);
4232 varDsc->lvRegNum = varDsc->lvArgInitReg;
4237 #endif // !LEGACY_BACKEND
4239 /*****************************************************************************
4240 * lvaAssignVirtualFrameOffsetsToArgs() : Assign virtual stack offsets to the
4241 * arguments, and implicit arguments (this ptr, return buffer, generics,
4244 void Compiler::lvaAssignVirtualFrameOffsetsToArgs()
4246 unsigned lclNum = 0;
4248 #ifdef UNIX_AMD64_ABI
4249 int callerArgOffset = 0;
4250 #endif // UNIX_AMD64_ABI
4253 Assign stack offsets to arguments (in reverse order of passing).
4255 This means that if we pass arguments left->right, we start at
4256 the end of the list and work backwards, for right->left we start
4257 with the first argument and move forward.
4259 This is all relative to our Virtual '0'
4262 if (Target::g_tgtArgOrder == Target::ARG_ORDER_L2R)
4264 argOffs = compArgSize;
4267 /* Update the argOffs to reflect arguments that are passed in registers */
4269 noway_assert(codeGen->intRegState.rsCalleeRegArgCount <= MAX_REG_ARG);
4270 noway_assert(compArgSize >= codeGen->intRegState.rsCalleeRegArgCount * sizeof(void*));
4273 argOffs -= codeGen->intRegState.rsCalleeRegArgCount * sizeof(void*);
4276 #ifndef LEGACY_BACKEND
4277 // Update the arg initial register locations.
4278 lvaUpdateArgsWithInitialReg();
4279 #endif // !LEGACY_BACKEND
4281 /* Is there a "this" argument? */
4283 if (!info.compIsStatic)
4285 noway_assert(lclNum == info.compThisArg);
4286 #ifndef _TARGET_X86_
4288 lvaAssignVirtualFrameOffsetToArg(lclNum, REGSIZE_BYTES, argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4289 #endif // _TARGET_X86_
4293 /* if we have a hidden buffer parameter, that comes here */
4295 if (info.compRetBuffArg != BAD_VAR_NUM)
4297 noway_assert(lclNum == info.compRetBuffArg);
4298 noway_assert(lvaTable[lclNum].lvIsRegArg);
4299 #ifndef _TARGET_X86_
4301 lvaAssignVirtualFrameOffsetToArg(lclNum, REGSIZE_BYTES, argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4302 #endif // _TARGET_X86_
4306 #if USER_ARGS_COME_LAST
4308 //@GENERICS: extra argument for instantiation info
4309 if (info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE)
4311 noway_assert(lclNum == (unsigned)info.compTypeCtxtArg);
4312 argOffs = lvaAssignVirtualFrameOffsetToArg(lclNum++, sizeof(void*),
4313 argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4316 if (info.compIsVarArgs)
4318 argOffs = lvaAssignVirtualFrameOffsetToArg(lclNum++, sizeof(void*),
4319 argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4322 #endif // USER_ARGS_COME_LAST
4324 CORINFO_ARG_LIST_HANDLE argLst = info.compMethodInfo->args.args;
4325 unsigned argSigLen = info.compMethodInfo->args.numArgs;
4329 // struct_n { int; int; ... n times };
4331 // Consider signature:
4333 // Foo (float a,double b,float c,double d,float e,double f,float g,double h,
4334 // float i,double j,float k,double l,struct_3 m) { }
4336 // Basically the signature is: (all float regs full, 1 double, struct_3);
4338 // The double argument occurs before pre spill in the argument iteration and
4339 // computes an argOffset of 0. struct_3 offset becomes 8. This is wrong.
4340 // Because struct_3 is prespilled and double occurs after prespill.
4341 // The correct offsets are double = 16 (aligned stk), struct_3 = 0..12,
4342 // Offset 12 will be skipped for double alignment of double.
4344 // Another example is (struct_2, all float regs full, double, struct_2);
4345 // Here, notice the order is similarly messed up because of 2 pre-spilled
4349 // ARG_INDEX(i) > ARG_INDEX(j) DOES NOT IMPLY |ARG_OFFSET(i)| > |ARG_OFFSET(j)|
4351 // Therefore, we'll do a two pass offset calculation, one that considers pre-spill
4352 // and the next, stack args.
4355 unsigned argLcls = 0;
4357 // Take care of pre spill registers first.
4358 regMaskTP preSpillMask = codeGen->regSet.rsMaskPreSpillRegs(false);
4359 regMaskTP tempMask = RBM_NONE;
4360 for (unsigned i = 0, preSpillLclNum = lclNum; i < argSigLen; ++i, ++preSpillLclNum)
4362 if (lvaIsPreSpilled(preSpillLclNum, preSpillMask))
4364 unsigned argSize = eeGetArgSize(argLst, &info.compMethodInfo->args);
4365 argOffs = lvaAssignVirtualFrameOffsetToArg(preSpillLclNum, argSize, argOffs);
4368 // Early out if we can. If size is 8 and base reg is 2, then the mask is 0x1100
4369 tempMask |= ((((1 << (roundUp(argSize) / REGSIZE_BYTES))) - 1) << lvaTable[preSpillLclNum].lvArgReg);
4370 if (tempMask == preSpillMask)
4372 // We won't encounter more pre-spilled registers,
4373 // so don't bother iterating further.
4377 argLst = info.compCompHnd->getArgNext(argLst);
4380 // Take care of non pre-spilled stack arguments.
4381 argLst = info.compMethodInfo->args.args;
4382 for (unsigned i = 0, stkLclNum = lclNum; i < argSigLen; ++i, ++stkLclNum)
4384 if (!lvaIsPreSpilled(stkLclNum, preSpillMask))
4387 lvaAssignVirtualFrameOffsetToArg(stkLclNum, eeGetArgSize(argLst, &info.compMethodInfo->args), argOffs);
4390 argLst = info.compCompHnd->getArgNext(argLst);
4394 #else // !_TARGET_ARM_
4395 for (unsigned i = 0; i < argSigLen; i++)
4397 unsigned argumentSize = eeGetArgSize(argLst, &info.compMethodInfo->args);
4399 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
4400 // On the stack frame the homed arg always takes a full number of slots
4401 // for proper stack alignment. Make sure the real struct size is properly rounded up.
4402 argumentSize = (unsigned)roundUp(argumentSize, TARGET_POINTER_SIZE);
4403 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
4406 lvaAssignVirtualFrameOffsetToArg(lclNum++, argumentSize, argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4407 argLst = info.compCompHnd->getArgNext(argLst);
4409 #endif // !_TARGET_ARM_
4411 #if !USER_ARGS_COME_LAST
4413 //@GENERICS: extra argument for instantiation info
4414 if (info.compMethodInfo->args.callConv & CORINFO_CALLCONV_PARAMTYPE)
4416 noway_assert(lclNum == (unsigned)info.compTypeCtxtArg);
4417 argOffs = lvaAssignVirtualFrameOffsetToArg(lclNum++, sizeof(void*),
4418 argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4421 if (info.compIsVarArgs)
4423 argOffs = lvaAssignVirtualFrameOffsetToArg(lclNum++, sizeof(void*),
4424 argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
4427 #endif // USER_ARGS_COME_LAST
4430 #ifdef UNIX_AMD64_ABI
4432 // lvaAssignVirtualFrameOffsetToArg() : Assign virtual stack offsets to an
4433 // individual argument, and return the offset for the next argument.
4434 // Note: This method only calculates the initial offset of the stack passed/spilled arguments
4435 // (if any - the RA might decide to spill(home on the stack) register passed arguments, if rarely used.)
4436 // The final offset is calculated in lvaFixVirtualFrameOffsets method. It accounts for FP existance,
4437 // ret address slot, stack frame padding, alloca instructions, etc.
4438 // Note: This is the implementation for UNIX_AMD64 System V platforms.
4440 int Compiler::lvaAssignVirtualFrameOffsetToArg(unsigned lclNum,
4442 int argOffs UNIX_AMD64_ABI_ONLY_ARG(int* callerArgOffset))
4444 noway_assert(lclNum < info.compArgsCount);
4445 noway_assert(argSize);
4447 if (Target::g_tgtArgOrder == Target::ARG_ORDER_L2R)
4452 unsigned fieldVarNum = BAD_VAR_NUM;
4454 noway_assert(lclNum < lvaCount);
4455 LclVarDsc* varDsc = lvaTable + lclNum;
4457 if (varDsc->lvPromotedStruct())
4459 noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
4460 fieldVarNum = varDsc->lvFieldLclStart;
4462 lvaPromotionType promotionType = lvaGetPromotionType(varDsc);
4464 if (promotionType == PROMOTION_TYPE_INDEPENDENT)
4466 lclNum = fieldVarNum;
4467 noway_assert(lclNum < lvaCount);
4468 varDsc = lvaTable + lclNum;
4469 assert(varDsc->lvIsStructField);
4473 noway_assert(varDsc->lvIsParam);
4475 if (varDsc->lvIsRegArg)
4477 // Argument is passed in a register, don't count it
4478 // when updating the current offset on the stack.
4480 if (varDsc->lvOnFrame)
4482 // The offset for args needs to be set only for the stack homed arguments for System V.
4483 varDsc->lvStkOffs = argOffs;
4487 varDsc->lvStkOffs = 0;
4492 // For Windows AMD64 there are 4 slots for the register passed arguments on the top of the caller's stack.
4493 // This is where they are always homed. So, they can be accessed with positive offset.
4494 // On System V platforms, if the RA decides to home a register passed arg on the stack, it creates a stack
4495 // location on the callee stack (like any other local var.) In such a case, the register passed, stack homed
4496 // arguments are accessed using negative offsets and the stack passed arguments are accessed using positive
4497 // offset (from the caller's stack.)
4498 // For System V platforms if there is no frame pointer the caller stack parameter offset should include the
4499 // callee allocated space. If frame register is used, the callee allocated space should not be included for
4500 // accessing the caller stack parameters. The last two requirements are met in lvaFixVirtualFrameOffsets
4501 // method, which fixes the offsets, based on frame pointer existence, existence of alloca instructions, ret
4502 // address pushed, ets.
4504 varDsc->lvStkOffs = *callerArgOffset;
4505 // Structs passed on stack could be of size less than TARGET_POINTER_SIZE.
4506 // Make sure they get at least TARGET_POINTER_SIZE on the stack - this is required for alignment.
4507 if (argSize > TARGET_POINTER_SIZE)
4509 *callerArgOffset += (int)roundUp(argSize, TARGET_POINTER_SIZE);
4513 *callerArgOffset += TARGET_POINTER_SIZE;
4517 // For struct promoted parameters we need to set the offsets for both LclVars.
4519 // For a dependent promoted struct we also assign the struct fields stack offset
4520 if (varDsc->lvPromotedStruct())
4522 lvaPromotionType promotionType = lvaGetPromotionType(varDsc);
4524 if (promotionType == PROMOTION_TYPE_DEPENDENT)
4526 noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
4528 assert(fieldVarNum == varDsc->lvFieldLclStart);
4529 lvaTable[fieldVarNum].lvStkOffs = varDsc->lvStkOffs;
4532 // For an independent promoted struct field we also assign the parent struct stack offset
4533 else if (varDsc->lvIsStructField)
4535 noway_assert(varDsc->lvParentLcl < lvaCount);
4536 lvaTable[varDsc->lvParentLcl].lvStkOffs = varDsc->lvStkOffs;
4539 if (Target::g_tgtArgOrder == Target::ARG_ORDER_R2L && !varDsc->lvIsRegArg)
4547 #else // !UNIX_AMD64_ABI
4550 // lvaAssignVirtualFrameOffsetToArg() : Assign virtual stack offsets to an
4551 // individual argument, and return the offset for the next argument.
4552 // Note: This method only calculates the initial offset of the stack passed/spilled arguments
4553 // (if any - the RA might decide to spill(home on the stack) register passed arguments, if rarely used.)
4554 // The final offset is calculated in lvaFixVirtualFrameOffsets method. It accounts for FP existance,
4555 // ret address slot, stack frame padding, alloca instructions, etc.
4556 // Note: This implementation for all the platforms but UNIX_AMD64 OSs (System V 64 bit.)
4557 int Compiler::lvaAssignVirtualFrameOffsetToArg(unsigned lclNum,
4559 int argOffs UNIX_AMD64_ABI_ONLY_ARG(int* callerArgOffset))
4561 noway_assert(lclNum < info.compArgsCount);
4562 noway_assert(argSize);
4564 if (Target::g_tgtArgOrder == Target::ARG_ORDER_L2R)
4569 unsigned fieldVarNum = BAD_VAR_NUM;
4571 noway_assert(lclNum < lvaCount);
4572 LclVarDsc* varDsc = lvaTable + lclNum;
4574 if (varDsc->lvPromotedStruct())
4576 noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
4577 fieldVarNum = varDsc->lvFieldLclStart;
4579 lvaPromotionType promotionType = lvaGetPromotionType(varDsc);
4581 if (promotionType == PROMOTION_TYPE_INDEPENDENT)
4583 lclNum = fieldVarNum;
4584 noway_assert(lclNum < lvaCount);
4585 varDsc = lvaTable + lclNum;
4586 assert(varDsc->lvIsStructField);
4590 noway_assert(varDsc->lvIsParam);
4592 if (varDsc->lvIsRegArg)
4594 /* Argument is passed in a register, don't count it
4595 * when updating the current offset on the stack */
4596 CLANG_FORMAT_COMMENT_ANCHOR;
4598 #if !defined(_TARGET_ARMARCH_)
4600 // TODO: Remove this noway_assert and replace occurrences of sizeof(void *) with argSize
4601 // Also investigate why we are incrementing argOffs for X86 as this seems incorrect
4603 noway_assert(argSize == sizeof(void*));
4607 #if defined(_TARGET_X86_)
4608 argOffs += sizeof(void*);
4609 #elif defined(_TARGET_AMD64_)
4610 // Register arguments on AMD64 also takes stack space. (in the backing store)
4611 varDsc->lvStkOffs = argOffs;
4612 argOffs += sizeof(void*);
4613 #elif defined(_TARGET_ARM64_)
4614 // Register arguments on ARM64 only take stack space when they have a frame home.
4615 #elif defined(_TARGET_ARM_)
4616 // On ARM we spill the registers in codeGen->regSet.rsMaskPreSpillRegArg
4617 // in the prolog, so we have to fill in lvStkOffs here
4619 regMaskTP regMask = genRegMask(varDsc->lvArgReg);
4620 if (codeGen->regSet.rsMaskPreSpillRegArg & regMask)
4622 // Signature: void foo(struct_8, int, struct_4)
4623 // ------- CALLER SP -------
4625 // r2 int - not prespilled, but added for alignment. argOffs should skip this.
4628 // -------------------------
4629 // If we added alignment we need to fix argOffs for all registers above alignment.
4630 if (codeGen->regSet.rsMaskPreSpillAlign != RBM_NONE)
4632 assert(genCountBits(codeGen->regSet.rsMaskPreSpillAlign) == 1);
4633 // Is register beyond the alignment pos?
4634 if (regMask > codeGen->regSet.rsMaskPreSpillAlign)
4636 // Increment argOffs just once for the _first_ register after alignment pos
4637 // in the prespill mask.
4638 if (!BitsBetween(codeGen->regSet.rsMaskPreSpillRegArg, regMask,
4639 codeGen->regSet.rsMaskPreSpillAlign))
4641 argOffs += TARGET_POINTER_SIZE;
4646 switch (varDsc->lvType)
4649 if (!varDsc->lvStructDoubleAlign)
4659 // Let's assign offsets to arg1, a double in r2. argOffs has to be 4 not 8.
4661 // ------- CALLER SP -------
4663 // r2 double -- argOffs = 4, but it doesn't need to be skipped, because there is no skipping.
4664 // r1 VACookie -- argOffs = 0
4665 // -------------------------
4667 // Consider argOffs as if it accounts for number of prespilled registers before the current
4668 // register. In the above example, for r2, it is r1 that is prespilled, but since r1 is
4669 // accounted for by argOffs being 4, there should have been no skipping. Instead, if we didn't
4670 // assign r1 to any variable, then argOffs would still be 0 which implies it is not accounting
4671 // for r1, equivalently r1 is skipped.
4673 // If prevRegsSize is unaccounted for by a corresponding argOffs, we must have skipped a register.
4675 genCountBits(codeGen->regSet.rsMaskPreSpillRegArg & (regMask - 1)) * TARGET_POINTER_SIZE;
4676 if (argOffs < prevRegsSize)
4678 // We must align up the argOffset to a multiple of 8 to account for skipped registers.
4679 argOffs = roundUp(argOffs, 2 * TARGET_POINTER_SIZE);
4681 // We should've skipped only a single register.
4682 assert(argOffs == prevRegsSize);
4687 // No alignment of argOffs required
4690 varDsc->lvStkOffs = argOffs;
4694 #error Unsupported or unset target architecture
4699 #if defined(_TARGET_ARM_)
4700 // Dev11 Bug 42817: incorrect codegen for DrawFlatCheckBox causes A/V in WinForms
4702 // Here we have method with a signature (int a1, struct a2, struct a3, int a4, int a5).
4703 // Struct parameter 'a2' is 16-bytes with no alignment requirements;
4704 // it uses r1,r2,r3 and [OutArg+0] when passed.
4705 // Struct parameter 'a3' is 16-bytes that is required to be double aligned;
4706 // the caller skips [OutArg+4] and starts the argument at [OutArg+8].
4707 // Thus the caller generates the correct code to pass the arguments.
4708 // When generating code to receive the arguments we set codeGen->regSet.rsMaskPreSpillRegArg to [r1,r2,r3]
4709 // and spill these three registers as the first instruction in the prolog.
4710 // Then when we layout the arguments' stack offsets we have an argOffs 0 which
4711 // points at the location that we spilled r1 into the stack. For this first
4712 // struct we take the lvIsRegArg path above with "codeGen->regSet.rsMaskPreSpillRegArg &" matching.
4713 // Next when we calculate the argOffs for the second 16-byte struct we have an argOffs
4714 // of 16, which appears to be aligned properly so we don't skip a stack slot.
4716 // To fix this we must recover the actual OutArg offset by subtracting off the
4717 // sizeof of the PreSpill register args.
4718 // Then we align this offset to a multiple of 8 and add back the sizeof
4719 // of the PreSpill register args.
4721 // Dev11 Bug 71767: failure of assert(sizeofPreSpillRegArgs <= argOffs)
4723 // We have a method with 'this' passed in r0, RetBuf arg in r1, VarArgs cookie
4724 // in r2. The first user arg is a 144 byte struct with double alignment required,
4725 // r3 is skipped, and the struct is passed on the stack. However, 'r3' is added
4726 // to the codeGen->regSet.rsMaskPreSpillRegArg mask by the VarArgs cookie code, since we need to
4727 // home all the potential varargs arguments in registers, even if we don't have
4728 // signature type information for the variadic arguments. However, due to alignment,
4729 // we have skipped a register that doesn't have a corresponding symbol. Make up
4730 // for that by increasing argOffs here.
4733 int sizeofPreSpillRegArgs = genCountBits(codeGen->regSet.rsMaskPreSpillRegs(true)) * REGSIZE_BYTES;
4735 if (argOffs < sizeofPreSpillRegArgs)
4737 // This can only happen if we skipped the last register spot because current stk arg
4738 // is a struct requiring alignment or a pre-spill alignment was required because the
4739 // first reg arg needed alignment.
4741 // Example 1: First Stk Argument requiring alignment in vararg case (same as above comment.)
4742 // Signature (int a0, int a1, int a2, struct {long} a3, ...)
4744 // stk arg a3 --> argOffs here will be 12 (r0-r2) but pre-spill will be 16.
4745 // ---- Caller SP ----
4746 // r3 --> Stack slot is skipped in this case.
4751 // Example 2: First Reg Argument requiring alignment in no-vararg case.
4752 // Signature (struct {long} a0, struct {int} a1, int a2, int a3)
4754 // stk arg --> argOffs here will be 12 {r0-r2} but pre-spill will be 16.
4755 // ---- Caller SP ----
4756 // r3 int a2 --> pushed (not pre-spilled) for alignment of a0 by lvaInitUserArgs.
4757 // r2 struct { int } a1
4758 // r0-r1 struct { long } a0
4759 CLANG_FORMAT_COMMENT_ANCHOR;
4761 #ifdef PROFILING_SUPPORTED
4762 // On Arm under profiler, r0-r3 are always prespilled on stack.
4763 // It is possible to have methods that accept only HFAs as parameters e.g. Signature(struct hfa1, struct
4764 // hfa2), in which case hfa1 and hfa2 will be en-registered in co-processor registers and will have an
4765 // argument offset less than size of preSpill.
4767 // For this reason the following conditions are asserted when not under profiler.
4768 if (!compIsProfilerHookNeeded())
4771 bool cond = ((info.compIsVarArgs || opts.compUseSoftFP) &&
4772 // Does cur stk arg require double alignment?
4773 ((varDsc->lvType == TYP_STRUCT && varDsc->lvStructDoubleAlign) ||
4774 (varDsc->lvType == TYP_DOUBLE) || (varDsc->lvType == TYP_LONG))) ||
4775 // Did first reg arg require alignment?
4776 (codeGen->regSet.rsMaskPreSpillAlign & genRegMask(REG_ARG_LAST));
4779 noway_assert(sizeofPreSpillRegArgs <=
4780 argOffs + TARGET_POINTER_SIZE); // at most one register of alignment
4782 argOffs = sizeofPreSpillRegArgs;
4785 noway_assert(argOffs >= sizeofPreSpillRegArgs);
4786 int argOffsWithoutPreSpillRegArgs = argOffs - sizeofPreSpillRegArgs;
4788 switch (varDsc->lvType)
4791 if (!varDsc->lvStructDoubleAlign)
4798 // We must align up the argOffset to a multiple of 8
4799 argOffs = roundUp(argOffsWithoutPreSpillRegArgs, 2 * TARGET_POINTER_SIZE) + sizeofPreSpillRegArgs;
4803 // No alignment of argOffs required
4806 #endif // _TARGET_ARM_
4808 varDsc->lvStkOffs = argOffs;
4811 // For struct promoted parameters we need to set the offsets for both LclVars.
4813 // For a dependent promoted struct we also assign the struct fields stack offset
4814 CLANG_FORMAT_COMMENT_ANCHOR;
4816 #if !defined(_TARGET_64BIT_)
4817 if ((varDsc->TypeGet() == TYP_LONG) && varDsc->lvPromoted)
4819 noway_assert(varDsc->lvFieldCnt == 2);
4820 fieldVarNum = varDsc->lvFieldLclStart;
4821 lvaTable[fieldVarNum].lvStkOffs = varDsc->lvStkOffs;
4822 lvaTable[fieldVarNum + 1].lvStkOffs = varDsc->lvStkOffs + genTypeSize(TYP_INT);
4825 #endif // !defined(_TARGET_64BIT_)
4826 if (varDsc->lvPromotedStruct())
4828 lvaPromotionType promotionType = lvaGetPromotionType(varDsc);
4830 if (promotionType == PROMOTION_TYPE_DEPENDENT)
4832 noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
4834 assert(fieldVarNum == varDsc->lvFieldLclStart);
4835 lvaTable[fieldVarNum].lvStkOffs = varDsc->lvStkOffs;
4838 // For an independent promoted struct field we also assign the parent struct stack offset
4839 else if (varDsc->lvIsStructField)
4841 noway_assert(varDsc->lvParentLcl < lvaCount);
4842 lvaTable[varDsc->lvParentLcl].lvStkOffs = varDsc->lvStkOffs;
4845 if (Target::g_tgtArgOrder == Target::ARG_ORDER_R2L && !varDsc->lvIsRegArg)
4852 #endif // !UNIX_AMD64_ABI
4854 /*****************************************************************************
4855 * lvaAssignVirtualFrameOffsetsToLocals() : Assign virtual stack offsets to
4856 * locals, temps, and anything else. These will all be negative offsets
4857 * (stack grows down) relative to the virtual '0'/return address
4859 void Compiler::lvaAssignVirtualFrameOffsetsToLocals()
4862 // codeGen->isFramePointerUsed is set in regalloc phase. Initialize it to a guess for pre-regalloc layout.
4863 if (lvaDoneFrameLayout <= PRE_REGALLOC_FRAME_LAYOUT)
4865 codeGen->setFramePointerUsed(codeGen->isFramePointerRequired());
4868 #ifdef _TARGET_XARCH_
4869 // On x86/amd64, the return address has already been pushed by the call instruction in the caller.
4870 stkOffs -= sizeof(void*); // return address;
4872 // TODO-AMD64-CQ: for X64 eventually this should be pushed with all the other
4873 // calleeregs. When you fix this, you'll also need to fix
4874 // the assert at the bottom of this method
4875 if (codeGen->doubleAlignOrFramePointerUsed())
4877 stkOffs -= REGSIZE_BYTES;
4879 #endif //_TARGET_XARCH_
4881 int preSpillSize = 0;
4882 bool mustDoubleAlign = false;
4885 mustDoubleAlign = true;
4886 preSpillSize = genCountBits(codeGen->regSet.rsMaskPreSpillRegs(true)) * REGSIZE_BYTES;
4887 #else // !_TARGET_ARM_
4889 if (genDoubleAlign())
4891 mustDoubleAlign = true; // X86 only
4894 #endif // !_TARGET_ARM_
4896 #ifdef _TARGET_ARM64_
4897 // If the frame pointer is used, then we'll save FP/LR at the bottom of the stack.
4898 // Otherwise, we won't store FP, and we'll store LR at the top, with the other callee-save
4899 // registers (if any).
4901 int initialStkOffs = 0;
4902 if (info.compIsVarArgs)
4904 // For varargs we always save all of the integer register arguments
4905 // so that they are contiguous with the incoming stack arguments.
4906 initialStkOffs = MAX_REG_ARG * REGSIZE_BYTES;
4907 stkOffs -= initialStkOffs;
4910 if (isFramePointerUsed())
4912 // Subtract off FP and LR.
4913 assert(compCalleeRegsPushed >= 2);
4914 stkOffs -= (compCalleeRegsPushed - 2) * REGSIZE_BYTES;
4918 stkOffs -= compCalleeRegsPushed * REGSIZE_BYTES;
4921 #else // !_TARGET_ARM64_
4922 stkOffs -= compCalleeRegsPushed * REGSIZE_BYTES;
4923 #endif // !_TARGET_ARM64_
4925 compLclFrameSize = 0;
4927 #ifdef _TARGET_AMD64_
4928 // In case of Amd64 compCalleeRegsPushed includes float regs (Xmm6-xmm15) that
4929 // need to be pushed. But Amd64 doesn't support push/pop of xmm registers.
4930 // Instead we need to allocate space for them on the stack and save them in prolog.
4931 // Therefore, we consider xmm registers being saved while computing stack offsets
4932 // but space for xmm registers is considered part of compLclFrameSize.
4934 // 1) We need to save the entire 128-bits of xmm register to stack, since amd64
4935 // prolog unwind codes allow encoding of an instruction that stores the entire xmm reg
4936 // at an offset relative to SP
4937 // 2) We adjust frame size so that SP is aligned at 16-bytes after pushing integer registers.
4938 // This means while saving the first xmm register to its allocated stack location we might
4939 // have to skip 8-bytes. The reason for padding is to use efficient "movaps" to save/restore
4940 // xmm registers to/from stack to match Jit64 codegen. Without the aligning on 16-byte
4941 // boundary we would have to use movups when offset turns out unaligned. Movaps is more
4942 // performant than movups.
4943 unsigned calleeFPRegsSavedSize = genCountBits(compCalleeFPRegsSavedMask) * XMM_REGSIZE_BYTES;
4944 if (calleeFPRegsSavedSize > 0 && ((stkOffs % XMM_REGSIZE_BYTES) != 0))
4946 // Take care of alignment
4947 int alignPad = (int)AlignmentPad((unsigned)-stkOffs, XMM_REGSIZE_BYTES);
4948 stkOffs -= alignPad;
4949 lvaIncrementFrameSize(alignPad);
4952 stkOffs -= calleeFPRegsSavedSize;
4953 lvaIncrementFrameSize(calleeFPRegsSavedSize);
4955 // Quirk for VS debug-launch scenario to work
4956 if (compVSQuirkStackPaddingNeeded > 0)
4961 printf("\nAdding VS quirk stack padding of %d bytes between save-reg area and locals\n",
4962 compVSQuirkStackPaddingNeeded);
4966 stkOffs -= compVSQuirkStackPaddingNeeded;
4967 lvaIncrementFrameSize(compVSQuirkStackPaddingNeeded);
4969 #endif //_TARGET_AMD64_
4971 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARMARCH_)
4972 if (ehNeedsPSPSym())
4974 // On ARM/ARM64, if we need a PSPSym, allocate it first, before anything else, including
4975 // padding (so we can avoid computing the same padding in the funclet
4976 // frame). Note that there is no special padding requirement for the PSPSym.
4977 noway_assert(codeGen->isFramePointerUsed()); // We need an explicit frame pointer
4978 assert(lvaPSPSym != BAD_VAR_NUM); // We should have created the PSPSym variable
4979 stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaPSPSym, TARGET_POINTER_SIZE, stkOffs);
4981 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARMARCH_)
4983 if (mustDoubleAlign)
4985 if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
4987 // Allocate a pointer sized stack slot, since we may need to double align here
4988 // when lvaDoneFrameLayout == FINAL_FRAME_LAYOUT
4990 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
4991 stkOffs -= TARGET_POINTER_SIZE;
4993 // If we have any TYP_LONG, TYP_DOUBLE or double aligned structs
4994 // then we need to allocate a second pointer sized stack slot,
4995 // since we may need to double align that LclVar when we see it
4996 // in the loop below. We will just always do this so that the
4997 // offsets that we calculate for the stack frame will always
4998 // be greater (or equal) to what they can be in the final layout.
5000 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5001 stkOffs -= TARGET_POINTER_SIZE;
5003 else // FINAL_FRAME_LAYOUT
5005 if (((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) != 0)
5007 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5008 stkOffs -= TARGET_POINTER_SIZE;
5010 // We should now have a double-aligned (stkOffs+preSpillSize)
5011 noway_assert(((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) == 0);
5015 if (lvaMonAcquired != BAD_VAR_NUM)
5017 // This var must go first, in what is called the 'frame header' for EnC so that it is
5018 // preserved when remapping occurs. See vm\eetwain.cpp for detailed comment specifying frame
5019 // layout requirements for EnC to work.
5020 stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaMonAcquired, lvaLclSize(lvaMonAcquired), stkOffs);
5023 if (opts.compNeedSecurityCheck)
5025 #ifdef JIT32_GCENCODER
5026 /* This can't work without an explicit frame, so make sure */
5027 noway_assert(codeGen->isFramePointerUsed());
5029 stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaSecurityObject, TARGET_POINTER_SIZE, stkOffs);
5032 if (compLocallocUsed)
5034 #ifdef JIT32_GCENCODER
5035 noway_assert(codeGen->isFramePointerUsed()); // else offsets of locals of frameless methods will be incorrect
5037 stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaLocAllocSPvar, TARGET_POINTER_SIZE, stkOffs);
5040 if (lvaReportParamTypeArg())
5042 #ifdef JIT32_GCENCODER
5043 noway_assert(codeGen->isFramePointerUsed());
5045 // For CORINFO_CALLCONV_PARAMTYPE (if needed)
5046 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5047 stkOffs -= TARGET_POINTER_SIZE;
5048 lvaCachedGenericContextArgOffs = stkOffs;
5050 #ifndef JIT32_GCENCODER
5051 else if (lvaKeepAliveAndReportThis())
5053 // When "this" is also used as generic context arg.
5054 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5055 stkOffs -= TARGET_POINTER_SIZE;
5056 lvaCachedGenericContextArgOffs = stkOffs;
5060 #if !FEATURE_EH_FUNCLETS
5061 /* If we need space for slots for shadow SP, reserve it now */
5062 if (ehNeedsShadowSPslots())
5064 noway_assert(codeGen->isFramePointerUsed()); // else offsets of locals of frameless methods will be incorrect
5065 if (!lvaReportParamTypeArg())
5067 #ifndef JIT32_GCENCODER
5068 if (!lvaKeepAliveAndReportThis())
5071 // In order to keep the gc info encoding smaller, the VM assumes that all methods with EH
5072 // have also saved space for a ParamTypeArg, so we need to do that here
5073 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5074 stkOffs -= TARGET_POINTER_SIZE;
5077 stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaShadowSPslotsVar, lvaLclSize(lvaShadowSPslotsVar), stkOffs);
5079 #endif // !FEATURE_EH_FUNCLETS
5081 if (compGSReorderStackLayout)
5083 assert(getNeedsGSSecurityCookie());
5084 stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaGSSecurityCookie, lvaLclSize(lvaGSSecurityCookie), stkOffs);
5088 If we're supposed to track lifetimes of pointer temps, we'll
5089 assign frame offsets in the following order:
5091 non-pointer local variables (also untracked pointer variables)
5092 pointer local variables
5099 ALLOC_NON_PTRS = 0x1, // assign offsets to non-ptr
5100 ALLOC_PTRS = 0x2, // Second pass, assign offsets to tracked ptrs
5101 ALLOC_UNSAFE_BUFFERS = 0x4,
5102 ALLOC_UNSAFE_BUFFERS_WITH_PTRS = 0x8
5104 UINT alloc_order[5];
5106 unsigned int cur = 0;
5108 if (compGSReorderStackLayout)
5110 noway_assert(getNeedsGSSecurityCookie());
5112 if (codeGen->isFramePointerUsed())
5114 alloc_order[cur++] = ALLOC_UNSAFE_BUFFERS;
5115 alloc_order[cur++] = ALLOC_UNSAFE_BUFFERS_WITH_PTRS;
5119 bool tempsAllocated = false;
5122 // On ARM, SP based offsets use smaller encoding. Since temps are relatively
5123 // rarer than lcl usage, allocate them farther from SP.
5124 if (!opts.MinOpts() && !compLocallocUsed)
5126 if (lvaTempsHaveLargerOffsetThanVars() && !codeGen->isFramePointerUsed())
5129 // Because we want the temps to have a larger offset than locals
5130 // and we're not using a frame pointer, we have to place the temps
5131 // above the vars. Otherwise we place them after the vars (at the
5132 // bottom of the frame).
5133 noway_assert(!tempsAllocated);
5134 stkOffs = lvaAllocateTemps(stkOffs, mustDoubleAlign);
5135 tempsAllocated = true;
5138 alloc_order[cur++] = ALLOC_NON_PTRS;
5140 if (opts.compDbgEnC)
5142 /* We will use just one pass, and assign offsets to all variables */
5143 alloc_order[cur - 1] |= ALLOC_PTRS;
5144 noway_assert(compGSReorderStackLayout == false);
5148 alloc_order[cur++] = ALLOC_PTRS;
5151 if (!codeGen->isFramePointerUsed() && compGSReorderStackLayout)
5153 alloc_order[cur++] = ALLOC_UNSAFE_BUFFERS_WITH_PTRS;
5154 alloc_order[cur++] = ALLOC_UNSAFE_BUFFERS;
5157 alloc_order[cur] = 0;
5159 noway_assert(cur < sizeof(alloc_order) / sizeof(alloc_order[0]));
5161 // Force first pass to happen
5162 UINT assignMore = 0xFFFFFFFF;
5163 bool have_LclVarDoubleAlign = false;
5165 for (cur = 0; alloc_order[cur]; cur++)
5167 if ((assignMore & alloc_order[cur]) == 0)
5177 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
5179 /* Ignore field locals of the promotion type PROMOTION_TYPE_FIELD_DEPENDENT.
5180 In other words, we will not calculate the "base" address of the struct local if
5181 the promotion type is PROMOTION_TYPE_FIELD_DEPENDENT.
5183 if (lvaIsFieldOfDependentlyPromotedStruct(varDsc))
5188 #if FEATURE_FIXED_OUT_ARGS
5189 // The scratch mem is used for the outgoing arguments, and it must be absolutely last
5190 if (lclNum == lvaOutgoingArgSpaceVar)
5196 bool allocateOnFrame = varDsc->lvOnFrame;
5198 if (varDsc->lvRegister && (lvaDoneFrameLayout == REGALLOC_FRAME_LAYOUT) &&
5199 ((varDsc->TypeGet() != TYP_LONG) || (varDsc->lvOtherReg != REG_STK)))
5201 allocateOnFrame = false;
5204 /* Ignore variables that are not on the stack frame */
5206 if (!allocateOnFrame)
5208 /* For EnC, all variables have to be allocated space on the
5209 stack, even though they may actually be enregistered. This
5210 way, the frame layout can be directly inferred from the
5214 if (!opts.compDbgEnC)
5218 else if (lclNum >= info.compLocalsCount)
5219 { // ignore temps for EnC
5223 else if (lvaGSSecurityCookie == lclNum && getNeedsGSSecurityCookie())
5225 continue; // This is allocated outside of this loop.
5228 // These need to be located as the very first variables (highest memory address)
5229 // and so they have already been assigned an offset
5231 #if FEATURE_EH_FUNCLETS
5232 lclNum == lvaPSPSym ||
5234 lclNum == lvaShadowSPslotsVar ||
5235 #endif // FEATURE_EH_FUNCLETS
5236 lclNum == lvaLocAllocSPvar || lclNum == lvaSecurityObject)
5238 assert(varDsc->lvStkOffs != BAD_STK_OFFS);
5242 if (lclNum == lvaMonAcquired)
5247 // This should be low on the stack. Hence, it will be assigned later.
5248 if (lclNum == lvaStubArgumentVar)
5250 #ifdef JIT32_GCENCODER
5251 noway_assert(codeGen->isFramePointerUsed());
5256 // This should be low on the stack. Hence, it will be assigned later.
5257 if (lclNum == lvaInlinedPInvokeFrameVar)
5259 noway_assert(codeGen->isFramePointerUsed());
5263 if (varDsc->lvIsParam)
5265 #if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI)
5267 // On Windows AMD64 we can use the caller-reserved stack area that is already setup
5268 assert(varDsc->lvStkOffs != BAD_STK_OFFS);
5271 #else // !_TARGET_AMD64_
5273 // A register argument that is not enregistered ends up as
5274 // a local variable which will need stack frame space.
5276 if (!varDsc->lvIsRegArg)
5281 #ifdef _TARGET_ARM64_
5282 if (info.compIsVarArgs)
5284 // Stack offset to varargs (parameters) should point to home area which will be preallocated.
5286 -initialStkOffs + genMapIntRegNumToRegArgNum(varDsc->GetArgReg()) * REGSIZE_BYTES;
5292 // On ARM we spill the registers in codeGen->regSet.rsMaskPreSpillRegArg
5293 // in the prolog, thus they don't need stack frame space.
5295 if ((codeGen->regSet.rsMaskPreSpillRegs(false) & genRegMask(varDsc->lvArgReg)) != 0)
5297 assert(varDsc->lvStkOffs != BAD_STK_OFFS);
5302 #endif // !_TARGET_AMD64_
5305 /* Make sure the type is appropriate */
5307 if (varDsc->lvIsUnsafeBuffer && compGSReorderStackLayout)
5309 if (varDsc->lvIsPtr)
5311 if ((alloc_order[cur] & ALLOC_UNSAFE_BUFFERS_WITH_PTRS) == 0)
5313 assignMore |= ALLOC_UNSAFE_BUFFERS_WITH_PTRS;
5319 if ((alloc_order[cur] & ALLOC_UNSAFE_BUFFERS) == 0)
5321 assignMore |= ALLOC_UNSAFE_BUFFERS;
5326 else if (varTypeIsGC(varDsc->TypeGet()) && varDsc->lvTracked)
5328 if ((alloc_order[cur] & ALLOC_PTRS) == 0)
5330 assignMore |= ALLOC_PTRS;
5336 if ((alloc_order[cur] & ALLOC_NON_PTRS) == 0)
5338 assignMore |= ALLOC_NON_PTRS;
5343 /* Need to align the offset? */
5345 if (mustDoubleAlign && (varDsc->lvType == TYP_DOUBLE // Align doubles for ARM and x86
5347 || varDsc->lvType == TYP_LONG // Align longs for ARM
5349 #ifndef _TARGET_64BIT_
5350 || varDsc->lvStructDoubleAlign // Align when lvStructDoubleAlign is true
5351 #endif // !_TARGET_64BIT_
5354 noway_assert((compLclFrameSize % TARGET_POINTER_SIZE) == 0);
5356 if ((lvaDoneFrameLayout != FINAL_FRAME_LAYOUT) && !have_LclVarDoubleAlign)
5358 // If this is the first TYP_LONG, TYP_DOUBLE or double aligned struct
5359 // then we have seen in this loop then we allocate a pointer sized
5360 // stack slot since we may need to double align this LclVar
5361 // when lvaDoneFrameLayout == FINAL_FRAME_LAYOUT
5363 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5364 stkOffs -= TARGET_POINTER_SIZE;
5368 if (((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) != 0)
5370 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5371 stkOffs -= TARGET_POINTER_SIZE;
5374 // We should now have a double-aligned (stkOffs+preSpillSize)
5375 noway_assert(((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) == 0);
5378 // Remember that we had to double align a LclVar
5379 have_LclVarDoubleAlign = true;
5382 // Reserve the stack space for this variable
5383 stkOffs = lvaAllocLocalAndSetVirtualOffset(lclNum, lvaLclSize(lclNum), stkOffs);
5384 #ifdef _TARGET_ARM64_
5385 // If we have an incoming register argument that has a struct promoted field
5386 // then we need to copy the lvStkOff (the stack home) from the reg arg to the field lclvar
5388 if (varDsc->lvIsRegArg && varDsc->lvPromotedStruct())
5390 noway_assert(varDsc->lvFieldCnt == 1); // We only handle one field here
5392 unsigned fieldVarNum = varDsc->lvFieldLclStart;
5393 lvaTable[fieldVarNum].lvStkOffs = varDsc->lvStkOffs;
5399 if (getNeedsGSSecurityCookie() && !compGSReorderStackLayout)
5401 // LOCALLOC used, but we have no unsafe buffer. Allocated cookie last, close to localloc buffer.
5402 stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaGSSecurityCookie, lvaLclSize(lvaGSSecurityCookie), stkOffs);
5405 if (tempsAllocated == false)
5407 /*-------------------------------------------------------------------------
5411 *-------------------------------------------------------------------------
5413 stkOffs = lvaAllocateTemps(stkOffs, mustDoubleAlign);
5416 /*-------------------------------------------------------------------------
5418 * Now do some final stuff
5420 *-------------------------------------------------------------------------
5423 // lvaInlinedPInvokeFrameVar and lvaStubArgumentVar need to be assigned last
5424 // Important: The stack walker depends on lvaStubArgumentVar immediately
5425 // following lvaInlinedPInvokeFrameVar in the frame.
5427 if (lvaStubArgumentVar != BAD_VAR_NUM)
5429 #ifdef JIT32_GCENCODER
5430 noway_assert(codeGen->isFramePointerUsed());
5432 stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaStubArgumentVar, lvaLclSize(lvaStubArgumentVar), stkOffs);
5435 if (lvaInlinedPInvokeFrameVar != BAD_VAR_NUM)
5437 noway_assert(codeGen->isFramePointerUsed());
5439 lvaAllocLocalAndSetVirtualOffset(lvaInlinedPInvokeFrameVar, lvaLclSize(lvaInlinedPInvokeFrameVar), stkOffs);
5442 if (mustDoubleAlign)
5444 if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
5446 // Allocate a pointer sized stack slot, since we may need to double align here
5447 // when lvaDoneFrameLayout == FINAL_FRAME_LAYOUT
5449 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5450 stkOffs -= TARGET_POINTER_SIZE;
5452 if (have_LclVarDoubleAlign)
5454 // If we have any TYP_LONG, TYP_DOUBLE or double aligned structs
5455 // the we need to allocate a second pointer sized stack slot,
5456 // since we may need to double align the last LclVar that we saw
5457 // in the loop above. We do this so that the offsets that we
5458 // calculate for the stack frame are always greater than they will
5459 // be in the final layout.
5461 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5462 stkOffs -= TARGET_POINTER_SIZE;
5465 else // FINAL_FRAME_LAYOUT
5467 if (((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) != 0)
5469 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5470 stkOffs -= TARGET_POINTER_SIZE;
5472 // We should now have a double-aligned (stkOffs+preSpillSize)
5473 noway_assert(((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) == 0);
5477 #if FEATURE_EH_FUNCLETS && defined(_TARGET_AMD64_)
5478 if (ehNeedsPSPSym())
5480 // On AMD64, if we need a PSPSym, allocate it last, immediately above the outgoing argument
5481 // space. Any padding will be higher on the stack than this
5482 // (including the padding added by lvaAlignFrame()).
5483 noway_assert(codeGen->isFramePointerUsed()); // We need an explicit frame pointer
5484 assert(lvaPSPSym != BAD_VAR_NUM); // We should have created the PSPSym variable
5485 stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaPSPSym, TARGET_POINTER_SIZE, stkOffs);
5487 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_AMD64_)
5489 #ifdef _TARGET_ARM64_
5490 if (isFramePointerUsed())
5492 // Create space for saving FP and LR.
5493 stkOffs -= 2 * REGSIZE_BYTES;
5495 #endif // _TARGET_ARM64_
5497 #if FEATURE_FIXED_OUT_ARGS
5498 if (lvaOutgoingArgSpaceSize > 0)
5500 #if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI) // No 4 slots for outgoing params on System V.
5501 noway_assert(lvaOutgoingArgSpaceSize >= (4 * sizeof(void*)));
5503 noway_assert((lvaOutgoingArgSpaceSize % sizeof(void*)) == 0);
5505 // Give it a value so we can avoid asserts in CHK builds.
5506 // Since this will always use an SP relative offset of zero
5507 // at the end of lvaFixVirtualFrameOffsets, it will be set to absolute '0'
5509 stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaOutgoingArgSpaceVar, lvaLclSize(lvaOutgoingArgSpaceVar), stkOffs);
5511 #endif // FEATURE_FIXED_OUT_ARGS
5513 // compLclFrameSize equals our negated virtual stack offset minus the pushed registers and return address
5514 // and the pushed frame pointer register which for some strange reason isn't part of 'compCalleeRegsPushed'.
5515 int pushedCount = compCalleeRegsPushed;
5517 #ifdef _TARGET_ARM64_
5518 if (info.compIsVarArgs)
5520 pushedCount += MAX_REG_ARG;
5524 #ifdef _TARGET_XARCH_
5525 if (codeGen->doubleAlignOrFramePointerUsed())
5527 pushedCount += 1; // pushed EBP (frame pointer)
5529 pushedCount += 1; // pushed PC (return address)
5532 noway_assert(compLclFrameSize == (unsigned)-(stkOffs + (pushedCount * (int)sizeof(void*))));
5535 int Compiler::lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, int stkOffs)
5537 noway_assert(lclNum != BAD_VAR_NUM);
5539 #ifdef _TARGET_64BIT_
5540 // Before final frame layout, assume the worst case, that every >=8 byte local will need
5541 // maximum padding to be aligned. This is because we generate code based on the stack offset
5542 // computed during tentative frame layout. These offsets cannot get bigger during final
5543 // frame layout, as that would possibly require different code generation (for example,
5544 // using a 4-byte offset instead of a 1-byte offset in an instruction). The offsets can get
5545 // smaller. It is possible there is different alignment at the point locals are allocated
5546 // between tentative and final frame layout which would introduce padding between locals
5547 // and thus increase the offset (from the stack pointer) of one of the locals. Hence the
5548 // need to assume the worst alignment before final frame layout.
5549 // We could probably improve this by sorting all the objects by alignment,
5550 // such that all 8 byte objects are together, 4 byte objects are together, etc., which
5551 // would require at most one alignment padding per group.
5553 // TYP_SIMD structs locals have alignment preference given by getSIMDTypeAlignment() for
5554 // better performance.
5555 if ((size >= 8) && ((lvaDoneFrameLayout != FINAL_FRAME_LAYOUT) || ((stkOffs % 8) != 0)
5556 #if defined(FEATURE_SIMD) && ALIGN_SIMD_TYPES
5557 || lclVarIsSIMDType(lclNum)
5561 // Note that stack offsets are negative
5562 assert(stkOffs < 0);
5564 // alignment padding
5566 #if defined(FEATURE_SIMD) && ALIGN_SIMD_TYPES
5567 if (lclVarIsSIMDType(lclNum) && !lvaIsImplicitByRefLocal(lclNum))
5569 int alignment = getSIMDTypeAlignment(lvaTable[lclNum].lvType);
5571 if (stkOffs % alignment != 0)
5573 if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
5575 pad = alignment - 1;
5576 // Note that all the objects will probably be misaligned, but we'll fix that in final layout.
5580 pad = alignment + (stkOffs % alignment); // +1 to +(alignment-1) bytes
5585 #endif // FEATURE_SIMD && ALIGN_SIMD_TYPES
5587 if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
5590 // Note that all the objects will probably be misaligned, but we'll fix that in final layout.
5594 pad = 8 + (stkOffs % 8); // +1 to +7 bytes
5597 // Will the pad ever be anything except 4? Do we put smaller-than-4-sized objects on the stack?
5598 lvaIncrementFrameSize(pad);
5605 gtDispLclVar(lclNum, /*pad*/ false);
5606 printf(", size=%d, stkOffs=%c0x%x, pad=%d\n", size, stkOffs < 0 ? '-' : '+',
5607 stkOffs < 0 ? -stkOffs : stkOffs, pad);
5611 #endif // _TARGET_64BIT_
5613 /* Reserve space on the stack by bumping the frame size */
5615 lvaIncrementFrameSize(size);
5617 lvaTable[lclNum].lvStkOffs = stkOffs;
5623 gtDispLclVar(lclNum, /*pad*/ false);
5624 printf(", size=%d, stkOffs=%c0x%x\n", size, stkOffs < 0 ? '-' : '+', stkOffs < 0 ? -stkOffs : stkOffs);
5631 #ifdef _TARGET_AMD64_
5632 /*****************************************************************************
5633 * lvaIsCalleeSavedIntRegCountEven() : returns true if the number of integer registers
5634 * pushed onto stack is even including RBP if used as frame pointer
5636 * Note that this excludes return address (PC) pushed by caller. To know whether
5637 * the SP offset after pushing integer registers is aligned, we need to take
5638 * negation of this routine.
5640 bool Compiler::lvaIsCalleeSavedIntRegCountEven()
5642 unsigned regsPushed = compCalleeRegsPushed + (codeGen->isFramePointerUsed() ? 1 : 0);
5643 return (regsPushed % (16 / REGSIZE_BYTES)) == 0;
5645 #endif //_TARGET_AMD64_
5647 /*****************************************************************************
5648 * lvaAlignFrame() : After allocating everything on the frame, reserve any
5649 * extra space needed to keep the frame aligned
5651 void Compiler::lvaAlignFrame()
5653 #if defined(_TARGET_AMD64_)
5655 // Leaf frames do not need full alignment, but the unwind info is smaller if we
5656 // are at least 8 byte aligned (and we assert as much)
5657 if ((compLclFrameSize % 8) != 0)
5659 lvaIncrementFrameSize(8 - (compLclFrameSize % 8));
5661 else if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
5663 // If we are not doing final layout, we don't know the exact value of compLclFrameSize
5664 // and thus do not know how much we will need to add in order to be aligned.
5665 // We add 8 so compLclFrameSize is still a multiple of 8.
5666 lvaIncrementFrameSize(8);
5668 assert((compLclFrameSize % 8) == 0);
5670 // Ensure that the stack is always 16-byte aligned by grabbing an unused QWORD
5671 // if needed, but off by 8 because of the return value.
5672 // And don't forget that compCalleeRegsPused does *not* include RBP if we are
5673 // using it as the frame pointer.
5675 bool regPushedCountAligned = lvaIsCalleeSavedIntRegCountEven();
5676 bool lclFrameSizeAligned = (compLclFrameSize % 16) == 0;
5678 // If this isn't the final frame layout, assume we have to push an extra QWORD
5679 // Just so the offsets are true upper limits.
5680 CLANG_FORMAT_COMMENT_ANCHOR;
5682 #ifdef UNIX_AMD64_ABI
5683 // The compNeedToAlignFrame flag is indicating if there is a need to align the frame.
5684 // On AMD64-Windows, if there are calls, 4 slots for the outgoing ars are allocated, except for
5685 // FastTailCall. This slots makes the frame size non-zero, so alignment logic will be called.
5686 // On AMD64-Unix, there are no such slots. There is a possibility to have calls in the method with frame size of 0.
5687 // The frame alignment logic won't kick in. This flags takes care of the AMD64-Unix case by remembering that there
5688 // are calls and making sure the frame alignment logic is executed.
5689 bool stackNeedsAlignment = (compLclFrameSize != 0 || opts.compNeedToAlignFrame);
5690 #else // !UNIX_AMD64_ABI
5691 bool stackNeedsAlignment = compLclFrameSize != 0;
5692 #endif // !UNIX_AMD64_ABI
5693 if ((!codeGen->isFramePointerUsed() && (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)) ||
5694 (stackNeedsAlignment && (regPushedCountAligned == lclFrameSizeAligned)))
5696 lvaIncrementFrameSize(REGSIZE_BYTES);
5699 #elif defined(_TARGET_ARM64_)
5701 // The stack on ARM64 must be 16 byte aligned.
5703 // First, align up to 8.
5704 if ((compLclFrameSize % 8) != 0)
5706 lvaIncrementFrameSize(8 - (compLclFrameSize % 8));
5708 else if (lvaDoneFrameLayout != FINAL_FRAME_LAYOUT)
5710 // If we are not doing final layout, we don't know the exact value of compLclFrameSize
5711 // and thus do not know how much we will need to add in order to be aligned.
5712 // We add 8 so compLclFrameSize is still a multiple of 8.
5713 lvaIncrementFrameSize(8);
5715 assert((compLclFrameSize % 8) == 0);
5717 // Ensure that the stack is always 16-byte aligned by grabbing an unused QWORD
5719 bool regPushedCountAligned = (compCalleeRegsPushed % (16 / REGSIZE_BYTES)) == 0;
5720 bool lclFrameSizeAligned = (compLclFrameSize % 16) == 0;
5722 // If this isn't the final frame layout, assume we have to push an extra QWORD
5723 // Just so the offsets are true upper limits.
5724 if ((lvaDoneFrameLayout != FINAL_FRAME_LAYOUT) || (regPushedCountAligned != lclFrameSizeAligned))
5726 lvaIncrementFrameSize(REGSIZE_BYTES);
5729 #elif defined(_TARGET_ARM_)
5731 // Ensure that stack offsets will be double-aligned by grabbing an unused DWORD if needed.
5733 bool lclFrameSizeAligned = (compLclFrameSize % sizeof(double)) == 0;
5734 bool regPushedCountAligned = ((compCalleeRegsPushed + genCountBits(codeGen->regSet.rsMaskPreSpillRegs(true))) %
5735 (sizeof(double) / sizeof(void*))) == 0;
5737 if (regPushedCountAligned != lclFrameSizeAligned)
5739 lvaIncrementFrameSize(sizeof(void*));
5742 #elif defined(_TARGET_X86_)
5744 if (genDoubleAlign())
5746 // Double Frame Alignement for x86 is handled in Compiler::lvaAssignVirtualFrameOffsetsToLocals()
5748 if (compLclFrameSize == 0)
5750 // This can only happen with JitStress=1 or JitDoubleAlign=2
5751 lvaIncrementFrameSize(sizeof(void*));
5756 NYI("TARGET specific lvaAlignFrame");
5757 #endif // !_TARGET_AMD64_
5760 /*****************************************************************************
5761 * lvaAssignFrameOffsetsToPromotedStructs() : Assign offsets to fields
5762 * within a promoted struct (worker for lvaAssignFrameOffsets).
5764 void Compiler::lvaAssignFrameOffsetsToPromotedStructs()
5766 LclVarDsc* varDsc = lvaTable;
5767 for (unsigned lclNum = 0; lclNum < lvaCount; lclNum++, varDsc++)
5769 // For promoted struct fields that are params, we will
5770 // assign their offsets in lvaAssignVirtualFrameOffsetToArg().
5771 // This is not true for the System V systems since there is no
5772 // outgoing args space. Assign the dependently promoted fields properly.
5774 if (varDsc->lvIsStructField
5775 #ifndef UNIX_AMD64_ABI
5776 // For System V platforms there is no outgoing args space.
5777 // A register passed struct arg is homed on the stack in a separate local var.
5778 // The offset of these structs is already calculated in lvaAssignVirtualFrameOffsetToArg methos.
5779 // Make sure the code below is not executed for these structs and the offset is not changed.
5780 && !varDsc->lvIsParam
5781 #endif // UNIX_AMD64_ABI
5784 LclVarDsc* parentvarDsc = &lvaTable[varDsc->lvParentLcl];
5785 lvaPromotionType promotionType = lvaGetPromotionType(parentvarDsc);
5787 if (promotionType == PROMOTION_TYPE_INDEPENDENT)
5789 // The stack offset for these field locals must have been calculated
5790 // by the normal frame offset assignment.
5795 noway_assert(promotionType == PROMOTION_TYPE_DEPENDENT);
5796 noway_assert(varDsc->lvOnFrame);
5797 varDsc->lvStkOffs = parentvarDsc->lvStkOffs + varDsc->lvFldOffset;
5803 /*****************************************************************************
5804 * lvaAllocateTemps() : Assign virtual offsets to temps (always negative).
5806 int Compiler::lvaAllocateTemps(int stkOffs, bool mustDoubleAlign)
5808 unsigned spillTempSize = 0;
5810 if (lvaDoneFrameLayout == FINAL_FRAME_LAYOUT)
5812 int preSpillSize = 0;
5814 preSpillSize = genCountBits(codeGen->regSet.rsMaskPreSpillRegs(true)) * TARGET_POINTER_SIZE;
5818 bool assignPtrs = true;
5820 /* Allocate temps */
5822 if (TRACK_GC_TEMP_LIFETIMES)
5824 /* first pointers, then non-pointers in second pass */
5830 /* Pointers and non-pointers together in single pass */
5835 assert(tmpAllFree());
5839 for (TempDsc* temp = tmpListBeg(); temp != nullptr; temp = tmpListNxt(temp))
5841 var_types tempType = temp->tdTempType();
5844 /* Make sure the type is appropriate */
5846 if (!assignPtrs && varTypeIsGC(tempType))
5850 if (!assignNptr && !varTypeIsGC(tempType))
5855 size = temp->tdTempSize();
5857 /* Figure out and record the stack offset of the temp */
5859 /* Need to align the offset? */
5860 CLANG_FORMAT_COMMENT_ANCHOR;
5862 #ifdef _TARGET_64BIT_
5863 if (varTypeIsGC(tempType) && ((stkOffs % TARGET_POINTER_SIZE) != 0))
5865 // Calculate 'pad' as the number of bytes to align up 'stkOffs' to be a multiple of TARGET_POINTER_SIZE
5866 // In practice this is really just a fancy way of writing 4. (as all stack locations are at least 4-byte
5867 // aligned). Note stkOffs is always negative, so (stkOffs % TARGET_POINTER_SIZE) yields a negative
5870 int alignPad = (int)AlignmentPad((unsigned)-stkOffs, TARGET_POINTER_SIZE);
5872 spillTempSize += alignPad;
5873 lvaIncrementFrameSize(alignPad);
5874 stkOffs -= alignPad;
5876 noway_assert((stkOffs % TARGET_POINTER_SIZE) == 0);
5880 if (mustDoubleAlign && (tempType == TYP_DOUBLE)) // Align doubles for x86 and ARM
5882 noway_assert((compLclFrameSize % TARGET_POINTER_SIZE) == 0);
5884 if (((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) != 0)
5886 spillTempSize += TARGET_POINTER_SIZE;
5887 lvaIncrementFrameSize(TARGET_POINTER_SIZE);
5888 stkOffs -= TARGET_POINTER_SIZE;
5890 // We should now have a double-aligned (stkOffs+preSpillSize)
5891 noway_assert(((stkOffs + preSpillSize) % (2 * TARGET_POINTER_SIZE)) == 0);
5894 spillTempSize += size;
5895 lvaIncrementFrameSize(size);
5897 temp->tdSetTempOffs(stkOffs);
5900 // Only required for the ARM platform that we have an accurate estimate for the spillTempSize
5901 noway_assert(spillTempSize <= lvaGetMaxSpillTempSize());
5904 /* If we've only assigned some temps, go back and do the rest now */
5908 assignNptr = !assignNptr;
5909 assignPtrs = !assignPtrs;
5915 else // We haven't run codegen, so there are no Spill temps yet!
5917 unsigned size = lvaGetMaxSpillTempSize();
5919 lvaIncrementFrameSize(size);
5928 /*****************************************************************************
5930 * Dump the register a local is in right now.
5931 * For non-LSRA, this will be the register it is always in. For LSRA, it's only the current
5932 * location, since the location changes and it is updated throughout code generation based on
5933 * LSRA register assignments.
5936 void Compiler::lvaDumpRegLocation(unsigned lclNum)
5938 LclVarDsc* varDsc = lvaTable + lclNum;
5939 var_types type = varDsc->TypeGet();
5941 #if FEATURE_STACK_FP_X87
5942 if (varTypeIsFloating(type))
5944 printf("fpu stack ");
5948 if (isRegPairType(type))
5952 noway_assert(varDsc->lvRegNum != REG_STK);
5954 if (doLSRA() && varDsc->lvRegNum == REG_STK)
5956 /* Hi-only enregistered long */
5957 int offset = varDsc->lvStkOffs;
5958 printf("%-3s:[%1s0x%02X]",
5959 getRegName(varDsc->lvOtherReg), // hi32
5960 (offset < 0 ? "-" : "+"), (offset < 0 ? -offset : offset));
5962 else if (varDsc->lvOtherReg != REG_STK)
5964 /* Fully enregistered long */
5966 getRegName(varDsc->lvOtherReg), // hi32
5967 getRegName(varDsc->lvRegNum)); // lo32
5971 /* Partially enregistered long */
5972 int offset = varDsc->lvStkOffs + 4;
5973 printf("[%1s0x%02X]:%-3s", (offset < 0 ? "-" : "+"), (offset < 0 ? -offset : offset),
5974 getRegName(varDsc->lvRegNum)); // lo32
5978 else if (varDsc->TypeGet() == TYP_DOUBLE)
5980 printf("%3s:%-3s ", getRegName(varDsc->lvRegNum), getRegName(varDsc->lvOtherReg));
5985 printf("%3s ", getRegName(varDsc->lvRegNum));
5989 /*****************************************************************************
5991 * Dump the frame location assigned to a local.
5992 * For non-LSRA, this will only be valid if there is no assigned register.
5993 * For LSRA, it's the home location, even though the variable doesn't always live
5994 * in its home location.
5997 void Compiler::lvaDumpFrameLocation(unsigned lclNum)
6003 offset = lvaFrameAddress(lclNum, compLocallocUsed, &baseReg, 0);
6006 offset = lvaFrameAddress(lclNum, &EBPbased);
6007 baseReg = EBPbased ? REG_FPBASE : REG_SPBASE;
6010 printf("[%2s%1s0x%02X] ", getRegName(baseReg), (offset < 0 ? "-" : "+"), (offset < 0 ? -offset : offset));
6013 /*****************************************************************************
6015 * dump a single lvaTable entry
6018 void Compiler::lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t refCntWtdWidth)
6020 LclVarDsc* varDsc = lvaTable + lclNum;
6021 var_types type = varDsc->TypeGet();
6023 if (curState == INITIAL_FRAME_LAYOUT)
6026 gtDispLclVar(lclNum);
6028 printf(" %7s ", varTypeName(type));
6029 if (genTypeSize(type) == 0)
6031 printf("(%2d) ", lvaLclSize(lclNum));
6036 if (varDsc->lvRefCnt == 0)
6038 // Print this with a special indicator that the variable is unused. Even though the
6039 // variable itself is unused, it might be a struct that is promoted, so seeing it
6040 // can be useful when looking at the promoted struct fields. It's also weird to see
6041 // missing var numbers if these aren't printed.
6045 #if FEATURE_FIXED_OUT_ARGS
6046 if ((lclNum == lvaOutgoingArgSpaceVar) && (lvaLclSize(lclNum) == 0))
6048 // Similar to above; print this anyway.
6057 gtDispLclVar(lclNum);
6059 printf("[V%02u", lclNum);
6060 if (varDsc->lvTracked)
6062 printf(",T%02u]", varDsc->lvVarIndex);
6069 printf(" (%3u,%*s)", varDsc->lvRefCnt, (int)refCntWtdWidth, refCntWtd2str(varDsc->lvRefCntWtd));
6071 printf(" %7s ", varTypeName(type));
6072 if (genTypeSize(type) == 0)
6074 printf("(%2d) ", lvaLclSize(lclNum));
6081 // The register or stack location field is 11 characters wide.
6082 if (varDsc->lvRefCnt == 0)
6084 printf("zero-ref ");
6086 else if (varDsc->lvRegister != 0)
6088 // It's always a register, and always in the same register.
6089 lvaDumpRegLocation(lclNum);
6091 else if (varDsc->lvOnFrame == 0)
6093 printf("registers ");
6097 // For RyuJIT backend, it might be in a register part of the time, but it will definitely have a stack home
6098 // location. Otherwise, it's always on the stack.
6099 if (lvaDoneFrameLayout != NO_FRAME_LAYOUT)
6101 lvaDumpFrameLocation(lclNum);
6106 if (varDsc->lvIsHfaRegArg())
6108 if (varDsc->lvHfaTypeIsFloat())
6110 printf(" (enregistered HFA: float) ");
6114 printf(" (enregistered HFA: double)");
6118 if (varDsc->lvDoNotEnregister)
6120 printf(" do-not-enreg[");
6121 if (varDsc->lvAddrExposed)
6125 if (varTypeIsStruct(varDsc))
6129 if (varDsc->lvVMNeedsStackAddr)
6133 if (varDsc->lvLiveInOutOfHndlr)
6137 if (varDsc->lvLclFieldExpr)
6141 if (varDsc->lvLclBlockOpAddr)
6145 if (varDsc->lvLiveAcrossUCall)
6149 if (varDsc->lvIsMultiRegArg)
6153 if (varDsc->lvIsMultiRegRet)
6157 #ifdef JIT32_GCENCODER
6158 if (varDsc->lvPinned)
6160 #endif // JIT32_GCENCODER
6164 if (varDsc->lvIsMultiRegArg)
6166 printf(" multireg-arg");
6168 if (varDsc->lvIsMultiRegRet)
6170 printf(" multireg-ret");
6172 if (varDsc->lvMustInit)
6174 printf(" must-init");
6176 if (varDsc->lvAddrExposed)
6178 printf(" addr-exposed");
6180 if (varDsc->lvHasLdAddrOp)
6182 printf(" ld-addr-op");
6184 if (varDsc->lvVerTypeInfo.IsThisPtr())
6188 if (varDsc->lvPinned)
6192 if (varDsc->lvRefAssign)
6194 printf(" ref-asgn");
6196 if (varDsc->lvStackByref)
6198 printf(" stack-byref");
6200 #ifndef _TARGET_64BIT_
6201 if (varDsc->lvStructDoubleAlign)
6202 printf(" double-align");
6203 #endif // !_TARGET_64BIT_
6204 if (varDsc->lvOverlappingFields)
6206 printf(" overlapping-fields");
6209 if (compGSReorderStackLayout && !varDsc->lvRegister)
6211 if (varDsc->lvIsPtr)
6215 if (varDsc->lvIsUnsafeBuffer)
6217 printf(" unsafe-buffer");
6220 if (varDsc->lvIsStructField)
6222 LclVarDsc* parentvarDsc = &lvaTable[varDsc->lvParentLcl];
6223 #if !defined(_TARGET_64BIT_)
6224 if (varTypeIsLong(parentvarDsc))
6226 bool isLo = (lclNum == parentvarDsc->lvFieldLclStart);
6227 printf(" V%02u.%s(offs=0x%02x)", varDsc->lvParentLcl, isLo ? "lo" : "hi", isLo ? 0 : genTypeSize(TYP_INT));
6230 #endif // !defined(_TARGET_64BIT_)
6232 CORINFO_CLASS_HANDLE typeHnd = parentvarDsc->lvVerTypeInfo.GetClassHandle();
6233 CORINFO_FIELD_HANDLE fldHnd = info.compCompHnd->getFieldInClass(typeHnd, varDsc->lvFldOrdinal);
6235 printf(" V%02u.%s(offs=0x%02x)", varDsc->lvParentLcl, eeGetFieldName(fldHnd), varDsc->lvFldOffset);
6237 lvaPromotionType promotionType = lvaGetPromotionType(parentvarDsc);
6238 // We should never have lvIsStructField set if it is a reg-sized non-field-addressed struct.
6239 assert(!varDsc->lvRegStruct);
6240 switch (promotionType)
6242 case PROMOTION_TYPE_NONE:
6245 case PROMOTION_TYPE_DEPENDENT:
6248 case PROMOTION_TYPE_INDEPENDENT:
6258 /*****************************************************************************
6263 void Compiler::lvaTableDump(FrameLayoutState curState)
6265 if (curState == NO_FRAME_LAYOUT)
6267 curState = lvaDoneFrameLayout;
6268 if (curState == NO_FRAME_LAYOUT)
6270 // Still no layout? Could be a bug, but just display the initial layout
6271 curState = INITIAL_FRAME_LAYOUT;
6275 if (curState == INITIAL_FRAME_LAYOUT)
6277 printf("; Initial");
6279 else if (curState == PRE_REGALLOC_FRAME_LAYOUT)
6281 printf("; Pre-RegAlloc");
6283 else if (curState == REGALLOC_FRAME_LAYOUT)
6285 printf("; RegAlloc");
6287 else if (curState == TENTATIVE_FRAME_LAYOUT)
6289 printf("; Tentative");
6291 else if (curState == FINAL_FRAME_LAYOUT)
6297 printf("UNKNOWN FrameLayoutState!");
6301 printf(" local variable assignments\n");
6307 // Figure out some sizes, to help line things up
6309 size_t refCntWtdWidth = 6; // Use 6 as the minimum width
6311 if (curState != INITIAL_FRAME_LAYOUT) // don't need this info for INITIAL_FRAME_LAYOUT
6313 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
6315 size_t width = strlen(refCntWtd2str(varDsc->lvRefCntWtd));
6316 if (width > refCntWtdWidth)
6318 refCntWtdWidth = width;
6323 // Do the actual output
6325 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
6327 lvaDumpEntry(lclNum, curState, refCntWtdWidth);
6330 //-------------------------------------------------------------------------
6331 // Display the code-gen temps
6333 assert(tmpAllFree());
6334 for (TempDsc* temp = tmpListBeg(); temp != nullptr; temp = tmpListNxt(temp))
6336 printf("; TEMP_%02u %26s%*s%7s -> ", -temp->tdTempNum(), " ", refCntWtdWidth, " ",
6337 varTypeName(temp->tdTempType()));
6338 int offset = temp->tdTempOffs();
6339 printf(" [%2s%1s0x%02X]\n", isFramePointerUsed() ? STR_FPBASE : STR_SPBASE, (offset < 0 ? "-" : "+"),
6340 (offset < 0 ? -offset : offset));
6343 if (curState >= TENTATIVE_FRAME_LAYOUT)
6346 printf("; Lcl frame size = %d\n", compLclFrameSize);
6351 /*****************************************************************************
6353 * Conservatively estimate the layout of the stack frame.
6355 * This function is only used before final frame layout. It conservatively estimates the
6356 * number of callee-saved registers that must be saved, then calls lvaAssignFrameOffsets().
6357 * To do final frame layout, the callee-saved registers are known precisely, so
6358 * lvaAssignFrameOffsets() is called directly.
6360 * Returns the (conservative, that is, overly large) estimated size of the frame,
6361 * including the callee-saved registers. This is only used by the emitter during code
6362 * generation when estimating the size of the offset of instructions accessing temps,
6363 * and only if temps have a larger offset than variables.
6366 unsigned Compiler::lvaFrameSize(FrameLayoutState curState)
6368 assert(curState < FINAL_FRAME_LAYOUT);
6372 /* Layout the stack frame conservatively.
6373 Assume all callee-saved registers are spilled to stack */
6375 compCalleeRegsPushed = CNT_CALLEE_SAVED;
6377 #if defined(_TARGET_ARMARCH_)
6378 if (compFloatingPointUsed)
6379 compCalleeRegsPushed += CNT_CALLEE_SAVED_FLOAT;
6381 compCalleeRegsPushed++; // we always push LR. See genPushCalleeSavedRegisters
6382 #elif defined(_TARGET_AMD64_)
6383 if (compFloatingPointUsed)
6385 compCalleeFPRegsSavedMask = RBM_FLT_CALLEE_SAVED;
6389 compCalleeFPRegsSavedMask = RBM_NONE;
6394 if (genDoubleAlign())
6396 // X86 only - account for extra 4-byte pad that may be created by "and esp, -8" instruction
6397 compCalleeRegsPushed++;
6401 #ifdef _TARGET_XARCH_
6402 // Since FP/EBP is included in the SAVED_REG_MAXSZ we need to
6403 // subtract 1 register if codeGen->isFramePointerUsed() is true.
6404 if (codeGen->isFramePointerUsed())
6406 compCalleeRegsPushed--;
6410 lvaAssignFrameOffsets(curState);
6412 unsigned calleeSavedRegMaxSz = CALLEE_SAVED_REG_MAXSZ;
6413 #if defined(_TARGET_ARMARCH_)
6414 if (compFloatingPointUsed)
6416 calleeSavedRegMaxSz += CALLEE_SAVED_FLOAT_MAXSZ;
6418 calleeSavedRegMaxSz += REGSIZE_BYTES; // we always push LR. See genPushCalleeSavedRegisters
6421 result = compLclFrameSize + calleeSavedRegMaxSz;
6425 //------------------------------------------------------------------------
6426 // lvaGetSPRelativeOffset: Given a variable, return the offset of that
6427 // variable in the frame from the stack pointer. This number will be positive,
6428 // since the stack pointer must be at a lower address than everything on the
6431 // This can't be called for localloc functions, since the stack pointer
6432 // varies, and thus there is no fixed offset to a variable from the stack pointer.
6435 // varNum - the variable number
6440 int Compiler::lvaGetSPRelativeOffset(unsigned varNum)
6442 assert(!compLocallocUsed);
6443 assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
6444 assert(varNum < lvaCount);
6445 const LclVarDsc* varDsc = lvaTable + varNum;
6446 assert(varDsc->lvOnFrame);
6447 int spRelativeOffset;
6449 if (varDsc->lvFramePointerBased)
6451 // The stack offset is relative to the frame pointer, so convert it to be
6452 // relative to the stack pointer (which makes no sense for localloc functions).
6453 spRelativeOffset = varDsc->lvStkOffs + codeGen->genSPtoFPdelta();
6457 spRelativeOffset = varDsc->lvStkOffs;
6460 assert(spRelativeOffset >= 0);
6461 return spRelativeOffset;
6464 /*****************************************************************************
6466 * Return the caller-SP-relative stack offset of a local/parameter.
6467 * Requires the local to be on the stack and frame layout to be complete.
6470 int Compiler::lvaGetCallerSPRelativeOffset(unsigned varNum)
6472 assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
6473 assert(varNum < lvaCount);
6474 LclVarDsc* varDsc = lvaTable + varNum;
6475 assert(varDsc->lvOnFrame);
6477 return lvaToCallerSPRelativeOffset(varDsc->lvStkOffs, varDsc->lvFramePointerBased);
6480 int Compiler::lvaToCallerSPRelativeOffset(int offset, bool isFpBased)
6482 assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
6486 offset += codeGen->genCallerSPtoFPdelta();
6490 offset += codeGen->genCallerSPtoInitialSPdelta();
6496 /*****************************************************************************
6498 * Return the Initial-SP-relative stack offset of a local/parameter.
6499 * Requires the local to be on the stack and frame layout to be complete.
6502 int Compiler::lvaGetInitialSPRelativeOffset(unsigned varNum)
6504 assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
6505 assert(varNum < lvaCount);
6506 LclVarDsc* varDsc = lvaTable + varNum;
6507 assert(varDsc->lvOnFrame);
6509 return lvaToInitialSPRelativeOffset(varDsc->lvStkOffs, varDsc->lvFramePointerBased);
6512 // Given a local variable offset, and whether that offset is frame-pointer based, return its offset from Initial-SP.
6513 // This is used, for example, to figure out the offset of the frame pointer from Initial-SP.
6514 int Compiler::lvaToInitialSPRelativeOffset(unsigned offset, bool isFpBased)
6516 assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
6517 #ifdef _TARGET_AMD64_
6520 // Currently, the frame starts by pushing ebp, ebp points to the saved ebp
6521 // (so we have ebp pointer chaining). Add the fixed-size frame size plus the
6522 // size of the callee-saved regs (not including ebp itself) to find Initial-SP.
6524 assert(codeGen->isFramePointerUsed());
6525 offset += codeGen->genSPtoFPdelta();
6529 // The offset is correct already!
6531 #else // !_TARGET_AMD64_
6532 NYI("lvaToInitialSPRelativeOffset");
6533 #endif // !_TARGET_AMD64_
6538 /*****************************************************************************/
6541 /*****************************************************************************
6542 * Pick a padding size at "random" for the local.
6543 * 0 means that it should not be converted to a GT_LCL_FLD
6546 static unsigned LCL_FLD_PADDING(unsigned lclNum)
6548 // Convert every 2nd variable
6554 // Pick a padding size at "random"
6555 unsigned size = lclNum % 7;
6560 /*****************************************************************************
6562 * Callback for fgWalkAllTreesPre()
6563 * Convert as many GT_LCL_VAR's to GT_LCL_FLD's
6568 The stress mode does 2 passes.
6570 In the first pass we will mark the locals where we CAN't apply the stress mode.
6571 In the second pass we will do the appropiate morphing wherever we've not determined we can't do it.
6573 Compiler::fgWalkResult Compiler::lvaStressLclFldCB(GenTreePtr* pTree, fgWalkData* data)
6575 GenTreePtr tree = *pTree;
6576 genTreeOps oper = tree->OperGet();
6586 if (tree->gtOp.gtOp1->gtOper != GT_LCL_VAR)
6588 return WALK_CONTINUE;
6590 lcl = tree->gtOp.gtOp1;
6594 return WALK_CONTINUE;
6597 Compiler* pComp = ((lvaStressLclFldArgs*)data->pCallbackData)->m_pCompiler;
6598 bool bFirstPass = ((lvaStressLclFldArgs*)data->pCallbackData)->m_bFirstPass;
6599 noway_assert(lcl->gtOper == GT_LCL_VAR);
6600 unsigned lclNum = lcl->gtLclVarCommon.gtLclNum;
6601 var_types type = lcl->TypeGet();
6602 LclVarDsc* varDsc = &pComp->lvaTable[lclNum];
6604 if (varDsc->lvNoLclFldStress)
6606 // Already determined we can't do anything for this var
6607 return WALK_SKIP_SUBTREES;
6612 // Ignore arguments and temps
6613 if (varDsc->lvIsParam || lclNum >= pComp->info.compLocalsCount)
6615 varDsc->lvNoLclFldStress = true;
6616 return WALK_SKIP_SUBTREES;
6619 // Fix for lcl_fld stress mode
6620 if (varDsc->lvKeepType)
6622 varDsc->lvNoLclFldStress = true;
6623 return WALK_SKIP_SUBTREES;
6626 // Can't have GC ptrs in TYP_BLK.
6627 if (!varTypeIsArithmetic(type))
6629 varDsc->lvNoLclFldStress = true;
6630 return WALK_SKIP_SUBTREES;
6633 // Weed out "small" types like TYP_BYTE as we don't mark the GT_LCL_VAR
6634 // node with the accurate small type. If we bash lvaTable[].lvType,
6635 // then there will be no indication that it was ever a small type.
6636 var_types varType = varDsc->TypeGet();
6637 if (varType != TYP_BLK && genTypeSize(varType) != genTypeSize(genActualType(varType)))
6639 varDsc->lvNoLclFldStress = true;
6640 return WALK_SKIP_SUBTREES;
6643 // Offset some of the local variable by a "random" non-zero amount
6644 unsigned padding = LCL_FLD_PADDING(lclNum);
6647 varDsc->lvNoLclFldStress = true;
6648 return WALK_SKIP_SUBTREES;
6654 noway_assert(varDsc->lvType == lcl->gtType || varDsc->lvType == TYP_BLK);
6655 var_types varType = varDsc->TypeGet();
6657 // Calculate padding
6658 unsigned padding = LCL_FLD_PADDING(lclNum);
6660 // Change the variable to a TYP_BLK
6661 if (varType != TYP_BLK)
6663 varDsc->lvExactSize = (unsigned)(roundUp(padding + pComp->lvaLclSize(lclNum)));
6664 varDsc->lvType = TYP_BLK;
6665 pComp->lvaSetVarAddrExposed(lclNum);
6668 tree->gtFlags |= GTF_GLOB_REF;
6670 /* Now morph the tree appropriately */
6671 if (oper == GT_LCL_VAR)
6673 /* Change lclVar(lclNum) to lclFld(lclNum,padding) */
6675 tree->ChangeOper(GT_LCL_FLD);
6676 tree->gtLclFld.gtLclOffs = padding;
6680 /* Change addr(lclVar) to addr(lclVar)+padding */
6682 noway_assert(oper == GT_ADDR);
6683 GenTreePtr newAddr = new (pComp, GT_NONE) GenTreeOp(*tree->AsOp());
6685 tree->ChangeOper(GT_ADD);
6686 tree->gtOp.gtOp1 = newAddr;
6687 tree->gtOp.gtOp2 = pComp->gtNewIconNode(padding);
6689 lcl->gtType = TYP_BLK;
6693 return WALK_SKIP_SUBTREES;
6696 /*****************************************************************************/
6698 void Compiler::lvaStressLclFld()
6700 if (!compStressCompile(STRESS_LCL_FLDS, 5))
6705 lvaStressLclFldArgs Args;
6706 Args.m_pCompiler = this;
6707 Args.m_bFirstPass = true;
6710 fgWalkAllTreesPre(lvaStressLclFldCB, &Args);
6713 Args.m_bFirstPass = false;
6714 fgWalkAllTreesPre(lvaStressLclFldCB, &Args);
6719 /*****************************************************************************
6721 * A little routine that displays a local variable bitset.
6722 * 'set' is mask of variables that have to be displayed
6723 * 'allVars' is the complete set of interesting variables (blank space is
6724 * inserted if its corresponding bit is not in 'set').
6728 void Compiler::lvaDispVarSet(VARSET_VALARG_TP set)
6730 VARSET_TP VARSET_INIT_NOCOPY(allVars, VarSetOps::MakeEmpty(this));
6731 lvaDispVarSet(set, allVars);
6734 void Compiler::lvaDispVarSet(VARSET_VALARG_TP set, VARSET_VALARG_TP allVars)
6738 bool needSpace = false;
6740 for (unsigned index = 0; index < lvaTrackedCount; index++)
6742 if (VarSetOps::IsMember(this, set, index))
6747 /* Look for the matching variable */
6749 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
6751 if ((varDsc->lvVarIndex == index) && varDsc->lvTracked)
6766 printf("V%02u", lclNum);
6768 else if (VarSetOps::IsMember(this, allVars, index))