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 Represents the method data we are currently JIT-compiling. XX
11 XX An instance of this class is created for every method we JIT. XX
12 XX This contains all the info needed for the method. So allocating a XX
13 XX a new instance per method makes it thread-safe. XX
14 XX It should be used to do all the memory management for the compiler run. XX
16 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
17 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
20 /*****************************************************************************/
23 /*****************************************************************************/
29 #include "jithashtable.h"
38 #include "cycletimer.h"
40 #include "arraystack.h"
43 #include "jitexpandarray.h"
44 #include "tinyarray.h"
47 #include "jittelemetry.h"
48 #include "namedintrinsiclist.h"
53 #include "codegeninterface.h"
55 #include "jitgcinfo.h"
57 #if DUMP_GC_TABLES && defined(JIT32_GCENCODER)
65 // This is only used locally in the JIT to indicate that
66 // a verification block should be inserted
67 #define SEH_VERIFICATION_EXCEPTION 0xe0564552 // VER
69 /*****************************************************************************
70 * Forward declarations
73 struct InfoHdr; // defined in GCInfo.h
74 struct escapeMapping_t; // defined in flowgraph.cpp
75 class emitter; // defined in emit.h
76 struct ShadowParamVarInfo; // defined in GSChecks.cpp
77 struct InitVarDscInfo; // defined in register_arg_convention.h
78 class FgStack; // defined in flowgraph.cpp
79 #if FEATURE_STACK_FP_X87
80 struct FlatFPStateX87; // defined in fp.h
83 class CSE_DataFlow; // defined in OptCSE.cpp
89 #ifndef LEGACY_BACKEND
90 class Lowering; // defined in lower.h
93 // The following are defined in this file, Compiler.h
97 /*****************************************************************************
103 /*****************************************************************************/
106 // Declare global operator new overloads that use the Compiler::compGetMem() function for allocation.
109 // I wanted to make the second argument optional, with default = CMK_Unknown, but that
110 // caused these to be ambiguous with the global placement new operators.
111 void* __cdecl operator new(size_t n, Compiler* context, CompMemKind cmk);
112 void* __cdecl operator new[](size_t n, Compiler* context, CompMemKind cmk);
113 void* __cdecl operator new(size_t n, void* p, const jitstd::placement_t& syntax_difference);
115 // Requires the definitions of "operator new" so including "LoopCloning.h" after the definitions.
116 #include "loopcloning.h"
118 /*****************************************************************************/
120 /* This is included here and not earlier as it needs the definition of "CSE"
121 * which is defined in the section above */
123 /*****************************************************************************/
125 unsigned genLog2(unsigned value);
126 unsigned genLog2(unsigned __int64 value);
128 var_types genActualType(var_types type);
129 var_types genUnsignedType(var_types type);
130 var_types genSignedType(var_types type);
132 unsigned ReinterpretHexAsDecimal(unsigned);
134 /*****************************************************************************/
136 #if defined(FEATURE_SIMD)
137 #if defined(_TARGET_XARCH_)
138 const unsigned TEMP_MAX_SIZE = YMM_REGSIZE_BYTES;
139 #elif defined(_TARGET_ARM64_)
140 const unsigned TEMP_MAX_SIZE = FP_REGSIZE_BYTES;
141 #endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
142 #else // !FEATURE_SIMD
143 const unsigned TEMP_MAX_SIZE = sizeof(double);
144 #endif // !FEATURE_SIMD
145 const unsigned TEMP_SLOT_COUNT = (TEMP_MAX_SIZE / sizeof(int));
147 const unsigned FLG_CCTOR = (CORINFO_FLG_CONSTRUCTOR | CORINFO_FLG_STATIC);
150 const int BAD_STK_OFFS = 0xBAADF00D; // for LclVarDsc::lvStkOffs
153 // The following holds the Local var info (scope information)
154 typedef const char* VarName; // Actual ASCII string
157 IL_OFFSET vsdLifeBeg; // instr offset of beg of life
158 IL_OFFSET vsdLifeEnd; // instr offset of end of life
159 unsigned vsdVarNum; // (remapped) LclVarDsc number
162 VarName vsdName; // name of the var
165 unsigned vsdLVnum; // 'which' in eeGetLVinfo().
166 // Also, it is the index of this entry in the info.compVarScopes array,
167 // which is useful since the array is also accessed via the
168 // compEnterScopeList and compExitScopeList sorted arrays.
171 /*****************************************************************************
173 * The following holds the local variable counts and the descriptor table.
176 // This is the location of a definition.
182 DefLoc() : m_blk(nullptr), m_tree(nullptr)
187 // This class encapsulates all info about a local variable that may vary for different SSA names
192 ValueNumPair m_vnPair;
200 typedef JitExpandArray<LclSsaVarDsc> PerSsaArray;
205 // The constructor. Most things can just be zero'ed.
206 LclVarDsc(Compiler* comp);
208 // note this only packs because var_types is a typedef of unsigned char
209 var_types lvType : 5; // TYP_INT/LONG/FLOAT/DOUBLE/REF
211 unsigned char lvIsParam : 1; // is this a parameter?
212 unsigned char lvIsRegArg : 1; // is this a register argument?
213 unsigned char lvFramePointerBased : 1; // 0 = off of REG_SPBASE (e.g., ESP), 1 = off of REG_FPBASE (e.g., EBP)
215 unsigned char lvStructGcCount : 3; // if struct, how many GC pointer (stop counting at 7). The only use of values >1
216 // is to help determine whether to use block init in the prolog.
217 unsigned char lvOnFrame : 1; // (part of) the variable lives on the frame
218 unsigned char lvDependReg : 1; // did the predictor depend upon this being enregistered
219 unsigned char lvRegister : 1; // assigned to live in a register? For RyuJIT backend, this is only set if the
220 // variable is in the same register for the entire function.
221 unsigned char lvTracked : 1; // is this a tracked variable?
222 bool lvTrackedNonStruct()
224 return lvTracked && lvType != TYP_STRUCT;
226 unsigned char lvPinned : 1; // is this a pinned variable?
228 unsigned char lvMustInit : 1; // must be initialized
229 unsigned char lvAddrExposed : 1; // The address of this variable is "exposed" -- passed as an argument, stored in a
230 // global location, etc.
231 // We cannot reason reliably about the value of the variable.
232 unsigned char lvDoNotEnregister : 1; // Do not enregister this variable.
233 unsigned char lvFieldAccessed : 1; // The var is a struct local, and a field of the variable is accessed. Affects
237 // These further document the reasons for setting "lvDoNotEnregister". (Note that "lvAddrExposed" is one of the
239 // also, lvType == TYP_STRUCT prevents enregistration. At least one of the reasons should be true.
240 unsigned char lvVMNeedsStackAddr : 1; // The VM may have access to a stack-relative address of the variable, and
241 // read/write its value.
242 unsigned char lvLiveInOutOfHndlr : 1; // The variable was live in or out of an exception handler, and this required
243 // the variable to be
244 // in the stack (at least at those boundaries.)
245 unsigned char lvLclFieldExpr : 1; // The variable is not a struct, but was accessed like one (e.g., reading a
246 // particular byte from an int).
247 unsigned char lvLclBlockOpAddr : 1; // The variable was written to via a block operation that took its address.
248 unsigned char lvLiveAcrossUCall : 1; // The variable is live across an unmanaged call.
250 unsigned char lvIsCSE : 1; // Indicates if this LclVar is a CSE variable.
251 unsigned char lvRefAssign : 1; // involved in pointer assignment
252 unsigned char lvHasLdAddrOp : 1; // has ldloca or ldarga opcode on this local.
253 unsigned char lvStackByref : 1; // This is a compiler temporary of TYP_BYREF that is known to point into our local
256 unsigned char lvHasILStoreOp : 1; // there is at least one STLOC or STARG on this local
257 unsigned char lvHasMultipleILStoreOp : 1; // there is more than one STLOC on this local
259 unsigned char lvIsTemp : 1; // Short-lifetime compiler temp (if lvIsParam is false), or implicit byref parameter
260 // (if lvIsParam is true)
262 unsigned char lvIsBoolean : 1; // set if variable is boolean
264 unsigned char lvRngOptDone : 1; // considered for range check opt?
265 unsigned char lvLoopInc : 1; // incremented in the loop?
266 unsigned char lvLoopAsg : 1; // reassigned in the loop (other than a monotonic inc/dec for the index var)?
267 unsigned char lvArrIndx : 1; // used as an array index?
268 unsigned char lvArrIndxOff : 1; // used as an array index with an offset?
269 unsigned char lvArrIndxDom : 1; // index dominates loop exit
271 unsigned char lvSingleDef : 1; // variable has a single def
272 unsigned char lvDisqualify : 1; // variable is no longer OK for add copy optimization
273 unsigned char lvVolatileHint : 1; // hint for AssertionProp
276 unsigned char lvSpilled : 1; // enregistered variable was spilled
277 #ifndef _TARGET_64BIT_
278 unsigned char lvStructDoubleAlign : 1; // Must we double align this struct?
279 #endif // !_TARGET_64BIT_
280 #ifdef _TARGET_64BIT_
281 unsigned char lvQuirkToLong : 1; // Quirk to allocate this LclVar as a 64-bit long
284 unsigned char lvKeepType : 1; // Don't change the type of this variable
285 unsigned char lvNoLclFldStress : 1; // Can't apply local field stress on this one
287 unsigned char lvIsPtr : 1; // Might this be used in an address computation? (used by buffer overflow security
289 unsigned char lvIsUnsafeBuffer : 1; // Does this contain an unsafe buffer requiring buffer overflow security checks?
290 unsigned char lvPromoted : 1; // True when this local is a promoted struct, a normed struct, or a "split" long on a
291 // 32-bit target. For implicit byref parameters, this gets hijacked between
292 // fgRetypeImplicitByRefArgs and fgMarkDemotedImplicitByRefArgs to indicate whether
293 // references to the arg are being rewritten as references to a promoted shadow local.
294 unsigned char lvIsStructField : 1; // Is this local var a field of a promoted struct local?
295 unsigned char lvContainsFloatingFields : 1; // Does this struct contains floating point fields?
296 unsigned char lvOverlappingFields : 1; // True when we have a struct with possibly overlapping fields
297 unsigned char lvContainsHoles : 1; // True when we have a promoted struct that contains holes
298 unsigned char lvCustomLayout : 1; // True when this struct has "CustomLayout"
300 unsigned char lvIsMultiRegArg : 1; // true if this is a multireg LclVar struct used in an argument context
301 unsigned char lvIsMultiRegRet : 1; // true if this is a multireg LclVar struct assigned from a multireg call
304 unsigned char _lvIsHfa : 1; // Is this a struct variable who's class handle is an HFA type
305 unsigned char _lvIsHfaRegArg : 1; // Is this a HFA argument variable? // TODO-CLEANUP: Remove this and replace
306 // with (lvIsRegArg && lvIsHfa())
307 unsigned char _lvHfaTypeIsFloat : 1; // Is the HFA type float or double?
308 #endif // FEATURE_HFA
311 // TODO-Cleanup: See the note on lvSize() - this flag is only in use by asserts that are checking for struct
312 // types, and is needed because of cases where TYP_STRUCT is bashed to an integral type.
313 // Consider cleaning this up so this workaround is not required.
314 unsigned char lvUnusedStruct : 1; // All references to this promoted struct are through its field locals.
315 // I.e. there is no longer any reference to the struct directly.
316 // In this case we can simply remove this struct local.
318 #ifndef LEGACY_BACKEND
319 unsigned char lvLRACandidate : 1; // Tracked for linear scan register allocation purposes
320 #endif // !LEGACY_BACKEND
323 // Note that both SIMD vector args and locals are marked as lvSIMDType = true, but the
324 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD*.
325 unsigned char lvSIMDType : 1; // This is a SIMD struct
326 unsigned char lvUsedInSIMDIntrinsic : 1; // This tells lclvar is used for simd intrinsic
327 var_types lvBaseType : 5; // Note: this only packs because var_types is a typedef of unsigned char
328 #endif // FEATURE_SIMD
329 unsigned char lvRegStruct : 1; // This is a reg-sized non-field-addressed struct.
331 unsigned char lvClassIsExact : 1; // lvClassHandle is the exact type
334 unsigned char lvClassInfoUpdated : 1; // true if this var has updated class handle or exactness
338 unsigned lvFieldLclStart; // The index of the local var representing the first field in the promoted struct
339 // local. For implicit byref parameters, this gets hijacked between
340 // fgRetypeImplicitByRefArgs and fgMarkDemotedImplicitByRefArgs to point to the
341 // struct local created to model the parameter's struct promotion, if any.
342 unsigned lvParentLcl; // The index of the local var representing the parent (i.e. the promoted struct local).
343 // Valid on promoted struct local fields.
346 unsigned char lvFieldCnt; // Number of fields in the promoted VarDsc.
347 unsigned char lvFldOffset;
348 unsigned char lvFldOrdinal;
350 #if FEATURE_MULTIREG_ARGS
351 regNumber lvRegNumForSlot(unsigned slotNum)
357 else if (slotNum == 1)
359 return lvOtherArgReg;
363 assert(false && "Invalid slotNum!");
368 #endif // FEATURE_MULTIREG_ARGS
386 bool lvIsHfaRegArg() const
389 return _lvIsHfaRegArg;
395 void lvSetIsHfaRegArg(bool value = true)
398 _lvIsHfaRegArg = value;
402 bool lvHfaTypeIsFloat() const
405 return _lvHfaTypeIsFloat;
411 void lvSetHfaTypeIsFloat(bool value)
414 _lvHfaTypeIsFloat = value;
418 // on Arm64 - Returns 1-4 indicating the number of register slots used by the HFA
419 // on Arm32 - Returns the total number of single FP register slots used by the HFA, max is 8
421 unsigned lvHfaSlots() const
424 assert(varTypeIsStruct(lvType));
426 return lvExactSize / sizeof(float);
427 #else // _TARGET_ARM64_
428 if (lvHfaTypeIsFloat())
430 return lvExactSize / sizeof(float);
434 return lvExactSize / sizeof(double);
436 #endif // _TARGET_ARM64_
439 // lvIsMultiRegArgOrRet()
440 // returns true if this is a multireg LclVar struct used in an argument context
441 // or if this is a multireg LclVar struct assigned from a multireg call
442 bool lvIsMultiRegArgOrRet()
444 return lvIsMultiRegArg || lvIsMultiRegRet;
448 regNumberSmall _lvRegNum; // Used to store the register this variable is in (or, the low register of a
449 // register pair). For LEGACY_BACKEND, this is only set if lvRegister is
450 // non-zero. For non-LEGACY_BACKEND, it is set during codegen any time the
451 // variable is enregistered (in non-LEGACY_BACKEND, lvRegister is only set
452 // to non-zero if the variable gets the same register assignment for its entire
454 #if !defined(_TARGET_64BIT_)
455 regNumberSmall _lvOtherReg; // Used for "upper half" of long var.
456 #endif // !defined(_TARGET_64BIT_)
458 regNumberSmall _lvArgReg; // The register in which this argument is passed.
460 #if FEATURE_MULTIREG_ARGS
461 regNumberSmall _lvOtherArgReg; // Used for the second part of the struct passed in a register.
462 // Note this is defined but not used by ARM32
463 #endif // FEATURE_MULTIREG_ARGS
465 #ifndef LEGACY_BACKEND
467 regNumberSmall _lvArgInitReg; // the register into which the argument is moved at entry
468 regPairNoSmall _lvArgInitRegPair; // the register pair into which the argument is moved at entry
470 #endif // !LEGACY_BACKEND
473 // The register number is stored in a small format (8 bits), but the getters return and the setters take
474 // a full-size (unsigned) format, to localize the casts here.
476 /////////////////////
478 __declspec(property(get = GetRegNum, put = SetRegNum)) regNumber lvRegNum;
480 regNumber GetRegNum() const
482 return (regNumber)_lvRegNum;
485 void SetRegNum(regNumber reg)
487 _lvRegNum = (regNumberSmall)reg;
488 assert(_lvRegNum == reg);
491 /////////////////////
493 #if defined(_TARGET_64BIT_)
494 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
496 regNumber GetOtherReg() const
498 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
499 // "unreachable code" warnings
503 void SetOtherReg(regNumber reg)
505 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
506 // "unreachable code" warnings
508 #else // !_TARGET_64BIT_
509 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
511 regNumber GetOtherReg() const
513 return (regNumber)_lvOtherReg;
516 void SetOtherReg(regNumber reg)
518 _lvOtherReg = (regNumberSmall)reg;
519 assert(_lvOtherReg == reg);
521 #endif // !_TARGET_64BIT_
523 /////////////////////
525 __declspec(property(get = GetArgReg, put = SetArgReg)) regNumber lvArgReg;
527 regNumber GetArgReg() const
529 return (regNumber)_lvArgReg;
532 void SetArgReg(regNumber reg)
534 _lvArgReg = (regNumberSmall)reg;
535 assert(_lvArgReg == reg);
538 #if FEATURE_MULTIREG_ARGS
539 __declspec(property(get = GetOtherArgReg, put = SetOtherArgReg)) regNumber lvOtherArgReg;
541 regNumber GetOtherArgReg() const
543 return (regNumber)_lvOtherArgReg;
546 void SetOtherArgReg(regNumber reg)
548 _lvOtherArgReg = (regNumberSmall)reg;
549 assert(_lvOtherArgReg == reg);
551 #endif // FEATURE_MULTIREG_ARGS
554 // Is this is a SIMD struct?
555 bool lvIsSIMDType() const
560 // Is this is a SIMD struct which is used for SIMD intrinsic?
561 bool lvIsUsedInSIMDIntrinsic() const
563 return lvUsedInSIMDIntrinsic;
566 // If feature_simd not enabled, return false
567 bool lvIsSIMDType() const
571 bool lvIsUsedInSIMDIntrinsic() const
577 /////////////////////
579 #ifndef LEGACY_BACKEND
580 __declspec(property(get = GetArgInitReg, put = SetArgInitReg)) regNumber lvArgInitReg;
582 regNumber GetArgInitReg() const
584 return (regNumber)_lvArgInitReg;
587 void SetArgInitReg(regNumber reg)
589 _lvArgInitReg = (regNumberSmall)reg;
590 assert(_lvArgInitReg == reg);
593 /////////////////////
595 __declspec(property(get = GetArgInitRegPair, put = SetArgInitRegPair)) regPairNo lvArgInitRegPair;
597 regPairNo GetArgInitRegPair() const
599 regPairNo regPair = (regPairNo)_lvArgInitRegPair;
600 assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
604 void SetArgInitRegPair(regPairNo regPair)
606 assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
607 _lvArgInitRegPair = (regPairNoSmall)regPair;
608 assert(_lvArgInitRegPair == regPair);
611 /////////////////////
613 bool lvIsRegCandidate() const
615 return lvLRACandidate != 0;
618 bool lvIsInReg() const
620 return lvIsRegCandidate() && (lvRegNum != REG_STK);
623 #else // LEGACY_BACKEND
625 bool lvIsRegCandidate() const
627 return lvTracked != 0;
630 bool lvIsInReg() const
632 return lvRegister != 0;
635 #endif // LEGACY_BACKEND
637 regMaskTP lvRegMask() const
639 regMaskTP regMask = RBM_NONE;
640 if (varTypeIsFloating(TypeGet()))
642 if (lvRegNum != REG_STK)
644 regMask = genRegMaskFloat(lvRegNum, TypeGet());
649 if (lvRegNum != REG_STK)
651 regMask = genRegMask(lvRegNum);
654 // For longs we may have two regs
655 if (isRegPairType(lvType) && lvOtherReg != REG_STK)
657 regMask |= genRegMask(lvOtherReg);
663 regMaskSmall lvPrefReg; // set of regs it prefers to live in
665 unsigned short lvVarIndex; // variable tracking index
666 unsigned short lvRefCnt; // unweighted (real) reference count. For implicit by reference
667 // parameters, this gets hijacked from fgMarkImplicitByRefArgs
668 // through fgMarkDemotedImplicitByRefArgs, to provide a static
669 // appearance count (computed during address-exposed analysis)
670 // that fgMakeOutgoingStructArgCopy consults during global morph
671 // to determine if eliding its copy is legal.
672 unsigned lvRefCntWtd; // weighted reference count
673 int lvStkOffs; // stack offset of home
674 unsigned lvExactSize; // (exact) size of the type in bytes
676 // Is this a promoted struct?
677 // This method returns true only for structs (including SIMD structs), not for
678 // locals that are split on a 32-bit target.
679 // It is only necessary to use this:
680 // 1) if only structs are wanted, and
681 // 2) if Lowering has already been done.
682 // Otherwise lvPromoted is valid.
683 bool lvPromotedStruct()
685 #if !defined(_TARGET_64BIT_)
686 return (lvPromoted && !varTypeIsLong(lvType));
687 #else // defined(_TARGET_64BIT_)
689 #endif // defined(_TARGET_64BIT_)
692 unsigned lvSize() const // Size needed for storage representation. Only used for structs or TYP_BLK.
694 // TODO-Review: Sometimes we get called on ARM with HFA struct variables that have been promoted,
695 // where the struct itself is no longer used because all access is via its member fields.
696 // When that happens, the struct is marked as unused and its type has been changed to
697 // TYP_INT (to keep the GC tracking code from looking at it).
698 // See Compiler::raAssignVars() for details. For example:
699 // N002 ( 4, 3) [00EA067C] ------------- return struct $346
700 // N001 ( 3, 2) [00EA0628] ------------- lclVar struct(U) V03 loc2
701 // float V03.f1 (offs=0x00) -> V12 tmp7
702 // f8 (last use) (last use) $345
703 // Here, the "struct(U)" shows that the "V03 loc2" variable is unused. Not shown is that V03
704 // is now TYP_INT in the local variable table. It's not really unused, because it's in the tree.
706 assert(varTypeIsStruct(lvType) || (lvType == TYP_BLK) || (lvPromoted && lvUnusedStruct));
708 #if defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
709 // For 32-bit architectures, we make local variable SIMD12 types 16 bytes instead of just 12. We can't do
710 // this for arguments, which must be passed according the defined ABI. We don't want to do this for
711 // dependently promoted struct fields, but we don't know that here. See lvaMapSimd12ToSimd16().
712 if ((lvType == TYP_SIMD12) && !lvIsParam)
714 assert(lvExactSize == 12);
717 #endif // defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
719 return (unsigned)(roundUp(lvExactSize, TARGET_POINTER_SIZE));
722 const size_t lvArgStackSize() const;
724 unsigned lvSlotNum; // original slot # (if remapped)
726 typeInfo lvVerTypeInfo; // type info needed for verification
728 CORINFO_CLASS_HANDLE lvClassHnd; // class handle for the local, or null if not known
730 CORINFO_FIELD_HANDLE lvFieldHnd; // field handle for promoted struct fields
732 BYTE* lvGcLayout; // GC layout info for structs
735 BlockSet lvRefBlks; // Set of blocks that contain refs
736 GenTreePtr lvDefStmt; // Pointer to the statement with the single definition
737 void lvaDisqualifyVar(); // Call to disqualify a local variable from use in optAddCopies
739 var_types TypeGet() const
741 return (var_types)lvType;
743 bool lvStackAligned() const
745 assert(lvIsStructField);
746 return ((lvFldOffset % TARGET_POINTER_SIZE) == 0);
748 bool lvNormalizeOnLoad() const
750 return varTypeIsSmall(TypeGet()) &&
751 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
752 (lvIsParam || lvAddrExposed || lvIsStructField);
755 bool lvNormalizeOnStore()
757 return varTypeIsSmall(TypeGet()) &&
758 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
759 !(lvIsParam || lvAddrExposed || lvIsStructField);
762 void lvaResetSortAgainFlag(Compiler* pComp);
763 void decRefCnts(BasicBlock::weight_t weight, Compiler* pComp, bool propagate = true);
764 void incRefCnts(BasicBlock::weight_t weight, Compiler* pComp, bool propagate = true);
765 void setPrefReg(regNumber regNum, Compiler* pComp);
766 void addPrefReg(regMaskTP regMask, Compiler* pComp);
767 bool IsFloatRegType() const
769 return isFloatRegType(lvType) || lvIsHfaRegArg();
771 var_types GetHfaType() const
773 return lvIsHfa() ? (lvHfaTypeIsFloat() ? TYP_FLOAT : TYP_DOUBLE) : TYP_UNDEF;
775 void SetHfaType(var_types type)
777 assert(varTypeIsFloating(type));
778 lvSetHfaTypeIsFloat(type == TYP_FLOAT);
781 #ifndef LEGACY_BACKEND
782 var_types lvaArgType();
785 PerSsaArray lvPerSsaData;
788 // Keep track of the # of SsaNames, for a bounds check.
789 unsigned lvNumSsaNames;
792 // Returns the address of the per-Ssa data for the given ssaNum (which is required
793 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
794 // not an SSA variable).
795 LclSsaVarDsc* GetPerSsaData(unsigned ssaNum)
797 assert(ssaNum != SsaConfig::RESERVED_SSA_NUM);
798 assert(SsaConfig::RESERVED_SSA_NUM == 0);
799 unsigned zeroBased = ssaNum - SsaConfig::UNINIT_SSA_NUM;
800 assert(zeroBased < lvNumSsaNames);
801 return &lvPerSsaData.GetRef(zeroBased);
806 void PrintVarReg() const
808 if (isRegPairType(TypeGet()))
810 printf("%s:%s", getRegName(lvOtherReg), // hi32
811 getRegName(lvRegNum)); // lo32
815 printf("%s", getRegName(lvRegNum));
820 }; // class LclVarDsc
823 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
824 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
828 XX The temporary lclVars allocated by the compiler for code generation XX
830 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
831 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
834 /*****************************************************************************
836 * The following keeps track of temporaries allocated in the stack frame
837 * during code-generation (after register allocation). These spill-temps are
838 * only used if we run out of registers while evaluating a tree.
840 * These are different from the more common temps allocated by lvaGrabTemp().
851 static const int BAD_TEMP_OFFSET = 0xDDDDDDDD; // used as a sentinel "bad value" for tdOffs in DEBUG
859 TempDsc(int _tdNum, unsigned _tdSize, var_types _tdType) : tdNum(_tdNum), tdSize((BYTE)_tdSize), tdType(_tdType)
863 0); // temps must have a negative number (so they have a different number from all local variables)
864 tdOffs = BAD_TEMP_OFFSET;
868 IMPL_LIMITATION("too many spill temps");
873 bool tdLegalOffset() const
875 return tdOffs != BAD_TEMP_OFFSET;
879 int tdTempOffs() const
881 assert(tdLegalOffset());
884 void tdSetTempOffs(int offs)
887 assert(tdLegalOffset());
889 void tdAdjustTempOffs(int offs)
892 assert(tdLegalOffset());
895 int tdTempNum() const
900 unsigned tdTempSize() const
904 var_types tdTempType() const
910 // interface to hide linearscan implementation from rest of compiler
911 class LinearScanInterface
914 virtual void doLinearScan() = 0;
915 virtual void recordVarLocationsAtStartOfBB(BasicBlock* bb) = 0;
916 virtual bool willEnregisterLocalVars() const = 0;
919 LinearScanInterface* getLinearScanAllocator(Compiler* comp);
921 // Information about arrays: their element type and size, and the offset of the first element.
922 // We label GT_IND's that are array indices with GTF_IND_ARR_INDEX, and, for such nodes,
923 // associate an array info via the map retrieved by GetArrayInfoMap(). This information is used,
924 // for example, in value numbering of array index expressions.
927 var_types m_elemType;
928 CORINFO_CLASS_HANDLE m_elemStructType;
930 unsigned m_elemOffset;
932 ArrayInfo() : m_elemType(TYP_UNDEF), m_elemStructType(nullptr), m_elemSize(0), m_elemOffset(0)
936 ArrayInfo(var_types elemType, unsigned elemSize, unsigned elemOffset, CORINFO_CLASS_HANDLE elemStructType)
937 : m_elemType(elemType), m_elemStructType(elemStructType), m_elemSize(elemSize), m_elemOffset(elemOffset)
942 // This enumeration names the phases into which we divide compilation. The phases should completely
943 // partition a compilation.
946 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) enum_nm,
947 #include "compphases.h"
951 extern const char* PhaseNames[];
952 extern const char* PhaseEnums[];
953 extern const LPCWSTR PhaseShortNames[];
955 // The following enum provides a simple 1:1 mapping to CLR API's
956 enum API_ICorJitInfo_Names
958 #define DEF_CLR_API(name) API_##name,
959 #include "ICorJitInfo_API_names.h"
963 //---------------------------------------------------------------
967 // A "CompTimeInfo" is a structure for tracking the compilation time of one or more methods.
968 // We divide a compilation into a sequence of contiguous phases, and track the total (per-thread) cycles
969 // of the compilation, as well as the cycles for each phase. We also track the number of bytecodes.
970 // If there is a failure in reading a timer at any point, the "CompTimeInfo" becomes invalid, as indicated
971 // by "m_timerFailure" being true.
972 // If FEATURE_JIT_METHOD_PERF is not set, we define a minimal form of this, enough to let other code compile.
975 #ifdef FEATURE_JIT_METHOD_PERF
976 // The string names of the phases.
977 static const char* PhaseNames[];
979 static bool PhaseHasChildren[];
980 static int PhaseParent[];
981 static bool PhaseReportsIRSize[];
983 unsigned m_byteCodeBytes;
984 unsigned __int64 m_totalCycles;
985 unsigned __int64 m_invokesByPhase[PHASE_NUMBER_OF];
986 unsigned __int64 m_cyclesByPhase[PHASE_NUMBER_OF];
987 #if MEASURE_CLRAPI_CALLS
988 unsigned __int64 m_CLRinvokesByPhase[PHASE_NUMBER_OF];
989 unsigned __int64 m_CLRcyclesByPhase[PHASE_NUMBER_OF];
992 unsigned m_nodeCountAfterPhase[PHASE_NUMBER_OF];
994 // For better documentation, we call EndPhase on
995 // non-leaf phases. We should also call EndPhase on the
996 // last leaf subphase; obviously, the elapsed cycles between the EndPhase
997 // for the last leaf subphase and the EndPhase for an ancestor should be very small.
998 // We add all such "redundant end phase" intervals to this variable below; we print
999 // it out in a report, so we can verify that it is, indeed, very small. If it ever
1000 // isn't, this means that we're doing something significant between the end of the last
1001 // declared subphase and the end of its parent.
1002 unsigned __int64 m_parentPhaseEndSlop;
1003 bool m_timerFailure;
1005 #if MEASURE_CLRAPI_CALLS
1006 // The following measures the time spent inside each individual CLR API call.
1007 unsigned m_allClrAPIcalls;
1008 unsigned m_perClrAPIcalls[API_ICorJitInfo_Names::API_COUNT];
1009 unsigned __int64 m_allClrAPIcycles;
1010 unsigned __int64 m_perClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
1011 unsigned __int32 m_maxClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
1012 #endif // MEASURE_CLRAPI_CALLS
1014 CompTimeInfo(unsigned byteCodeBytes);
1018 #ifdef FEATURE_JIT_METHOD_PERF
1020 #if MEASURE_CLRAPI_CALLS
1021 struct WrapICorJitInfo;
1024 // This class summarizes the JIT time information over the course of a run: the number of methods compiled,
1025 // and the total and maximum timings. (These are instances of the "CompTimeInfo" type described above).
1026 // The operation of adding a single method's timing to the summary may be performed concurrently by several
1027 // threads, so it is protected by a lock.
1028 // This class is intended to be used as a singleton type, with only a single instance.
1029 class CompTimeSummaryInfo
1031 // This lock protects the fields of all CompTimeSummaryInfo(s) (of which we expect there to be one).
1032 static CritSecObject s_compTimeSummaryLock;
1036 CompTimeInfo m_total;
1037 CompTimeInfo m_maximum;
1039 int m_numFilteredMethods;
1040 CompTimeInfo m_filtered;
1042 // This method computes the number of cycles/sec for the current machine. The cycles are those counted
1043 // by GetThreadCycleTime; we assume that these are of equal duration, though that is not necessarily true.
1044 // If any OS interaction fails, returns 0.0.
1045 double CyclesPerSecond();
1047 // This can use what ever data you want to determine if the value to be added
1048 // belongs in the filtered section (it's always included in the unfiltered section)
1049 bool IncludedInFilteredData(CompTimeInfo& info);
1052 // This is the unique CompTimeSummaryInfo object for this instance of the runtime.
1053 static CompTimeSummaryInfo s_compTimeSummary;
1055 CompTimeSummaryInfo()
1056 : m_numMethods(0), m_totMethods(0), m_total(0), m_maximum(0), m_numFilteredMethods(0), m_filtered(0)
1060 // Assumes that "info" is a completed CompTimeInfo for a compilation; adds it to the summary.
1061 // This is thread safe.
1062 void AddInfo(CompTimeInfo& info, bool includePhases);
1064 // Print the summary information to "f".
1065 // This is not thread-safe; assumed to be called by only one thread.
1066 void Print(FILE* f);
1069 // A JitTimer encapsulates a CompTimeInfo for a single compilation. It also tracks the start of compilation,
1070 // and when the current phase started. This is intended to be part of a Compilation object. This is
1071 // disabled (FEATURE_JIT_METHOD_PERF not defined) when FEATURE_CORECLR is set, or on non-windows platforms.
1075 unsigned __int64 m_start; // Start of the compilation.
1076 unsigned __int64 m_curPhaseStart; // Start of the current phase.
1077 #if MEASURE_CLRAPI_CALLS
1078 unsigned __int64 m_CLRcallStart; // Start of the current CLR API call (if any).
1079 unsigned __int64 m_CLRcallInvokes; // CLR API invokes under current outer so far
1080 unsigned __int64 m_CLRcallCycles; // CLR API cycles under current outer so far.
1081 int m_CLRcallAPInum; // The enum/index of the current CLR API call (or -1).
1082 static double s_cyclesPerSec; // Cached for speedier measurements
1085 Phases m_lastPhase; // The last phase that was completed (or (Phases)-1 to start).
1087 CompTimeInfo m_info; // The CompTimeInfo for this compilation.
1089 static CritSecObject s_csvLock; // Lock to protect the time log file.
1090 void PrintCsvMethodStats(Compiler* comp);
1093 void* operator new(size_t);
1094 void* operator new[](size_t);
1095 void operator delete(void*);
1096 void operator delete[](void*);
1099 // Initialized the timer instance
1100 JitTimer(unsigned byteCodeSize);
1102 static JitTimer* Create(Compiler* comp, unsigned byteCodeSize)
1104 return ::new (comp, CMK_Unknown) JitTimer(byteCodeSize);
1107 static void PrintCsvHeader();
1109 // Ends the current phase (argument is for a redundant check).
1110 void EndPhase(Compiler* compiler, Phases phase);
1112 #if MEASURE_CLRAPI_CALLS
1113 // Start and end a timed CLR API call.
1114 void CLRApiCallEnter(unsigned apix);
1115 void CLRApiCallLeave(unsigned apix);
1116 #endif // MEASURE_CLRAPI_CALLS
1118 // Completes the timing of the current method, which is assumed to have "byteCodeBytes" bytes of bytecode,
1119 // and adds it to "sum".
1120 void Terminate(Compiler* comp, CompTimeSummaryInfo& sum, bool includePhases);
1122 // Attempts to query the cycle counter of the current thread. If successful, returns "true" and sets
1123 // *cycles to the cycle counter value. Otherwise, returns false and sets the "m_timerFailure" flag of
1124 // "m_info" to true.
1125 bool GetThreadCycles(unsigned __int64* cycles)
1127 bool res = CycleTimer::GetThreadCyclesS(cycles);
1130 m_info.m_timerFailure = true;
1135 #endif // FEATURE_JIT_METHOD_PERF
1137 //------------------- Function/Funclet info -------------------------------
1138 enum FuncKind : BYTE
1140 FUNC_ROOT, // The main/root function (always id==0)
1141 FUNC_HANDLER, // a funclet associated with an EH handler (finally, fault, catch, filter handler)
1142 FUNC_FILTER, // a funclet associated with an EH filter
1151 BYTE funFlags; // Currently unused, just here for padding
1152 unsigned short funEHIndex; // index, into the ebd table, of innermost EH clause corresponding to this
1153 // funclet. It is only valid if funKind field indicates this is a
1154 // EH-related funclet: FUNC_HANDLER or FUNC_FILTER
1156 #if defined(_TARGET_AMD64_)
1158 // TODO-AMD64-Throughput: make the AMD64 info more like the ARM info to avoid having this large static array.
1159 emitLocation* startLoc;
1160 emitLocation* endLoc;
1161 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1162 emitLocation* coldEndLoc;
1163 UNWIND_INFO unwindHeader;
1164 // Maximum of 255 UNWIND_CODE 'nodes' and then the unwind header. If there are an odd
1165 // number of codes, the VM or Zapper will 4-byte align the whole thing.
1166 BYTE unwindCodes[offsetof(UNWIND_INFO, UnwindCode) + (0xFF * sizeof(UNWIND_CODE))];
1167 unsigned unwindCodeSlot;
1169 #elif defined(_TARGET_X86_)
1171 #if defined(_TARGET_UNIX_)
1172 emitLocation* startLoc;
1173 emitLocation* endLoc;
1174 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1175 emitLocation* coldEndLoc;
1176 #endif // _TARGET_UNIX_
1178 #elif defined(_TARGET_ARMARCH_)
1180 UnwindInfo uwi; // Unwind information for this function/funclet's hot section
1181 UnwindInfo* uwiCold; // Unwind information for this function/funclet's cold section
1182 // Note: we only have a pointer here instead of the actual object,
1183 // to save memory in the JIT case (compared to the NGEN case),
1184 // where we don't have any cold section.
1185 // Note 2: we currently don't support hot/cold splitting in functions
1186 // with EH, so uwiCold will be NULL for all funclets.
1188 #if defined(_TARGET_UNIX_)
1189 emitLocation* startLoc;
1190 emitLocation* endLoc;
1191 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1192 emitLocation* coldEndLoc;
1193 #endif // _TARGET_UNIX_
1195 #endif // _TARGET_ARMARCH_
1197 #if defined(_TARGET_UNIX_)
1198 jitstd::vector<CFI_CODE>* cfiCodes;
1199 #endif // _TARGET_UNIX_
1201 // Eventually we may want to move rsModifiedRegsMask, lvaOutgoingArgSize, and anything else
1202 // that isn't shared between the main function body and funclets.
1205 struct fgArgTabEntry
1208 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1211 otherRegNum = REG_NA;
1212 isStruct = false; // is this a struct arg
1214 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1216 GenTreePtr node; // Initially points at the Op1 field of 'parent', but if the argument is replaced with an GT_ASG or
1218 // it will point at the actual argument in the gtCallLateArgs list.
1219 GenTreePtr parent; // Points at the GT_LIST node in the gtCallArgs for this argument
1221 unsigned argNum; // The original argument number, also specifies the required argument evaluation order from the IL
1223 regNumber regNum; // The (first) register to use when passing this argument, set to REG_STK for arguments passed on
1225 unsigned numRegs; // Count of number of registers that this argument uses
1227 // A slot is a pointer sized region in the OutArg area.
1228 unsigned slotNum; // When an argument is passed in the OutArg area this is the slot number in the OutArg area
1229 unsigned numSlots; // Count of number of slots that this argument uses
1231 unsigned alignment; // 1 or 2 (slots/registers)
1232 unsigned lateArgInx; // index into gtCallLateArgs list
1233 unsigned tmpNum; // the LclVar number if we had to force evaluation of this arg
1235 bool isSplit : 1; // True when this argument is split between the registers and OutArg area
1236 bool needTmp : 1; // True when we force this argument's evaluation into a temp LclVar
1237 bool needPlace : 1; // True when we must replace this argument with a placeholder node
1238 bool isTmp : 1; // True when we setup a temp LclVar for this argument due to size issues with the struct
1239 bool processed : 1; // True when we have decided the evaluation order for this argument in the gtCallLateArgs
1240 bool isHfaRegArg : 1; // True when the argument is passed as a HFA in FP registers.
1241 bool isBackFilled : 1; // True when the argument fills a register slot skipped due to alignment requirements of
1242 // previous arguments.
1243 bool isNonStandard : 1; // True if it is an arg that is passed in a reg other than a standard arg reg, or is forced
1244 // to be on the stack despite its arg list position.
1246 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1247 bool isStruct : 1; // True if this is a struct arg
1249 regNumber otherRegNum; // The (second) register to use when passing this argument.
1251 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
1252 #elif !defined(_TARGET_64BIT_)
1253 __declspec(property(get = getIsStruct)) bool isStruct;
1256 return varTypeIsStruct(node);
1258 #endif // !_TARGET_64BIT_
1261 void SetIsHfaRegArg(bool hfaRegArg)
1263 isHfaRegArg = hfaRegArg;
1266 void SetIsBackFilled(bool backFilled)
1268 isBackFilled = backFilled;
1271 bool IsBackFilled() const
1273 return isBackFilled;
1275 #else // !_TARGET_ARM_
1276 // To make the callers easier, we allow these calls (and the isHfaRegArg and isBackFilled data members) for all
1278 void SetIsHfaRegArg(bool hfaRegArg)
1282 void SetIsBackFilled(bool backFilled)
1286 bool IsBackFilled() const
1290 #endif // !_TARGET_ARM_
1296 typedef struct fgArgTabEntry* fgArgTabEntryPtr;
1298 //-------------------------------------------------------------------------
1300 // The class fgArgInfo is used to handle the arguments
1301 // when morphing a GT_CALL node.
1306 Compiler* compiler; // Back pointer to the compiler instance so that we can allocate memory
1307 GenTreeCall* callTree; // Back pointer to the GT_CALL node for this fgArgInfo
1308 unsigned argCount; // Updatable arg count value
1309 unsigned nextSlotNum; // Updatable slot count value
1310 unsigned stkLevel; // Stack depth when we make this call (for x86)
1312 #if defined(UNIX_X86_ABI)
1313 bool alignmentDone; // Updateable flag, set to 'true' after we've done any required alignment.
1314 unsigned stkSizeBytes; // Size of stack used by this call, in bytes. Calculated during fgMorphArgs().
1315 unsigned padStkAlign; // Stack alignment in bytes required before arguments are pushed for this call.
1316 // Computed dynamically during codegen, based on stkSizeBytes and the current
1317 // stack level (genStackLevel) when the first stack adjustment is made for
1321 #if FEATURE_FIXED_OUT_ARGS
1322 unsigned outArgSize; // Size of the out arg area for the call, will be at least MIN_ARG_AREA_FOR_CALL
1325 unsigned argTableSize; // size of argTable array (equal to the argCount when done with fgMorphArgs)
1326 bool hasRegArgs; // true if we have one or more register arguments
1327 bool hasStackArgs; // true if we have one or more stack arguments
1328 bool argsComplete; // marker for state
1329 bool argsSorted; // marker for state
1330 fgArgTabEntryPtr* argTable; // variable sized array of per argument descrption: (i.e. argTable[argTableSize])
1333 void AddArg(fgArgTabEntryPtr curArgTabEntry);
1336 fgArgInfo(Compiler* comp, GenTreeCall* call, unsigned argCount);
1337 fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall);
1339 fgArgTabEntryPtr AddRegArg(
1340 unsigned argNum, GenTreePtr node, GenTreePtr parent, regNumber regNum, unsigned numRegs, unsigned alignment);
1342 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
1343 fgArgTabEntryPtr AddRegArg(
1350 const bool isStruct,
1351 const regNumber otherRegNum = REG_NA,
1352 const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* const structDescPtr = nullptr);
1353 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
1355 fgArgTabEntryPtr AddStkArg(unsigned argNum,
1359 unsigned alignment FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(const bool isStruct));
1361 void RemorphReset();
1362 fgArgTabEntryPtr RemorphRegArg(
1363 unsigned argNum, GenTreePtr node, GenTreePtr parent, regNumber regNum, unsigned numRegs, unsigned alignment);
1365 void RemorphStkArg(unsigned argNum, GenTreePtr node, GenTreePtr parent, unsigned numSlots, unsigned alignment);
1367 void SplitArg(unsigned argNum, unsigned numRegs, unsigned numSlots);
1369 void EvalToTmp(unsigned argNum, unsigned tmpNum, GenTreePtr newNode);
1371 void ArgsComplete();
1375 void EvalArgsToTemps();
1377 void RecordStkLevel(unsigned stkLvl);
1378 unsigned RetrieveStkLevel();
1384 fgArgTabEntryPtr* ArgTable()
1388 unsigned GetNextSlotNum()
1398 return hasStackArgs;
1400 bool AreArgsComplete() const
1402 return argsComplete;
1404 #if FEATURE_FIXED_OUT_ARGS
1405 unsigned GetOutArgSize() const
1409 void SetOutArgSize(unsigned newVal)
1411 outArgSize = newVal;
1413 #endif // FEATURE_FIXED_OUT_ARGS
1415 void ComputeStackAlignment(unsigned curStackLevelInBytes)
1417 #if defined(UNIX_X86_ABI)
1418 padStkAlign = AlignmentPad(curStackLevelInBytes, STACK_ALIGN);
1419 #endif // defined(UNIX_X86_ABI)
1422 void SetStkSizeBytes(unsigned newStkSizeBytes)
1424 #if defined(UNIX_X86_ABI)
1425 stkSizeBytes = newStkSizeBytes;
1426 #endif // defined(UNIX_X86_ABI)
1429 #if defined(UNIX_X86_ABI)
1430 unsigned GetStkAlign()
1434 unsigned GetStkSizeBytes() const
1436 return stkSizeBytes;
1438 bool IsStkAlignmentDone() const
1440 return alignmentDone;
1442 void SetStkAlignmentDone()
1444 alignmentDone = true;
1446 #endif // defined(UNIX_X86_ABI)
1448 // Get the late arg for arg at position argIndex. Caller must ensure this position has a late arg.
1449 GenTreePtr GetLateArg(unsigned argIndex);
1451 void Dump(Compiler* compiler);
1455 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1456 // We have the ability to mark source expressions with "Test Labels."
1457 // These drive assertions within the JIT, or internal JIT testing. For example, we could label expressions
1458 // that should be CSE defs, and other expressions that should uses of those defs, with a shared label.
1460 enum TestLabel // This must be kept identical to System.Runtime.CompilerServices.JitTestLabel.TestLabel.
1463 TL_VN, // Defines a "VN equivalence class". (For full VN, including exceptions thrown).
1464 TL_VNNorm, // Like above, but uses the non-exceptional value of the expression.
1465 TL_CSE_Def, // This must be identified in the JIT as a CSE def
1466 TL_CSE_Use, // This must be identified in the JIT as a CSE use
1467 TL_LoopHoist, // Expression must (or must not) be hoisted out of the loop.
1470 struct TestLabelAndNum
1475 TestLabelAndNum() : m_tl(TestLabel(0)), m_num(0)
1480 typedef JitHashTable<GenTreePtr, JitPtrKeyFuncs<GenTree>, TestLabelAndNum> NodeToTestDataMap;
1482 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1486 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1487 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1489 XX The big guy. The sections are currently organized as : XX
1491 XX o GenTree and BasicBlock XX
1503 XX o PrologScopeInfo XX
1504 XX o CodeGenerator XX
1509 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1510 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1515 friend class emitter;
1516 friend class UnwindInfo;
1517 friend class UnwindFragmentInfo;
1518 friend class UnwindEpilogInfo;
1519 friend class JitTimer;
1520 friend class LinearScan;
1521 friend class fgArgInfo;
1522 friend class Rationalizer;
1524 friend class Lowering;
1525 friend class CSE_DataFlow;
1526 friend class CSE_Heuristic;
1527 friend class CodeGenInterface;
1528 friend class CodeGen;
1529 friend class LclVarDsc;
1530 friend class TempDsc;
1532 friend class ObjectAllocator;
1534 #ifndef _TARGET_64BIT_
1535 friend class DecomposeLongs;
1536 #endif // !_TARGET_64BIT_
1539 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1540 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1542 XX Misc structs definitions XX
1544 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1545 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1549 hashBvGlobalData hbvGlobalData; // Used by the hashBv bitvector package.
1568 bool dumpIRDataflow;
1569 bool dumpIRBlockHeaders;
1571 LPCWSTR dumpIRPhase;
1572 LPCWSTR dumpIRFormat;
1574 bool shouldUseVerboseTrees();
1575 bool asciiTrees; // If true, dump trees using only ASCII characters
1576 bool shouldDumpASCIITrees();
1577 bool verboseSsa; // If true, produce especially verbose dump output in SSA construction.
1578 bool shouldUseVerboseSsa();
1579 bool treesBeforeAfterMorph; // If true, print trees before/after morphing (paired by an intra-compilation id:
1580 int morphNum; // This counts the the trees that have been morphed, allowing us to label each uniquely.
1582 const char* VarNameToStr(VarName name)
1587 DWORD expensiveDebugCheckLevel;
1590 #if FEATURE_MULTIREG_RET
1591 GenTreePtr impAssignMultiRegTypeToVar(GenTreePtr op, CORINFO_CLASS_HANDLE hClass);
1592 #endif // FEATURE_MULTIREG_RET
1595 bool isSingleFloat32Struct(CORINFO_CLASS_HANDLE hClass);
1596 #endif // ARM_SOFTFP
1598 //-------------------------------------------------------------------------
1599 // Functions to handle homogeneous floating-point aggregates (HFAs) in ARM.
1600 // HFAs are one to four element structs where each element is the same
1601 // type, either all float or all double. They are treated specially
1602 // in the ARM Procedure Call Standard, specifically, they are passed in
1603 // floating-point registers instead of the general purpose registers.
1606 bool IsHfa(CORINFO_CLASS_HANDLE hClass);
1607 bool IsHfa(GenTreePtr tree);
1609 var_types GetHfaType(GenTreePtr tree);
1610 unsigned GetHfaCount(GenTreePtr tree);
1612 var_types GetHfaType(CORINFO_CLASS_HANDLE hClass);
1613 unsigned GetHfaCount(CORINFO_CLASS_HANDLE hClass);
1615 bool IsMultiRegPassedType(CORINFO_CLASS_HANDLE hClass);
1616 bool IsMultiRegReturnedType(CORINFO_CLASS_HANDLE hClass);
1618 //-------------------------------------------------------------------------
1619 // The following is used for validating format of EH table
1623 typedef struct EHNodeDsc* pEHNodeDsc;
1625 EHNodeDsc* ehnTree; // root of the tree comprising the EHnodes.
1626 EHNodeDsc* ehnNext; // root of the tree comprising the EHnodes.
1639 EHBlockType ehnBlockType; // kind of EH block
1640 IL_OFFSET ehnStartOffset; // IL offset of start of the EH block
1641 IL_OFFSET ehnEndOffset; // IL offset past end of the EH block. (TODO: looks like verInsertEhNode() sets this to
1642 // the last IL offset, not "one past the last one", i.e., the range Start to End is
1644 pEHNodeDsc ehnNext; // next (non-nested) block in sequential order
1645 pEHNodeDsc ehnChild; // leftmost nested block
1647 pEHNodeDsc ehnTryNode; // for filters and handlers, the corresponding try node
1648 pEHNodeDsc ehnHandlerNode; // for a try node, the corresponding handler node
1650 pEHNodeDsc ehnFilterNode; // if this is a try node and has a filter, otherwise 0
1651 pEHNodeDsc ehnEquivalent; // if blockType=tryNode, start offset and end offset is same,
1653 inline void ehnSetTryNodeType()
1655 ehnBlockType = TryNode;
1657 inline void ehnSetFilterNodeType()
1659 ehnBlockType = FilterNode;
1661 inline void ehnSetHandlerNodeType()
1663 ehnBlockType = HandlerNode;
1665 inline void ehnSetFinallyNodeType()
1667 ehnBlockType = FinallyNode;
1669 inline void ehnSetFaultNodeType()
1671 ehnBlockType = FaultNode;
1674 inline BOOL ehnIsTryBlock()
1676 return ehnBlockType == TryNode;
1678 inline BOOL ehnIsFilterBlock()
1680 return ehnBlockType == FilterNode;
1682 inline BOOL ehnIsHandlerBlock()
1684 return ehnBlockType == HandlerNode;
1686 inline BOOL ehnIsFinallyBlock()
1688 return ehnBlockType == FinallyNode;
1690 inline BOOL ehnIsFaultBlock()
1692 return ehnBlockType == FaultNode;
1695 // returns true if there is any overlap between the two nodes
1696 static inline BOOL ehnIsOverlap(pEHNodeDsc node1, pEHNodeDsc node2)
1698 if (node1->ehnStartOffset < node2->ehnStartOffset)
1700 return (node1->ehnEndOffset >= node2->ehnStartOffset);
1704 return (node1->ehnStartOffset <= node2->ehnEndOffset);
1708 // fails with BADCODE if inner is not completely nested inside outer
1709 static inline BOOL ehnIsNested(pEHNodeDsc inner, pEHNodeDsc outer)
1711 return ((inner->ehnStartOffset >= outer->ehnStartOffset) && (inner->ehnEndOffset <= outer->ehnEndOffset));
1715 //-------------------------------------------------------------------------
1716 // Exception handling functions
1719 #if !FEATURE_EH_FUNCLETS
1721 bool ehNeedsShadowSPslots()
1723 return (info.compXcptnsCount || opts.compDbgEnC);
1726 // 0 for methods with no EH
1727 // 1 for methods with non-nested EH, or where only the try blocks are nested
1728 // 2 for a method with a catch within a catch
1730 unsigned ehMaxHndNestingCount;
1732 #endif // !FEATURE_EH_FUNCLETS
1734 static bool jitIsBetween(unsigned value, unsigned start, unsigned end);
1735 static bool jitIsBetweenInclusive(unsigned value, unsigned start, unsigned end);
1737 bool bbInCatchHandlerILRange(BasicBlock* blk);
1738 bool bbInFilterILRange(BasicBlock* blk);
1739 bool bbInTryRegions(unsigned regionIndex, BasicBlock* blk);
1740 bool bbInExnFlowRegions(unsigned regionIndex, BasicBlock* blk);
1741 bool bbInHandlerRegions(unsigned regionIndex, BasicBlock* blk);
1742 bool bbInCatchHandlerRegions(BasicBlock* tryBlk, BasicBlock* hndBlk);
1743 unsigned short bbFindInnermostCommonTryRegion(BasicBlock* bbOne, BasicBlock* bbTwo);
1745 unsigned short bbFindInnermostTryRegionContainingHandlerRegion(unsigned handlerIndex);
1746 unsigned short bbFindInnermostHandlerRegionContainingTryRegion(unsigned tryIndex);
1748 // Returns true if "block" is the start of a try region.
1749 bool bbIsTryBeg(BasicBlock* block);
1751 // Returns true if "block" is the start of a handler or filter region.
1752 bool bbIsHandlerBeg(BasicBlock* block);
1754 // Returns true iff "block" is where control flows if an exception is raised in the
1755 // try region, and sets "*regionIndex" to the index of the try for the handler.
1756 // Differs from "IsHandlerBeg" in the case of filters, where this is true for the first
1757 // block of the filter, but not for the filter's handler.
1758 bool bbIsExFlowBlock(BasicBlock* block, unsigned* regionIndex);
1760 bool ehHasCallableHandlers();
1762 // Return the EH descriptor for the given region index.
1763 EHblkDsc* ehGetDsc(unsigned regionIndex);
1765 // Return the EH index given a region descriptor.
1766 unsigned ehGetIndex(EHblkDsc* ehDsc);
1768 // Return the EH descriptor index of the enclosing try, for the given region index.
1769 unsigned ehGetEnclosingTryIndex(unsigned regionIndex);
1771 // Return the EH descriptor index of the enclosing handler, for the given region index.
1772 unsigned ehGetEnclosingHndIndex(unsigned regionIndex);
1774 // Return the EH descriptor for the most nested 'try' region this BasicBlock is a member of (or nullptr if this
1775 // block is not in a 'try' region).
1776 EHblkDsc* ehGetBlockTryDsc(BasicBlock* block);
1778 // Return the EH descriptor for the most nested filter or handler region this BasicBlock is a member of (or nullptr
1779 // if this block is not in a filter or handler region).
1780 EHblkDsc* ehGetBlockHndDsc(BasicBlock* block);
1782 // Return the EH descriptor for the most nested region that may handle exceptions raised in this BasicBlock (or
1783 // nullptr if this block's exceptions propagate to caller).
1784 EHblkDsc* ehGetBlockExnFlowDsc(BasicBlock* block);
1786 EHblkDsc* ehIsBlockTryLast(BasicBlock* block);
1787 EHblkDsc* ehIsBlockHndLast(BasicBlock* block);
1788 bool ehIsBlockEHLast(BasicBlock* block);
1790 bool ehBlockHasExnFlowDsc(BasicBlock* block);
1792 // Return the region index of the most nested EH region this block is in.
1793 unsigned ehGetMostNestedRegionIndex(BasicBlock* block, bool* inTryRegion);
1795 // Find the true enclosing try index, ignoring 'mutual protect' try. Uses IL ranges to check.
1796 unsigned ehTrueEnclosingTryIndexIL(unsigned regionIndex);
1798 // Return the index of the most nested enclosing region for a particular EH region. Returns NO_ENCLOSING_INDEX
1799 // if there is no enclosing region. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion'
1800 // is set to 'true' if the enclosing region is a 'try', or 'false' if the enclosing region is a handler.
1801 // (It can never be a filter.)
1802 unsigned ehGetEnclosingRegionIndex(unsigned regionIndex, bool* inTryRegion);
1804 // A block has been deleted. Update the EH table appropriately.
1805 void ehUpdateForDeletedBlock(BasicBlock* block);
1807 // Determine whether a block can be deleted while preserving the EH normalization rules.
1808 bool ehCanDeleteEmptyBlock(BasicBlock* block);
1810 // Update the 'last' pointers in the EH table to reflect new or deleted blocks in an EH region.
1811 void ehUpdateLastBlocks(BasicBlock* oldLast, BasicBlock* newLast);
1813 // For a finally handler, find the region index that the BBJ_CALLFINALLY lives in that calls the handler,
1814 // or NO_ENCLOSING_INDEX if the BBJ_CALLFINALLY lives in the main function body. Normally, the index
1815 // is the same index as the handler (and the BBJ_CALLFINALLY lives in the 'try' region), but for AMD64 the
1816 // BBJ_CALLFINALLY lives in the enclosing try or handler region, whichever is more nested, or the main function
1817 // body. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion' is set to 'true' if the
1818 // BBJ_CALLFINALLY lives in the returned index's 'try' region, or 'false' if lives in the handler region. (It never
1819 // lives in a filter.)
1820 unsigned ehGetCallFinallyRegionIndex(unsigned finallyIndex, bool* inTryRegion);
1822 // Find the range of basic blocks in which all BBJ_CALLFINALLY will be found that target the 'finallyIndex' region's
1823 // handler. Set begBlk to the first block, and endBlk to the block after the last block of the range
1824 // (nullptr if the last block is the last block in the program).
1825 // Precondition: 'finallyIndex' is the EH region of a try/finally clause.
1826 void ehGetCallFinallyBlockRange(unsigned finallyIndex, BasicBlock** begBlk, BasicBlock** endBlk);
1829 // Given a BBJ_CALLFINALLY block and the EH region index of the finally it is calling, return
1830 // 'true' if the BBJ_CALLFINALLY is in the correct EH region.
1831 bool ehCallFinallyInCorrectRegion(BasicBlock* blockCallFinally, unsigned finallyIndex);
1834 #if FEATURE_EH_FUNCLETS
1835 // Do we need a PSPSym in the main function? For codegen purposes, we only need one
1836 // if there is a filter that protects a region with a nested EH clause (such as a
1837 // try/catch nested in the 'try' body of a try/filter/filter-handler). See
1838 // genFuncletProlog() for more details. However, the VM seems to use it for more
1839 // purposes, maybe including debugging. Until we are sure otherwise, always create
1840 // a PSPSym for functions with any EH.
1841 bool ehNeedsPSPSym() const
1845 #else // _TARGET_X86_
1846 return compHndBBtabCount > 0;
1847 #endif // _TARGET_X86_
1850 bool ehAnyFunclets(); // Are there any funclets in this function?
1851 unsigned ehFuncletCount(); // Return the count of funclets in the function
1853 unsigned bbThrowIndex(BasicBlock* blk); // Get the index to use as the cache key for sharing throw blocks
1854 #else // !FEATURE_EH_FUNCLETS
1855 bool ehAnyFunclets()
1859 unsigned ehFuncletCount()
1864 unsigned bbThrowIndex(BasicBlock* blk)
1866 return blk->bbTryIndex;
1867 } // Get the index to use as the cache key for sharing throw blocks
1868 #endif // !FEATURE_EH_FUNCLETS
1870 // Returns a flowList representing the "EH predecessors" of "blk". These are the normal predecessors of
1871 // "blk", plus one special case: if "blk" is the first block of a handler, considers the predecessor(s) of the first
1872 // first block of the corresponding try region to be "EH predecessors". (If there is a single such predecessor,
1873 // for example, we want to consider that the immediate dominator of the catch clause start block, so it's
1874 // convenient to also consider it a predecessor.)
1875 flowList* BlockPredsWithEH(BasicBlock* blk);
1877 // This table is useful for memoization of the method above.
1878 typedef JitHashTable<BasicBlock*, JitPtrKeyFuncs<BasicBlock>, flowList*> BlockToFlowListMap;
1879 BlockToFlowListMap* m_blockToEHPreds;
1880 BlockToFlowListMap* GetBlockToEHPreds()
1882 if (m_blockToEHPreds == nullptr)
1884 m_blockToEHPreds = new (getAllocator()) BlockToFlowListMap(getAllocator());
1886 return m_blockToEHPreds;
1889 void* ehEmitCookie(BasicBlock* block);
1890 UNATIVE_OFFSET ehCodeOffset(BasicBlock* block);
1892 EHblkDsc* ehInitHndRange(BasicBlock* src, IL_OFFSET* hndBeg, IL_OFFSET* hndEnd, bool* inFilter);
1894 EHblkDsc* ehInitTryRange(BasicBlock* src, IL_OFFSET* tryBeg, IL_OFFSET* tryEnd);
1896 EHblkDsc* ehInitHndBlockRange(BasicBlock* blk, BasicBlock** hndBeg, BasicBlock** hndLast, bool* inFilter);
1898 EHblkDsc* ehInitTryBlockRange(BasicBlock* blk, BasicBlock** tryBeg, BasicBlock** tryLast);
1900 void fgSetTryEnd(EHblkDsc* handlerTab, BasicBlock* newTryLast);
1902 void fgSetHndEnd(EHblkDsc* handlerTab, BasicBlock* newHndLast);
1904 void fgSkipRmvdBlocks(EHblkDsc* handlerTab);
1906 void fgAllocEHTable();
1908 void fgRemoveEHTableEntry(unsigned XTnum);
1910 #if FEATURE_EH_FUNCLETS
1912 EHblkDsc* fgAddEHTableEntry(unsigned XTnum);
1914 #endif // FEATURE_EH_FUNCLETS
1918 #endif // !FEATURE_EH
1920 void fgSortEHTable();
1922 // Causes the EH table to obey some well-formedness conditions, by inserting
1923 // empty BB's when necessary:
1924 // * No block is both the first block of a handler and the first block of a try.
1925 // * No block is the first block of multiple 'try' regions.
1926 // * No block is the last block of multiple EH regions.
1927 void fgNormalizeEH();
1928 bool fgNormalizeEHCase1();
1929 bool fgNormalizeEHCase2();
1930 bool fgNormalizeEHCase3();
1933 void dispIncomingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
1934 void dispOutgoingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
1935 void fgVerifyHandlerTab();
1936 void fgDispHandlerTab();
1939 bool fgNeedToSortEHTable;
1941 void verInitEHTree(unsigned numEHClauses);
1942 void verInsertEhNode(CORINFO_EH_CLAUSE* clause, EHblkDsc* handlerTab);
1943 void verInsertEhNodeInTree(EHNodeDsc** ppRoot, EHNodeDsc* node);
1944 void verInsertEhNodeParent(EHNodeDsc** ppRoot, EHNodeDsc* node);
1945 void verCheckNestingLevel(EHNodeDsc* initRoot);
1948 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1949 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1951 XX GenTree and BasicBlock XX
1953 XX Functions to allocate and display the GenTrees and BasicBlocks XX
1955 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1956 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1959 // Functions to create nodes
1960 GenTreeStmt* gtNewStmt(GenTreePtr expr = nullptr, IL_OFFSETX offset = BAD_IL_OFFSET);
1963 GenTreePtr gtNewOperNode(genTreeOps oper, var_types type, GenTreePtr op1, bool doSimplifications = TRUE);
1965 // For binary opers.
1966 GenTreePtr gtNewOperNode(genTreeOps oper, var_types type, GenTreePtr op1, GenTreePtr op2);
1968 GenTreePtr gtNewQmarkNode(var_types type, GenTreePtr cond, GenTreePtr colon);
1970 GenTreePtr gtNewLargeOperNode(genTreeOps oper,
1971 var_types type = TYP_I_IMPL,
1972 GenTreePtr op1 = nullptr,
1973 GenTreePtr op2 = nullptr);
1975 GenTreeIntCon* gtNewIconNode(ssize_t value, var_types type = TYP_INT);
1977 GenTree* gtNewPhysRegNode(regNumber reg, var_types type);
1979 GenTreePtr gtNewJmpTableNode();
1981 GenTreePtr gtNewIndOfIconHandleNode(var_types indType, size_t value, unsigned iconFlags, bool isInvariant);
1983 GenTreePtr gtNewIconHandleNode(size_t value, unsigned flags, FieldSeqNode* fields = nullptr);
1985 unsigned gtTokenToIconFlags(unsigned token);
1987 GenTreePtr gtNewIconEmbHndNode(void* value, void* pValue, unsigned flags, void* compileTimeHandle);
1989 GenTreePtr gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd);
1990 GenTreePtr gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd);
1991 GenTreePtr gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd);
1992 GenTreePtr gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd);
1994 GenTreePtr gtNewStringLiteralNode(InfoAccessType iat, void* pValue);
1996 GenTreePtr gtNewLconNode(__int64 value);
1998 GenTreePtr gtNewDconNode(double value);
2000 GenTreePtr gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle);
2002 GenTreePtr gtNewZeroConNode(var_types type);
2004 GenTreePtr gtNewOneConNode(var_types type);
2007 GenTreePtr gtNewSIMDVectorZero(var_types simdType, var_types baseType, unsigned size);
2008 GenTreePtr gtNewSIMDVectorOne(var_types simdType, var_types baseType, unsigned size);
2011 GenTreeBlk* gtNewBlkOpNode(
2012 genTreeOps oper, GenTreePtr dst, GenTreePtr srcOrFillVal, GenTreePtr sizeOrClsTok, bool isVolatile);
2014 GenTree* gtNewBlkOpNode(GenTreePtr dst, GenTreePtr srcOrFillVal, unsigned size, bool isVolatile, bool isCopyBlock);
2016 GenTree* gtNewPutArgReg(var_types type, GenTreePtr arg, regNumber argReg);
2018 GenTree* gtNewBitCastNode(var_types type, GenTreePtr arg);
2021 void gtBlockOpInit(GenTreePtr result, GenTreePtr dst, GenTreePtr srcOrFillVal, bool isVolatile);
2024 GenTree* gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTreePtr addr);
2025 void gtSetObjGcInfo(GenTreeObj* objNode);
2026 GenTree* gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTreePtr addr);
2027 GenTree* gtNewBlockVal(GenTreePtr addr, unsigned size);
2029 GenTree* gtNewCpObjNode(GenTreePtr dst, GenTreePtr src, CORINFO_CLASS_HANDLE structHnd, bool isVolatile);
2031 GenTreeArgList* gtNewListNode(GenTreePtr op1, GenTreeArgList* op2);
2033 GenTreeCall* gtNewCallNode(gtCallTypes callType,
2034 CORINFO_METHOD_HANDLE handle,
2036 GenTreeArgList* args,
2037 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2039 GenTreeCall* gtNewIndCallNode(GenTreePtr addr,
2041 GenTreeArgList* args,
2042 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2044 GenTreeCall* gtNewHelperCallNode(unsigned helper, var_types type, GenTreeArgList* args = nullptr);
2046 GenTreePtr gtNewLclvNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs = BAD_IL_OFFSET);
2049 GenTreeSIMD* gtNewSIMDNode(
2050 var_types type, GenTreePtr op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
2051 GenTreeSIMD* gtNewSIMDNode(var_types type,
2054 SIMDIntrinsicID simdIntrinsicID,
2057 void SetOpLclRelatedToSIMDIntrinsic(GenTreePtr op);
2060 #if FEATURE_HW_INTRINSICS
2061 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
2062 var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
2063 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
2064 var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
2065 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID);
2066 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type,
2069 NamedIntrinsic hwIntrinsicID);
2070 GenTree* gtNewMustThrowException(unsigned helper, var_types type);
2071 CORINFO_CLASS_HANDLE gtGetStructHandleForHWSIMD(var_types simdType, var_types simdBaseType);
2072 #endif // FEATURE_HW_INTRINSICS
2074 GenTreePtr gtNewLclLNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs = BAD_IL_OFFSET);
2075 GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset);
2076 GenTreePtr gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate, var_types type);
2078 GenTreePtr gtNewCodeRef(BasicBlock* block);
2080 GenTreePtr gtNewFieldRef(
2081 var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTreePtr obj = nullptr, DWORD offset = 0, bool nullcheck = false);
2083 GenTreePtr gtNewIndexRef(var_types typ, GenTreePtr arrayOp, GenTreePtr indexOp);
2085 GenTreeArrLen* gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset);
2087 GenTree* gtNewIndir(var_types typ, GenTree* addr);
2089 GenTreeArgList* gtNewArgList(GenTreePtr op);
2090 GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2);
2091 GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2, GenTreePtr op3);
2093 static fgArgTabEntryPtr gtArgEntryByArgNum(GenTreeCall* call, unsigned argNum);
2094 static fgArgTabEntryPtr gtArgEntryByNode(GenTreeCall* call, GenTreePtr node);
2095 fgArgTabEntryPtr gtArgEntryByLateArgIndex(GenTreeCall* call, unsigned lateArgInx);
2096 bool gtArgIsThisPtr(fgArgTabEntryPtr argEntry);
2098 GenTreePtr gtNewAssignNode(GenTreePtr dst, GenTreePtr src);
2100 GenTreePtr gtNewTempAssign(unsigned tmp, GenTreePtr val);
2102 GenTreePtr gtNewRefCOMfield(GenTreePtr objPtr,
2103 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2104 CORINFO_ACCESS_FLAGS access,
2105 CORINFO_FIELD_INFO* pFieldInfo,
2107 CORINFO_CLASS_HANDLE structType,
2110 GenTreePtr gtNewNothingNode();
2112 GenTreePtr gtNewArgPlaceHolderNode(var_types type, CORINFO_CLASS_HANDLE clsHnd);
2114 GenTreePtr gtUnusedValNode(GenTreePtr expr);
2116 GenTreePtr gtNewCastNode(var_types typ, GenTreePtr op1, var_types castType);
2118 GenTreePtr gtNewCastNodeL(var_types typ, GenTreePtr op1, var_types castType);
2120 GenTreePtr gtNewAllocObjNode(unsigned int helper, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTreePtr op1);
2122 GenTree* gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* lookupTree);
2124 //------------------------------------------------------------------------
2125 // Other GenTree functions
2127 GenTreePtr gtClone(GenTree* tree, bool complexOK = false);
2129 // If `tree` is a lclVar with lclNum `varNum`, return an IntCns with value `varVal`; otherwise,
2130 // create a copy of `tree`, adding specified flags, replacing uses of lclVar `deepVarNum` with
2131 // IntCnses with value `deepVarVal`.
2132 GenTreePtr gtCloneExpr(
2133 GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal);
2135 // Create a copy of `tree`, optionally adding specifed flags, and optionally mapping uses of local
2136 // `varNum` to int constants with value `varVal`.
2137 GenTreePtr gtCloneExpr(GenTree* tree, unsigned addFlags = 0, unsigned varNum = (unsigned)-1, int varVal = 0)
2139 return gtCloneExpr(tree, addFlags, varNum, varVal, varNum, varVal);
2142 GenTreePtr gtReplaceTree(GenTreePtr stmt, GenTreePtr tree, GenTreePtr replacementTree);
2144 void gtUpdateSideEffects(GenTree* stmt, GenTree* tree);
2146 void gtUpdateTreeAncestorsSideEffects(GenTree* tree);
2148 void gtUpdateStmtSideEffects(GenTree* stmt);
2150 void gtResetNodeSideEffects(GenTree* tree);
2152 // Returns "true" iff the complexity (not formally defined, but first interpretation
2153 // is #of nodes in subtree) of "tree" is greater than "limit".
2154 // (This is somewhat redundant with the "gtCostEx/gtCostSz" fields, but can be used
2155 // before they have been set.)
2156 bool gtComplexityExceeds(GenTreePtr* tree, unsigned limit);
2158 bool gtCompareTree(GenTree* op1, GenTree* op2);
2160 GenTreePtr gtReverseCond(GenTree* tree);
2162 bool gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly);
2164 bool gtHasLocalsWithAddrOp(GenTreePtr tree);
2166 unsigned gtSetListOrder(GenTree* list, bool regs, bool isListCallArgs);
2168 void gtWalkOp(GenTree** op1, GenTree** op2, GenTree* base, bool constOnly);
2171 unsigned gtHashValue(GenTree* tree);
2173 GenTreePtr gtWalkOpEffectiveVal(GenTreePtr op);
2176 void gtPrepareCost(GenTree* tree);
2177 bool gtIsLikelyRegVar(GenTree* tree);
2179 unsigned gtSetEvalOrderAndRestoreFPstkLevel(GenTree* tree);
2181 // Returns true iff the secondNode can be swapped with firstNode.
2182 bool gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode);
2184 unsigned gtSetEvalOrder(GenTree* tree);
2186 #if FEATURE_STACK_FP_X87
2188 void gtComputeFPlvls(GenTreePtr tree);
2189 #endif // FEATURE_STACK_FP_X87
2191 void gtSetStmtInfo(GenTree* stmt);
2193 // Returns "true" iff "node" has any of the side effects in "flags".
2194 bool gtNodeHasSideEffects(GenTreePtr node, unsigned flags);
2196 // Returns "true" iff "tree" or its (transitive) children have any of the side effects in "flags".
2197 bool gtTreeHasSideEffects(GenTreePtr tree, unsigned flags);
2199 // Appends 'expr' in front of 'list'
2200 // 'list' will typically start off as 'nullptr'
2201 // when 'list' is non-null a GT_COMMA node is used to insert 'expr'
2202 GenTreePtr gtBuildCommaList(GenTreePtr list, GenTreePtr expr);
2204 void gtExtractSideEffList(GenTreePtr expr,
2206 unsigned flags = GTF_SIDE_EFFECT,
2207 bool ignoreRoot = false);
2209 GenTreePtr gtGetThisArg(GenTreeCall* call);
2211 // Static fields of struct types (and sometimes the types that those are reduced to) are represented by having the
2212 // static field contain an object pointer to the boxed struct. This simplifies the GC implementation...but
2213 // complicates the JIT somewhat. This predicate returns "true" iff a node with type "fieldNodeType", representing
2214 // the given "fldHnd", is such an object pointer.
2215 bool gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd);
2217 // Return true if call is a recursive call; return false otherwise.
2218 // Note when inlining, this looks for calls back to the root method.
2219 bool gtIsRecursiveCall(GenTreeCall* call)
2221 return gtIsRecursiveCall(call->gtCallMethHnd);
2224 bool gtIsRecursiveCall(CORINFO_METHOD_HANDLE callMethodHandle)
2226 return (callMethodHandle == impInlineRoot()->info.compMethodHnd);
2229 //-------------------------------------------------------------------------
2231 GenTree* gtFoldExpr(GenTree* tree);
2234 // TODO-Amd64-Unix: Remove this when the clang optimizer is fixed and/or the method implementation is
2235 // refactored in a simpler code. This is a workaround for a bug in the clang-3.5 optimizer. The issue is that in
2236 // release build the optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner case
2237 // of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div operation instead of 64 bit) - see
2238 // the implementation of the method in gentree.cpp. For the case of lval1 and lval2 equal to MIN_LONG
2239 // (0x8000000000000000) this results in raising a SIGFPE. The method implementation is rather complex. Disable
2240 // optimizations for now.
2241 __attribute__((optnone))
2243 gtFoldExprConst(GenTree* tree);
2244 GenTree* gtFoldExprSpecial(GenTree* tree);
2245 GenTree* gtFoldExprCompare(GenTree* tree);
2246 GenTree* gtFoldExprCall(GenTreeCall* call);
2247 GenTree* gtFoldTypeCompare(GenTree* tree);
2248 GenTree* gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2);
2250 // Options to control behavior of gtTryRemoveBoxUpstreamEffects
2251 enum BoxRemovalOptions
2253 BR_REMOVE_AND_NARROW, // remove effects, minimize remaining work, return possibly narrowed source tree
2254 BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE, // remove effects and minimize remaining work, return type handle tree
2255 BR_REMOVE_BUT_NOT_NARROW, // remove effects, return original source tree
2256 BR_DONT_REMOVE, // just check if removal is possible
2257 BR_MAKE_LOCAL_COPY // revise box to copy to temp local and return local's address
2260 GenTree* gtTryRemoveBoxUpstreamEffects(GenTree* tree, BoxRemovalOptions options = BR_REMOVE_AND_NARROW);
2261 GenTree* gtOptimizeEnumHasFlag(GenTree* thisOp, GenTree* flagOp);
2263 //-------------------------------------------------------------------------
2264 // Get the handle, if any.
2265 CORINFO_CLASS_HANDLE gtGetStructHandleIfPresent(GenTreePtr tree);
2266 // Get the handle, and assert if not found.
2267 CORINFO_CLASS_HANDLE gtGetStructHandle(GenTreePtr tree);
2268 // Get the handle for a ref type.
2269 CORINFO_CLASS_HANDLE gtGetClassHandle(GenTreePtr tree, bool* isExact, bool* isNonNull);
2271 //-------------------------------------------------------------------------
2272 // Functions to display the trees
2275 void gtDispNode(GenTreePtr tree, IndentStack* indentStack, __in_z const char* msg, bool isLIR);
2277 void gtDispVN(GenTreePtr tree);
2278 void gtDispConst(GenTreePtr tree);
2279 void gtDispLeaf(GenTreePtr tree, IndentStack* indentStack);
2280 void gtDispNodeName(GenTreePtr tree);
2281 void gtDispRegVal(GenTreePtr tree);
2293 void gtDispChild(GenTreePtr child,
2294 IndentStack* indentStack,
2296 __in_opt const char* msg = nullptr,
2297 bool topOnly = false);
2298 void gtDispTree(GenTreePtr tree,
2299 IndentStack* indentStack = nullptr,
2300 __in_opt const char* msg = nullptr,
2301 bool topOnly = false,
2302 bool isLIR = false);
2303 void gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut);
2304 int gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining);
2305 char* gtGetLclVarName(unsigned lclNum);
2306 void gtDispLclVar(unsigned varNum, bool padForBiggestDisp = true);
2307 void gtDispTreeList(GenTreePtr tree, IndentStack* indentStack = nullptr);
2308 void gtGetArgMsg(GenTreeCall* call, GenTreePtr arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength);
2309 void gtGetLateArgMsg(GenTreeCall* call, GenTreePtr arg, int argNum, int listCount, char* bufp, unsigned bufLength);
2310 void gtDispArgList(GenTreeCall* call, IndentStack* indentStack);
2311 void gtDispFieldSeq(FieldSeqNode* pfsn);
2313 void gtDispRange(LIR::ReadOnlyRange const& range);
2315 void gtDispTreeRange(LIR::Range& containingRange, GenTree* tree);
2317 void gtDispLIRNode(GenTree* node, const char* prefixMsg = nullptr);
2329 typedef fgWalkResult(fgWalkPreFn)(GenTreePtr* pTree, fgWalkData* data);
2330 typedef fgWalkResult(fgWalkPostFn)(GenTreePtr* pTree, fgWalkData* data);
2333 static fgWalkPreFn gtAssertColonCond;
2335 static fgWalkPreFn gtMarkColonCond;
2336 static fgWalkPreFn gtClearColonCond;
2338 GenTreePtr* gtFindLink(GenTreePtr stmt, GenTreePtr node);
2339 bool gtHasCatchArg(GenTreePtr tree);
2340 bool gtHasUnmanagedCall(GenTreePtr tree);
2342 typedef ArrayStack<GenTree*> GenTreeStack;
2344 static bool gtHasCallOnStack(GenTreeStack* parentStack);
2345 void gtCheckQuirkAddrExposedLclVar(GenTreePtr argTree, GenTreeStack* parentStack);
2347 //=========================================================================
2348 // BasicBlock functions
2350 // This is a debug flag we will use to assert when creating block during codegen
2351 // as this interferes with procedure splitting. If you know what you're doing, set
2352 // it to true before creating the block. (DEBUG only)
2353 bool fgSafeBasicBlockCreation;
2356 BasicBlock* bbNewBasicBlock(BBjumpKinds jumpKind);
2359 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2360 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2364 XX The variables to be used by the code generator. XX
2366 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2367 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2371 // For both PROMOTION_TYPE_NONE and PROMOTION_TYPE_DEPENDENT the struct will
2372 // be placed in the stack frame and it's fields must be laid out sequentially.
2374 // For PROMOTION_TYPE_INDEPENDENT each of the struct's fields is replaced by
2375 // a local variable that can be enregistered or placed in the stack frame.
2376 // The fields do not need to be laid out sequentially
2378 enum lvaPromotionType
2380 PROMOTION_TYPE_NONE, // The struct local is not promoted
2381 PROMOTION_TYPE_INDEPENDENT, // The struct local is promoted,
2382 // and its field locals are independent of its parent struct local.
2383 PROMOTION_TYPE_DEPENDENT // The struct local is promoted,
2384 // but its field locals depend on its parent struct local.
2387 static int __cdecl RefCntCmp(const void* op1, const void* op2);
2388 static int __cdecl WtdRefCntCmp(const void* op1, const void* op2);
2390 /*****************************************************************************/
2392 enum FrameLayoutState
2395 INITIAL_FRAME_LAYOUT,
2396 PRE_REGALLOC_FRAME_LAYOUT,
2397 REGALLOC_FRAME_LAYOUT,
2398 TENTATIVE_FRAME_LAYOUT,
2403 bool lvaRefCountingStarted; // Set to true when we have started counting the local vars
2404 bool lvaLocalVarRefCounted; // Set to true after we have called lvaMarkLocalVars()
2405 bool lvaSortAgain; // true: We need to sort the lvaTable
2406 bool lvaTrackedFixed; // true: We cannot add new 'tracked' variable
2407 unsigned lvaCount; // total number of locals
2409 unsigned lvaRefCount; // total number of references to locals
2410 LclVarDsc* lvaTable; // variable descriptor table
2411 unsigned lvaTableCnt; // lvaTable size (>= lvaCount)
2413 LclVarDsc** lvaRefSorted; // table sorted by refcount
2415 unsigned short lvaTrackedCount; // actual # of locals being tracked
2416 unsigned lvaTrackedCountInSizeTUnits; // min # of size_t's sufficient to hold a bit for all the locals being tracked
2418 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
2419 // Only for AMD64 System V cache the first caller stack homed argument.
2420 unsigned lvaFirstStackIncomingArgNum; // First argument with stack slot in the caller.
2421 #endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
2424 VARSET_TP lvaTrackedVars; // set of tracked variables
2426 #ifndef _TARGET_64BIT_
2427 VARSET_TP lvaLongVars; // set of long (64-bit) variables
2429 VARSET_TP lvaFloatVars; // set of floating-point (32-bit and 64-bit) variables
2431 unsigned lvaCurEpoch; // VarSets are relative to a specific set of tracked var indices.
2432 // It that changes, this changes. VarSets from different epochs
2433 // cannot be meaningfully combined.
2435 unsigned GetCurLVEpoch()
2440 // reverse map of tracked number to var number
2441 unsigned lvaTrackedToVarNum[lclMAX_TRACKED];
2443 #ifdef LEGACY_BACKEND
2444 // variable interference graph
2445 VARSET_TP lvaVarIntf[lclMAX_TRACKED];
2448 // variable preference graph
2449 VARSET_TP lvaVarPref[lclMAX_TRACKED];
2453 // # of procs compiled a with double-aligned stack
2454 static unsigned s_lvaDoubleAlignedProcsCount;
2458 // Getters and setters for address-exposed and do-not-enregister local var properties.
2459 bool lvaVarAddrExposed(unsigned varNum);
2460 void lvaSetVarAddrExposed(unsigned varNum);
2461 bool lvaVarDoNotEnregister(unsigned varNum);
2463 // Reasons why we can't enregister. Some of these correspond to debug properties of local vars.
2464 enum DoNotEnregisterReason
2469 DNER_VMNeedsStackAddr,
2470 DNER_LiveInOutOfHandler,
2471 DNER_LiveAcrossUnmanagedCall,
2472 DNER_BlockOp, // Is read or written via a block operation that explicitly takes the address.
2473 DNER_IsStructArg, // Is a struct passed as an argument in a way that requires a stack location.
2474 DNER_DepField, // It is a field of a dependently promoted struct
2475 DNER_NoRegVars, // opts.compFlags & CLFLG_REGVAR is not set
2476 DNER_MinOptsGC, // It is a GC Ref and we are compiling MinOpts
2477 #if !defined(LEGACY_BACKEND) && !defined(_TARGET_64BIT_)
2478 DNER_LongParamField, // It is a decomposed field of a long parameter.
2480 #ifdef JIT32_GCENCODER
2485 void lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregisterReason reason));
2487 unsigned lvaVarargsHandleArg;
2489 unsigned lvaVarargsBaseOfStkArgs; // Pointer (computed based on incoming varargs handle) to the start of the stack
2491 #endif // _TARGET_X86_
2493 unsigned lvaInlinedPInvokeFrameVar; // variable representing the InlinedCallFrame
2494 unsigned lvaReversePInvokeFrameVar; // variable representing the reverse PInvoke frame
2495 #if FEATURE_FIXED_OUT_ARGS
2496 unsigned lvaPInvokeFrameRegSaveVar; // variable representing the RegSave for PInvoke inlining.
2498 unsigned lvaMonAcquired; // boolean variable introduced into in synchronized methods
2499 // that tracks whether the lock has been taken
2501 unsigned lvaArg0Var; // The lclNum of arg0. Normally this will be info.compThisArg.
2502 // However, if there is a "ldarga 0" or "starg 0" in the IL,
2503 // we will redirect all "ldarg(a) 0" and "starg 0" to this temp.
2505 unsigned lvaInlineeReturnSpillTemp; // The temp to spill the non-VOID return expression
2506 // in case there are multiple BBJ_RETURN blocks in the inlinee
2507 // or if the inlinee has GC ref locals.
2509 #if FEATURE_FIXED_OUT_ARGS
2510 unsigned lvaOutgoingArgSpaceVar; // dummy TYP_LCLBLK var for fixed outgoing argument space
2511 PhasedVar<unsigned> lvaOutgoingArgSpaceSize; // size of fixed outgoing argument space
2512 #endif // FEATURE_FIXED_OUT_ARGS
2515 // On architectures whose ABIs allow structs to be passed in registers, struct promotion will sometimes
2516 // require us to "rematerialize" a struct from it's separate constituent field variables. Packing several sub-word
2517 // field variables into an argument register is a hard problem. It's easier to reserve a word of memory into which
2518 // such field can be copied, after which the assembled memory word can be read into the register. We will allocate
2519 // this variable to be this scratch word whenever struct promotion occurs.
2520 unsigned lvaPromotedStructAssemblyScratchVar;
2521 #endif // _TARGET_ARM_
2524 unsigned lvaReturnEspCheck; // confirms ESP not corrupted on return
2525 unsigned lvaCallEspCheck; // confirms ESP not corrupted after a call
2528 unsigned lvaGenericsContextUseCount;
2530 bool lvaKeepAliveAndReportThis(); // Synchronized instance method of a reference type, or
2531 // CORINFO_GENERICS_CTXT_FROM_THIS?
2532 bool lvaReportParamTypeArg(); // Exceptions and CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG?
2534 //-------------------------------------------------------------------------
2535 // All these frame offsets are inter-related and must be kept in sync
2537 #if !FEATURE_EH_FUNCLETS
2538 // This is used for the callable handlers
2539 unsigned lvaShadowSPslotsVar; // TYP_BLK variable for all the shadow SP slots
2540 #endif // FEATURE_EH_FUNCLETS
2542 unsigned lvaCachedGenericContextArgOffs;
2543 unsigned lvaCachedGenericContextArgOffset(); // For CORINFO_CALLCONV_PARAMTYPE and if generic context is passed as
2546 unsigned lvaLocAllocSPvar; // variable which has the result of the last alloca/localloc
2548 unsigned lvaNewObjArrayArgs; // variable with arguments for new MD array helper
2550 // TODO-Review: Prior to reg predict we reserve 24 bytes for Spill temps.
2551 // after the reg predict we will use a computed maxTmpSize
2552 // which is based upon the number of spill temps predicted by reg predict
2553 // All this is necessary because if we under-estimate the size of the spill
2554 // temps we could fail when encoding instructions that reference stack offsets for ARM.
2556 // Pre codegen max spill temp size.
2557 static const unsigned MAX_SPILL_TEMP_SIZE = 24;
2559 //-------------------------------------------------------------------------
2561 unsigned lvaGetMaxSpillTempSize();
2563 bool lvaIsPreSpilled(unsigned lclNum, regMaskTP preSpillMask);
2564 #endif // _TARGET_ARM_
2565 void lvaAssignFrameOffsets(FrameLayoutState curState);
2566 void lvaFixVirtualFrameOffsets();
2568 #ifndef LEGACY_BACKEND
2569 void lvaUpdateArgsWithInitialReg();
2570 #endif // !LEGACY_BACKEND
2572 void lvaAssignVirtualFrameOffsetsToArgs();
2573 #ifdef UNIX_AMD64_ABI
2574 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs, int* callerArgOffset);
2575 #else // !UNIX_AMD64_ABI
2576 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs);
2577 #endif // !UNIX_AMD64_ABI
2578 void lvaAssignVirtualFrameOffsetsToLocals();
2579 int lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, int stkOffs);
2580 #ifdef _TARGET_AMD64_
2581 // Returns true if compCalleeRegsPushed (including RBP if used as frame pointer) is even.
2582 bool lvaIsCalleeSavedIntRegCountEven();
2584 void lvaAlignFrame();
2585 void lvaAssignFrameOffsetsToPromotedStructs();
2586 int lvaAllocateTemps(int stkOffs, bool mustDoubleAlign);
2589 void lvaDumpRegLocation(unsigned lclNum);
2590 void lvaDumpFrameLocation(unsigned lclNum);
2591 void lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t refCntWtdWidth = 6);
2592 void lvaTableDump(FrameLayoutState curState = NO_FRAME_LAYOUT); // NO_FRAME_LAYOUT means use the current frame
2593 // layout state defined by lvaDoneFrameLayout
2596 // Limit frames size to 1GB. The maximum is 2GB in theory - make it intentionally smaller
2597 // to avoid bugs from borderline cases.
2598 #define MAX_FrameSize 0x3FFFFFFF
2599 void lvaIncrementFrameSize(unsigned size);
2601 unsigned lvaFrameSize(FrameLayoutState curState);
2603 // Returns the caller-SP-relative offset for the SP/FP relative offset determined by FP based.
2604 int lvaToCallerSPRelativeOffset(int offs, bool isFpBased);
2606 // Returns the caller-SP-relative offset for the local variable "varNum."
2607 int lvaGetCallerSPRelativeOffset(unsigned varNum);
2609 // Returns the SP-relative offset for the local variable "varNum". Illegal to ask this for functions with localloc.
2610 int lvaGetSPRelativeOffset(unsigned varNum);
2612 int lvaToInitialSPRelativeOffset(unsigned offset, bool isFpBased);
2613 int lvaGetInitialSPRelativeOffset(unsigned varNum);
2615 //------------------------ For splitting types ----------------------------
2617 void lvaInitTypeRef();
2619 void lvaInitArgs(InitVarDscInfo* varDscInfo);
2620 void lvaInitThisPtr(InitVarDscInfo* varDscInfo);
2621 void lvaInitRetBuffArg(InitVarDscInfo* varDscInfo);
2622 void lvaInitUserArgs(InitVarDscInfo* varDscInfo);
2623 void lvaInitGenericsCtxt(InitVarDscInfo* varDscInfo);
2624 void lvaInitVarArgsHandle(InitVarDscInfo* varDscInfo);
2626 void lvaInitVarDsc(LclVarDsc* varDsc,
2628 CorInfoType corInfoType,
2629 CORINFO_CLASS_HANDLE typeHnd,
2630 CORINFO_ARG_LIST_HANDLE varList,
2631 CORINFO_SIG_INFO* varSig);
2633 static unsigned lvaTypeRefMask(var_types type);
2635 var_types lvaGetActualType(unsigned lclNum);
2636 var_types lvaGetRealType(unsigned lclNum);
2638 //-------------------------------------------------------------------------
2642 unsigned lvaLclSize(unsigned varNum);
2643 unsigned lvaLclExactSize(unsigned varNum);
2645 bool lvaLclVarRefs(GenTreePtr tree, GenTreePtr* findPtr, varRefKinds* refsPtr, void* result);
2647 // Call lvaLclVarRefs on "true"; accumulate "*result" into whichever of
2648 // "allVars" and "trkdVars" is indiated by the nullness of "findPtr"; return
2649 // the return result.
2650 bool lvaLclVarRefsAccum(
2651 GenTreePtr tree, GenTreePtr* findPtr, varRefKinds* refsPtr, ALLVARSET_TP* allVars, VARSET_TP* trkdVars);
2653 // If "findPtr" is non-NULL, assumes "result" is an "ALLVARSET_TP*", and
2654 // (destructively) unions "allVars" into "*result". Otherwise, assumes "result" is a "VARSET_TP*",
2655 // and (destructively) unions "trkedVars" into "*result".
2656 void lvaLclVarRefsAccumIntoRes(GenTreePtr* findPtr,
2658 ALLVARSET_VALARG_TP allVars,
2659 VARSET_VALARG_TP trkdVars);
2661 bool lvaHaveManyLocals() const;
2663 unsigned lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason));
2664 unsigned lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason));
2665 unsigned lvaGrabTempWithImplicitUse(bool shortLifetime DEBUGARG(const char* reason));
2668 void lvaSortByRefCount();
2669 void lvaDumpRefCounts();
2671 void lvaMarkLocalVars(BasicBlock* block);
2673 void lvaMarkLocalVars(); // Local variable ref-counting
2675 void lvaAllocOutgoingArgSpaceVar(); // Set up lvaOutgoingArgSpaceVar
2677 VARSET_VALRET_TP lvaStmtLclMask(GenTreePtr stmt);
2679 void lvaIncRefCnts(GenTreePtr tree);
2680 void lvaDecRefCnts(GenTreePtr tree);
2682 void lvaDecRefCnts(BasicBlock* basicBlock, GenTreePtr tree);
2683 void lvaRecursiveDecRefCounts(GenTreePtr tree);
2684 void lvaRecursiveIncRefCounts(GenTreePtr tree);
2687 struct lvaStressLclFldArgs
2689 Compiler* m_pCompiler;
2693 static fgWalkPreFn lvaStressLclFldCB;
2694 void lvaStressLclFld();
2696 void lvaDispVarSet(VARSET_VALARG_TP set, VARSET_VALARG_TP allVars);
2697 void lvaDispVarSet(VARSET_VALARG_TP set);
2702 int lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset);
2704 int lvaFrameAddress(int varNum, bool* pFPbased);
2707 bool lvaIsParameter(unsigned varNum);
2708 bool lvaIsRegArgument(unsigned varNum);
2709 BOOL lvaIsOriginalThisArg(unsigned varNum); // Is this varNum the original this argument?
2710 BOOL lvaIsOriginalThisReadOnly(); // return TRUE if there is no place in the code
2711 // that writes to arg0
2713 // Struct parameters that are passed by reference are marked as both lvIsParam and lvIsTemp
2714 // (this is an overload of lvIsTemp because there are no temp parameters).
2715 // For x64 this is 3, 5, 6, 7, >8 byte structs that are passed by reference.
2716 // For ARM64, this is structs larger than 16 bytes that are passed by reference.
2717 bool lvaIsImplicitByRefLocal(unsigned varNum)
2719 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
2720 LclVarDsc* varDsc = &(lvaTable[varNum]);
2721 if (varDsc->lvIsParam && varDsc->lvIsTemp)
2723 assert(varTypeIsStruct(varDsc) || (varDsc->lvType == TYP_BYREF));
2726 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
2730 // Returns true if this local var is a multireg struct
2731 bool lvaIsMultiregStruct(LclVarDsc* varDsc);
2733 // If the local is a TYP_STRUCT, get/set a class handle describing it
2734 CORINFO_CLASS_HANDLE lvaGetStruct(unsigned varNum);
2735 void lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool unsafeValueClsCheck, bool setTypeInfo = true);
2737 // If the local is TYP_REF, set or update the associated class information.
2738 void lvaSetClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
2739 void lvaSetClass(unsigned varNum, GenTreePtr tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
2740 void lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
2741 void lvaUpdateClass(unsigned varNum, GenTreePtr tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
2743 #define MAX_NumOfFieldsInPromotableStruct 4 // Maximum number of fields in promotable struct
2745 // Info about struct fields
2746 struct lvaStructFieldInfo
2748 CORINFO_FIELD_HANDLE fldHnd;
2749 unsigned char fldOffset;
2750 unsigned char fldOrdinal;
2753 CORINFO_CLASS_HANDLE fldTypeHnd;
2756 // Info about struct to be promoted.
2757 struct lvaStructPromotionInfo
2759 CORINFO_CLASS_HANDLE typeHnd;
2761 bool requiresScratchVar;
2764 unsigned char fieldCnt;
2765 lvaStructFieldInfo fields[MAX_NumOfFieldsInPromotableStruct];
2767 lvaStructPromotionInfo()
2768 : typeHnd(nullptr), canPromote(false), requiresScratchVar(false), containsHoles(false), customLayout(false)
2773 static int __cdecl lvaFieldOffsetCmp(const void* field1, const void* field2);
2774 void lvaCanPromoteStructType(CORINFO_CLASS_HANDLE typeHnd,
2775 lvaStructPromotionInfo* StructPromotionInfo,
2777 void lvaCanPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo);
2778 bool lvaShouldPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* structPromotionInfo);
2779 void lvaPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo);
2780 #if !defined(_TARGET_64BIT_)
2781 void lvaPromoteLongVars();
2782 #endif // !defined(_TARGET_64BIT_)
2783 unsigned lvaGetFieldLocal(LclVarDsc* varDsc, unsigned int fldOffset);
2784 lvaPromotionType lvaGetPromotionType(const LclVarDsc* varDsc);
2785 lvaPromotionType lvaGetPromotionType(unsigned varNum);
2786 lvaPromotionType lvaGetParentPromotionType(const LclVarDsc* varDsc);
2787 lvaPromotionType lvaGetParentPromotionType(unsigned varNum);
2788 bool lvaIsFieldOfDependentlyPromotedStruct(const LclVarDsc* varDsc);
2789 bool lvaIsGCTracked(const LclVarDsc* varDsc);
2791 #if defined(FEATURE_SIMD)
2792 bool lvaMapSimd12ToSimd16(const LclVarDsc* varDsc)
2794 assert(varDsc->lvType == TYP_SIMD12);
2795 assert(varDsc->lvExactSize == 12);
2797 #if defined(_TARGET_64BIT_)
2798 assert(varDsc->lvSize() == 16);
2799 #endif // defined(_TARGET_64BIT_)
2801 // We make local variable SIMD12 types 16 bytes instead of just 12. lvSize()
2802 // already does this calculation. However, we also need to prevent mapping types if the var is a
2803 // dependently promoted struct field, which must remain its exact size within its parent struct.
2804 // However, we don't know this until late, so we may have already pretended the field is bigger
2806 if ((varDsc->lvSize() == 16) && !lvaIsFieldOfDependentlyPromotedStruct(varDsc))
2815 #endif // defined(FEATURE_SIMD)
2817 BYTE* lvaGetGcLayout(unsigned varNum);
2818 bool lvaTypeIsGC(unsigned varNum);
2819 unsigned lvaGSSecurityCookie; // LclVar number
2820 bool lvaTempsHaveLargerOffsetThanVars();
2822 unsigned lvaSecurityObject; // variable representing the security object on the stack
2823 unsigned lvaStubArgumentVar; // variable representing the secret stub argument coming in EAX
2825 #if FEATURE_EH_FUNCLETS
2826 unsigned lvaPSPSym; // variable representing the PSPSym
2829 InlineInfo* impInlineInfo;
2830 InlineStrategy* m_inlineStrategy;
2832 // The Compiler* that is the root of the inlining tree of which "this" is a member.
2833 Compiler* impInlineRoot();
2835 #if defined(DEBUG) || defined(INLINE_DATA)
2836 unsigned __int64 getInlineCycleCount()
2838 return m_compCycles;
2840 #endif // defined(DEBUG) || defined(INLINE_DATA)
2842 bool fgNoStructPromotion; // Set to TRUE to turn off struct promotion for this method.
2843 bool fgNoStructParamPromotion; // Set to TRUE to turn off struct promotion for parameters this method.
2845 //=========================================================================
2847 //=========================================================================
2850 //---------------- Local variable ref-counting ----------------------------
2853 BasicBlock* lvaMarkRefsCurBlock;
2854 GenTreePtr lvaMarkRefsCurStmt;
2856 BasicBlock::weight_t lvaMarkRefsWeight;
2858 void lvaMarkLclRefs(GenTreePtr tree);
2860 bool IsDominatedByExceptionalEntry(BasicBlock* block);
2861 void SetVolatileHint(LclVarDsc* varDsc);
2863 // Keeps the mapping from SSA #'s to VN's for the implicit memory variables.
2864 PerSsaArray lvMemoryPerSsaData;
2865 unsigned lvMemoryNumSsaNames;
2868 // Returns the address of the per-Ssa data for memory at the given ssaNum (which is required
2869 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
2870 // not an SSA variable).
2871 LclSsaVarDsc* GetMemoryPerSsaData(unsigned ssaNum)
2873 assert(ssaNum != SsaConfig::RESERVED_SSA_NUM);
2874 assert(SsaConfig::RESERVED_SSA_NUM == 0);
2876 assert(ssaNum < lvMemoryNumSsaNames);
2877 return &lvMemoryPerSsaData.GetRef(ssaNum);
2881 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2882 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2886 XX Imports the given method and converts it to semantic trees XX
2888 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2889 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2895 void impImport(BasicBlock* method);
2897 CORINFO_CLASS_HANDLE impGetRefAnyClass();
2898 CORINFO_CLASS_HANDLE impGetRuntimeArgumentHandle();
2899 CORINFO_CLASS_HANDLE impGetTypeHandleClass();
2900 CORINFO_CLASS_HANDLE impGetStringClass();
2901 CORINFO_CLASS_HANDLE impGetObjectClass();
2903 // Returns underlying type of handles returned by ldtoken instruction
2904 inline var_types GetRuntimeHandleUnderlyingType()
2906 // RuntimeTypeHandle is backed by raw pointer on CoreRT and by object reference on other runtimes
2907 return IsTargetAbi(CORINFO_CORERT_ABI) ? TYP_I_IMPL : TYP_REF;
2910 //=========================================================================
2912 //=========================================================================
2915 //-------------------- Stack manipulation ---------------------------------
2917 unsigned impStkSize; // Size of the full stack
2919 #define SMALL_STACK_SIZE 16 // number of elements in impSmallStack
2921 StackEntry impSmallStack[SMALL_STACK_SIZE]; // Use this array if possible
2923 struct SavedStack // used to save/restore stack contents.
2925 unsigned ssDepth; // number of values on stack
2926 StackEntry* ssTrees; // saved tree values
2929 bool impIsPrimitive(CorInfoType type);
2930 bool impILConsumesAddr(const BYTE* codeAddr, CORINFO_METHOD_HANDLE fncHandle, CORINFO_MODULE_HANDLE scpHandle);
2932 void impResolveToken(const BYTE* addr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CorInfoTokenKind kind);
2934 void impPushOnStack(GenTreePtr tree, typeInfo ti);
2935 void impPushNullObjRefOnStack();
2936 StackEntry impPopStack();
2937 StackEntry& impStackTop(unsigned n = 0);
2938 unsigned impStackHeight();
2940 void impSaveStackState(SavedStack* savePtr, bool copy);
2941 void impRestoreStackState(SavedStack* savePtr);
2943 GenTreePtr impImportLdvirtftn(GenTreePtr thisPtr,
2944 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2945 CORINFO_CALL_INFO* pCallInfo);
2947 void impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken);
2949 void impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
2951 bool impCanPInvokeInline();
2952 bool impCanPInvokeInlineCallSite(BasicBlock* block);
2953 void impCheckForPInvokeCall(
2954 GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block);
2955 GenTreeCall* impImportIndirectCall(CORINFO_SIG_INFO* sig, IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2956 void impPopArgsForUnmanagedCall(GenTreePtr call, CORINFO_SIG_INFO* sig);
2958 void impInsertHelperCall(CORINFO_HELPER_DESC* helperCall);
2959 void impHandleAccessAllowed(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
2960 void impHandleAccessAllowedInternal(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
2962 var_types impImportCall(OPCODE opcode,
2963 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2964 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call on a
2966 GenTreePtr newobjThis,
2968 CORINFO_CALL_INFO* callInfo,
2969 IL_OFFSET rawILOffset);
2971 void impDevirtualizeCall(GenTreeCall* call,
2972 CORINFO_METHOD_HANDLE* method,
2973 unsigned* methodFlags,
2974 CORINFO_CONTEXT_HANDLE* contextHandle,
2975 CORINFO_CONTEXT_HANDLE* exactContextHandle);
2977 CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(CORINFO_METHOD_HANDLE specialIntrinsicHandle);
2979 bool impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo);
2981 GenTreePtr impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HANDLE retClsHnd);
2983 GenTreePtr impFixupStructReturnType(GenTreePtr op, CORINFO_CLASS_HANDLE retClsHnd);
2986 var_types impImportJitTestLabelMark(int numArgs);
2989 GenTreePtr impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken);
2991 GenTreePtr impImportStaticReadOnlyField(void* fldAddr, var_types lclTyp);
2993 GenTreePtr impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken,
2994 CORINFO_ACCESS_FLAGS access,
2995 CORINFO_FIELD_INFO* pFieldInfo,
2998 static void impBashVarAddrsToI(GenTreePtr tree1, GenTreePtr tree2 = nullptr);
3000 GenTreePtr impImplicitIorI4Cast(GenTreePtr tree, var_types dstTyp);
3002 GenTreePtr impImplicitR4orR8Cast(GenTreePtr tree, var_types dstTyp);
3004 void impImportLeave(BasicBlock* block);
3005 void impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr);
3006 GenTree* impIntrinsic(GenTree* newobjThis,
3007 CORINFO_CLASS_HANDLE clsHnd,
3008 CORINFO_METHOD_HANDLE method,
3009 CORINFO_SIG_INFO* sig,
3010 unsigned methodFlags,
3014 CORINFO_RESOLVED_TOKEN* pContstrainedResolvedToken,
3015 CORINFO_THIS_TRANSFORM constraintCallThisTransform,
3016 CorInfoIntrinsics* pIntrinsicID,
3017 bool* isSpecialIntrinsic = nullptr);
3018 GenTree* impMathIntrinsic(CORINFO_METHOD_HANDLE method,
3019 CORINFO_SIG_INFO* sig,
3021 CorInfoIntrinsics intrinsicID,
3023 NamedIntrinsic lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method);
3025 #if FEATURE_HW_INTRINSICS
3026 InstructionSet lookupHWIntrinsicISA(const char* className);
3027 NamedIntrinsic lookupHWIntrinsic(const char* methodName, InstructionSet isa);
3028 InstructionSet isaOfHWIntrinsic(NamedIntrinsic intrinsic);
3029 bool isIntrinsicAnIsSupportedPropertyGetter(NamedIntrinsic intrinsic);
3030 #ifdef _TARGET_XARCH_
3031 GenTree* impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3032 GenTree* impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3033 GenTree* impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3034 GenTree* impSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3035 GenTree* impSSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3036 GenTree* impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3037 GenTree* impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3038 GenTree* impAVXIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3039 GenTree* impAVX2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3040 GenTree* impAESIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3041 GenTree* impBMI1Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3042 GenTree* impBMI2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3043 GenTree* impFMAIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3044 GenTree* impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3045 GenTree* impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3046 GenTree* impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
3047 #endif // _TARGET_XARCH_
3048 #endif // FEATURE_HW_INTRINSICS
3049 GenTreePtr impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
3050 CORINFO_SIG_INFO* sig,
3053 CorInfoIntrinsics intrinsicID);
3054 GenTreePtr impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig);
3056 GenTreePtr impMethodPointer(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3058 GenTreePtr impTransformThis(GenTreePtr thisPtr,
3059 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
3060 CORINFO_THIS_TRANSFORM transform);
3062 //----------------- Manipulating the trees and stmts ----------------------
3064 GenTreePtr impTreeList; // Trees for the BB being imported
3065 GenTreePtr impTreeLast; // The last tree for the current BB
3070 CHECK_SPILL_ALL = -1,
3071 CHECK_SPILL_NONE = -2
3074 void impBeginTreeList();
3075 void impEndTreeList(BasicBlock* block, GenTreePtr firstStmt, GenTreePtr lastStmt);
3076 void impEndTreeList(BasicBlock* block);
3077 void impAppendStmtCheck(GenTreePtr stmt, unsigned chkLevel);
3078 void impAppendStmt(GenTreePtr stmt, unsigned chkLevel);
3079 void impInsertStmtBefore(GenTreePtr stmt, GenTreePtr stmtBefore);
3080 GenTreePtr impAppendTree(GenTreePtr tree, unsigned chkLevel, IL_OFFSETX offset);
3081 void impInsertTreeBefore(GenTreePtr tree, IL_OFFSETX offset, GenTreePtr stmtBefore);
3082 void impAssignTempGen(unsigned tmp,
3085 GenTreePtr* pAfterStmt = nullptr,
3086 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3087 BasicBlock* block = nullptr);
3088 void impAssignTempGen(unsigned tmpNum,
3090 CORINFO_CLASS_HANDLE structHnd,
3092 GenTreePtr* pAfterStmt = nullptr,
3093 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3094 BasicBlock* block = nullptr);
3095 GenTreePtr impCloneExpr(GenTreePtr tree,
3097 CORINFO_CLASS_HANDLE structHnd,
3099 GenTreePtr* pAfterStmt DEBUGARG(const char* reason));
3100 GenTreePtr impAssignStruct(GenTreePtr dest,
3102 CORINFO_CLASS_HANDLE structHnd,
3104 GenTreePtr* pAfterStmt = nullptr,
3105 BasicBlock* block = nullptr);
3106 GenTreePtr impAssignStructPtr(GenTreePtr dest,
3108 CORINFO_CLASS_HANDLE structHnd,
3110 GenTreePtr* pAfterStmt = nullptr,
3111 BasicBlock* block = nullptr);
3113 GenTreePtr impGetStructAddr(GenTreePtr structVal,
3114 CORINFO_CLASS_HANDLE structHnd,
3118 var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd,
3119 BYTE* gcLayout = nullptr,
3120 unsigned* numGCVars = nullptr,
3121 var_types* simdBaseType = nullptr);
3123 GenTreePtr impNormStructVal(GenTreePtr structVal,
3124 CORINFO_CLASS_HANDLE structHnd,
3126 bool forceNormalization = false);
3128 GenTreePtr impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3129 BOOL* pRuntimeLookup = nullptr,
3130 BOOL mustRestoreHandle = FALSE,
3131 BOOL importParent = FALSE);
3133 GenTreePtr impParentClassTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3134 BOOL* pRuntimeLookup = nullptr,
3135 BOOL mustRestoreHandle = FALSE)
3137 return impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, TRUE);
3140 GenTreePtr impLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3141 CORINFO_LOOKUP* pLookup,
3143 void* compileTimeHandle);
3145 GenTreePtr getRuntimeContextTree(CORINFO_RUNTIME_LOOKUP_KIND kind);
3147 GenTreePtr impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3148 CORINFO_LOOKUP* pLookup,
3149 void* compileTimeHandle);
3151 GenTreePtr impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP* pLookup, unsigned flags, void* compileTimeHandle);
3153 GenTreeCall* impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3154 CorInfoHelpFunc helper,
3156 GenTreeArgList* arg = nullptr,
3157 CORINFO_LOOKUP_KIND* pGenericLookupKind = nullptr);
3159 GenTreePtr impCastClassOrIsInstToTree(GenTreePtr op1,
3161 CORINFO_RESOLVED_TOKEN* pResolvedToken,
3164 GenTree* impOptimizeCastClassOrIsInst(GenTree* op1, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isCastClass);
3166 bool VarTypeIsMultiByteAndCanEnreg(var_types type,
3167 CORINFO_CLASS_HANDLE typeClass,
3171 static bool IsIntrinsicImplementedByUserCall(CorInfoIntrinsics intrinsicId);
3172 static bool IsTargetIntrinsic(CorInfoIntrinsics intrinsicId);
3173 static bool IsMathIntrinsic(CorInfoIntrinsics intrinsicId);
3174 static bool IsMathIntrinsic(GenTreePtr tree);
3177 //----------------- Importing the method ----------------------------------
3179 CORINFO_CONTEXT_HANDLE impTokenLookupContextHandle; // The context used for looking up tokens.
3182 unsigned impCurOpcOffs;
3183 const char* impCurOpcName;
3184 bool impNestedStackSpill;
3186 // For displaying instrs with generated native code (-n:B)
3187 GenTreePtr impLastILoffsStmt; // oldest stmt added for which we did not gtStmtLastILoffs
3188 void impNoteLastILoffs();
3191 /* IL offset of the stmt currently being imported. It gets set to
3192 BAD_IL_OFFSET after it has been set in the appended trees. Then it gets
3193 updated at IL offsets for which we have to report mapping info.
3194 It also includes flag bits, so use jitGetILoffs()
3195 to get the actual IL offset value.
3198 IL_OFFSETX impCurStmtOffs;
3199 void impCurStmtOffsSet(IL_OFFSET offs);
3201 void impNoteBranchOffs();
3203 unsigned impInitBlockLineInfo();
3205 GenTreePtr impCheckForNullPointer(GenTreePtr obj);
3206 bool impIsThis(GenTreePtr obj);
3207 bool impIsLDFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3208 bool impIsDUP_LDVIRTFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3209 bool impIsAnySTLOC(OPCODE opcode)
3211 return ((opcode == CEE_STLOC) || (opcode == CEE_STLOC_S) ||
3212 ((opcode >= CEE_STLOC_0) && (opcode <= CEE_STLOC_3)));
3215 GenTreeArgList* impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenTreeArgList* prefixTree = nullptr);
3217 GenTreeArgList* impPopRevList(unsigned count, CORINFO_SIG_INFO* sig, unsigned skipReverseCount = 0);
3220 * Get current IL offset with stack-empty info incoporated
3222 IL_OFFSETX impCurILOffset(IL_OFFSET offs, bool callInstruction = false);
3224 //---------------- Spilling the importer stack ----------------------------
3226 // The maximum number of bytes of IL processed without clean stack state.
3227 // It allows to limit the maximum tree size and depth.
3228 static const unsigned MAX_TREE_SIZE = 200;
3229 bool impCanSpillNow(OPCODE prevOpcode);
3235 SavedStack pdSavedStack;
3236 ThisInitState pdThisPtrInit;
3239 PendingDsc* impPendingList; // list of BBs currently waiting to be imported.
3240 PendingDsc* impPendingFree; // Freed up dscs that can be reused
3242 // We keep a byte-per-block map (dynamically extended) in the top-level Compiler object of a compilation.
3243 JitExpandArray<BYTE> impPendingBlockMembers;
3245 // Return the byte for "b" (allocating/extending impPendingBlockMembers if necessary.)
3246 // Operates on the map in the top-level ancestor.
3247 BYTE impGetPendingBlockMember(BasicBlock* blk)
3249 return impInlineRoot()->impPendingBlockMembers.Get(blk->bbInd());
3252 // Set the byte for "b" to "val" (allocating/extending impPendingBlockMembers if necessary.)
3253 // Operates on the map in the top-level ancestor.
3254 void impSetPendingBlockMember(BasicBlock* blk, BYTE val)
3256 impInlineRoot()->impPendingBlockMembers.Set(blk->bbInd(), val);
3259 bool impCanReimport;
3261 bool impSpillStackEntry(unsigned level,
3265 bool bAssertOnRecursion,
3270 void impSpillStackEnsure(bool spillLeaves = false);
3271 void impEvalSideEffects();
3272 void impSpillSpecialSideEff();
3273 void impSpillSideEffects(bool spillGlobEffects, unsigned chkLevel DEBUGARG(const char* reason));
3274 void impSpillValueClasses();
3275 void impSpillEvalStack();
3276 static fgWalkPreFn impFindValueClasses;
3277 void impSpillLclRefs(ssize_t lclNum);
3279 BasicBlock* impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_HANDLE clsHnd, bool isSingleBlockFilter);
3281 void impImportBlockCode(BasicBlock* block);
3283 void impReimportMarkBlock(BasicBlock* block);
3284 void impReimportMarkSuccessors(BasicBlock* block);
3286 void impVerifyEHBlock(BasicBlock* block, bool isTryStart);
3288 void impImportBlockPending(BasicBlock* block);
3290 // Similar to impImportBlockPending, but assumes that block has already been imported once and is being
3291 // reimported for some reason. It specifically does *not* look at verCurrentState to set the EntryState
3292 // for the block, but instead, just re-uses the block's existing EntryState.
3293 void impReimportBlockPending(BasicBlock* block);
3295 var_types impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTreePtr* pOp1, GenTreePtr* pOp2);
3297 void impImportBlock(BasicBlock* block);
3299 // Assumes that "block" is a basic block that completes with a non-empty stack. We will assign the values
3300 // on the stack to local variables (the "spill temp" variables). The successor blocks will assume that
3301 // its incoming stack contents are in those locals. This requires "block" and its successors to agree on
3302 // the variables that will be used -- and for all the predecessors of those successors, and the
3303 // successors of those predecessors, etc. Call such a set of blocks closed under alternating
3304 // successor/predecessor edges a "spill clique." A block is a "predecessor" or "successor" member of the
3305 // clique (or, conceivably, both). Each block has a specified sequence of incoming and outgoing spill
3306 // temps. If "block" already has its outgoing spill temps assigned (they are always a contiguous series
3307 // of local variable numbers, so we represent them with the base local variable number), returns that.
3308 // Otherwise, picks a set of spill temps, and propagates this choice to all blocks in the spill clique of
3309 // which "block" is a member (asserting, in debug mode, that no block in this clique had its spill temps
3310 // chosen already. More precisely, that the incoming or outgoing spill temps are not chosen, depending
3311 // on which kind of member of the clique the block is).
3312 unsigned impGetSpillTmpBase(BasicBlock* block);
3314 // Assumes that "block" is a basic block that completes with a non-empty stack. We have previously
3315 // assigned the values on the stack to local variables (the "spill temp" variables). The successor blocks
3316 // will assume that its incoming stack contents are in those locals. This requires "block" and its
3317 // successors to agree on the variables and their types that will be used. The CLI spec allows implicit
3318 // conversions between 'int' and 'native int' or 'float' and 'double' stack types. So one predecessor can
3319 // push an int and another can push a native int. For 64-bit we have chosen to implement this by typing
3320 // the "spill temp" as native int, and then importing (or re-importing as needed) so that all the
3321 // predecessors in the "spill clique" push a native int (sign-extending if needed), and all the
3322 // successors receive a native int. Similarly float and double are unified to double.
3323 // This routine is called after a type-mismatch is detected, and it will walk the spill clique to mark
3324 // blocks for re-importation as appropriate (both successors, so they get the right incoming type, and
3325 // predecessors, so they insert an upcast if needed).
3326 void impReimportSpillClique(BasicBlock* block);
3328 // When we compute a "spill clique" (see above) these byte-maps are allocated to have a byte per basic
3329 // block, and represent the predecessor and successor members of the clique currently being computed.
3330 // *** Access to these will need to be locked in a parallel compiler.
3331 JitExpandArray<BYTE> impSpillCliquePredMembers;
3332 JitExpandArray<BYTE> impSpillCliqueSuccMembers;
3340 // Abstract class for receiving a callback while walking a spill clique
3341 class SpillCliqueWalker
3344 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk) = 0;
3347 // This class is used for setting the bbStkTempsIn and bbStkTempsOut on the blocks within a spill clique
3348 class SetSpillTempsBase : public SpillCliqueWalker
3353 SetSpillTempsBase(unsigned baseTmp) : m_baseTmp(baseTmp)
3356 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3359 // This class is used for implementing impReimportSpillClique part on each block within the spill clique
3360 class ReimportSpillClique : public SpillCliqueWalker
3365 ReimportSpillClique(Compiler* pComp) : m_pComp(pComp)
3368 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3371 // This is the heart of the algorithm for walking spill cliques. It invokes callback->Visit for each
3372 // predecessor or successor within the spill clique
3373 void impWalkSpillCliqueFromPred(BasicBlock* pred, SpillCliqueWalker* callback);
3375 // For a BasicBlock that has already been imported, the EntryState has an array of GenTrees for the
3376 // incoming locals. This walks that list an resets the types of the GenTrees to match the types of
3377 // the VarDscs. They get out of sync when we have int/native int issues (see impReimportSpillClique).
3378 void impRetypeEntryStateTemps(BasicBlock* blk);
3380 BYTE impSpillCliqueGetMember(SpillCliqueDir predOrSucc, BasicBlock* blk);
3381 void impSpillCliqueSetMember(SpillCliqueDir predOrSucc, BasicBlock* blk, BYTE val);
3383 void impPushVar(GenTree* op, typeInfo tiRetVal);
3384 void impLoadVar(unsigned lclNum, IL_OFFSET offset, typeInfo tiRetVal);
3385 void impLoadVar(unsigned lclNum, IL_OFFSET offset)
3387 impLoadVar(lclNum, offset, lvaTable[lclNum].lvVerTypeInfo);
3389 void impLoadArg(unsigned ilArgNum, IL_OFFSET offset);
3390 void impLoadLoc(unsigned ilLclNum, IL_OFFSET offset);
3391 bool impReturnInstruction(BasicBlock* block, int prefixFlags, OPCODE& opcode);
3394 void impMarkLclDstNotPromotable(unsigned tmpNum, GenTreePtr op, CORINFO_CLASS_HANDLE hClass);
3397 // A free list of linked list nodes used to represent to-do stacks of basic blocks.
3398 struct BlockListNode
3401 BlockListNode* m_next;
3402 BlockListNode(BasicBlock* blk, BlockListNode* next = nullptr) : m_blk(blk), m_next(next)
3405 void* operator new(size_t sz, Compiler* comp);
3407 BlockListNode* impBlockListNodeFreeList;
3409 BlockListNode* AllocBlockListNode();
3410 void FreeBlockListNode(BlockListNode* node);
3412 bool impIsValueType(typeInfo* pTypeInfo);
3413 var_types mangleVarArgsType(var_types type);
3416 regNumber getCallArgIntRegister(regNumber floatReg);
3417 regNumber getCallArgFloatRegister(regNumber intReg);
3418 #endif // FEATURE_VARARG
3421 static unsigned jitTotalMethodCompiled;
3425 static LONG jitNestingLevel;
3428 static BOOL impIsAddressInLocal(GenTreePtr tree, GenTreePtr* lclVarTreeOut);
3430 void impMakeDiscretionaryInlineObservations(InlineInfo* pInlineInfo, InlineResult* inlineResult);
3432 // STATIC inlining decision based on the IL code.
3433 void impCanInlineIL(CORINFO_METHOD_HANDLE fncHandle,
3434 CORINFO_METHOD_INFO* methInfo,
3436 InlineResult* inlineResult);
3438 void impCheckCanInline(GenTreePtr call,
3439 CORINFO_METHOD_HANDLE fncHandle,
3441 CORINFO_CONTEXT_HANDLE exactContextHnd,
3442 InlineCandidateInfo** ppInlineCandidateInfo,
3443 InlineResult* inlineResult);
3445 void impInlineRecordArgInfo(InlineInfo* pInlineInfo,
3446 GenTreePtr curArgVal,
3448 InlineResult* inlineResult);
3450 void impInlineInitVars(InlineInfo* pInlineInfo);
3452 unsigned impInlineFetchLocal(unsigned lclNum DEBUGARG(const char* reason));
3454 GenTreePtr impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, InlLclVarInfo* lclTypeInfo);
3456 BOOL impInlineIsThis(GenTreePtr tree, InlArgInfo* inlArgInfo);
3458 BOOL impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTreePtr additionalTreesToBeEvaluatedBefore,
3459 GenTreePtr variableBeingDereferenced,
3460 InlArgInfo* inlArgInfo);
3462 void impMarkInlineCandidate(GenTreePtr call,
3463 CORINFO_CONTEXT_HANDLE exactContextHnd,
3464 bool exactContextNeedsRuntimeLookup,
3465 CORINFO_CALL_INFO* callInfo);
3467 bool impTailCallRetTypeCompatible(var_types callerRetType,
3468 CORINFO_CLASS_HANDLE callerRetTypeClass,
3469 var_types calleeRetType,
3470 CORINFO_CLASS_HANDLE calleeRetTypeClass);
3472 bool impIsTailCallILPattern(bool tailPrefixed,
3474 const BYTE* codeAddrOfNextOpcode,
3475 const BYTE* codeEnd,
3477 bool* IsCallPopRet = nullptr);
3479 bool impIsImplicitTailCallCandidate(
3480 OPCODE curOpcode, const BYTE* codeAddrOfNextOpcode, const BYTE* codeEnd, int prefixFlags, bool isRecursive);
3482 CORINFO_RESOLVED_TOKEN* impAllocateToken(CORINFO_RESOLVED_TOKEN token);
3485 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3486 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3490 XX Info about the basic-blocks, their contents and the flow analysis XX
3492 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3493 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3497 BasicBlock* fgFirstBB; // Beginning of the basic block list
3498 BasicBlock* fgLastBB; // End of the basic block list
3499 BasicBlock* fgFirstColdBlock; // First block to be placed in the cold section
3500 #if FEATURE_EH_FUNCLETS
3501 BasicBlock* fgFirstFuncletBB; // First block of outlined funclets (to allow block insertion before the funclets)
3503 BasicBlock* fgFirstBBScratch; // Block inserted for initialization stuff. Is nullptr if no such block has been
3505 BasicBlockList* fgReturnBlocks; // list of BBJ_RETURN blocks
3506 unsigned fgEdgeCount; // # of control flow edges between the BBs
3507 unsigned fgBBcount; // # of BBs in the method
3509 unsigned fgBBcountAtCodegen; // # of BBs in the method at the start of codegen
3511 unsigned fgBBNumMax; // The max bbNum that has been assigned to basic blocks
3512 unsigned fgDomBBcount; // # of BBs for which we have dominator and reachability information
3513 BasicBlock** fgBBInvPostOrder; // The flow graph stored in an array sorted in topological order, needed to compute
3514 // dominance. Indexed by block number. Size: fgBBNumMax + 1.
3516 // After the dominance tree is computed, we cache a DFS preorder number and DFS postorder number to compute
3517 // dominance queries in O(1). fgDomTreePreOrder and fgDomTreePostOrder are arrays giving the block's preorder and
3518 // postorder number, respectively. The arrays are indexed by basic block number. (Note that blocks are numbered
3519 // starting from one. Thus, we always waste element zero. This makes debugging easier and makes the code less likely
3520 // to suffer from bugs stemming from forgetting to add or subtract one from the block number to form an array
3521 // index). The arrays are of size fgBBNumMax + 1.
3522 unsigned* fgDomTreePreOrder;
3523 unsigned* fgDomTreePostOrder;
3525 bool fgBBVarSetsInited;
3527 // Allocate array like T* a = new T[fgBBNumMax + 1];
3528 // Using helper so we don't keep forgetting +1.
3529 template <typename T>
3530 T* fgAllocateTypeForEachBlk(CompMemKind cmk = CMK_Unknown)
3532 return (T*)compGetMem((fgBBNumMax + 1) * sizeof(T), cmk);
3535 // BlockSets are relative to a specific set of BasicBlock numbers. If that changes
3536 // (if the blocks are renumbered), this changes. BlockSets from different epochs
3537 // cannot be meaningfully combined. Note that new blocks can be created with higher
3538 // block numbers without changing the basic block epoch. These blocks *cannot*
3539 // participate in a block set until the blocks are all renumbered, causing the epoch
3540 // to change. This is useful if continuing to use previous block sets is valuable.
3541 // If the epoch is zero, then it is uninitialized, and block sets can't be used.
3542 unsigned fgCurBBEpoch;
3544 unsigned GetCurBasicBlockEpoch()
3546 return fgCurBBEpoch;
3549 // The number of basic blocks in the current epoch. When the blocks are renumbered,
3550 // this is fgBBcount. As blocks are added, fgBBcount increases, fgCurBBEpochSize remains
3551 // the same, until a new BasicBlock epoch is created, such as when the blocks are all renumbered.
3552 unsigned fgCurBBEpochSize;
3554 // The number of "size_t" elements required to hold a bitset large enough for fgCurBBEpochSize
3555 // bits. This is precomputed to avoid doing math every time BasicBlockBitSetTraits::GetArrSize() is called.
3556 unsigned fgBBSetCountInSizeTUnits;
3558 void NewBasicBlockEpoch()
3560 INDEBUG(unsigned oldEpochArrSize = fgBBSetCountInSizeTUnits);
3562 // We have a new epoch. Compute and cache the size needed for new BlockSets.
3564 fgCurBBEpochSize = fgBBNumMax + 1;
3565 fgBBSetCountInSizeTUnits =
3566 unsigned(roundUp(fgCurBBEpochSize, sizeof(size_t) * 8)) / unsigned(sizeof(size_t) * 8);
3569 // All BlockSet objects are now invalid!
3570 fgReachabilitySetsValid = false; // the bbReach sets are now invalid!
3571 fgEnterBlksSetValid = false; // the fgEnterBlks set is now invalid!
3575 unsigned epochArrSize = BasicBlockBitSetTraits::GetArrSize(this, sizeof(size_t));
3576 printf("\nNew BlockSet epoch %d, # of blocks (including unused BB00): %u, bitset array size: %u (%s)",
3577 fgCurBBEpoch, fgCurBBEpochSize, epochArrSize, (epochArrSize <= 1) ? "short" : "long");
3578 if ((fgCurBBEpoch != 1) && ((oldEpochArrSize <= 1) != (epochArrSize <= 1)))
3580 // If we're not just establishing the first epoch, and the epoch array size has changed such that we're
3581 // going to change our bitset representation from short (just a size_t bitset) to long (a pointer to an
3582 // array of size_t bitsets), then print that out.
3583 printf("; NOTE: BlockSet size was previously %s!", (oldEpochArrSize <= 1) ? "short" : "long");
3590 void EnsureBasicBlockEpoch()
3592 if (fgCurBBEpochSize != fgBBNumMax + 1)
3594 NewBasicBlockEpoch();
3598 BasicBlock* fgNewBasicBlock(BBjumpKinds jumpKind);
3599 void fgEnsureFirstBBisScratch();
3600 bool fgFirstBBisScratch();
3601 bool fgBBisScratch(BasicBlock* block);
3603 void fgExtendEHRegionBefore(BasicBlock* block);
3604 void fgExtendEHRegionAfter(BasicBlock* block);
3606 BasicBlock* fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
3608 BasicBlock* fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
3610 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
3613 BasicBlock* nearBlk,
3614 bool putInFilter = false,
3615 bool runRarely = false,
3616 bool insertAtEnd = false);
3618 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
3620 bool runRarely = false,
3621 bool insertAtEnd = false);
3623 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind);
3625 BasicBlock* fgNewBBinRegionWorker(BBjumpKinds jumpKind,
3626 BasicBlock* afterBlk,
3627 unsigned xcptnIndex,
3628 bool putInTryRegion);
3630 void fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk);
3631 void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk);
3632 void fgUnlinkBlock(BasicBlock* block);
3634 unsigned fgMeasureIR();
3636 #if OPT_BOOL_OPS // Used to detect multiple logical "not" assignments.
3637 bool fgMultipleNots;
3640 bool fgModified; // True if the flow graph has been modified recently
3641 bool fgComputePredsDone; // Have we computed the bbPreds list
3642 bool fgCheapPredsValid; // Is the bbCheapPreds list valid?
3643 bool fgDomsComputed; // Have we computed the dominator sets?
3644 bool fgOptimizedFinally; // Did we optimize any try-finallys?
3646 bool fgHasSwitch; // any BBJ_SWITCH jumps?
3647 bool fgHasPostfix; // any postfix ++/-- found?
3648 unsigned fgIncrCount; // number of increment nodes found
3650 BlockSet fgEnterBlks; // Set of blocks which have a special transfer of control; the "entry" blocks plus EH handler
3654 bool fgReachabilitySetsValid; // Are the bbReach sets valid?
3655 bool fgEnterBlksSetValid; // Is the fgEnterBlks set valid?
3658 bool fgRemoveRestOfBlock; // true if we know that we will throw
3659 bool fgStmtRemoved; // true if we remove statements -> need new DFA
3661 // There are two modes for ordering of the trees.
3662 // - In FGOrderTree, the dominant ordering is the tree order, and the nodes contained in
3663 // each tree and sub-tree are contiguous, and can be traversed (in gtNext/gtPrev order)
3664 // by traversing the tree according to the order of the operands.
3665 // - In FGOrderLinear, the dominant ordering is the linear order.
3672 FlowGraphOrder fgOrder;
3674 // The following are boolean flags that keep track of the state of internal data structures
3676 bool fgStmtListThreaded; // true if the node list is now threaded
3677 bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
3678 bool fgEdgeWeightsComputed; // true after we have called fgComputeEdgeWeights
3679 bool fgHaveValidEdgeWeights; // true if we were successful in computing all of the edge weights
3680 bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
3681 bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
3682 bool fgNeedsUpdateFlowGraph; // true if we need to run fgUpdateFlowGraph
3683 BasicBlock::weight_t fgCalledCount; // count of the number of times this method was called
3684 // This is derived from the profile data
3685 // or is BB_UNITY_WEIGHT when we don't have profile data
3687 #if FEATURE_EH_FUNCLETS
3688 bool fgFuncletsCreated; // true if the funclet creation phase has been run
3689 #endif // FEATURE_EH_FUNCLETS
3691 bool fgGlobalMorph; // indicates if we are during the global morphing phase
3692 // since fgMorphTree can be called from several places
3694 bool impBoxTempInUse; // the temp below is valid and available
3695 unsigned impBoxTemp; // a temporary that is used for boxing
3698 bool jitFallbackCompile; // Are we doing a fallback compile? That is, have we executed a NO_WAY assert,
3699 // and we are trying to compile again in a "safer", minopts mode?
3703 unsigned impInlinedCodeSize;
3706 //-------------------------------------------------------------------------
3712 void fgTransformFatCalli();
3716 void fgRemoveEmptyTry();
3718 void fgRemoveEmptyFinally();
3720 void fgMergeFinallyChains();
3722 void fgCloneFinally();
3724 void fgCleanupContinuation(BasicBlock* continuation);
3726 void fgUpdateFinallyTargetFlags();
3728 void fgClearAllFinallyTargetBits();
3730 void fgAddFinallyTargetFlags();
3732 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
3733 // Sometimes we need to defer updating the BBF_FINALLY_TARGET bit. fgNeedToAddFinallyTargetBits signals
3734 // when this is necessary.
3735 bool fgNeedToAddFinallyTargetBits;
3736 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
3738 bool fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block,
3739 BasicBlock* handler,
3740 BlockToBlockMap& continuationMap);
3742 GenTreePtr fgGetCritSectOfStaticMethod();
3744 #if FEATURE_EH_FUNCLETS
3746 void fgAddSyncMethodEnterExit();
3748 GenTree* fgCreateMonitorTree(unsigned lvaMonitorBool, unsigned lvaThisVar, BasicBlock* block, bool enter);
3750 void fgConvertSyncReturnToLeave(BasicBlock* block);
3752 #endif // FEATURE_EH_FUNCLETS
3754 void fgAddReversePInvokeEnterExit();
3756 bool fgMoreThanOneReturnBlock();
3758 // The number of separate return points in the method.
3759 unsigned fgReturnCount;
3761 void fgAddInternal();
3763 bool fgFoldConditional(BasicBlock* block);
3765 #ifdef LEGACY_BACKEND
3766 void fgMorphStmts(BasicBlock* block, bool* mult, bool* lnot, bool* loadw);
3768 void fgMorphStmts(BasicBlock* block, bool* lnot, bool* loadw);
3770 void fgMorphBlocks();
3772 bool fgMorphBlockStmt(BasicBlock* block, GenTreeStmt* stmt DEBUGARG(const char* msg));
3774 void fgCheckArgCnt();
3775 void fgSetOptions();
3778 static fgWalkPreFn fgAssertNoQmark;
3779 void fgPreExpandQmarkChecks(GenTreePtr expr);
3780 void fgPostExpandQmarkChecks();
3781 static void fgCheckQmarkAllowedForm(GenTreePtr tree);
3784 IL_OFFSET fgFindBlockILOffset(BasicBlock* block);
3786 BasicBlock* fgSplitBlockAtBeginning(BasicBlock* curr);
3787 BasicBlock* fgSplitBlockAtEnd(BasicBlock* curr);
3788 BasicBlock* fgSplitBlockAfterStatement(BasicBlock* curr, GenTree* stmt);
3789 BasicBlock* fgSplitBlockAfterNode(BasicBlock* curr, GenTree* node); // for LIR
3790 BasicBlock* fgSplitEdge(BasicBlock* curr, BasicBlock* succ);
3792 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree, BasicBlock* block, IL_OFFSETX offs);
3793 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree);
3794 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree, BasicBlock* block);
3795 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree, IL_OFFSETX offs);
3797 GenTreePtr fgGetTopLevelQmark(GenTreePtr expr, GenTreePtr* ppDst = nullptr);
3798 void fgExpandQmarkForCastInstOf(BasicBlock* block, GenTreePtr stmt);
3799 void fgExpandQmarkStmt(BasicBlock* block, GenTreePtr expr);
3800 void fgExpandQmarkNodes();
3804 // Do "simple lowering." This functionality is (conceptually) part of "general"
3805 // lowering that is distributed between fgMorph and the lowering phase of LSRA.
3806 void fgSimpleLowering();
3808 #ifdef LEGACY_BACKEND
3809 bool fgShouldCreateAssignOp(GenTreePtr tree, bool* bReverse);
3812 GenTreePtr fgInitThisClass();
3814 GenTreeCall* fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper);
3816 GenTreeCall* fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls);
3818 inline bool backendRequiresLocalVarLifetimes()
3820 #if defined(LEGACY_BACKEND)
3823 return !opts.MinOpts() || m_pLinearScan->willEnregisterLocalVars();
3827 void fgLocalVarLiveness();
3829 void fgLocalVarLivenessInit();
3831 #ifdef LEGACY_BACKEND
3832 GenTreePtr fgLegacyPerStatementLocalVarLiveness(GenTreePtr startNode, GenTreePtr relopNode);
3834 void fgPerNodeLocalVarLiveness(GenTree* node);
3836 void fgPerBlockLocalVarLiveness();
3838 VARSET_VALRET_TP fgGetHandlerLiveVars(BasicBlock* block);
3840 void fgLiveVarAnalysis(bool updateInternalOnly = false);
3842 // This is used in the liveness computation, as a temporary. When we use the
3843 // arbitrary-length VarSet representation, it is better not to allocate a new one
3845 VARSET_TP fgMarkIntfUnionVS;
3847 bool fgMarkIntf(VARSET_VALARG_TP varSet);
3849 bool fgMarkIntf(VARSET_VALARG_TP varSet1, VARSET_VALARG_TP varSet2);
3851 bool fgMarkIntf(VARSET_VALARG_TP varSet1, unsigned varIndex);
3853 void fgUpdateRefCntForClone(BasicBlock* addedToBlock, GenTreePtr clonedTree);
3855 void fgUpdateRefCntForExtract(GenTreePtr wholeTree, GenTreePtr keptTree);
3857 void fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call);
3859 void fgComputeLifeTrackedLocalUse(VARSET_TP& life, LclVarDsc& varDsc, GenTreeLclVarCommon* node);
3860 bool fgComputeLifeTrackedLocalDef(VARSET_TP& life,
3861 VARSET_VALARG_TP keepAliveVars,
3863 GenTreeLclVarCommon* node);
3864 void fgComputeLifeUntrackedLocal(VARSET_TP& life,
3865 VARSET_VALARG_TP keepAliveVars,
3867 GenTreeLclVarCommon* lclVarNode,
3869 bool fgComputeLifeLocal(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTree* lclVarNode, GenTree* node);
3871 void fgComputeLife(VARSET_TP& life,
3872 GenTreePtr startNode,
3874 VARSET_VALARG_TP volatileVars,
3875 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
3877 void fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALARG_TP volatileVars);
3879 bool fgRemoveDeadStore(GenTree** pTree,
3881 VARSET_VALARG_TP life,
3883 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
3885 // For updating liveset during traversal AFTER fgComputeLife has completed
3886 VARSET_VALRET_TP fgGetVarBits(GenTreePtr tree);
3887 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTreePtr tree);
3889 // Returns the set of live variables after endTree,
3890 // assuming that liveSet is the set of live variables BEFORE tree.
3891 // Requires that fgComputeLife has completed, and that tree is in the same
3892 // statement as endTree, and that it comes before endTree in execution order
3894 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTreePtr tree, GenTreePtr endTree)
3896 VARSET_TP newLiveSet(VarSetOps::MakeCopy(this, liveSet));
3897 while (tree != nullptr && tree != endTree->gtNext)
3899 VarSetOps::AssignNoCopy(this, newLiveSet, fgUpdateLiveSet(newLiveSet, tree));
3900 tree = tree->gtNext;
3902 assert(tree == endTree->gtNext);
3906 void fgInterBlockLocalVarLiveness();
3908 // The presence of "x op= y" operations presents some difficulties for SSA: this is both a use of some SSA name of
3909 // "x", and a def of a new SSA name for "x". The tree only has one local variable for "x", so it has to choose
3910 // whether to treat that as the use or def. It chooses the "use", and thus the old SSA name. This map allows us
3911 // to record/recover the "def" SSA number, given the lcl var node for "x" in such a tree.
3912 typedef JitHashTable<GenTreePtr, JitPtrKeyFuncs<GenTree>, unsigned> NodeToUnsignedMap;
3913 NodeToUnsignedMap* m_opAsgnVarDefSsaNums;
3914 NodeToUnsignedMap* GetOpAsgnVarDefSsaNums()
3916 if (m_opAsgnVarDefSsaNums == nullptr)
3918 m_opAsgnVarDefSsaNums = new (getAllocator()) NodeToUnsignedMap(getAllocator());
3920 return m_opAsgnVarDefSsaNums;
3923 // Requires value numbering phase to have completed. Returns the value number ("gtVN") of the
3924 // "tree," EXCEPT in the case of GTF_VAR_USEASG, because the tree node's gtVN member is the
3925 // "use" VN. Performs a lookup into the map of (use asg tree -> def VN.) to return the "def's"
3927 inline ValueNum GetUseAsgDefVNOrTreeVN(GenTreePtr tree);
3929 // Requires that "lcl" has the GTF_VAR_DEF flag set. Returns the SSA number of "lcl".
3930 // Except: assumes that lcl is a def, and if it is
3931 // a def appearing in "lcl op= rhs" (GTF_VAR_USEASG), looks up and returns the SSA number for the "def",
3932 // rather than the "use" SSA number recorded in the tree "lcl".
3933 inline unsigned GetSsaNumForLocalVarDef(GenTreePtr lcl);
3935 // Some assignments assign to a local "indirectly": they are part of a comma expression that takes the address
3936 // of the local (or a field thereof), assigns this address to a temp, and uses an indirection of this temp as
3937 // the LHS of the assignment. This actually arises in exactly one situation. At the source level we assign one
3938 // struct local to another: "s1 = s2". This becomes a copyblk. If "s2" is promoted into field variables "s2f0",
3939 // ..."s2fn", then the copyblk will morph to a comma expression that takes the address of "s1" and does field-wise
3941 // (byref addrS1 = &s1,
3942 // *(addrS1 * offsetof(f0)) = s2f0,
3944 // *(addrS1 * offsetof(fn)) = s2fn)
3946 // It would be a shame, given the simple form at the source level, to be unable to track the values in the
3947 // fields of "s1" after this. But "s1" does not appear in the assignments that modify it. How, then, to
3948 // give it SSA names and value numbers?
3950 // The solution is to use the side table described below to annotate each of the field-wise assignments at the
3951 // end with an instance of the structure below, whose fields are described in the declaration.
3952 struct IndirectAssignmentAnnotation
3954 unsigned m_lclNum; // The local num that is being indirectly assigned.
3955 FieldSeqNode* m_fieldSeq; // If the LHS of the struct assignment is itself a struct field dereference,
3956 // as in "s0.g = s2", then "m_lclNum" would be "s0", and "m_fieldSeq" would
3957 // be the singleton field sequence "g". The individual assignments would
3958 // further append the fields of "s.g" to that.
3959 bool m_isEntire; // True iff this assignment writes all of m_lclNum. (This can occur if the
3960 // structure has a single field).
3961 unsigned m_defSsaNum; // The new SSA number of "m_lclNum" after the assignment.
3962 unsigned m_useSsaNum; // Only valid if "m_isEntire" is false; if so, the SSA number of "m_lclNum" before the
3965 IndirectAssignmentAnnotation(unsigned lclNum,
3966 FieldSeqNode* fldSeq,
3968 unsigned defSsaNum = SsaConfig::RESERVED_SSA_NUM,
3969 unsigned useSsaNum = SsaConfig::RESERVED_SSA_NUM)
3970 : m_lclNum(lclNum), m_fieldSeq(fldSeq), m_isEntire(isEntire), m_defSsaNum(defSsaNum), m_useSsaNum(useSsaNum)
3974 typedef JitHashTable<GenTreePtr, JitPtrKeyFuncs<GenTree>, IndirectAssignmentAnnotation*> NodeToIndirAssignMap;
3975 NodeToIndirAssignMap* m_indirAssignMap;
3976 NodeToIndirAssignMap* GetIndirAssignMap()
3978 if (m_indirAssignMap == nullptr)
3980 // Create a CompAllocator that labels sub-structure with CMK_IndirAssignMap, and use that for allocation.
3981 CompAllocator* ialloc = new (this, CMK_IndirAssignMap) CompAllocator(this, CMK_IndirAssignMap);
3982 m_indirAssignMap = new (ialloc) NodeToIndirAssignMap(ialloc);
3984 return m_indirAssignMap;
3987 // Performs SSA conversion.
3990 // Reset any data structures to the state expected by "fgSsaBuild", so it can be run again.
3991 void fgResetForSsa();
3993 unsigned fgSsaPassesCompleted; // Number of times fgSsaBuild has been run.
3995 // Returns "true" iff lcl "lclNum" should be excluded from SSA.
3996 inline bool fgExcludeFromSsa(unsigned lclNum);
3998 // Returns "true" if a struct temp of the given type requires needs zero init in this block
3999 inline bool fgStructTempNeedsExplicitZeroInit(LclVarDsc* varDsc, BasicBlock* block);
4001 // The value numbers for this compilation.
4002 ValueNumStore* vnStore;
4005 ValueNumStore* GetValueNumStore()
4010 // Do value numbering (assign a value number to each
4012 void fgValueNumber();
4014 // Computes new GcHeap VN via the assignment H[elemTypeEq][arrVN][inx][fldSeq] = rhsVN.
4015 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
4016 // The 'indType' is the indirection type of the lhs of the assignment and will typically
4017 // match the element type of the array or fldSeq. When this type doesn't match
4018 // or if the fldSeq is 'NotAField' we invalidate the array contents H[elemTypeEq][arrVN]
4020 ValueNum fgValueNumberArrIndexAssign(CORINFO_CLASS_HANDLE elemTypeEq,
4023 FieldSeqNode* fldSeq,
4027 // Requires that "tree" is a GT_IND marked as an array index, and that its address argument
4028 // has been parsed to yield the other input arguments. If evaluation of the address
4029 // can raise exceptions, those should be captured in the exception set "excVN."
4030 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
4031 // Marks "tree" with the VN for H[elemTypeEq][arrVN][inx][fldSeq] (for the liberal VN; a new unique
4032 // VN for the conservative VN.) Also marks the tree's argument as the address of an array element.
4033 // The type tree->TypeGet() will typically match the element type of the array or fldSeq.
4034 // When this type doesn't match or if the fldSeq is 'NotAField' we return a new unique VN
4036 ValueNum fgValueNumberArrIndexVal(GenTreePtr tree,
4037 CORINFO_CLASS_HANDLE elemTypeEq,
4041 FieldSeqNode* fldSeq);
4043 // Requires "funcApp" to be a VNF_PtrToArrElem, and "addrXvn" to represent the exception set thrown
4044 // by evaluating the array index expression "tree". Returns the value number resulting from
4045 // dereferencing the array in the current GcHeap state. If "tree" is non-null, it must be the
4046 // "GT_IND" that does the dereference, and it is given the returned value number.
4047 ValueNum fgValueNumberArrIndexVal(GenTreePtr tree, struct VNFuncApp* funcApp, ValueNum addrXvn);
4049 // Compute the value number for a byref-exposed load of the given type via the given pointerVN.
4050 ValueNum fgValueNumberByrefExposedLoad(var_types type, ValueNum pointerVN);
4052 unsigned fgVNPassesCompleted; // Number of times fgValueNumber has been run.
4054 // Utility functions for fgValueNumber.
4056 // Perform value-numbering for the trees in "blk".
4057 void fgValueNumberBlock(BasicBlock* blk);
4059 // Requires that "entryBlock" is the entry block of loop "loopNum", and that "loopNum" is the
4060 // innermost loop of which "entryBlock" is the entry. Returns the value number that should be
4061 // assumed for the memoryKind at the start "entryBlk".
4062 ValueNum fgMemoryVNForLoopSideEffects(MemoryKind memoryKind, BasicBlock* entryBlock, unsigned loopNum);
4064 // Called when an operation (performed by "tree", described by "msg") may cause the GcHeap to be mutated.
4065 // As GcHeap is a subset of ByrefExposed, this will also annotate the ByrefExposed mutation.
4066 void fgMutateGcHeap(GenTreePtr tree DEBUGARG(const char* msg));
4068 // Called when an operation (performed by "tree", described by "msg") may cause an address-exposed local to be
4070 void fgMutateAddressExposedLocal(GenTreePtr tree DEBUGARG(const char* msg));
4072 // For a GC heap store at curTree, record the new curMemoryVN's and update curTree's MemorySsaMap.
4073 // As GcHeap is a subset of ByrefExposed, this will also record the ByrefExposed store.
4074 void recordGcHeapStore(GenTreePtr curTree, ValueNum gcHeapVN DEBUGARG(const char* msg));
4076 // For a store to an address-exposed local at curTree, record the new curMemoryVN and update curTree's MemorySsaMap.
4077 void recordAddressExposedLocalStore(GenTreePtr curTree, ValueNum memoryVN DEBUGARG(const char* msg));
4079 // Tree caused an update in the current memory VN. If "tree" has an associated heap SSA #, record that
4080 // value in that SSA #.
4081 void fgValueNumberRecordMemorySsa(MemoryKind memoryKind, GenTreePtr tree);
4083 // The input 'tree' is a leaf node that is a constant
4084 // Assign the proper value number to the tree
4085 void fgValueNumberTreeConst(GenTreePtr tree);
4087 // Assumes that all inputs to "tree" have had value numbers assigned; assigns a VN to tree.
4088 // (With some exceptions: the VN of the lhs of an assignment is assigned as part of the
4090 // If "evalAsgLhsInd" is true, evaluate a GT_IND node, even if it's labeled as the LHS of
4092 void fgValueNumberTree(GenTreePtr tree, bool evalAsgLhsInd = false);
4094 // Does value-numbering for a block assignment.
4095 void fgValueNumberBlockAssignment(GenTreePtr tree, bool evalAsgLhsInd);
4097 // Does value-numbering for a cast tree.
4098 void fgValueNumberCastTree(GenTreePtr tree);
4100 // Does value-numbering for an intrinsic tree.
4101 void fgValueNumberIntrinsic(GenTreePtr tree);
4103 // Does value-numbering for a call. We interpret some helper calls.
4104 void fgValueNumberCall(GenTreeCall* call);
4106 // The VN of some nodes in "args" may have changed -- reassign VNs to the arg list nodes.
4107 void fgUpdateArgListVNs(GenTreeArgList* args);
4109 // Does value-numbering for a helper "call" that has a VN function symbol "vnf".
4110 void fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc);
4112 // Requires "helpCall" to be a helper call. Assigns it a value number;
4113 // we understand the semantics of some of the calls. Returns "true" if
4114 // the call may modify the heap (we assume arbitrary memory side effects if so).
4115 bool fgValueNumberHelperCall(GenTreeCall* helpCall);
4117 // Requires "helpFunc" to be pure. Returns the corresponding VNFunc.
4118 VNFunc fgValueNumberHelperMethVNFunc(CorInfoHelpFunc helpFunc);
4120 // These are the current value number for the memory implicit variables while
4121 // doing value numbering. These are the value numbers under the "liberal" interpretation
4122 // of memory values; the "conservative" interpretation needs no VN, since every access of
4123 // memory yields an unknown value.
4124 ValueNum fgCurMemoryVN[MemoryKindCount];
4126 // Return a "pseudo"-class handle for an array element type. If "elemType" is TYP_STRUCT,
4127 // requires "elemStructType" to be non-null (and to have a low-order zero). Otherwise, low order bit
4128 // is 1, and the rest is an encoding of "elemTyp".
4129 static CORINFO_CLASS_HANDLE EncodeElemType(var_types elemTyp, CORINFO_CLASS_HANDLE elemStructType)
4131 if (elemStructType != nullptr)
4133 assert(varTypeIsStruct(elemTyp) || elemTyp == TYP_REF || elemTyp == TYP_BYREF ||
4134 varTypeIsIntegral(elemTyp));
4135 assert((size_t(elemStructType) & 0x1) == 0x0); // Make sure the encoding below is valid.
4136 return elemStructType;
4140 elemTyp = varTypeUnsignedToSigned(elemTyp);
4141 return CORINFO_CLASS_HANDLE(size_t(elemTyp) << 1 | 0x1);
4144 // If "clsHnd" is the result of an "EncodePrim" call, returns true and sets "*pPrimType" to the
4145 // var_types it represents. Otherwise, returns TYP_STRUCT (on the assumption that "clsHnd" is
4146 // the struct type of the element).
4147 static var_types DecodeElemType(CORINFO_CLASS_HANDLE clsHnd)
4149 size_t clsHndVal = size_t(clsHnd);
4150 if (clsHndVal & 0x1)
4152 return var_types(clsHndVal >> 1);
4160 // Convert a BYTE which represents the VM's CorInfoGCtype to the JIT's var_types
4161 var_types getJitGCType(BYTE gcType);
4163 enum structPassingKind
4165 SPK_Unknown, // Invalid value, never returned
4166 SPK_PrimitiveType, // The struct is passed/returned using a primitive type.
4167 SPK_ByValue, // The struct is passed/returned by value (using the ABI rules)
4168 // for ARM64 and UNIX_X64 in multiple registers. (when all of the
4169 // parameters registers are used, then the stack will be used)
4170 // for X86 passed on the stack, for ARM32 passed in registers
4171 // or the stack or split between registers and the stack.
4172 SPK_ByValueAsHfa, // The struct is passed/returned as an HFA in multiple registers.
4174 }; // The struct is passed/returned by reference to a copy/buffer.
4176 // Get the "primitive" type that is is used when we are given a struct of size 'structSize'.
4177 // For pointer sized structs the 'clsHnd' is used to determine if the struct contains GC ref.
4178 // A "primitive" type is one of the scalar types: byte, short, int, long, ref, float, double
4179 // If we can't or shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
4181 var_types getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS_HANDLE clsHnd);
4183 // Get the type that is used to pass values of the given struct type.
4184 // If you have already retrieved the struct size then pass it as the optional third argument
4186 var_types getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4187 structPassingKind* wbPassStruct,
4188 unsigned structSize = 0);
4190 // Get the type that is used to return values of the given struct type.
4191 // If you have already retrieved the struct size then pass it as the optional third argument
4193 var_types getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4194 structPassingKind* wbPassStruct = nullptr,
4195 unsigned structSize = 0);
4198 // Print a representation of "vnp" or "vn" on standard output.
4199 // If "level" is non-zero, we also print out a partial expansion of the value.
4200 void vnpPrint(ValueNumPair vnp, unsigned level);
4201 void vnPrint(ValueNum vn, unsigned level);
4204 bool fgDominate(BasicBlock* b1, BasicBlock* b2); // Return true if b1 dominates b2
4206 // Dominator computation member functions
4207 // Not exposed outside Compiler
4209 bool fgReachable(BasicBlock* b1, BasicBlock* b2); // Returns true if block b1 can reach block b2
4211 void fgComputeDoms(); // Computes the immediate dominators for each basic block in the
4212 // flow graph. We first assume the fields bbIDom on each
4213 // basic block are invalid. This computation is needed later
4214 // by fgBuildDomTree to build the dominance tree structure.
4215 // Based on: A Simple, Fast Dominance Algorithm
4216 // by Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
4218 void fgCompDominatedByExceptionalEntryBlocks();
4220 BlockSet_ValRet_T fgGetDominatorSet(BasicBlock* block); // Returns a set of blocks that dominate the given block.
4221 // Note: this is relatively slow compared to calling fgDominate(),
4222 // especially if dealing with a single block versus block check.
4224 void fgComputeReachabilitySets(); // Compute bbReach sets. (Also sets BBF_GC_SAFE_POINT flag on blocks.)
4226 void fgComputeEnterBlocksSet(); // Compute the set of entry blocks, 'fgEnterBlks'.
4228 bool fgRemoveUnreachableBlocks(); // Remove blocks determined to be unreachable by the bbReach sets.
4230 void fgComputeReachability(); // Perform flow graph node reachability analysis.
4232 BasicBlock* fgIntersectDom(BasicBlock* a, BasicBlock* b); // Intersect two immediate dominator sets.
4234 void fgDfsInvPostOrder(); // In order to compute dominance using fgIntersectDom, the flow graph nodes must be
4235 // processed in topological sort, this function takes care of that.
4237 void fgDfsInvPostOrderHelper(BasicBlock* block, BlockSet& visited, unsigned* count);
4239 BlockSet_ValRet_T fgDomFindStartNodes(); // Computes which basic blocks don't have incoming edges in the flow graph.
4240 // Returns this as a set.
4242 BlockSet_ValRet_T fgDomTreeEntryNodes(BasicBlockList** domTree); // Computes which nodes in the dominance forest are
4243 // root nodes. Returns this as a set.
4246 void fgDispDomTree(BasicBlockList** domTree); // Helper that prints out the Dominator Tree in debug builds.
4249 void fgBuildDomTree(); // Once we compute all the immediate dominator sets for each node in the flow graph
4250 // (performed by fgComputeDoms), this procedure builds the dominance tree represented
4253 // In order to speed up the queries of the form 'Does A dominates B', we can perform a DFS preorder and postorder
4254 // traversal of the dominance tree and the dominance query will become A dominates B iif preOrder(A) <= preOrder(B)
4255 // && postOrder(A) >= postOrder(B) making the computation O(1).
4256 void fgTraverseDomTree(unsigned bbNum, BasicBlockList** domTree, unsigned* preNum, unsigned* postNum);
4258 // When the flow graph changes, we need to update the block numbers, predecessor lists, reachability sets, and
4260 void fgUpdateChangedFlowGraph();
4263 // Compute the predecessors of the blocks in the control flow graph.
4264 void fgComputePreds();
4266 // Remove all predecessor information.
4267 void fgRemovePreds();
4269 // Compute the cheap flow graph predecessors lists. This is used in some early phases
4270 // before the full predecessors lists are computed.
4271 void fgComputeCheapPreds();
4274 void fgAddCheapPred(BasicBlock* block, BasicBlock* blockPred);
4276 void fgRemoveCheapPred(BasicBlock* block, BasicBlock* blockPred);
4286 // Initialize the per-block variable sets (used for liveness analysis).
4287 void fgInitBlockVarSets();
4289 // true if we've gone through and created GC Poll calls.
4290 bool fgGCPollsCreated;
4291 void fgMarkGCPollBlocks();
4292 void fgCreateGCPolls();
4293 bool fgCreateGCPoll(GCPollType pollType, BasicBlock* block);
4295 // Requires that "block" is a block that returns from
4296 // a finally. Returns the number of successors (jump targets of
4297 // of blocks in the covered "try" that did a "LEAVE".)
4298 unsigned fgNSuccsOfFinallyRet(BasicBlock* block);
4300 // Requires that "block" is a block that returns (in the sense of BBJ_EHFINALLYRET) from
4301 // a finally. Returns its "i"th successor (jump targets of
4302 // of blocks in the covered "try" that did a "LEAVE".)
4303 // Requires that "i" < fgNSuccsOfFinallyRet(block).
4304 BasicBlock* fgSuccOfFinallyRet(BasicBlock* block, unsigned i);
4307 // Factor out common portions of the impls of the methods above.
4308 void fgSuccOfFinallyRetWork(BasicBlock* block, unsigned i, BasicBlock** bres, unsigned* nres);
4311 // For many purposes, it is desirable to be able to enumerate the *distinct* targets of a switch statement,
4312 // skipping duplicate targets. (E.g., in flow analyses that are only interested in the set of possible targets.)
4313 // SwitchUniqueSuccSet contains the non-duplicated switch targets.
4314 // (Code that modifies the jump table of a switch has an obligation to call Compiler::UpdateSwitchTableTarget,
4315 // which in turn will call the "UpdateTarget" method of this type if a SwitchUniqueSuccSet has already
4316 // been computed for the switch block. If a switch block is deleted or is transformed into a non-switch,
4317 // we leave the entry associated with the block, but it will no longer be accessed.)
4318 struct SwitchUniqueSuccSet
4320 unsigned numDistinctSuccs; // Number of distinct targets of the switch.
4321 BasicBlock** nonDuplicates; // Array of "numDistinctSuccs", containing all the distinct switch target
4324 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4325 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4326 // remove it from "this", and ensure that "to" is a member. Use "alloc" to do any required allocation.
4327 void UpdateTarget(CompAllocator* alloc, BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4330 typedef JitHashTable<BasicBlock*, JitPtrKeyFuncs<BasicBlock>, SwitchUniqueSuccSet> BlockToSwitchDescMap;
4333 // Maps BasicBlock*'s that end in switch statements to SwitchUniqueSuccSets that allow
4334 // iteration over only the distinct successors.
4335 BlockToSwitchDescMap* m_switchDescMap;
4338 BlockToSwitchDescMap* GetSwitchDescMap(bool createIfNull = true)
4340 if ((m_switchDescMap == nullptr) && createIfNull)
4342 m_switchDescMap = new (getAllocator()) BlockToSwitchDescMap(getAllocator());
4344 return m_switchDescMap;
4347 // Invalidate the map of unique switch block successors. For example, since the hash key of the map
4348 // depends on block numbers, we must invalidate the map when the blocks are renumbered, to ensure that
4349 // we don't accidentally look up and return the wrong switch data.
4350 void InvalidateUniqueSwitchSuccMap()
4352 m_switchDescMap = nullptr;
4355 // Requires "switchBlock" to be a block that ends in a switch. Returns
4356 // the corresponding SwitchUniqueSuccSet.
4357 SwitchUniqueSuccSet GetDescriptorForSwitch(BasicBlock* switchBlk);
4359 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4360 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4361 // remove it from "this", and ensure that "to" is a member.
4362 void UpdateSwitchTableTarget(BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4364 // Remove the "SwitchUniqueSuccSet" of "switchBlk" in the BlockToSwitchDescMap.
4365 void fgInvalidateSwitchDescMapEntry(BasicBlock* switchBlk);
4367 BasicBlock* fgFirstBlockOfHandler(BasicBlock* block);
4369 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred);
4371 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred, flowList*** ptrToPred);
4373 flowList* fgSpliceOutPred(BasicBlock* block, BasicBlock* blockPred);
4375 flowList* fgRemoveRefPred(BasicBlock* block, BasicBlock* blockPred);
4377 flowList* fgRemoveAllRefPreds(BasicBlock* block, BasicBlock* blockPred);
4379 flowList* fgRemoveAllRefPreds(BasicBlock* block, flowList** ptrToPred);
4381 void fgRemoveBlockAsPred(BasicBlock* block);
4383 void fgChangeSwitchBlock(BasicBlock* oldSwitchBlock, BasicBlock* newSwitchBlock);
4385 void fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* newTarget, BasicBlock* oldTarget);
4387 void fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, BasicBlock* oldTarget);
4389 void fgReplacePred(BasicBlock* block, BasicBlock* oldPred, BasicBlock* newPred);
4391 flowList* fgAddRefPred(BasicBlock* block,
4392 BasicBlock* blockPred,
4393 flowList* oldEdge = nullptr,
4394 bool initializingPreds = false); // Only set to 'true' when we are computing preds in
4397 void fgFindBasicBlocks();
4399 bool fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt);
4401 bool fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionIndex, bool putInTryRegion);
4403 BasicBlock* fgFindInsertPoint(unsigned regionIndex,
4404 bool putInTryRegion,
4405 BasicBlock* startBlk,
4407 BasicBlock* nearBlk,
4408 BasicBlock* jumpBlk,
4411 unsigned fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNesting = nullptr);
4413 void fgRemoveEmptyBlocks();
4415 void fgRemoveStmt(BasicBlock* block, GenTreePtr stmt, bool updateRefCnt = true);
4417 bool fgCheckRemoveStmt(BasicBlock* block, GenTreePtr stmt);
4419 void fgCreateLoopPreHeader(unsigned lnum);
4421 void fgUnreachableBlock(BasicBlock* block);
4423 void fgRemoveConditionalJump(BasicBlock* block);
4425 BasicBlock* fgLastBBInMainFunction();
4427 BasicBlock* fgEndBBAfterMainFunction();
4429 void fgUnlinkRange(BasicBlock* bBeg, BasicBlock* bEnd);
4431 void fgRemoveBlock(BasicBlock* block, bool unreachable);
4433 bool fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4435 void fgCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4437 void fgUpdateLoopsAfterCompacting(BasicBlock* block, BasicBlock* bNext);
4439 BasicBlock* fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst);
4441 bool fgRenumberBlocks();
4443 bool fgExpandRarelyRunBlocks();
4445 bool fgEhAllowsMoveBlock(BasicBlock* bBefore, BasicBlock* bAfter);
4447 void fgMoveBlocksAfter(BasicBlock* bStart, BasicBlock* bEnd, BasicBlock* insertAfterBlk);
4449 enum FG_RELOCATE_TYPE
4451 FG_RELOCATE_TRY, // relocate the 'try' region
4452 FG_RELOCATE_HANDLER // relocate the handler region (including the filter if necessary)
4454 BasicBlock* fgRelocateEHRange(unsigned regionIndex, FG_RELOCATE_TYPE relocateType);
4456 #if FEATURE_EH_FUNCLETS
4457 #if defined(_TARGET_ARM_)
4458 void fgClearFinallyTargetBit(BasicBlock* block);
4459 #endif // defined(_TARGET_ARM_)
4460 bool fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block);
4461 bool fgAnyIntraHandlerPreds(BasicBlock* block);
4462 void fgInsertFuncletPrologBlock(BasicBlock* block);
4463 void fgCreateFuncletPrologBlocks();
4464 void fgCreateFunclets();
4465 #else // !FEATURE_EH_FUNCLETS
4466 bool fgRelocateEHRegions();
4467 #endif // !FEATURE_EH_FUNCLETS
4469 bool fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* target);
4471 bool fgBlockEndFavorsTailDuplication(BasicBlock* block);
4473 bool fgBlockIsGoodTailDuplicationCandidate(BasicBlock* block);
4475 bool fgOptimizeFallthroughTailDup(BasicBlock* block, BasicBlock* target);
4477 bool fgOptimizeEmptyBlock(BasicBlock* block);
4479 bool fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBlock* bDest);
4481 bool fgOptimizeBranch(BasicBlock* bJump);
4483 bool fgOptimizeSwitchBranches(BasicBlock* block);
4485 bool fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev);
4487 bool fgOptimizeSwitchJumps();
4489 void fgPrintEdgeWeights();
4491 void fgComputeEdgeWeights();
4493 void fgReorderBlocks();
4495 void fgDetermineFirstColdBlock();
4497 bool fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc = nullptr);
4499 bool fgUpdateFlowGraph(bool doTailDup = false);
4501 void fgFindOperOrder();
4503 // method that returns if you should split here
4504 typedef bool(fgSplitPredicate)(GenTree* tree, GenTree* parent, fgWalkData* data);
4506 void fgSetBlockOrder();
4508 void fgRemoveReturnBlock(BasicBlock* block);
4510 /* Helper code that has been factored out */
4511 inline void fgConvertBBToThrowBB(BasicBlock* block);
4513 bool fgCastNeeded(GenTreePtr tree, var_types toType);
4514 GenTreePtr fgDoNormalizeOnStore(GenTreePtr tree);
4515 GenTreePtr fgMakeTmpArgNode(
4516 unsigned tmpVarNum FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(const bool passedInRegisters));
4518 // The following check for loops that don't execute calls
4519 bool fgLoopCallMarked;
4521 void fgLoopCallTest(BasicBlock* srcBB, BasicBlock* dstBB);
4522 void fgLoopCallMark();
4524 void fgMarkLoopHead(BasicBlock* block);
4526 unsigned fgGetCodeEstimate(BasicBlock* block);
4529 const char* fgProcessEscapes(const char* nameIn, escapeMapping_t* map);
4530 FILE* fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, LPCWSTR type);
4531 bool fgDumpFlowGraph(Phases phase);
4533 #endif // DUMP_FLOWGRAPHS
4538 void fgDispBBLiveness(BasicBlock* block);
4539 void fgDispBBLiveness();
4540 void fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth = 0);
4541 void fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, bool dumpTrees);
4542 void fgDispBasicBlocks(bool dumpTrees = false);
4543 void fgDumpStmtTree(GenTreePtr stmt, unsigned bbNum);
4544 void fgDumpBlock(BasicBlock* block);
4545 void fgDumpTrees(BasicBlock* firstBlock, BasicBlock* lastBlock);
4547 static fgWalkPreFn fgStress64RsltMulCB;
4548 void fgStress64RsltMul();
4549 void fgDebugCheckUpdate();
4550 void fgDebugCheckBBlist(bool checkBBNum = false, bool checkBBRefs = true);
4551 void fgDebugCheckBlockLinks();
4552 void fgDebugCheckLinks(bool morphTrees = false);
4553 void fgDebugCheckStmtsList(BasicBlock* block, bool morphTrees);
4554 void fgDebugCheckNodeLinks(BasicBlock* block, GenTreePtr stmt);
4555 void fgDebugCheckNodesUniqueness();
4557 void fgDebugCheckFlags(GenTreePtr tree);
4558 void fgDebugCheckFlagsHelper(GenTreePtr tree, unsigned treeFlags, unsigned chkFlags);
4559 void fgDebugCheckTryFinallyExits();
4562 #ifdef LEGACY_BACKEND
4563 static void fgOrderBlockOps(GenTreePtr tree,
4567 GenTreePtr* opsPtr, // OUT
4568 regMaskTP* regsPtr); // OUT
4569 #endif // LEGACY_BACKEND
4571 static GenTreePtr fgGetFirstNode(GenTreePtr tree);
4572 static bool fgTreeIsInStmt(GenTree* tree, GenTreeStmt* stmt);
4573 void fgTraverseRPO();
4575 //--------------------- Walking the trees in the IR -----------------------
4580 fgWalkPreFn* wtprVisitorFn;
4581 fgWalkPostFn* wtpoVisitorFn;
4582 void* pCallbackData; // user-provided data
4583 bool wtprLclsOnly; // whether to only visit lclvar nodes
4584 GenTreePtr parent; // parent of current node, provided to callback
4585 GenTreeStack* parentStack; // stack of parent nodes, if asked for
4587 bool printModified; // callback can use this
4591 fgWalkResult fgWalkTreePre(GenTreePtr* pTree,
4592 fgWalkPreFn* visitor,
4593 void* pCallBackData = nullptr,
4594 bool lclVarsOnly = false,
4595 bool computeStack = false);
4597 fgWalkResult fgWalkTree(GenTreePtr* pTree,
4598 fgWalkPreFn* preVisitor,
4599 fgWalkPostFn* postVisitor,
4600 void* pCallBackData = nullptr);
4602 void fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData);
4606 fgWalkResult fgWalkTreePost(GenTreePtr* pTree,
4607 fgWalkPostFn* visitor,
4608 void* pCallBackData = nullptr,
4609 bool computeStack = false);
4611 // An fgWalkPreFn that looks for expressions that have inline throws in
4612 // minopts mode. Basically it looks for tress with gtOverflowEx() or
4613 // GTF_IND_RNGCHK. It returns WALK_ABORT if one is found. It
4614 // returns WALK_SKIP_SUBTREES if GTF_EXCEPT is not set (assumes flags
4615 // properly propagated to parent trees). It returns WALK_CONTINUE
4617 static fgWalkResult fgChkThrowCB(GenTreePtr* pTree, Compiler::fgWalkData* data);
4618 static fgWalkResult fgChkLocAllocCB(GenTreePtr* pTree, Compiler::fgWalkData* data);
4619 static fgWalkResult fgChkQmarkCB(GenTreePtr* pTree, Compiler::fgWalkData* data);
4621 /**************************************************************************
4623 *************************************************************************/
4626 friend class SsaBuilder;
4627 friend struct ValueNumberState;
4629 //--------------------- Detect the basic blocks ---------------------------
4631 BasicBlock** fgBBs; // Table of pointers to the BBs
4633 void fgInitBBLookup();
4634 BasicBlock* fgLookupBB(unsigned addr);
4636 void fgMarkJumpTarget(BYTE* jumpTarget, IL_OFFSET offs);
4638 void fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget);
4640 void fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock);
4642 void fgLinkBasicBlocks();
4644 unsigned fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget);
4646 void fgCheckBasicBlockControlFlow();
4648 void fgControlFlowPermitted(BasicBlock* blkSrc,
4649 BasicBlock* blkDest,
4650 BOOL IsLeave = false /* is the src a leave block */);
4652 bool fgFlowToFirstBlockOfInnerTry(BasicBlock* blkSrc, BasicBlock* blkDest, bool sibling);
4654 void fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, bool isInlining);
4656 void fgAdjustForAddressExposedOrWrittenThis();
4658 bool fgProfileData_ILSizeMismatch;
4659 ICorJitInfo::ProfileBuffer* fgProfileBuffer;
4660 ULONG fgProfileBufferCount;
4661 ULONG fgNumProfileRuns;
4663 unsigned fgStressBBProf()
4666 unsigned result = JitConfig.JitStressBBProf();
4669 if (compStressCompile(STRESS_BB_PROFILE, 15))
4680 bool fgHaveProfileData();
4681 bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weight);
4682 void fgInstrumentMethod();
4685 // fgIsUsingProfileWeights - returns true if we have real profile data for this method
4686 // or if we have some fake profile data for the stress mode
4687 bool fgIsUsingProfileWeights()
4689 return (fgHaveProfileData() || fgStressBBProf());
4692 // fgProfileRunsCount - returns total number of scenario runs for the profile data
4693 // or BB_UNITY_WEIGHT when we aren't using profile data.
4694 unsigned fgProfileRunsCount()
4696 return fgIsUsingProfileWeights() ? fgNumProfileRuns : BB_UNITY_WEIGHT;
4699 //-------- Insert a statement at the start or end of a basic block --------
4703 static bool fgBlockContainsStatementBounded(BasicBlock* block, GenTree* stmt, bool answerOnBoundExceeded = true);
4707 GenTreeStmt* fgInsertStmtAtEnd(BasicBlock* block, GenTreePtr node);
4709 public: // Used by linear scan register allocation
4710 GenTreeStmt* fgInsertStmtNearEnd(BasicBlock* block, GenTreePtr node);
4713 GenTreePtr fgInsertStmtAtBeg(BasicBlock* block, GenTreePtr stmt);
4714 GenTreePtr fgInsertStmtAfter(BasicBlock* block, GenTreePtr insertionPoint, GenTreePtr stmt);
4716 public: // Used by linear scan register allocation
4717 GenTreePtr fgInsertStmtBefore(BasicBlock* block, GenTreePtr insertionPoint, GenTreePtr stmt);
4720 GenTreePtr fgInsertStmtListAfter(BasicBlock* block, GenTreePtr stmtAfter, GenTreePtr stmtList);
4722 GenTreePtr fgMorphSplitTree(GenTree** splitPoint, GenTree* stmt, BasicBlock* blk);
4724 // Create a new temporary variable to hold the result of *ppTree,
4725 // and transform the graph accordingly.
4726 GenTree* fgInsertCommaFormTemp(GenTree** ppTree, CORINFO_CLASS_HANDLE structType = nullptr);
4727 GenTree* fgMakeMultiUse(GenTree** ppTree);
4730 // Recognize a bitwise rotation pattern and convert into a GT_ROL or a GT_ROR node.
4731 GenTreePtr fgRecognizeAndMorphBitwiseRotation(GenTreePtr tree);
4732 bool fgOperIsBitwiseRotationRoot(genTreeOps oper);
4734 //-------- Determine the order in which the trees will be evaluated -------
4736 unsigned fgTreeSeqNum;
4737 GenTree* fgTreeSeqLst;
4738 GenTree* fgTreeSeqBeg;
4740 GenTree* fgSetTreeSeq(GenTree* tree, GenTree* prev = nullptr, bool isLIR = false);
4741 void fgSetTreeSeqHelper(GenTree* tree, bool isLIR);
4742 void fgSetTreeSeqFinish(GenTreePtr tree, bool isLIR);
4743 void fgSetStmtSeq(GenTree* tree);
4744 void fgSetBlockOrder(BasicBlock* block);
4746 //------------------------- Morphing --------------------------------------
4748 unsigned fgPtrArgCntCur;
4749 unsigned fgPtrArgCntMax;
4750 hashBv* fgOutgoingArgTemps;
4751 hashBv* fgCurrentlyInUseArgTemps;
4753 bool compCanEncodePtrArgCntMax();
4755 void fgSetRngChkTarget(GenTreePtr tree, bool delay = true);
4757 BasicBlock* fgSetRngChkTargetInner(SpecialCodeKind kind, bool delay, unsigned* stkDepth);
4760 void fgMoveOpsLeft(GenTreePtr tree);
4763 bool fgIsCommaThrow(GenTreePtr tree, bool forFolding = false);
4765 bool fgIsThrow(GenTreePtr tree);
4767 bool fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2);
4768 bool fgIsBlockCold(BasicBlock* block);
4770 GenTreePtr fgMorphCastIntoHelper(GenTreePtr tree, int helper, GenTreePtr oper);
4772 GenTreePtr fgMorphIntoHelperCall(GenTreePtr tree, int helper, GenTreeArgList* args);
4774 GenTreePtr fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType, unsigned lclOffs);
4776 bool fgMorphRelopToQmark(GenTreePtr tree);
4778 // A "MorphAddrContext" carries information from the surrounding context. If we are evaluating a byref address,
4779 // it is useful to know whether the address will be immediately dereferenced, or whether the address value will
4780 // be used, perhaps by passing it as an argument to a called method. This affects how null checking is done:
4781 // for sufficiently small offsets, we can rely on OS page protection to implicitly null-check addresses that we
4782 // know will be dereferenced. To know that reliance on implicit null checking is sound, we must further know that
4783 // all offsets between the top-level indirection and the bottom are constant, and that their sum is sufficiently
4784 // small; hence the other fields of MorphAddrContext.
4785 enum MorphAddrContextKind
4790 struct MorphAddrContext
4792 MorphAddrContextKind m_kind;
4793 bool m_allConstantOffsets; // Valid only for "m_kind == MACK_Ind". True iff all offsets between
4794 // top-level indirection and here have been constants.
4795 size_t m_totalOffset; // Valid only for "m_kind == MACK_Ind", and if "m_allConstantOffsets" is true.
4796 // In that case, is the sum of those constant offsets.
4798 MorphAddrContext(MorphAddrContextKind kind) : m_kind(kind), m_allConstantOffsets(true), m_totalOffset(0)
4803 // A MACK_CopyBlock context is immutable, so we can just make one of these and share it.
4804 static MorphAddrContext s_CopyBlockMAC;
4807 GenTreePtr getSIMDStructFromField(GenTreePtr tree,
4808 var_types* baseTypeOut,
4810 unsigned* simdSizeOut,
4811 bool ignoreUsedInSIMDIntrinsic = false);
4812 GenTreePtr fgMorphFieldAssignToSIMDIntrinsicSet(GenTreePtr tree);
4813 GenTreePtr fgMorphFieldToSIMDIntrinsicGet(GenTreePtr tree);
4814 bool fgMorphCombineSIMDFieldAssignments(BasicBlock* block, GenTreePtr stmt);
4815 void impMarkContiguousSIMDFieldAssignments(GenTreePtr stmt);
4817 // fgPreviousCandidateSIMDFieldAsgStmt is only used for tracking previous simd field assignment
4818 // in function: Complier::impMarkContiguousSIMDFieldAssignments.
4819 GenTreePtr fgPreviousCandidateSIMDFieldAsgStmt;
4821 #endif // FEATURE_SIMD
4822 GenTreePtr fgMorphArrayIndex(GenTreePtr tree);
4823 GenTreePtr fgMorphCast(GenTreePtr tree);
4824 GenTreePtr fgUnwrapProxy(GenTreePtr objRef);
4825 GenTreeCall* fgMorphArgs(GenTreeCall* call);
4827 void fgMakeOutgoingStructArgCopy(GenTreeCall* call,
4830 CORINFO_CLASS_HANDLE copyBlkClass FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(
4831 const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structDescPtr));
4833 void fgFixupStructReturn(GenTreePtr call);
4834 GenTreePtr fgMorphLocalVar(GenTreePtr tree, bool forceRemorph);
4837 bool fgAddrCouldBeNull(GenTreePtr addr);
4840 GenTreePtr fgMorphField(GenTreePtr tree, MorphAddrContext* mac);
4841 bool fgCanFastTailCall(GenTreeCall* call);
4842 bool fgCheckStmtAfterTailCall();
4843 void fgMorphTailCall(GenTreeCall* call);
4844 void fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCall* recursiveTailCall);
4845 GenTreePtr fgAssignRecursiveCallArgToCallerParam(GenTreePtr arg,
4846 fgArgTabEntryPtr argTabEntry,
4848 IL_OFFSETX callILOffset,
4849 GenTreePtr tmpAssignmentInsertionPoint,
4850 GenTreePtr paramAssignmentInsertionPoint);
4851 static int fgEstimateCallStackSize(GenTreeCall* call);
4852 GenTreePtr fgMorphCall(GenTreeCall* call);
4853 void fgMorphCallInline(GenTreeCall* call, InlineResult* result);
4854 void fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result);
4856 void fgNoteNonInlineCandidate(GenTreeStmt* stmt, GenTreeCall* call);
4857 static fgWalkPreFn fgFindNonInlineCandidate;
4859 GenTreePtr fgOptimizeDelegateConstructor(GenTreeCall* call,
4860 CORINFO_CONTEXT_HANDLE* ExactContextHnd,
4861 CORINFO_RESOLVED_TOKEN* ldftnToken);
4862 GenTreePtr fgMorphLeaf(GenTreePtr tree);
4863 void fgAssignSetVarDef(GenTreePtr tree);
4864 GenTreePtr fgMorphOneAsgBlockOp(GenTreePtr tree);
4865 GenTreePtr fgMorphInitBlock(GenTreePtr tree);
4866 GenTreePtr fgMorphBlkToInd(GenTreeBlk* tree, var_types type);
4867 GenTreePtr fgMorphGetStructAddr(GenTreePtr* pTree, CORINFO_CLASS_HANDLE clsHnd, bool isRValue = false);
4868 GenTreePtr fgMorphBlkNode(GenTreePtr tree, bool isDest);
4869 GenTreePtr fgMorphBlockOperand(GenTreePtr tree, var_types asgType, unsigned blockWidth, bool isDest);
4870 void fgMorphUnsafeBlk(GenTreeObj* obj);
4871 GenTreePtr fgMorphCopyBlock(GenTreePtr tree);
4872 GenTreePtr fgMorphForRegisterFP(GenTreePtr tree);
4873 GenTreePtr fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac = nullptr);
4874 GenTreePtr fgMorphSmpOpPre(GenTreePtr tree);
4875 GenTreePtr fgMorphModToSubMulDiv(GenTreeOp* tree);
4876 GenTreePtr fgMorphSmpOpOptional(GenTreeOp* tree);
4877 GenTreePtr fgMorphRecognizeBoxNullable(GenTree* compare);
4879 GenTreePtr fgMorphToEmulatedFP(GenTreePtr tree);
4880 GenTreePtr fgMorphConst(GenTreePtr tree);
4883 GenTreePtr fgMorphTree(GenTreePtr tree, MorphAddrContext* mac = nullptr);
4886 #if LOCAL_ASSERTION_PROP
4887 void fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTreePtr tree));
4888 void fgKillDependentAssertions(unsigned lclNum DEBUGARG(GenTreePtr tree));
4890 void fgMorphTreeDone(GenTreePtr tree, GenTreePtr oldTree = nullptr DEBUGARG(int morphNum = 0));
4892 GenTreeStmt* fgMorphStmt;
4894 unsigned fgGetBigOffsetMorphingTemp(var_types type); // We cache one temp per type to be
4895 // used when morphing big offset.
4897 //----------------------- Liveness analysis -------------------------------
4899 VARSET_TP fgCurUseSet; // vars used by block (before an assignment)
4900 VARSET_TP fgCurDefSet; // vars assigned by block (before a use)
4902 MemoryKindSet fgCurMemoryUse; // True iff the current basic block uses memory.
4903 MemoryKindSet fgCurMemoryDef; // True iff the current basic block modifies memory.
4904 MemoryKindSet fgCurMemoryHavoc; // True if the current basic block is known to set memory to a "havoc" value.
4906 bool byrefStatesMatchGcHeapStates; // True iff GcHeap and ByrefExposed memory have all the same def points.
4908 void fgMarkUseDef(GenTreeLclVarCommon* tree);
4910 void fgBeginScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
4911 void fgEndScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
4913 void fgMarkInScope(BasicBlock* block, VARSET_VALARG_TP inScope);
4914 void fgUnmarkInScope(BasicBlock* block, VARSET_VALARG_TP unmarkScope);
4916 void fgExtendDbgScopes();
4917 void fgExtendDbgLifetimes();
4920 void fgDispDebugScopes();
4923 //-------------------------------------------------------------------------
4925 // The following keeps track of any code we've added for things like array
4926 // range checking or explicit calls to enable GC, and so on.
4931 AddCodeDsc* acdNext;
4932 BasicBlock* acdDstBlk; // block to which we jump
4934 SpecialCodeKind acdKind; // what kind of a special block is this?
4935 unsigned short acdStkLvl;
4939 static unsigned acdHelper(SpecialCodeKind codeKind);
4941 AddCodeDsc* fgAddCodeList;
4943 bool fgRngChkThrowAdded;
4944 AddCodeDsc* fgExcptnTargetCache[SCK_COUNT];
4946 BasicBlock* fgRngChkTarget(BasicBlock* block, unsigned stkDepth, SpecialCodeKind kind);
4948 BasicBlock* fgAddCodeRef(BasicBlock* srcBlk, unsigned refData, SpecialCodeKind kind, unsigned stkDepth = 0);
4951 AddCodeDsc* fgFindExcptnTarget(SpecialCodeKind kind, unsigned refData);
4954 bool fgIsCodeAdded();
4956 bool fgIsThrowHlpBlk(BasicBlock* block);
4957 unsigned fgThrowHlpBlkStkLevel(BasicBlock* block);
4959 unsigned fgBigOffsetMorphingTemps[TYP_COUNT];
4961 unsigned fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo);
4962 void fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* result);
4963 void fgInsertInlineeBlocks(InlineInfo* pInlineInfo);
4964 GenTreePtr fgInlinePrependStatements(InlineInfo* inlineInfo);
4965 void fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, GenTreePtr stmt);
4967 #if FEATURE_MULTIREG_RET
4968 GenTreePtr fgGetStructAsStructPtr(GenTreePtr tree);
4969 GenTreePtr fgAssignStructInlineeToVar(GenTreePtr child, CORINFO_CLASS_HANDLE retClsHnd);
4970 void fgAttachStructInlineeToAsg(GenTreePtr tree, GenTreePtr child, CORINFO_CLASS_HANDLE retClsHnd);
4971 #endif // FEATURE_MULTIREG_RET
4973 static fgWalkPreFn fgUpdateInlineReturnExpressionPlaceHolder;
4976 static fgWalkPreFn fgDebugCheckInlineCandidates;
4978 void CheckNoFatPointerCandidatesLeft();
4979 static fgWalkPreFn fgDebugCheckFatPointerCandidates;
4982 void fgPromoteStructs();
4983 fgWalkResult fgMorphStructField(GenTreePtr tree, fgWalkData* fgWalkPre);
4984 fgWalkResult fgMorphLocalField(GenTreePtr tree, fgWalkData* fgWalkPre);
4986 // Identify which parameters are implicit byrefs, and flag their LclVarDscs.
4987 void fgMarkImplicitByRefArgs();
4989 // Change implicit byrefs' types from struct to pointer, and for any that were
4990 // promoted, create new promoted struct temps.
4991 void fgRetypeImplicitByRefArgs();
4993 // Rewrite appearances of implicit byrefs (manifest the implied additional level of indirection).
4994 bool fgMorphImplicitByRefArgs(GenTreePtr tree);
4995 GenTreePtr fgMorphImplicitByRefArgs(GenTreePtr tree, bool isAddr);
4997 // Clear up annotations for any struct promotion temps created for implicit byrefs.
4998 void fgMarkDemotedImplicitByRefArgs();
5000 static fgWalkPreFn fgMarkAddrTakenLocalsPreCB;
5001 static fgWalkPostFn fgMarkAddrTakenLocalsPostCB;
5002 void fgMarkAddressExposedLocals();
5003 bool fgNodesMayInterfere(GenTree* store, GenTree* load);
5005 static fgWalkPreFn fgUpdateSideEffectsPre;
5006 static fgWalkPostFn fgUpdateSideEffectsPost;
5008 // Returns true if the type of tree is of size at least "width", or if "tree" is not a
5010 bool fgFitsInOrNotLoc(GenTreePtr tree, unsigned width);
5012 // The given local variable, required to be a struct variable, is being assigned via
5013 // a "lclField", to make it masquerade as an integral type in the ABI. Make sure that
5014 // the variable is not enregistered, and is therefore not promoted independently.
5015 void fgLclFldAssign(unsigned lclNum);
5017 static fgWalkPreFn gtHasLocalsWithAddrOpCB;
5019 enum TypeProducerKind
5021 TPK_Unknown = 0, // May not be a RuntimeType
5022 TPK_Handle = 1, // RuntimeType via handle
5023 TPK_GetType = 2, // RuntimeType via Object.get_Type()
5024 TPK_Null = 3, // Tree value is null
5025 TPK_Other = 4 // RuntimeType via other means
5028 TypeProducerKind gtGetTypeProducerKind(GenTree* tree);
5029 bool gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call);
5030 bool gtIsActiveCSE_Candidate(GenTreePtr tree);
5033 bool fgPrintInlinedMethods;
5036 bool fgIsBigOffset(size_t offset);
5038 // The following are used when morphing special cases of integer div/mod operations and also by codegen
5039 bool fgIsSignedDivOptimizable(GenTreePtr divisor);
5040 bool fgIsUnsignedDivOptimizable(GenTreePtr divisor);
5041 bool fgIsSignedModOptimizable(GenTreePtr divisor);
5042 bool fgIsUnsignedModOptimizable(GenTreePtr divisor);
5044 bool fgNeedReturnSpillTemp();
5047 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5048 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5052 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5053 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5060 LclVarDsc* optIsTrackedLocal(GenTreePtr tree);
5063 void optRemoveRangeCheck(GenTreePtr tree, GenTreePtr stmt);
5064 bool optIsRangeCheckRemovable(GenTreePtr tree);
5067 static fgWalkPreFn optValidRangeCheckIndex;
5068 static fgWalkPreFn optRemoveTreeVisitor; // Helper passed to Compiler::fgWalkAllTreesPre() to decrement the LclVar
5071 void optRemoveTree(GenTreePtr deadTree, GenTreePtr keepList);
5073 /**************************************************************************
5075 *************************************************************************/
5078 // Do hoisting for all loops.
5079 void optHoistLoopCode();
5081 // To represent sets of VN's that have already been hoisted in outer loops.
5082 typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, bool> VNToBoolMap;
5083 typedef VNToBoolMap VNSet;
5085 struct LoopHoistContext
5088 // The set of variables hoisted in the current loop (or nullptr if there are none).
5089 VNSet* m_pHoistedInCurLoop;
5092 // Value numbers of expressions that have been hoisted in parent loops in the loop nest.
5093 VNSet m_hoistedInParentLoops;
5094 // Value numbers of expressions that have been hoisted in the current (or most recent) loop in the nest.
5095 // Previous decisions on loop-invariance of value numbers in the current loop.
5096 VNToBoolMap m_curLoopVnInvariantCache;
5098 VNSet* GetHoistedInCurLoop(Compiler* comp)
5100 if (m_pHoistedInCurLoop == nullptr)
5102 m_pHoistedInCurLoop = new (comp->getAllocatorLoopHoist()) VNSet(comp->getAllocatorLoopHoist());
5104 return m_pHoistedInCurLoop;
5107 VNSet* ExtractHoistedInCurLoop()
5109 VNSet* res = m_pHoistedInCurLoop;
5110 m_pHoistedInCurLoop = nullptr;
5114 LoopHoistContext(Compiler* comp)
5115 : m_pHoistedInCurLoop(nullptr)
5116 , m_hoistedInParentLoops(comp->getAllocatorLoopHoist())
5117 , m_curLoopVnInvariantCache(comp->getAllocatorLoopHoist())
5122 // Do hoisting for loop "lnum" (an index into the optLoopTable), and all loops nested within it.
5123 // Tracks the expressions that have been hoisted by containing loops by temporary recording their
5124 // value numbers in "m_hoistedInParentLoops". This set is not modified by the call.
5125 void optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);
5127 // Do hoisting for a particular loop ("lnum" is an index into the optLoopTable.)
5128 // Assumes that expressions have been hoisted in containing loops if their value numbers are in
5129 // "m_hoistedInParentLoops".
5131 void optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt);
5133 // Hoist all expressions in "blk" that are invariant in loop "lnum" (an index into the optLoopTable)
5134 // outside of that loop. Exempt expressions whose value number is in "m_hoistedInParentLoops"; add VN's of hoisted
5135 // expressions to "hoistInLoop".
5136 void optHoistLoopExprsForBlock(BasicBlock* blk, unsigned lnum, LoopHoistContext* hoistCtxt);
5138 // Return true if the tree looks profitable to hoist out of loop 'lnum'.
5139 bool optIsProfitableToHoistableTree(GenTreePtr tree, unsigned lnum);
5141 // Hoist all proper sub-expressions of "tree" (which occurs in "stmt", which occurs in "blk")
5142 // that are invariant in loop "lnum" (an index into the optLoopTable)
5143 // outside of that loop. Exempt expressions whose value number is in "hoistedInParents"; add VN's of hoisted
5144 // expressions to "hoistInLoop".
5145 // Returns "true" iff "tree" is loop-invariant (wrt "lnum").
5146 // Assumes that the value of "*firstBlockAndBeforeSideEffect" indicates that we're in the first block, and before
5147 // any possible globally visible side effects. Assume is called in evaluation order, and updates this.
5148 bool optHoistLoopExprsForTree(GenTreePtr tree,
5150 LoopHoistContext* hoistCtxt,
5151 bool* firstBlockAndBeforeSideEffect,
5153 bool* pCctorDependent);
5155 // Performs the hoisting 'tree' into the PreHeader for loop 'lnum'
5156 void optHoistCandidate(GenTreePtr tree, unsigned lnum, LoopHoistContext* hoistCtxt);
5158 // Returns true iff the ValueNum "vn" represents a value that is loop-invariant in "lnum".
5159 // Constants and init values are always loop invariant.
5160 // VNPhi's connect VN's to the SSA definition, so we can know if the SSA def occurs in the loop.
5161 bool optVNIsLoopInvariant(ValueNum vn, unsigned lnum, VNToBoolMap* recordedVNs);
5163 // Returns "true" iff "tree" is valid at the head of loop "lnum", in the context of the hoist substitution
5164 // "subst". If "tree" is a local SSA var, it is valid if its SSA definition occurs outside of the loop, or
5165 // if it is in the domain of "subst" (meaning that it's definition has been previously hoisted, with a "standin"
5166 // local.) If tree is a constant, it is valid. Otherwise, if it is an operator, it is valid iff its children are.
5167 bool optTreeIsValidAtLoopHead(GenTreePtr tree, unsigned lnum);
5169 // If "blk" is the entry block of a natural loop, returns true and sets "*pLnum" to the index of the loop
5170 // in the loop table.
5171 bool optBlockIsLoopEntry(BasicBlock* blk, unsigned* pLnum);
5173 // Records the set of "side effects" of all loops: fields (object instance and static)
5174 // written to, and SZ-array element type equivalence classes updated.
5175 void optComputeLoopSideEffects();
5178 // Requires "lnum" to be the index of an outermost loop in the loop table. Traverses the body of that loop,
5179 // including all nested loops, and records the set of "side effects" of the loop: fields (object instance and
5180 // static) written to, and SZ-array element type equivalence classes updated.
5181 void optComputeLoopNestSideEffects(unsigned lnum);
5183 // Add the side effects of "blk" (which is required to be within a loop) to all loops of which it is a part.
5184 void optComputeLoopSideEffectsOfBlock(BasicBlock* blk);
5186 // Hoist the expression "expr" out of loop "lnum".
5187 void optPerformHoistExpr(GenTreePtr expr, unsigned lnum);
5190 void optOptimizeBools();
5193 GenTree* optIsBoolCond(GenTree* condBranch, GenTree** compPtr, bool* boolPtr);
5195 void optOptimizeBoolsGcStress(BasicBlock* condBlock);
5198 void optOptimizeLayout(); // Optimize the BasicBlock layout of the method
5200 void optOptimizeLoops(); // for "while-do" loops duplicates simple loop conditions and transforms
5201 // the loop into a "do-while" loop
5202 // Also finds all natural loops and records them in the loop table
5204 // Optionally clone loops in the loop table.
5205 void optCloneLoops();
5207 // Clone loop "loopInd" in the loop table.
5208 void optCloneLoop(unsigned loopInd, LoopCloneContext* context);
5210 // Ensure that loop "loopInd" has a unique head block. (If the existing entry has
5211 // non-loop predecessors other than the head entry, create a new, empty block that goes (only) to the entry,
5212 // and redirects the preds of the entry to this new block.) Sets the weight of the newly created block to
5214 void optEnsureUniqueHead(unsigned loopInd, unsigned ambientWeight);
5216 void optUnrollLoops(); // Unrolls loops (needs to have cost info)
5219 // This enumeration describes what is killed by a call.
5223 CALLINT_NONE, // no interference (most helpers)
5224 CALLINT_REF_INDIRS, // kills GC ref indirections (SETFIELD OBJ)
5225 CALLINT_SCL_INDIRS, // kills non GC ref indirections (SETFIELD non-OBJ)
5226 CALLINT_ALL_INDIRS, // kills both GC ref and non GC ref indirections (SETFIELD STRUCT)
5227 CALLINT_ALL, // kills everything (normal method call)
5231 // A "LoopDsc" describes a ("natural") loop. We (currently) require the body of a loop to be a contiguous (in
5232 // bbNext order) sequence of basic blocks. (At times, we may require the blocks in a loop to be "properly numbered"
5233 // in bbNext order; we use comparisons on the bbNum to decide order.)
5234 // The blocks that define the body are
5235 // first <= top <= entry <= bottom .
5236 // The "head" of the loop is a block outside the loop that has "entry" as a successor. We only support loops with a
5237 // single 'head' block. The meanings of these blocks are given in the definitions below. Also see the picture at
5238 // Compiler::optFindNaturalLoops().
5241 BasicBlock* lpHead; // HEAD of the loop (not part of the looping of the loop) -- has ENTRY as a successor.
5242 BasicBlock* lpFirst; // FIRST block (in bbNext order) reachable within this loop. (May be part of a nested
5243 // loop, but not the outer loop.)
5244 BasicBlock* lpTop; // loop TOP (the back edge from lpBottom reaches here) (in most cases FIRST and TOP are the
5246 BasicBlock* lpEntry; // the ENTRY in the loop (in most cases TOP or BOTTOM)
5247 BasicBlock* lpBottom; // loop BOTTOM (from here we have a back edge to the TOP)
5248 BasicBlock* lpExit; // if a single exit loop this is the EXIT (in most cases BOTTOM)
5250 callInterf lpAsgCall; // "callInterf" for calls in the loop
5251 ALLVARSET_TP lpAsgVars; // set of vars assigned within the loop (all vars, not just tracked)
5252 varRefKinds lpAsgInds : 8; // set of inds modified within the loop
5254 unsigned short lpFlags; // Mask of the LPFLG_* constants
5256 unsigned char lpExitCnt; // number of exits from the loop
5258 unsigned char lpParent; // The index of the most-nested loop that completely contains this one,
5259 // or else BasicBlock::NOT_IN_LOOP if no such loop exists.
5260 unsigned char lpChild; // The index of a nested loop, or else BasicBlock::NOT_IN_LOOP if no child exists.
5261 // (Actually, an "immediately" nested loop --
5262 // no other child of this loop is a parent of lpChild.)
5263 unsigned char lpSibling; // The index of another loop that is an immediate child of lpParent,
5264 // or else BasicBlock::NOT_IN_LOOP. One can enumerate all the children of a loop
5265 // by following "lpChild" then "lpSibling" links.
5267 #define LPFLG_DO_WHILE 0x0001 // it's a do-while loop (i.e ENTRY is at the TOP)
5268 #define LPFLG_ONE_EXIT 0x0002 // the loop has only one exit
5270 #define LPFLG_ITER 0x0004 // for (i = icon or lclVar; test_condition(); i++)
5271 #define LPFLG_HOISTABLE 0x0008 // the loop is in a form that is suitable for hoisting expressions
5272 #define LPFLG_CONST 0x0010 // for (i=icon;i<icon;i++){ ... } - constant loop
5274 #define LPFLG_VAR_INIT 0x0020 // iterator is initialized with a local var (var # found in lpVarInit)
5275 #define LPFLG_CONST_INIT 0x0040 // iterator is initialized with a constant (found in lpConstInit)
5277 #define LPFLG_VAR_LIMIT 0x0100 // iterator is compared with a local var (var # found in lpVarLimit)
5278 #define LPFLG_CONST_LIMIT 0x0200 // iterator is compared with a constant (found in lpConstLimit)
5279 #define LPFLG_ARRLEN_LIMIT 0x0400 // iterator is compared with a.len or a[i].len (found in lpArrLenLimit)
5280 #define LPFLG_SIMD_LIMIT 0x0080 // iterator is compared with Vector<T>.Count (found in lpConstLimit)
5282 #define LPFLG_HAS_PREHEAD 0x0800 // lpHead is known to be a preHead for this loop
5283 #define LPFLG_REMOVED 0x1000 // has been removed from the loop table (unrolled or optimized away)
5284 #define LPFLG_DONT_UNROLL 0x2000 // do not unroll this loop
5286 #define LPFLG_ASGVARS_YES 0x4000 // "lpAsgVars" has been computed
5287 #define LPFLG_ASGVARS_INC 0x8000 // "lpAsgVars" is incomplete -- vars beyond those representable in an AllVarSet
5288 // type are assigned to.
5290 bool lpLoopHasMemoryHavoc[MemoryKindCount]; // The loop contains an operation that we assume has arbitrary
5291 // memory side effects. If this is set, the fields below
5292 // may not be accurate (since they become irrelevant.)
5293 bool lpContainsCall; // True if executing the loop body *may* execute a call
5295 VARSET_TP lpVarInOut; // The set of variables that are IN or OUT during the execution of this loop
5296 VARSET_TP lpVarUseDef; // The set of variables that are USE or DEF during the execution of this loop
5298 int lpHoistedExprCount; // The register count for the non-FP expressions from inside this loop that have been
5300 int lpLoopVarCount; // The register count for the non-FP LclVars that are read/written inside this loop
5301 int lpVarInOutCount; // The register count for the non-FP LclVars that are alive inside or accross this loop
5303 int lpHoistedFPExprCount; // The register count for the FP expressions from inside this loop that have been
5305 int lpLoopVarFPCount; // The register count for the FP LclVars that are read/written inside this loop
5306 int lpVarInOutFPCount; // The register count for the FP LclVars that are alive inside or accross this loop
5308 typedef JitHashTable<CORINFO_FIELD_HANDLE, JitPtrKeyFuncs<struct CORINFO_FIELD_STRUCT_>, bool> FieldHandleSet;
5309 FieldHandleSet* lpFieldsModified; // This has entries (mappings to "true") for all static field and object
5310 // instance fields modified
5313 typedef JitHashTable<CORINFO_CLASS_HANDLE, JitPtrKeyFuncs<struct CORINFO_CLASS_STRUCT_>, bool> ClassHandleSet;
5314 ClassHandleSet* lpArrayElemTypesModified; // Bits set indicate the set of sz array element types such that
5315 // arrays of that type are modified
5318 // Adds the variable liveness information for 'blk' to 'this' LoopDsc
5319 void AddVariableLiveness(Compiler* comp, BasicBlock* blk);
5321 inline void AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd);
5322 // This doesn't *always* take a class handle -- it can also take primitive types, encoded as class handles
5323 // (shifted left, with a low-order bit set to distinguish.)
5324 // Use the {Encode/Decode}ElemType methods to construct/destruct these.
5325 inline void AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd);
5327 /* The following values are set only for iterator loops, i.e. has the flag LPFLG_ITER set */
5329 GenTreePtr lpIterTree; // The "i <op>= const" tree
5330 unsigned lpIterVar(); // iterator variable #
5331 int lpIterConst(); // the constant with which the iterator is incremented
5332 genTreeOps lpIterOper(); // the type of the operation on the iterator (ASG_ADD, ASG_SUB, etc.)
5333 void VERIFY_lpIterTree();
5335 var_types lpIterOperType(); // For overflow instructions
5338 int lpConstInit; // initial constant value of iterator : Valid if LPFLG_CONST_INIT
5339 unsigned lpVarInit; // initial local var number to which we initialize the iterator : Valid if
5343 /* The following is for LPFLG_ITER loops only (i.e. the loop condition is "i RELOP const or var" */
5345 GenTreePtr lpTestTree; // pointer to the node containing the loop test
5346 genTreeOps lpTestOper(); // the type of the comparison between the iterator and the limit (GT_LE, GT_GE, etc.)
5347 void VERIFY_lpTestTree();
5349 bool lpIsReversed(); // true if the iterator node is the second operand in the loop condition
5350 GenTreePtr lpIterator(); // the iterator node in the loop test
5351 GenTreePtr lpLimit(); // the limit node in the loop test
5353 int lpConstLimit(); // limit constant value of iterator - loop condition is "i RELOP const" : Valid if
5354 // LPFLG_CONST_LIMIT
5355 unsigned lpVarLimit(); // the lclVar # in the loop condition ( "i RELOP lclVar" ) : Valid if
5357 bool lpArrLenLimit(Compiler* comp, ArrIndex* index); // The array length in the loop condition ( "i RELOP
5358 // arr.len" or "i RELOP arr[i][j].len" ) : Valid if
5359 // LPFLG_ARRLEN_LIMIT
5361 // Returns "true" iff "*this" contains the blk.
5362 bool lpContains(BasicBlock* blk)
5364 return lpFirst->bbNum <= blk->bbNum && blk->bbNum <= lpBottom->bbNum;
5366 // Returns "true" iff "*this" (properly) contains the range [first, bottom] (allowing firsts
5367 // to be equal, but requiring bottoms to be different.)
5368 bool lpContains(BasicBlock* first, BasicBlock* bottom)
5370 return lpFirst->bbNum <= first->bbNum && bottom->bbNum < lpBottom->bbNum;
5373 // Returns "true" iff "*this" (properly) contains "lp2" (allowing firsts to be equal, but requiring
5374 // bottoms to be different.)
5375 bool lpContains(const LoopDsc& lp2)
5377 return lpContains(lp2.lpFirst, lp2.lpBottom);
5380 // Returns "true" iff "*this" is (properly) contained by the range [first, bottom]
5381 // (allowing firsts to be equal, but requiring bottoms to be different.)
5382 bool lpContainedBy(BasicBlock* first, BasicBlock* bottom)
5384 return first->bbNum <= lpFirst->bbNum && lpBottom->bbNum < bottom->bbNum;
5387 // Returns "true" iff "*this" is (properly) contained by "lp2"
5388 // (allowing firsts to be equal, but requiring bottoms to be different.)
5389 bool lpContainedBy(const LoopDsc& lp2)
5391 return lpContains(lp2.lpFirst, lp2.lpBottom);
5394 // Returns "true" iff "*this" is disjoint from the range [top, bottom].
5395 bool lpDisjoint(BasicBlock* first, BasicBlock* bottom)
5397 return bottom->bbNum < lpFirst->bbNum || lpBottom->bbNum < first->bbNum;
5399 // Returns "true" iff "*this" is disjoint from "lp2".
5400 bool lpDisjoint(const LoopDsc& lp2)
5402 return lpDisjoint(lp2.lpFirst, lp2.lpBottom);
5404 // Returns "true" iff the loop is well-formed (see code for defn).
5407 return lpFirst->bbNum <= lpTop->bbNum && lpTop->bbNum <= lpEntry->bbNum &&
5408 lpEntry->bbNum <= lpBottom->bbNum &&
5409 (lpHead->bbNum < lpTop->bbNum || lpHead->bbNum > lpBottom->bbNum);
5414 bool fgMightHaveLoop(); // returns true if there are any backedges
5415 bool fgHasLoops; // True if this method has any loops, set in fgComputeReachability
5418 LoopDsc optLoopTable[MAX_LOOP_NUM]; // loop descriptor table
5419 unsigned char optLoopCount; // number of tracked loops
5421 bool optRecordLoop(BasicBlock* head,
5427 unsigned char exitCnt);
5430 unsigned optCallCount; // number of calls made in the method
5431 unsigned optIndirectCallCount; // number of virtual, interface and indirect calls made in the method
5432 unsigned optNativeCallCount; // number of Pinvoke/Native calls made in the method
5433 unsigned optLoopsCloned; // number of loops cloned in the current method.
5436 unsigned optFindLoopNumberFromBeginBlock(BasicBlock* begBlk);
5437 void optPrintLoopInfo(unsigned loopNum,
5439 BasicBlock* lpFirst,
5441 BasicBlock* lpEntry,
5442 BasicBlock* lpBottom,
5443 unsigned char lpExitCnt,
5445 unsigned parentLoop = BasicBlock::NOT_IN_LOOP);
5446 void optPrintLoopInfo(unsigned lnum);
5447 void optPrintLoopRecording(unsigned lnum);
5449 void optCheckPreds();
5452 void optSetBlockWeights();
5454 void optMarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk, bool excludeEndBlk);
5456 void optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk);
5458 void optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmarkLoop = false);
5460 bool optIsLoopTestEvalIntoTemp(GenTreePtr test, GenTreePtr* newTest);
5461 unsigned optIsLoopIncrTree(GenTreePtr incr);
5462 bool optCheckIterInLoopTest(unsigned loopInd, GenTreePtr test, BasicBlock* from, BasicBlock* to, unsigned iterVar);
5463 bool optComputeIterInfo(GenTreePtr incr, BasicBlock* from, BasicBlock* to, unsigned* pIterVar);
5464 bool optPopulateInitInfo(unsigned loopInd, GenTreePtr init, unsigned iterVar);
5465 bool optExtractInitTestIncr(BasicBlock* head,
5470 GenTreePtr* ppIncr);
5472 void optFindNaturalLoops();
5474 // Ensures that all the loops in the loop nest rooted at "loopInd" (an index into the loop table) are 'canonical' --
5475 // each loop has a unique "top." Returns "true" iff the flowgraph has been modified.
5476 bool optCanonicalizeLoopNest(unsigned char loopInd);
5478 // Ensures that the loop "loopInd" (an index into the loop table) is 'canonical' -- it has a unique "top,"
5479 // unshared with any other loop. Returns "true" iff the flowgraph has been modified
5480 bool optCanonicalizeLoop(unsigned char loopInd);
5482 // Requires "l1" to be a valid loop table index, and not "BasicBlock::NOT_IN_LOOP". Requires "l2" to be
5483 // a valid loop table index, or else "BasicBlock::NOT_IN_LOOP". Returns true
5484 // iff "l2" is not NOT_IN_LOOP, and "l1" contains "l2".
5485 bool optLoopContains(unsigned l1, unsigned l2);
5487 // Requires "loopInd" to be a valid index into the loop table.
5488 // Updates the loop table by changing loop "loopInd", whose head is required
5489 // to be "from", to be "to". Also performs this transformation for any
5490 // loop nested in "loopInd" that shares the same head as "loopInd".
5491 void optUpdateLoopHead(unsigned loopInd, BasicBlock* from, BasicBlock* to);
5493 // Updates the successors of "blk": if "blk2" is a successor of "blk", and there is a mapping for "blk2->blk3" in
5494 // "redirectMap", change "blk" so that "blk3" is this successor. Note that the predecessor lists are not updated.
5495 void optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap);
5497 // Marks the containsCall information to "lnum" and any parent loops.
5498 void AddContainsCallAllContainingLoops(unsigned lnum);
5499 // Adds the variable liveness information from 'blk' to "lnum" and any parent loops.
5500 void AddVariableLivenessAllContainingLoops(unsigned lnum, BasicBlock* blk);
5501 // Adds "fldHnd" to the set of modified fields of "lnum" and any parent loops.
5502 void AddModifiedFieldAllContainingLoops(unsigned lnum, CORINFO_FIELD_HANDLE fldHnd);
5503 // Adds "elemType" to the set of modified array element types of "lnum" and any parent loops.
5504 void AddModifiedElemTypeAllContainingLoops(unsigned lnum, CORINFO_CLASS_HANDLE elemType);
5506 // Requires that "from" and "to" have the same "bbJumpKind" (perhaps because "to" is a clone
5507 // of "from".) Copies the jump destination from "from" to "to".
5508 void optCopyBlkDest(BasicBlock* from, BasicBlock* to);
5510 // The depth of the loop described by "lnum" (an index into the loop table.) (0 == top level)
5511 unsigned optLoopDepth(unsigned lnum)
5513 unsigned par = optLoopTable[lnum].lpParent;
5514 if (par == BasicBlock::NOT_IN_LOOP)
5520 return 1 + optLoopDepth(par);
5524 void fgOptWhileLoop(BasicBlock* block);
5526 bool optComputeLoopRep(int constInit,
5529 genTreeOps iterOper,
5531 genTreeOps testOper,
5534 unsigned* iterCount);
5535 #if FEATURE_STACK_FP_X87
5538 VARSET_TP optAllFloatVars; // mask of all tracked FP variables
5539 VARSET_TP optAllFPregVars; // mask of all enregistered FP variables
5540 VARSET_TP optAllNonFPvars; // mask of all tracked non-FP variables
5541 #endif // FEATURE_STACK_FP_X87
5544 static fgWalkPreFn optIsVarAssgCB;
5547 bool optIsVarAssigned(BasicBlock* beg, BasicBlock* end, GenTreePtr skip, unsigned var);
5549 bool optIsVarAssgLoop(unsigned lnum, unsigned var);
5551 int optIsSetAssgLoop(unsigned lnum, ALLVARSET_VALARG_TP vars, varRefKinds inds = VR_NONE);
5553 bool optNarrowTree(GenTreePtr tree, var_types srct, var_types dstt, ValueNumPair vnpNarrow, bool doit);
5555 /**************************************************************************
5556 * Optimization conditions
5557 *************************************************************************/
5559 bool optFastCodeOrBlendedLoop(BasicBlock::weight_t bbWeight);
5560 bool optPentium4(void);
5561 bool optAvoidIncDec(BasicBlock::weight_t bbWeight);
5562 bool optAvoidIntMult(void);
5567 // The following is the upper limit on how many expressions we'll keep track
5568 // of for the CSE analysis.
5570 static const unsigned MAX_CSE_CNT = EXPSET_SZ;
5572 static const int MIN_CSE_COST = 2;
5574 // Keeps tracked cse indices
5575 BitVecTraits* cseTraits;
5578 /* Generic list of nodes - used by the CSE logic */
5586 typedef struct treeLst* treeLstPtr;
5590 treeStmtLst* tslNext;
5591 GenTreePtr tslTree; // tree node
5592 GenTreePtr tslStmt; // statement containing the tree
5593 BasicBlock* tslBlock; // block containing the statement
5596 typedef struct treeStmtLst* treeStmtLstPtr;
5598 // The following logic keeps track of expressions via a simple hash table.
5602 CSEdsc* csdNextInBucket; // used by the hash table
5604 unsigned csdHashValue; // the orginal hashkey
5606 unsigned csdIndex; // 1..optCSECandidateCount
5607 char csdLiveAcrossCall; // 0 or 1
5609 unsigned short csdDefCount; // definition count
5610 unsigned short csdUseCount; // use count (excluding the implicit uses at defs)
5612 unsigned csdDefWtCnt; // weighted def count
5613 unsigned csdUseWtCnt; // weighted use count (excluding the implicit uses at defs)
5615 GenTreePtr csdTree; // treenode containing the 1st occurance
5616 GenTreePtr csdStmt; // stmt containing the 1st occurance
5617 BasicBlock* csdBlock; // block containing the 1st occurance
5619 treeStmtLstPtr csdTreeList; // list of matching tree nodes: head
5620 treeStmtLstPtr csdTreeLast; // list of matching tree nodes: tail
5622 ValueNum defConservativeVN; // if all def occurrences share the same conservative value
5623 // number, this will reflect it; otherwise, NoVN.
5626 static const size_t s_optCSEhashSize;
5627 CSEdsc** optCSEhash;
5630 typedef JitHashTable<GenTreePtr, JitPtrKeyFuncs<GenTree>, GenTreePtr> NodeToNodeMap;
5632 NodeToNodeMap* optCseCheckedBoundMap; // Maps bound nodes to ancestor compares that should be
5633 // re-numbered with the bound to improve range check elimination
5635 // Given a compare, look for a cse candidate checked bound feeding it and add a map entry if found.
5636 void optCseUpdateCheckedBoundMap(GenTreePtr compare);
5640 CSEdsc* optCSEfindDsc(unsigned index);
5641 void optUnmarkCSE(GenTreePtr tree);
5643 // user defined callback data for the tree walk function optCSE_MaskHelper()
5644 struct optCSE_MaskData
5646 EXPSET_TP CSE_defMask;
5647 EXPSET_TP CSE_useMask;
5650 // Treewalk helper for optCSE_DefMask and optCSE_UseMask
5651 static fgWalkPreFn optCSE_MaskHelper;
5653 // This function walks all the node for an given tree
5654 // and return the mask of CSE definitions and uses for the tree
5656 void optCSE_GetMaskData(GenTreePtr tree, optCSE_MaskData* pMaskData);
5658 // Given a binary tree node return true if it is safe to swap the order of evaluation for op1 and op2.
5659 bool optCSE_canSwap(GenTree* firstNode, GenTree* secondNode);
5660 bool optCSE_canSwap(GenTree* tree);
5662 static fgWalkPostFn optPropagateNonCSE;
5663 static fgWalkPreFn optHasNonCSEChild;
5665 static fgWalkPreFn optUnmarkCSEs;
5667 static int __cdecl optCSEcostCmpEx(const void* op1, const void* op2);
5668 static int __cdecl optCSEcostCmpSz(const void* op1, const void* op2);
5670 void optCleanupCSEs();
5673 void optEnsureClearCSEInfo();
5676 #endif // FEATURE_ANYCSE
5678 #if FEATURE_VALNUM_CSE
5679 /**************************************************************************
5680 * Value Number based CSEs
5681 *************************************************************************/
5684 void optOptimizeValnumCSEs();
5687 void optValnumCSE_Init();
5688 unsigned optValnumCSE_Index(GenTreePtr tree, GenTreePtr stmt);
5689 unsigned optValnumCSE_Locate();
5690 void optValnumCSE_InitDataFlow();
5691 void optValnumCSE_DataFlow();
5692 void optValnumCSE_Availablity();
5693 void optValnumCSE_Heuristic();
5694 void optValnumCSE_UnmarkCSEs(GenTreePtr deadTree, GenTreePtr keepList);
5696 #endif // FEATURE_VALNUM_CSE
5699 bool optDoCSE; // True when we have found a duplicate CSE tree
5700 bool optValnumCSE_phase; // True when we are executing the optValnumCSE_phase
5701 unsigned optCSECandidateTotal; // Grand total of CSE candidates for both Lexical and ValNum
5702 unsigned optCSECandidateCount; // Count of CSE's candidates, reset for Lexical and ValNum CSE's
5703 unsigned optCSEstart; // The first local variable number that is a CSE
5704 unsigned optCSEcount; // The total count of CSE's introduced.
5705 unsigned optCSEweight; // The weight of the current block when we are
5706 // scanning for CSE expressions
5708 bool optIsCSEcandidate(GenTreePtr tree);
5710 // lclNumIsTrueCSE returns true if the LclVar was introduced by the CSE phase of the compiler
5712 bool lclNumIsTrueCSE(unsigned lclNum) const
5714 return ((optCSEcount > 0) && (lclNum >= optCSEstart) && (lclNum < optCSEstart + optCSEcount));
5717 // lclNumIsCSE returns true if the LclVar should be treated like a CSE with regards to constant prop.
5719 bool lclNumIsCSE(unsigned lclNum) const
5721 return lvaTable[lclNum].lvIsCSE;
5725 bool optConfigDisableCSE();
5726 bool optConfigDisableCSE2();
5728 void optOptimizeCSEs();
5730 #endif // FEATURE_ANYCSE
5738 unsigned ivaVar; // Variable we are interested in, or -1
5739 ALLVARSET_TP ivaMaskVal; // Set of variables assigned to. This is a set of all vars, not tracked vars.
5740 bool ivaMaskIncomplete; // Variables not representable in ivaMaskVal were assigned to.
5741 varRefKinds ivaMaskInd; // What kind of indirect assignments are there?
5742 callInterf ivaMaskCall; // What kind of calls are there?
5745 static callInterf optCallInterf(GenTreeCall* call);
5748 // VN based copy propagation.
5749 typedef ArrayStack<GenTreePtr> GenTreePtrStack;
5750 typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, GenTreePtrStack*> LclNumToGenTreePtrStack;
5752 // Kill set to track variables with intervening definitions.
5753 VARSET_TP optCopyPropKillSet;
5755 // Copy propagation functions.
5756 void optCopyProp(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree, LclNumToGenTreePtrStack* curSsaName);
5757 void optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
5758 void optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
5759 bool optIsSsaLocal(GenTreePtr tree);
5760 int optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2);
5761 void optVnCopyProp();
5763 /**************************************************************************
5764 * Early value propagation
5765 *************************************************************************/
5771 SSAName(unsigned lvNum, unsigned ssaNum) : m_lvNum(lvNum), m_ssaNum(ssaNum)
5775 static unsigned GetHashCode(SSAName ssaNm)
5777 return (ssaNm.m_lvNum << 16) | (ssaNm.m_ssaNum);
5780 static bool Equals(SSAName ssaNm1, SSAName ssaNm2)
5782 return (ssaNm1.m_lvNum == ssaNm2.m_lvNum) && (ssaNm1.m_ssaNum == ssaNm2.m_ssaNum);
5786 #define OMF_HAS_NEWARRAY 0x00000001 // Method contains 'new' of an array
5787 #define OMF_HAS_NEWOBJ 0x00000002 // Method contains 'new' of an object type.
5788 #define OMF_HAS_ARRAYREF 0x00000004 // Method contains array element loads or stores.
5789 #define OMF_HAS_VTABLEREF 0x00000008 // Method contains method table reference.
5790 #define OMF_HAS_NULLCHECK 0x00000010 // Method contains null check.
5791 #define OMF_HAS_FATPOINTER 0x00000020 // Method contains call, that needs fat pointer transformation.
5793 bool doesMethodHaveFatPointer()
5795 return (optMethodFlags & OMF_HAS_FATPOINTER) != 0;
5798 void setMethodHasFatPointer()
5800 optMethodFlags |= OMF_HAS_FATPOINTER;
5803 void clearMethodHasFatPointer()
5805 optMethodFlags &= ~OMF_HAS_FATPOINTER;
5808 void addFatPointerCandidate(GenTreeCall* call);
5810 unsigned optMethodFlags;
5812 // Recursion bound controls how far we can go backwards tracking for a SSA value.
5813 // No throughput diff was found with backward walk bound between 3-8.
5814 static const int optEarlyPropRecurBound = 5;
5816 enum class optPropKind
5824 bool gtIsVtableRef(GenTreePtr tree);
5825 GenTreePtr getArrayLengthFromAllocation(GenTreePtr tree);
5826 GenTreePtr getObjectHandleNodeFromAllocation(GenTreePtr tree);
5827 GenTreePtr optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropKind valueKind, int walkDepth);
5828 GenTreePtr optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind);
5829 GenTreePtr optEarlyPropRewriteTree(GenTreePtr tree);
5830 bool optDoEarlyPropForBlock(BasicBlock* block);
5831 bool optDoEarlyPropForFunc();
5832 void optEarlyProp();
5833 void optFoldNullCheck(GenTreePtr tree);
5834 bool optCanMoveNullCheckPastTree(GenTreePtr tree, bool isInsideTry);
5837 /**************************************************************************
5838 * Value/Assertion propagation
5839 *************************************************************************/
5841 // Data structures for assertion prop
5842 BitVecTraits* apTraits;
5845 enum optAssertionKind
5862 O1K_CONSTANT_LOOP_BND,
5883 optAssertionKind assertionKind;
5886 unsigned lclNum; // assigned to or property of this local var number
5894 struct AssertionDscOp1
5896 optOp1Kind kind; // a normal LclVar, or Exact-type or Subtype
5903 struct AssertionDscOp2
5905 optOp2Kind kind; // a const or copy assignment
5909 ssize_t iconVal; // integer
5910 unsigned iconFlags; // gtFlags
5912 struct Range // integer subrange
5926 bool IsCheckedBoundArithBound()
5928 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_BOUND_OPER_BND);
5930 bool IsCheckedBoundBound()
5932 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_BOUND_LOOP_BND);
5934 bool IsConstantBound()
5936 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) &&
5937 op1.kind == O1K_CONSTANT_LOOP_BND);
5939 bool IsBoundsCheckNoThrow()
5941 return ((assertionKind == OAK_NO_THROW) && (op1.kind == O1K_ARR_BND));
5944 bool IsCopyAssertion()
5946 return ((assertionKind == OAK_EQUAL) && (op1.kind == O1K_LCLVAR) && (op2.kind == O2K_LCLVAR_COPY));
5949 static bool SameKind(AssertionDsc* a1, AssertionDsc* a2)
5951 return a1->assertionKind == a2->assertionKind && a1->op1.kind == a2->op1.kind &&
5952 a1->op2.kind == a2->op2.kind;
5955 static bool ComplementaryKind(optAssertionKind kind, optAssertionKind kind2)
5957 if (kind == OAK_EQUAL)
5959 return kind2 == OAK_NOT_EQUAL;
5961 else if (kind == OAK_NOT_EQUAL)
5963 return kind2 == OAK_EQUAL;
5968 static ssize_t GetLowerBoundForIntegralType(var_types type)
5987 static ssize_t GetUpperBoundForIntegralType(var_types type)
6010 bool HasSameOp1(AssertionDsc* that, bool vnBased)
6012 if (op1.kind != that->op1.kind)
6016 else if (op1.kind == O1K_ARR_BND)
6019 return (op1.bnd.vnIdx == that->op1.bnd.vnIdx) && (op1.bnd.vnLen == that->op1.bnd.vnLen);
6023 return ((vnBased && (op1.vn == that->op1.vn)) ||
6024 (!vnBased && (op1.lcl.lclNum == that->op1.lcl.lclNum)));
6028 bool HasSameOp2(AssertionDsc* that, bool vnBased)
6030 if (op2.kind != that->op2.kind)
6036 case O2K_IND_CNS_INT:
6038 return ((op2.u1.iconVal == that->op2.u1.iconVal) && (op2.u1.iconFlags == that->op2.u1.iconFlags));
6040 case O2K_CONST_LONG:
6041 return (op2.lconVal == that->op2.lconVal);
6043 case O2K_CONST_DOUBLE:
6044 // exact match because of positive and negative zero.
6045 return (memcmp(&op2.dconVal, &that->op2.dconVal, sizeof(double)) == 0);
6047 case O2K_LCLVAR_COPY:
6049 return (op2.lcl.lclNum == that->op2.lcl.lclNum) &&
6050 (!vnBased || op2.lcl.ssaNum == that->op2.lcl.ssaNum);
6053 return ((op2.u2.loBound == that->op2.u2.loBound) && (op2.u2.hiBound == that->op2.u2.hiBound));
6056 // we will return false
6060 assert(!"Unexpected value for op2.kind in AssertionDsc.");
6066 bool Complementary(AssertionDsc* that, bool vnBased)
6068 return ComplementaryKind(assertionKind, that->assertionKind) && HasSameOp1(that, vnBased) &&
6069 HasSameOp2(that, vnBased);
6072 bool Equals(AssertionDsc* that, bool vnBased)
6074 if (assertionKind != that->assertionKind)
6078 else if (assertionKind == OAK_NO_THROW)
6080 assert(op2.kind == O2K_INVALID);
6081 return HasSameOp1(that, vnBased);
6085 return HasSameOp1(that, vnBased) && HasSameOp2(that, vnBased);
6091 static fgWalkPreFn optAddCopiesCallback;
6092 static fgWalkPreFn optVNAssertionPropCurStmtVisitor;
6093 unsigned optAddCopyLclNum;
6094 GenTreePtr optAddCopyAsgnNode;
6096 bool optLocalAssertionProp; // indicates that we are performing local assertion prop
6097 bool optAssertionPropagated; // set to true if we modified the trees
6098 bool optAssertionPropagatedCurrentStmt;
6100 GenTreePtr optAssertionPropCurrentTree;
6102 AssertionIndex* optComplementaryAssertionMap;
6103 JitExpandArray<ASSERT_TP>* optAssertionDep; // table that holds dependent assertions (assertions
6104 // using the value of a local var) for each local var
6105 AssertionDsc* optAssertionTabPrivate; // table that holds info about value assignments
6106 AssertionIndex optAssertionCount; // total number of assertions in the assertion table
6107 AssertionIndex optMaxAssertionCount;
6110 void optVnNonNullPropCurStmt(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree);
6111 fgWalkResult optVNConstantPropCurStmt(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree);
6112 GenTreePtr optVNConstantPropOnRelOp(GenTreePtr tree);
6113 GenTreePtr optVNConstantPropOnJTrue(BasicBlock* block, GenTreePtr stmt, GenTreePtr test);
6114 GenTreePtr optVNConstantPropOnTree(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree);
6115 GenTreePtr optPrepareTreeForReplacement(GenTreePtr extractTree, GenTreePtr replaceTree);
6117 AssertionIndex GetAssertionCount()
6119 return optAssertionCount;
6121 ASSERT_TP* bbJtrueAssertionOut;
6122 typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, ASSERT_TP> ValueNumToAssertsMap;
6123 ValueNumToAssertsMap* optValueNumToAsserts;
6125 // Assertion prop helpers.
6126 ASSERT_TP& GetAssertionDep(unsigned lclNum);
6127 AssertionDsc* optGetAssertion(AssertionIndex assertIndex);
6128 void optAssertionInit(bool isLocalProp);
6129 void optAssertionTraitsInit(AssertionIndex assertionCount);
6130 #if LOCAL_ASSERTION_PROP
6131 void optAssertionReset(AssertionIndex limit);
6132 void optAssertionRemove(AssertionIndex index);
6135 // Assertion prop data flow functions.
6136 void optAssertionPropMain();
6137 GenTreePtr optVNAssertionPropCurStmt(BasicBlock* block, GenTreePtr stmt);
6138 bool optIsTreeKnownIntValue(bool vnBased, GenTreePtr tree, ssize_t* pConstant, unsigned* pIconFlags);
6139 ASSERT_TP* optInitAssertionDataflowFlags();
6140 ASSERT_TP* optComputeAssertionGen();
6142 // Assertion Gen functions.
6143 void optAssertionGen(GenTreePtr tree);
6144 AssertionIndex optAssertionGenPhiDefn(GenTreePtr tree);
6145 AssertionInfo optCreateJTrueBoundsAssertion(GenTreePtr tree);
6146 AssertionInfo optAssertionGenJtrue(GenTreePtr tree);
6147 AssertionIndex optCreateJtrueAssertions(GenTreePtr op1, GenTreePtr op2, Compiler::optAssertionKind assertionKind);
6148 AssertionIndex optFindComplementary(AssertionIndex assertionIndex);
6149 void optMapComplementary(AssertionIndex assertionIndex, AssertionIndex index);
6151 // Assertion creation functions.
6152 AssertionIndex optCreateAssertion(GenTreePtr op1, GenTreePtr op2, optAssertionKind assertionKind);
6153 AssertionIndex optCreateAssertion(GenTreePtr op1,
6155 optAssertionKind assertionKind,
6156 AssertionDsc* assertion);
6157 void optCreateComplementaryAssertion(AssertionIndex assertionIndex, GenTreePtr op1, GenTreePtr op2);
6159 bool optAssertionVnInvolvesNan(AssertionDsc* assertion);
6160 AssertionIndex optAddAssertion(AssertionDsc* assertion);
6161 void optAddVnAssertionMapping(ValueNum vn, AssertionIndex index);
6163 void optPrintVnAssertionMapping();
6165 ASSERT_TP optGetVnMappedAssertions(ValueNum vn);
6167 // Used for respective assertion propagations.
6168 AssertionIndex optAssertionIsSubrange(GenTreePtr tree, var_types toType, ASSERT_VALARG_TP assertions);
6169 AssertionIndex optAssertionIsSubtype(GenTreePtr tree, GenTreePtr methodTableArg, ASSERT_VALARG_TP assertions);
6170 AssertionIndex optAssertionIsNonNullInternal(GenTreePtr op, ASSERT_VALARG_TP assertions);
6171 bool optAssertionIsNonNull(GenTreePtr op,
6172 ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased) DEBUGARG(AssertionIndex* pIndex));
6174 // Used for Relop propagation.
6175 AssertionIndex optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP assertions, GenTreePtr op1, GenTreePtr op2);
6176 AssertionIndex optLocalAssertionIsEqualOrNotEqual(
6177 optOp1Kind op1Kind, unsigned lclNum, optOp2Kind op2Kind, ssize_t cnsVal, ASSERT_VALARG_TP assertions);
6179 // Assertion prop for lcl var functions.
6180 bool optAssertionProp_LclVarTypeCheck(GenTreePtr tree, LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc);
6181 GenTreePtr optCopyAssertionProp(AssertionDsc* curAssertion,
6183 GenTreePtr stmt DEBUGARG(AssertionIndex index));
6184 GenTreePtr optConstantAssertionProp(AssertionDsc* curAssertion,
6185 const GenTreePtr tree,
6186 const GenTreePtr stmt DEBUGARG(AssertionIndex index));
6187 GenTreePtr optVnConstantAssertionProp(const GenTreePtr tree, const GenTreePtr stmt);
6189 // Assertion propagation functions.
6190 GenTreePtr optAssertionProp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6191 GenTreePtr optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6192 GenTreePtr optAssertionProp_Ind(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6193 GenTreePtr optAssertionProp_Cast(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6194 GenTreePtr optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, const GenTreePtr stmt);
6195 GenTreePtr optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6196 GenTreePtr optAssertionProp_Comma(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6197 GenTreePtr optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6198 GenTreePtr optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6199 GenTreePtr optAssertionPropLocal_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6200 GenTreePtr optAssertionProp_Update(const GenTreePtr newTree, const GenTreePtr tree, const GenTreePtr stmt);
6201 GenTreePtr optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, const GenTreePtr stmt);
6203 // Implied assertion functions.
6204 void optImpliedAssertions(AssertionIndex assertionIndex, ASSERT_TP& activeAssertions);
6205 void optImpliedByTypeOfAssertions(ASSERT_TP& activeAssertions);
6206 void optImpliedByCopyAssertion(AssertionDsc* copyAssertion, AssertionDsc* depAssertion, ASSERT_TP& result);
6207 void optImpliedByConstAssertion(AssertionDsc* curAssertion, ASSERT_TP& result);
6210 void optPrintAssertion(AssertionDsc* newAssertion, AssertionIndex assertionIndex = 0);
6211 void optDebugCheckAssertion(AssertionDsc* assertion);
6212 void optDebugCheckAssertions(AssertionIndex AssertionIndex);
6214 void optAddCopies();
6215 #endif // ASSERTION_PROP
6217 /**************************************************************************
6219 *************************************************************************/
6222 struct LoopCloneVisitorInfo
6224 LoopCloneContext* context;
6227 LoopCloneVisitorInfo(LoopCloneContext* context, unsigned loopNum, GenTreePtr stmt)
6228 : context(context), loopNum(loopNum), stmt(nullptr)
6233 bool optIsStackLocalInvariant(unsigned loopNum, unsigned lclNum);
6234 bool optExtractArrIndex(GenTreePtr tree, ArrIndex* result, unsigned lhsNum);
6235 bool optReconstructArrIndex(GenTreePtr tree, ArrIndex* result, unsigned lhsNum);
6236 bool optIdentifyLoopOptInfo(unsigned loopNum, LoopCloneContext* context);
6237 static fgWalkPreFn optCanOptimizeByLoopCloningVisitor;
6238 fgWalkResult optCanOptimizeByLoopCloning(GenTreePtr tree, LoopCloneVisitorInfo* info);
6239 void optObtainLoopCloningOpts(LoopCloneContext* context);
6240 bool optIsLoopClonable(unsigned loopInd);
6242 bool optCanCloneLoops();
6245 void optDebugLogLoopCloning(BasicBlock* block, GenTreePtr insertBefore);
6247 void optPerformStaticOptimizations(unsigned loopNum, LoopCloneContext* context DEBUGARG(bool fastPath));
6248 bool optComputeDerefConditions(unsigned loopNum, LoopCloneContext* context);
6249 bool optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext* context);
6250 BasicBlock* optInsertLoopChoiceConditions(LoopCloneContext* context,
6254 void optInsertLoopCloningStress(BasicBlock* head);
6256 #if COUNT_RANGECHECKS
6257 static unsigned optRangeChkRmv;
6258 static unsigned optRangeChkAll;
6267 #define MAX_ARRAYS 4 // a magic max number of arrays tracked for bounds check elimination
6272 RngChkDsc* rcdNextInBucket; // used by the hash table
6274 unsigned short rcdHashValue; // to make matching faster
6275 unsigned short rcdIndex; // 0..optRngChkCount-1
6277 GenTreePtr rcdTree; // the array index tree
6280 unsigned optRngChkCount;
6281 static const size_t optRngChkHashSize;
6283 ssize_t optGetArrayRefScaleAndIndex(GenTreePtr mul, GenTreePtr* pIndex DEBUGARG(bool bRngChk));
6284 GenTreePtr optFindLocalInit(BasicBlock* block, GenTreePtr local, VARSET_TP* pKilledInOut, bool* isKilledAfterInit);
6286 bool optReachWithoutCall(BasicBlock* srcBB, BasicBlock* dstBB);
6289 bool optLoopsMarked;
6292 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6293 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6297 XX Does the register allocation and puts the remaining lclVars on the stack XX
6299 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6300 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6304 #ifndef LEGACY_BACKEND
6309 #else // LEGACY_BACKEND
6314 #endif // LEGACY_BACKEND
6316 #ifdef LEGACY_BACKEND
6318 void raAssignVars(); // register allocation
6319 #endif // LEGACY_BACKEND
6321 VARSET_TP raRegVarsMask; // Set of all enregistered variables (not including FEATURE_STACK_FP_X87 enregistered
6323 regNumber raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc);
6325 void raMarkStkVars();
6328 // Some things are used by both LSRA and regpredict allocators.
6330 FrameType rpFrameType;
6331 bool rpMustCreateEBPCalled; // Set to true after we have called rpMustCreateEBPFrame once
6333 #ifdef LEGACY_BACKEND
6334 regMaskTP rpMaskPInvokeEpilogIntf; // pinvoke epilog trashes esi/edi holding stack args needed to setup tail call's
6336 #endif // LEGACY_BACKEND
6338 bool rpMustCreateEBPFrame(INDEBUG(const char** wbReason));
6340 #if FEATURE_FP_REGALLOC
6341 enum enumConfigRegisterFP
6343 CONFIG_REGISTER_FP_NONE = 0x0,
6344 CONFIG_REGISTER_FP_CALLEE_TRASH = 0x1,
6345 CONFIG_REGISTER_FP_CALLEE_SAVED = 0x2,
6346 CONFIG_REGISTER_FP_FULL = 0x3,
6348 enumConfigRegisterFP raConfigRegisterFP();
6349 #endif // FEATURE_FP_REGALLOC
6352 regMaskTP raConfigRestrictMaskFP();
6355 #ifndef LEGACY_BACKEND
6356 Lowering* m_pLowering; // Lowering; needed to Lower IR that's added or modified after Lowering.
6357 LinearScanInterface* m_pLinearScan; // Linear Scan allocator
6358 #else // LEGACY_BACKEND
6359 unsigned raAvoidArgRegMask; // Mask of incoming argument registers that we may need to avoid
6360 VARSET_TP raLclRegIntf[REG_COUNT]; // variable to register interference graph
6361 bool raNewBlocks; // True is we added killing blocks for FPU registers
6362 unsigned rpPasses; // Number of passes made by the register predicter
6363 unsigned rpPassesMax; // Maximum number of passes made by the register predicter
6364 unsigned rpPassesPessimize; // Number of passes non-pessimizing made by the register predicter
6365 unsigned rpStkPredict; // Weighted count of variables were predicted STK (lower means register allocation is better)
6366 unsigned rpPredictSpillCnt; // Predicted number of integer spill tmps for the current tree
6367 regMaskTP rpPredictAssignMask; // Mask of registers to consider in rpPredictAssignRegVars()
6368 VARSET_TP rpLastUseVars; // Set of last use variables in rpPredictTreeRegUse
6369 VARSET_TP rpUseInPlace; // Set of variables that we used in place
6370 int rpAsgVarNum; // VarNum for the target of GT_ASG node
6371 bool rpPredictAssignAgain; // Must rerun the rpPredictAssignRegVars()
6372 bool rpAddedVarIntf; // Set to true if we need to add a new var intf
6373 bool rpLostEnreg; // Set to true if we lost an enregister var that had lvDependReg set
6374 bool rpReverseEBPenreg; // Decided to reverse the enregistration of EBP
6376 bool rpRegAllocDone; // Set to true after we have completed register allocation
6378 regMaskTP rpPredictMap[PREDICT_COUNT]; // Holds the regMaskTP for each of the enum values
6380 void raSetupArgMasks(RegState* r);
6382 const regNumber* raGetRegVarOrder(var_types regType, unsigned* wbVarOrderSize);
6384 void raDumpVarIntf(); // Dump the variable to variable interference graph
6385 void raDumpRegIntf(); // Dump the variable to register interference graph
6387 void raAdjustVarIntf();
6389 regMaskTP rpPredictRegMask(rpPredictReg predictReg, var_types type);
6391 bool rpRecordRegIntf(regMaskTP regMask, VARSET_VALARG_TP life DEBUGARG(const char* msg));
6393 bool rpRecordVarIntf(unsigned varNum, VARSET_VALARG_TP intfVar DEBUGARG(const char* msg));
6394 regMaskTP rpPredictRegPick(var_types type, rpPredictReg predictReg, regMaskTP lockedRegs);
6396 regMaskTP rpPredictGrabReg(var_types type, rpPredictReg predictReg, regMaskTP lockedRegs);
6398 static fgWalkPreFn rpMarkRegIntf;
6400 regMaskTP rpPredictAddressMode(
6401 GenTreePtr tree, var_types type, regMaskTP lockedRegs, regMaskTP rsvdRegs, GenTreePtr lenCSE);
6403 void rpPredictRefAssign(unsigned lclNum);
6405 regMaskTP rpPredictBlkAsgRegUse(GenTreePtr tree, rpPredictReg predictReg, regMaskTP lockedRegs, regMaskTP rsvdRegs);
6407 regMaskTP rpPredictTreeRegUse(GenTreePtr tree, rpPredictReg predictReg, regMaskTP lockedRegs, regMaskTP rsvdRegs);
6409 regMaskTP rpPredictAssignRegVars(regMaskTP regAvail);
6411 void rpPredictRegUse(); // Entry point
6413 unsigned raPredictTreeRegUse(GenTreePtr tree);
6414 unsigned raPredictListRegUse(GenTreePtr list);
6416 void raSetRegVarOrder(var_types regType,
6417 regNumber* customVarOrder,
6418 unsigned* customVarOrderSize,
6420 regMaskTP avoidReg);
6422 // We use (unsigned)-1 as an uninitialized sentinel for rpStkPredict and
6423 // also as the maximum value of lvRefCntWtd. Don't allow overflow, and
6424 // saturate at UINT_MAX - 1, to avoid using the sentinel.
6425 void raAddToStkPredict(unsigned val)
6427 unsigned newStkPredict = rpStkPredict + val;
6428 if ((newStkPredict < rpStkPredict) || (newStkPredict == UINT_MAX))
6429 rpStkPredict = UINT_MAX - 1;
6431 rpStkPredict = newStkPredict;
6435 #if !FEATURE_FP_REGALLOC
6436 void raDispFPlifeInfo();
6440 regMaskTP genReturnRegForTree(GenTreePtr tree);
6441 #endif // LEGACY_BACKEND
6443 /* raIsVarargsStackArg is called by raMaskStkVars and by
6444 lvaSortByRefCount. It identifies the special case
6445 where a varargs function has a parameter passed on the
6446 stack, other than the special varargs handle. Such parameters
6447 require special treatment, because they cannot be tracked
6448 by the GC (their offsets in the stack are not known
6452 bool raIsVarargsStackArg(unsigned lclNum)
6456 LclVarDsc* varDsc = &lvaTable[lclNum];
6458 assert(varDsc->lvIsParam);
6460 return (info.compIsVarArgs && !varDsc->lvIsRegArg && (lclNum != lvaVarargsHandleArg));
6462 #else // _TARGET_X86_
6466 #endif // _TARGET_X86_
6469 #ifdef LEGACY_BACKEND
6470 // Records the current prediction, if it's better than any previous recorded prediction.
6471 void rpRecordPrediction();
6472 // Applies the best recorded prediction, if one exists and is better than the current prediction.
6473 void rpUseRecordedPredictionIfBetter();
6475 // Data members used in the methods above.
6476 unsigned rpBestRecordedStkPredict;
6477 struct VarRegPrediction
6479 bool m_isEnregistered;
6480 regNumberSmall m_regNum;
6481 regNumberSmall m_otherReg;
6483 VarRegPrediction* rpBestRecordedPrediction;
6484 #endif // LEGACY_BACKEND
6487 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6488 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6492 XX Get to the class and method info from the Execution Engine given XX
6493 XX tokens for the class and method XX
6495 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6496 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6500 /* These are the different addressing modes used to access a local var.
6501 * The JIT has to report the location of the locals back to the EE
6502 * for debugging purposes.
6508 VLT_REG_BYREF, // this type is currently only used for value types on X64
6511 VLT_STK_BYREF, // this type is currently only used for value types on X64
6525 siVarLocType vlType;
6528 // VLT_REG/VLT_REG_FP -- Any pointer-sized enregistered value (TYP_INT, TYP_REF, etc)
6530 // VLT_REG_BYREF -- the specified register contains the address of the variable
6538 // VLT_STK -- Any 32 bit value which is on the stack
6539 // eg. [ESP+0x20], or [EBP-0x28]
6540 // VLT_STK_BYREF -- the specified stack location contains the address of the variable
6541 // eg. mov EAX, [ESP+0x20]; [EAX]
6545 regNumber vlsBaseReg;
6546 NATIVE_OFFSET vlsOffset;
6549 // VLT_REG_REG -- TYP_LONG/TYP_DOUBLE with both DWords enregistered
6558 // VLT_REG_STK -- Partly enregistered TYP_LONG/TYP_DOUBLE
6559 // eg { LowerDWord=EAX UpperDWord=[ESP+0x8] }
6567 regNumber vlrssBaseReg;
6568 NATIVE_OFFSET vlrssOffset;
6572 // VLT_STK_REG -- Partly enregistered TYP_LONG/TYP_DOUBLE
6573 // eg { LowerDWord=[ESP+0x8] UpperDWord=EAX }
6579 regNumber vlsrsBaseReg;
6580 NATIVE_OFFSET vlsrsOffset;
6586 // VLT_STK2 -- Any 64 bit value which is on the stack, in 2 successsive DWords
6587 // eg 2 DWords at [ESP+0x10]
6591 regNumber vls2BaseReg;
6592 NATIVE_OFFSET vls2Offset;
6595 // VLT_FPSTK -- enregisterd TYP_DOUBLE (on the FP stack)
6596 // eg. ST(3). Actually it is ST("FPstkHeight - vpFpStk")
6603 // VLT_FIXED_VA -- fixed argument of a varargs function.
6604 // The argument location depends on the size of the variable
6605 // arguments (...). Inspecting the VARARGS_HANDLE indicates the
6606 // location of the first arg. This argument can then be accessed
6607 // relative to the position of the first arg
6611 unsigned vlfvOffset;
6618 void* rpValue; // pointer to the in-process
6619 // location of the value.
6625 bool vlIsInReg(regNumber reg);
6626 bool vlIsOnStk(regNumber reg, signed offset);
6629 /*************************************************************************/
6634 void eeGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6635 CORINFO_RESOLVED_TOKEN* pConstrainedToken,
6636 CORINFO_CALLINFO_FLAGS flags,
6637 CORINFO_CALL_INFO* pResult);
6638 inline CORINFO_CALLINFO_FLAGS addVerifyFlag(CORINFO_CALLINFO_FLAGS flags);
6640 void eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6641 CORINFO_ACCESS_FLAGS flags,
6642 CORINFO_FIELD_INFO* pResult);
6646 BOOL eeIsValueClass(CORINFO_CLASS_HANDLE clsHnd);
6648 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(TRACK_LSRA_STATS)
6650 bool IsSuperPMIException(unsigned code)
6652 // Copied from NDP\clr\src\ToolBox\SuperPMI\SuperPMI-Shared\ErrorHandling.h
6654 const unsigned EXCEPTIONCODE_DebugBreakorAV = 0xe0421000;
6655 const unsigned EXCEPTIONCODE_MC = 0xe0422000;
6656 const unsigned EXCEPTIONCODE_LWM = 0xe0423000;
6657 const unsigned EXCEPTIONCODE_SASM = 0xe0424000;
6658 const unsigned EXCEPTIONCODE_SSYM = 0xe0425000;
6659 const unsigned EXCEPTIONCODE_CALLUTILS = 0xe0426000;
6660 const unsigned EXCEPTIONCODE_TYPEUTILS = 0xe0427000;
6661 const unsigned EXCEPTIONCODE_ASSERT = 0xe0440000;
6665 case EXCEPTIONCODE_DebugBreakorAV:
6666 case EXCEPTIONCODE_MC:
6667 case EXCEPTIONCODE_LWM:
6668 case EXCEPTIONCODE_SASM:
6669 case EXCEPTIONCODE_SSYM:
6670 case EXCEPTIONCODE_CALLUTILS:
6671 case EXCEPTIONCODE_TYPEUTILS:
6672 case EXCEPTIONCODE_ASSERT:
6679 const char* eeGetMethodName(CORINFO_METHOD_HANDLE hnd, const char** className);
6680 const char* eeGetMethodFullName(CORINFO_METHOD_HANDLE hnd);
6682 bool eeIsNativeMethod(CORINFO_METHOD_HANDLE method);
6683 CORINFO_METHOD_HANDLE eeGetMethodHandleForNative(CORINFO_METHOD_HANDLE method);
6686 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6687 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig, bool* isPinned);
6688 unsigned eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6690 // VOM info, method sigs
6692 void eeGetSig(unsigned sigTok,
6693 CORINFO_MODULE_HANDLE scope,
6694 CORINFO_CONTEXT_HANDLE context,
6695 CORINFO_SIG_INFO* retSig);
6697 void eeGetCallSiteSig(unsigned sigTok,
6698 CORINFO_MODULE_HANDLE scope,
6699 CORINFO_CONTEXT_HANDLE context,
6700 CORINFO_SIG_INFO* retSig);
6702 void eeGetMethodSig(CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* retSig, CORINFO_CLASS_HANDLE owner = nullptr);
6704 // Method entry-points, instrs
6706 void* eeGetFieldAddress(CORINFO_FIELD_HANDLE handle, void*** ppIndir);
6708 CORINFO_METHOD_HANDLE eeMarkNativeTarget(CORINFO_METHOD_HANDLE method);
6710 CORINFO_EE_INFO eeInfo;
6711 bool eeInfoInitialized;
6713 CORINFO_EE_INFO* eeGetEEInfo();
6715 // Gets the offset of a SDArray's first element
6716 unsigned eeGetArrayDataOffset(var_types type);
6717 // Gets the offset of a MDArray's first element
6718 unsigned eeGetMDArrayDataOffset(var_types type, unsigned rank);
6720 GenTreePtr eeGetPInvokeCookie(CORINFO_SIG_INFO* szMetaSig);
6722 // Returns the page size for the target machine as reported by the EE.
6723 inline size_t eeGetPageSize()
6725 return eeGetEEInfo()->osPageSize;
6728 // Returns the frame size at which we will generate a loop to probe the stack.
6729 inline size_t getVeryLargeFrameSize()
6732 // The looping probe code is 40 bytes, whereas the straight-line probing for
6733 // the (0x2000..0x3000) case is 44, so use looping for anything 0x2000 bytes
6734 // or greater, to generate smaller code.
6735 return 2 * eeGetPageSize();
6737 return 3 * eeGetPageSize();
6741 //------------------------------------------------------------------------
6742 // VirtualStubParam: virtual stub dispatch extra parameter (slot address).
6744 // It represents Abi and target specific registers for the parameter.
6746 class VirtualStubParamInfo
6749 VirtualStubParamInfo(bool isCoreRTABI)
6751 #if defined(_TARGET_X86_)
6754 #elif defined(_TARGET_AMD64_)
6765 #elif defined(_TARGET_ARM_)
6776 #elif defined(_TARGET_ARM64_)
6780 #error Unsupported or unset target architecture
6783 #ifdef LEGACY_BACKEND
6784 #if defined(_TARGET_X86_)
6785 predict = PREDICT_REG_EAX;
6786 #elif defined(_TARGET_ARM_)
6787 predict = PREDICT_REG_R4;
6789 #error Unsupported or unset target architecture
6791 #endif // LEGACY_BACKEND
6794 regNumber GetReg() const
6799 _regMask_enum GetRegMask() const
6804 #ifdef LEGACY_BACKEND
6805 rpPredictReg GetPredict() const
6813 _regMask_enum regMask;
6815 #ifdef LEGACY_BACKEND
6816 rpPredictReg predict;
6820 VirtualStubParamInfo* virtualStubParamInfo;
6822 inline bool IsTargetAbi(CORINFO_RUNTIME_ABI abi)
6824 return eeGetEEInfo()->targetAbi == abi;
6827 inline bool generateCFIUnwindCodes()
6829 #if defined(_TARGET_UNIX_)
6830 return IsTargetAbi(CORINFO_CORERT_ABI);
6838 unsigned eeGetEHcount(CORINFO_METHOD_HANDLE handle);
6840 // Debugging support - Line number info
6842 void eeGetStmtOffsets();
6844 unsigned eeBoundariesCount;
6846 struct boundariesDsc
6848 UNATIVE_OFFSET nativeIP;
6850 unsigned sourceReason;
6851 } * eeBoundaries; // Boundaries to report to EE
6852 void eeSetLIcount(unsigned count);
6853 void eeSetLIinfo(unsigned which, UNATIVE_OFFSET offs, unsigned srcIP, bool stkEmpty, bool callInstruction);
6857 static void eeDispILOffs(IL_OFFSET offs);
6858 static void eeDispLineInfo(const boundariesDsc* line);
6859 void eeDispLineInfos();
6862 // Debugging support - Local var info
6866 unsigned eeVarsCount;
6868 struct VarResultInfo
6870 UNATIVE_OFFSET startOffset;
6871 UNATIVE_OFFSET endOffset;
6875 void eeSetLVcount(unsigned count);
6876 void eeSetLVinfo(unsigned which,
6877 UNATIVE_OFFSET startOffs,
6878 UNATIVE_OFFSET length,
6883 const siVarLoc& loc);
6887 void eeDispVar(ICorDebugInfo::NativeVarInfo* var);
6888 void eeDispVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars);
6891 // ICorJitInfo wrappers
6893 void eeReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize);
6895 void eeAllocUnwindInfo(BYTE* pHotCode,
6901 CorJitFuncKind funcKind);
6903 void eeSetEHcount(unsigned cEH);
6905 void eeSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause);
6907 WORD eeGetRelocTypeHint(void* target);
6909 // ICorStaticInfo wrapper functions
6911 bool eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken);
6913 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
6915 static void dumpSystemVClassificationType(SystemVClassificationType ct);
6918 void eeGetSystemVAmd64PassStructInRegisterDescriptor(
6919 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
6920 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr);
6921 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
6923 template <typename ParamType>
6924 bool eeRunWithErrorTrap(void (*function)(ParamType*), ParamType* param)
6926 return eeRunWithErrorTrapImp(reinterpret_cast<void (*)(void*)>(function), reinterpret_cast<void*>(param));
6929 bool eeRunWithErrorTrapImp(void (*function)(void*), void* param);
6931 // Utility functions
6933 const char* eeGetFieldName(CORINFO_FIELD_HANDLE fieldHnd, const char** classNamePtr = nullptr);
6936 const wchar_t* eeGetCPString(size_t stringHandle);
6939 const char* eeGetClassName(CORINFO_CLASS_HANDLE clsHnd);
6941 static CORINFO_METHOD_HANDLE eeFindHelper(unsigned helper);
6942 static CorInfoHelpFunc eeGetHelperNum(CORINFO_METHOD_HANDLE method);
6944 static fgWalkPreFn CountSharedStaticHelper;
6945 static bool IsSharedStaticHelper(GenTreePtr tree);
6946 static bool IsTreeAlwaysHoistable(GenTreePtr tree);
6947 static bool IsGcSafePoint(GenTreePtr tree);
6949 static CORINFO_FIELD_HANDLE eeFindJitDataOffs(unsigned jitDataOffs);
6950 // returns true/false if 'field' is a Jit Data offset
6951 static bool eeIsJitDataOffs(CORINFO_FIELD_HANDLE field);
6952 // returns a number < 0 if 'field' is not a Jit Data offset, otherwise the data offset (limited to 2GB)
6953 static int eeGetJitDataOffs(CORINFO_FIELD_HANDLE field);
6955 /*****************************************************************************/
6960 enum TEMP_USAGE_TYPE
6966 static var_types tmpNormalizeType(var_types type);
6967 TempDsc* tmpGetTemp(var_types type); // get temp for the given type
6968 void tmpRlsTemp(TempDsc* temp);
6969 TempDsc* tmpFindNum(int temp, TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const;
6972 TempDsc* tmpListBeg(TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const;
6973 TempDsc* tmpListNxt(TempDsc* curTemp, TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const;
6977 bool tmpAllFree() const;
6980 #ifndef LEGACY_BACKEND
6981 void tmpPreAllocateTemps(var_types type, unsigned count);
6982 #endif // !LEGACY_BACKEND
6985 #ifdef LEGACY_BACKEND
6986 unsigned tmpIntSpillMax; // number of int-sized spill temps
6987 unsigned tmpDoubleSpillMax; // number of double-sized spill temps
6988 #endif // LEGACY_BACKEND
6990 unsigned tmpCount; // Number of temps
6991 unsigned tmpSize; // Size of all the temps
6994 // Used by RegSet::rsSpillChk()
6995 unsigned tmpGetCount; // Temps which haven't been released yet
6998 static unsigned tmpSlot(unsigned size); // which slot in tmpFree[] or tmpUsed[] to use
7000 TempDsc* tmpFree[TEMP_MAX_SIZE / sizeof(int)];
7001 TempDsc* tmpUsed[TEMP_MAX_SIZE / sizeof(int)];
7004 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7005 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7009 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7010 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7014 CodeGenInterface* codeGen;
7016 // The following holds information about instr offsets in terms of generated code.
7020 IPmappingDsc* ipmdNext; // next line# record
7021 IL_OFFSETX ipmdILoffsx; // the instr offset
7022 emitLocation ipmdNativeLoc; // the emitter location of the native code corresponding to the IL offset
7023 bool ipmdIsLabel; // Can this code be a branch label?
7026 // Record the instr offset mapping to the generated code
7028 IPmappingDsc* genIPmappingList;
7029 IPmappingDsc* genIPmappingLast;
7031 // Managed RetVal - A side hash table meant to record the mapping from a
7032 // GT_CALL node to its IL offset. This info is used to emit sequence points
7033 // that can be used by debugger to determine the native offset at which the
7034 // managed RetVal will be available.
7036 // In fact we can store IL offset in a GT_CALL node. This was ruled out in
7037 // favor of a side table for two reasons: 1) We need IL offset for only those
7038 // GT_CALL nodes (created during importation) that correspond to an IL call and
7039 // whose return type is other than TYP_VOID. 2) GT_CALL node is a frequently used
7040 // structure and IL offset is needed only when generating debuggable code. Therefore
7041 // it is desirable to avoid memory size penalty in retail scenarios.
7042 typedef JitHashTable<GenTreePtr, JitPtrKeyFuncs<GenTree>, IL_OFFSETX> CallSiteILOffsetTable;
7043 CallSiteILOffsetTable* genCallSite2ILOffsetMap;
7045 unsigned genReturnLocal; // Local number for the return value when applicable.
7046 BasicBlock* genReturnBB; // jumped to when not optimizing for speed.
7048 // The following properties are part of CodeGenContext. Getters are provided here for
7049 // convenience and backward compatibility, but the properties can only be set by invoking
7050 // the setter on CodeGenContext directly.
7052 __declspec(property(get = getEmitter)) emitter* genEmitter;
7053 emitter* getEmitter()
7055 return codeGen->getEmitter();
7058 const bool isFramePointerUsed()
7060 return codeGen->isFramePointerUsed();
7063 __declspec(property(get = getInterruptible, put = setInterruptible)) bool genInterruptible;
7064 bool getInterruptible()
7066 return codeGen->genInterruptible;
7068 void setInterruptible(bool value)
7070 codeGen->setInterruptible(value);
7074 const bool genDoubleAlign()
7076 return codeGen->doDoubleAlign();
7078 DWORD getCanDoubleAlign();
7079 bool shouldDoubleAlign(unsigned refCntStk,
7081 unsigned refCntWtdReg,
7082 unsigned refCntStkParam,
7083 unsigned refCntWtdStkDbl);
7084 #endif // DOUBLE_ALIGN
7086 __declspec(property(get = getFullPtrRegMap, put = setFullPtrRegMap)) bool genFullPtrRegMap;
7087 bool getFullPtrRegMap()
7089 return codeGen->genFullPtrRegMap;
7091 void setFullPtrRegMap(bool value)
7093 codeGen->setFullPtrRegMap(value);
7096 // Things that MAY belong either in CodeGen or CodeGenContext
7098 #if FEATURE_EH_FUNCLETS
7099 FuncInfoDsc* compFuncInfos;
7100 unsigned short compCurrFuncIdx;
7101 unsigned short compFuncInfoCount;
7103 unsigned short compFuncCount()
7105 assert(fgFuncletsCreated);
7106 return compFuncInfoCount;
7109 #else // !FEATURE_EH_FUNCLETS
7111 // This is a no-op when there are no funclets!
7112 void genUpdateCurrentFunclet(BasicBlock* block)
7117 FuncInfoDsc compFuncInfoRoot;
7119 static const unsigned compCurrFuncIdx = 0;
7121 unsigned short compFuncCount()
7126 #endif // !FEATURE_EH_FUNCLETS
7128 FuncInfoDsc* funCurrentFunc();
7129 void funSetCurrentFunc(unsigned funcIdx);
7130 FuncInfoDsc* funGetFunc(unsigned funcIdx);
7131 unsigned int funGetFuncIdx(BasicBlock* block);
7135 VARSET_TP compCurLife; // current live variables
7136 GenTreePtr compCurLifeTree; // node after which compCurLife has been computed
7138 template <bool ForCodeGen>
7139 void compChangeLife(VARSET_VALARG_TP newLife DEBUGARG(GenTreePtr tree));
7141 void genChangeLife(VARSET_VALARG_TP newLife DEBUGARG(GenTreePtr tree))
7143 compChangeLife</*ForCodeGen*/ true>(newLife DEBUGARG(tree));
7146 template <bool ForCodeGen>
7147 void compUpdateLife(GenTreePtr tree);
7149 // Updates "compCurLife" to its state after evaluate of "true". If "pLastUseVars" is
7150 // non-null, sets "*pLastUseVars" to the set of tracked variables for which "tree" was a last
7151 // use. (Can be more than one var in the case of dependently promoted struct vars.)
7152 template <bool ForCodeGen>
7153 void compUpdateLifeVar(GenTreePtr tree, VARSET_TP* pLastUseVars = nullptr);
7155 template <bool ForCodeGen>
7156 inline void compUpdateLife(VARSET_VALARG_TP newLife);
7158 // Gets a register mask that represent the kill set for a helper call since
7159 // not all JIT Helper calls follow the standard ABI on the target architecture.
7160 regMaskTP compHelperCallKillSet(CorInfoHelpFunc helper);
7162 // Gets a register mask that represent the kill set for a NoGC helper call.
7163 regMaskTP compNoGCHelperCallKillSet(CorInfoHelpFunc helper);
7166 // Requires that "varDsc" be a promoted struct local variable being passed as an argument, beginning at
7167 // "firstArgRegNum", which is assumed to have already been aligned to the register alignment restriction of the
7168 // struct type. Adds bits to "*pArgSkippedRegMask" for any argument registers *not* used in passing "varDsc" --
7169 // i.e., internal "holes" caused by internal alignment constraints. For example, if the struct contained an int and
7170 // a double, and we at R0 (on ARM), then R1 would be skipped, and the bit for R1 would be added to the mask.
7171 void fgAddSkippedRegsInPromotedStructArg(LclVarDsc* varDsc, unsigned firstArgRegNum, regMaskTP* pArgSkippedRegMask);
7172 #endif // _TARGET_ARM_
7174 // If "tree" is a indirection (GT_IND, or GT_OBJ) whose arg is an ADDR, whose arg is a LCL_VAR, return that LCL_VAR
7176 static GenTreePtr fgIsIndirOfAddrOfLocal(GenTreePtr tree);
7178 // This is indexed by GT_OBJ nodes that are address of promoted struct variables, which
7179 // have been annotated with the GTF_VAR_DEATH flag. If such a node is *not* mapped in this
7180 // table, one may assume that all the (tracked) field vars die at this point. Otherwise,
7181 // the node maps to a pointer to a VARSET_TP, containing set bits for each of the tracked field
7182 // vars of the promoted struct local that go dead at the given node (the set bits are the bits
7183 // for the tracked var indices of the field vars, as in a live var set).
7184 NodeToVarsetPtrMap* m_promotedStructDeathVars;
7186 NodeToVarsetPtrMap* GetPromotedStructDeathVars()
7188 if (m_promotedStructDeathVars == nullptr)
7190 m_promotedStructDeathVars = new (getAllocator()) NodeToVarsetPtrMap(getAllocator());
7192 return m_promotedStructDeathVars;
7196 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7197 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7201 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7202 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7205 #if !defined(__GNUC__)
7206 #pragma region Unwind information
7211 // Infrastructure functions: start/stop/reserve/emit.
7214 void unwindBegProlog();
7215 void unwindEndProlog();
7216 void unwindBegEpilog();
7217 void unwindEndEpilog();
7218 void unwindReserve();
7219 void unwindEmit(void* pHotCode, void* pColdCode);
7222 // Specific unwind information functions: called by code generation to indicate a particular
7223 // prolog or epilog unwindable instruction has been generated.
7226 void unwindPush(regNumber reg);
7227 void unwindAllocStack(unsigned size);
7228 void unwindSetFrameReg(regNumber reg, unsigned offset);
7229 void unwindSaveReg(regNumber reg, unsigned offset);
7231 #if defined(_TARGET_ARM_)
7232 void unwindPushMaskInt(regMaskTP mask);
7233 void unwindPushMaskFloat(regMaskTP mask);
7234 void unwindPopMaskInt(regMaskTP mask);
7235 void unwindPopMaskFloat(regMaskTP mask);
7236 void unwindBranch16(); // The epilog terminates with a 16-bit branch (e.g., "bx lr")
7237 void unwindNop(unsigned codeSizeInBytes); // Generate unwind NOP code. 'codeSizeInBytes' is 2 or 4 bytes. Only
7238 // called via unwindPadding().
7239 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7240 // instruction and the current location.
7241 #endif // _TARGET_ARM_
7243 #if defined(_TARGET_ARM64_)
7245 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7246 // instruction and the current location.
7247 void unwindSaveReg(regNumber reg, int offset); // str reg, [sp, #offset]
7248 void unwindSaveRegPreindexed(regNumber reg, int offset); // str reg, [sp, #offset]!
7249 void unwindSaveRegPair(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]
7250 void unwindSaveRegPairPreindexed(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]!
7251 void unwindSaveNext(); // unwind code: save_next
7252 void unwindReturn(regNumber reg); // ret lr
7253 #endif // defined(_TARGET_ARM64_)
7256 // Private "helper" functions for the unwind implementation.
7260 #if FEATURE_EH_FUNCLETS
7261 void unwindGetFuncLocations(FuncInfoDsc* func,
7262 bool getHotSectionData,
7263 /* OUT */ emitLocation** ppStartLoc,
7264 /* OUT */ emitLocation** ppEndLoc);
7265 #endif // FEATURE_EH_FUNCLETS
7267 void unwindReserveFunc(FuncInfoDsc* func);
7268 void unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
7270 #if defined(_TARGET_AMD64_) || (defined(_TARGET_X86_) && FEATURE_EH_FUNCLETS)
7272 void unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode);
7273 void unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode);
7275 #endif // _TARGET_AMD64_ || (_TARGET_X86_ && FEATURE_EH_FUNCLETS)
7277 UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func);
7279 #if defined(_TARGET_AMD64_)
7281 void unwindBegPrologWindows();
7282 void unwindPushWindows(regNumber reg);
7283 void unwindAllocStackWindows(unsigned size);
7284 void unwindSetFrameRegWindows(regNumber reg, unsigned offset);
7285 void unwindSaveRegWindows(regNumber reg, unsigned offset);
7287 #ifdef UNIX_AMD64_ABI
7288 void unwindSaveRegCFI(regNumber reg, unsigned offset);
7289 #endif // UNIX_AMD64_ABI
7290 #elif defined(_TARGET_ARM_)
7292 void unwindPushPopMaskInt(regMaskTP mask, bool useOpsize16);
7293 void unwindPushPopMaskFloat(regMaskTP mask);
7294 void unwindSplit(FuncInfoDsc* func);
7296 #endif // _TARGET_ARM_
7298 #if defined(_TARGET_UNIX_)
7299 int mapRegNumToDwarfReg(regNumber reg);
7300 void createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR opcode, USHORT dwarfReg, INT offset = 0);
7301 void unwindPushCFI(regNumber reg);
7302 void unwindBegPrologCFI();
7303 void unwindPushMaskCFI(regMaskTP regMask, bool isFloat);
7304 void unwindAllocStackCFI(unsigned size);
7305 void unwindSetFrameRegCFI(regNumber reg, unsigned offset);
7306 void unwindEmitFuncCFI(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
7308 void DumpCfiInfo(bool isHotCode,
7309 UNATIVE_OFFSET startOffset,
7310 UNATIVE_OFFSET endOffset,
7312 const CFI_CODE* const pCfiCode);
7315 #endif // _TARGET_UNIX_
7317 #if !defined(__GNUC__)
7318 #pragma endregion // Note: region is NOT under !defined(__GNUC__)
7322 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7323 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7327 XX Info about SIMD types, methods and the SIMD assembly (i.e. the assembly XX
7328 XX that contains the distinguished, well-known SIMD type definitions). XX
7330 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7331 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7334 // Get highest available level for SIMD codegen
7335 SIMDLevel getSIMDSupportLevel()
7337 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7338 if (compSupports(InstructionSet_AVX2))
7340 return SIMD_AVX2_Supported;
7345 return SIMD_SSE4_Supported;
7349 assert(canUseSSE2());
7350 return SIMD_SSE2_Supported;
7352 assert(!"Available instruction set(s) for SIMD codegen is not defined for target arch");
7354 return SIMD_Not_Supported;
7360 // Should we support SIMD intrinsics?
7363 // Have we identified any SIMD types?
7364 // This is currently used by struct promotion to avoid getting type information for a struct
7365 // field to see if it is a SIMD type, if we haven't seen any SIMD types or operations in
7367 bool _usesSIMDTypes;
7368 bool usesSIMDTypes()
7370 return _usesSIMDTypes;
7372 void setUsesSIMDTypes(bool value)
7374 _usesSIMDTypes = value;
7377 // This is a temp lclVar allocated on the stack as TYP_SIMD. It is used to implement intrinsics
7378 // that require indexed access to the individual fields of the vector, which is not well supported
7379 // by the hardware. It is allocated when/if such situations are encountered during Lowering.
7380 unsigned lvaSIMDInitTempVarNum;
7383 CORINFO_CLASS_HANDLE SIMDFloatHandle;
7384 CORINFO_CLASS_HANDLE SIMDDoubleHandle;
7385 CORINFO_CLASS_HANDLE SIMDIntHandle;
7386 CORINFO_CLASS_HANDLE SIMDUShortHandle;
7387 CORINFO_CLASS_HANDLE SIMDUByteHandle;
7388 CORINFO_CLASS_HANDLE SIMDShortHandle;
7389 CORINFO_CLASS_HANDLE SIMDByteHandle;
7390 CORINFO_CLASS_HANDLE SIMDLongHandle;
7391 CORINFO_CLASS_HANDLE SIMDUIntHandle;
7392 CORINFO_CLASS_HANDLE SIMDULongHandle;
7393 CORINFO_CLASS_HANDLE SIMDVector2Handle;
7394 CORINFO_CLASS_HANDLE SIMDVector3Handle;
7395 CORINFO_CLASS_HANDLE SIMDVector4Handle;
7396 CORINFO_CLASS_HANDLE SIMDVectorHandle;
7398 #if FEATURE_HW_INTRINSICS
7399 CORINFO_CLASS_HANDLE Vector128FloatHandle;
7400 CORINFO_CLASS_HANDLE Vector128DoubleHandle;
7401 CORINFO_CLASS_HANDLE Vector128IntHandle;
7402 CORINFO_CLASS_HANDLE Vector128UShortHandle;
7403 CORINFO_CLASS_HANDLE Vector128UByteHandle;
7404 CORINFO_CLASS_HANDLE Vector128ShortHandle;
7405 CORINFO_CLASS_HANDLE Vector128ByteHandle;
7406 CORINFO_CLASS_HANDLE Vector128LongHandle;
7407 CORINFO_CLASS_HANDLE Vector128UIntHandle;
7408 CORINFO_CLASS_HANDLE Vector128ULongHandle;
7409 CORINFO_CLASS_HANDLE Vector256FloatHandle;
7410 CORINFO_CLASS_HANDLE Vector256DoubleHandle;
7411 CORINFO_CLASS_HANDLE Vector256IntHandle;
7412 CORINFO_CLASS_HANDLE Vector256UShortHandle;
7413 CORINFO_CLASS_HANDLE Vector256UByteHandle;
7414 CORINFO_CLASS_HANDLE Vector256ShortHandle;
7415 CORINFO_CLASS_HANDLE Vector256ByteHandle;
7416 CORINFO_CLASS_HANDLE Vector256LongHandle;
7417 CORINFO_CLASS_HANDLE Vector256UIntHandle;
7418 CORINFO_CLASS_HANDLE Vector256ULongHandle;
7421 // Get the handle for a SIMD type.
7422 CORINFO_CLASS_HANDLE gtGetStructHandleForSIMD(var_types simdType, var_types simdBaseType)
7424 if (simdBaseType == TYP_FLOAT)
7429 return SIMDVector2Handle;
7431 return SIMDVector3Handle;
7433 if ((getSIMDVectorType() == TYP_SIMD32) || (SIMDVector4Handle != NO_CLASS_HANDLE))
7435 return SIMDVector4Handle;
7444 assert(simdType == getSIMDVectorType());
7445 switch (simdBaseType)
7448 return SIMDFloatHandle;
7450 return SIMDDoubleHandle;
7452 return SIMDIntHandle;
7454 return SIMDUShortHandle;
7456 return SIMDUByteHandle;
7458 return SIMDShortHandle;
7460 return SIMDByteHandle;
7462 return SIMDLongHandle;
7464 return SIMDUIntHandle;
7466 return SIMDULongHandle;
7468 assert(!"Didn't find a class handle for simdType");
7470 return NO_CLASS_HANDLE;
7474 CORINFO_METHOD_HANDLE SIMDVectorFloat_set_Item;
7475 CORINFO_METHOD_HANDLE SIMDVectorFloat_get_Length;
7476 CORINFO_METHOD_HANDLE SIMDVectorFloat_op_Addition;
7478 // Returns true if the tree corresponds to a TYP_SIMD lcl var.
7479 // Note that both SIMD vector args and locals are mared as lvSIMDType = true, but
7480 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD or TYP_STRUCT.
7481 bool isSIMDTypeLocal(GenTree* tree)
7483 return tree->OperIsLocal() && lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7486 // Returns true if the type of the tree is a byref of TYP_SIMD
7487 bool isAddrOfSIMDType(GenTree* tree)
7489 if (tree->TypeGet() == TYP_BYREF || tree->TypeGet() == TYP_I_IMPL)
7491 switch (tree->OperGet())
7494 return varTypeIsSIMD(tree->gtGetOp1());
7496 case GT_LCL_VAR_ADDR:
7497 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7500 return isSIMDTypeLocal(tree);
7507 static bool isRelOpSIMDIntrinsic(SIMDIntrinsicID intrinsicId)
7509 return (intrinsicId == SIMDIntrinsicEqual || intrinsicId == SIMDIntrinsicLessThan ||
7510 intrinsicId == SIMDIntrinsicLessThanOrEqual || intrinsicId == SIMDIntrinsicGreaterThan ||
7511 intrinsicId == SIMDIntrinsicGreaterThanOrEqual);
7514 // Returns base type of a TYP_SIMD local.
7515 // Returns TYP_UNKNOWN if the local is not TYP_SIMD.
7516 var_types getBaseTypeOfSIMDLocal(GenTree* tree)
7518 if (isSIMDTypeLocal(tree))
7520 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvBaseType;
7526 bool isSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7528 return info.compCompHnd->isInSIMDModule(clsHnd);
7531 bool isIntrinsicType(CORINFO_CLASS_HANDLE clsHnd)
7533 return (info.compCompHnd->getClassAttribs(clsHnd) & CORINFO_FLG_INTRINSIC_TYPE) != 0;
7536 const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName)
7538 return info.compCompHnd->getClassNameFromMetadata(cls, namespaceName);
7541 CORINFO_CLASS_HANDLE getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index)
7543 return info.compCompHnd->getTypeInstantiationArgument(cls, index);
7546 bool isSIMDClass(typeInfo* pTypeInfo)
7548 return pTypeInfo->IsStruct() && isSIMDClass(pTypeInfo->GetClassHandleForValueClass());
7551 // Get the base (element) type and size in bytes for a SIMD type. Returns TYP_UNKNOWN
7552 // if it is not a SIMD type or is an unsupported base type.
7553 var_types getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes = nullptr);
7555 var_types getBaseTypeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7557 return getBaseTypeAndSizeOfSIMDType(typeHnd, nullptr);
7560 // Get SIMD Intrinsic info given the method handle.
7561 // Also sets typeHnd, argCount, baseType and sizeBytes out params.
7562 const SIMDIntrinsicInfo* getSIMDIntrinsicInfo(CORINFO_CLASS_HANDLE* typeHnd,
7563 CORINFO_METHOD_HANDLE methodHnd,
7564 CORINFO_SIG_INFO* sig,
7567 var_types* baseType,
7568 unsigned* sizeBytes);
7570 // Pops and returns GenTree node from importers type stack.
7571 // Normalizes TYP_STRUCT value in case of GT_CALL, GT_RET_EXPR and arg nodes.
7572 GenTreePtr impSIMDPopStack(var_types type, bool expectAddr = false);
7574 // Create a GT_SIMD tree for a Get property of SIMD vector with a fixed index.
7575 GenTreeSIMD* impSIMDGetFixed(var_types simdType, var_types baseType, unsigned simdSize, int index);
7577 // Creates a GT_SIMD tree for Select operation
7578 GenTreePtr impSIMDSelect(CORINFO_CLASS_HANDLE typeHnd,
7580 unsigned simdVectorSize,
7585 // Creates a GT_SIMD tree for Min/Max operation
7586 GenTreePtr impSIMDMinMax(SIMDIntrinsicID intrinsicId,
7587 CORINFO_CLASS_HANDLE typeHnd,
7589 unsigned simdVectorSize,
7593 // Transforms operands and returns the SIMD intrinsic to be applied on
7594 // transformed operands to obtain given relop result.
7595 SIMDIntrinsicID impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId,
7596 CORINFO_CLASS_HANDLE typeHnd,
7597 unsigned simdVectorSize,
7598 var_types* baseType,
7602 // Creates a GT_SIMD tree for Abs intrinsic.
7603 GenTreePtr impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType, unsigned simdVectorSize, GenTree* op1);
7605 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7606 // Transforms operands and returns the SIMD intrinsic to be applied on
7607 // transformed operands to obtain == comparison result.
7608 SIMDIntrinsicID impSIMDLongRelOpEqual(CORINFO_CLASS_HANDLE typeHnd,
7609 unsigned simdVectorSize,
7613 // Transforms operands and returns the SIMD intrinsic to be applied on
7614 // transformed operands to obtain > comparison result.
7615 SIMDIntrinsicID impSIMDLongRelOpGreaterThan(CORINFO_CLASS_HANDLE typeHnd,
7616 unsigned simdVectorSize,
7620 // Transforms operands and returns the SIMD intrinsic to be applied on
7621 // transformed operands to obtain >= comparison result.
7622 SIMDIntrinsicID impSIMDLongRelOpGreaterThanOrEqual(CORINFO_CLASS_HANDLE typeHnd,
7623 unsigned simdVectorSize,
7627 // Transforms operands and returns the SIMD intrinsic to be applied on
7628 // transformed operands to obtain >= comparison result in case of int32
7629 // and small int base type vectors.
7630 SIMDIntrinsicID impSIMDIntegralRelOpGreaterThanOrEqual(
7631 CORINFO_CLASS_HANDLE typeHnd, unsigned simdVectorSize, var_types baseType, GenTree** op1, GenTree** op2);
7632 #endif // defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7634 void setLclRelatedToSIMDIntrinsic(GenTreePtr tree);
7635 bool areFieldsContiguous(GenTreePtr op1, GenTreePtr op2);
7636 bool areArrayElementsContiguous(GenTreePtr op1, GenTreePtr op2);
7637 bool areArgumentsContiguous(GenTreePtr op1, GenTreePtr op2);
7638 GenTreePtr createAddressNodeForSIMDInit(GenTreePtr tree, unsigned simdSize);
7640 // check methodHnd to see if it is a SIMD method that is expanded as an intrinsic in the JIT.
7641 GenTreePtr impSIMDIntrinsic(OPCODE opcode,
7642 GenTreePtr newobjThis,
7643 CORINFO_CLASS_HANDLE clsHnd,
7644 CORINFO_METHOD_HANDLE method,
7645 CORINFO_SIG_INFO* sig,
7648 GenTreePtr getOp1ForConstructor(OPCODE opcode, GenTreePtr newobjThis, CORINFO_CLASS_HANDLE clsHnd);
7650 // Whether SIMD vector occupies part of SIMD register.
7651 // SSE2: vector2f/3f are considered sub register SIMD types.
7652 // AVX: vector2f, 3f and 4f are all considered sub register SIMD types.
7653 bool isSubRegisterSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7655 unsigned sizeBytes = 0;
7656 var_types baseType = getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7657 return (baseType == TYP_FLOAT) && (sizeBytes < getSIMDVectorRegisterByteLength());
7660 bool isSubRegisterSIMDType(GenTreeSIMD* simdNode)
7662 return (simdNode->gtSIMDSize < getSIMDVectorRegisterByteLength());
7665 // Get the type for the hardware SIMD vector.
7666 // This is the maximum SIMD type supported for this target.
7667 var_types getSIMDVectorType()
7669 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7670 if (getSIMDSupportLevel() == SIMD_AVX2_Supported)
7676 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7679 #elif defined(_TARGET_ARM64_)
7682 assert(!"getSIMDVectorType() unimplemented on target arch");
7687 // Get the size of the SIMD type in bytes
7688 int getSIMDTypeSizeInBytes(CORINFO_CLASS_HANDLE typeHnd)
7690 unsigned sizeBytes = 0;
7691 (void)getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7695 // Get the the number of elements of basetype of SIMD vector given by its size and baseType
7696 static int getSIMDVectorLength(unsigned simdSize, var_types baseType);
7698 // Get the the number of elements of basetype of SIMD vector given by its type handle
7699 int getSIMDVectorLength(CORINFO_CLASS_HANDLE typeHnd);
7701 // Get preferred alignment of SIMD type.
7702 int getSIMDTypeAlignment(var_types simdType);
7704 // Get the number of bytes in a System.Numeric.Vector<T> for the current compilation.
7705 // Note - cannot be used for System.Runtime.Intrinsic
7706 unsigned getSIMDVectorRegisterByteLength()
7708 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7709 if (getSIMDSupportLevel() == SIMD_AVX2_Supported)
7711 return YMM_REGSIZE_BYTES;
7715 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7716 return XMM_REGSIZE_BYTES;
7718 #elif defined(_TARGET_ARM64_)
7719 return FP_REGSIZE_BYTES;
7721 assert(!"getSIMDVectorRegisterByteLength() unimplemented on target arch");
7726 // The minimum and maximum possible number of bytes in a SIMD vector.
7728 // maxSIMDStructBytes
7729 // The minimum SIMD size supported by System.Numeric.Vectors or System.Runtime.Intrinsic
7730 // SSE: 16-byte Vector<T> and Vector128<T>
7731 // AVX: 32-byte Vector256<T> (Vector<T> is 16-byte)
7732 // AVX2: 32-byte Vector<T> and Vector256<T>
7733 unsigned int maxSIMDStructBytes()
7735 #if FEATURE_HW_INTRINSICS && defined(_TARGET_XARCH_)
7736 if (compSupports(InstructionSet_AVX))
7738 return YMM_REGSIZE_BYTES;
7742 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7743 return XMM_REGSIZE_BYTES;
7746 return getSIMDVectorRegisterByteLength();
7749 unsigned int minSIMDStructBytes()
7751 return emitTypeSize(TYP_SIMD8);
7754 // Returns the codegen type for a given SIMD size.
7755 var_types getSIMDTypeForSize(unsigned size)
7757 var_types simdType = TYP_UNDEF;
7760 simdType = TYP_SIMD8;
7762 else if (size == 12)
7764 simdType = TYP_SIMD12;
7766 else if (size == 16)
7768 simdType = TYP_SIMD16;
7770 else if (size == 32)
7772 simdType = TYP_SIMD32;
7776 noway_assert(!"Unexpected size for SIMD type");
7781 unsigned getSIMDInitTempVarNum()
7783 if (lvaSIMDInitTempVarNum == BAD_VAR_NUM)
7785 lvaSIMDInitTempVarNum = lvaGrabTempWithImplicitUse(false DEBUGARG("SIMDInitTempVar"));
7786 lvaTable[lvaSIMDInitTempVarNum].lvType = getSIMDVectorType();
7788 return lvaSIMDInitTempVarNum;
7791 #endif // FEATURE_SIMD
7794 //------------------------------------------------------------------------
7795 // largestEnregisterableStruct: The size in bytes of the largest struct that can be enregistered.
7797 // Notes: It is not guaranteed that the struct of this size or smaller WILL be a
7798 // candidate for enregistration.
7800 unsigned largestEnregisterableStructSize()
7803 unsigned vectorRegSize = getSIMDVectorRegisterByteLength();
7804 if (vectorRegSize > TARGET_POINTER_SIZE)
7806 return vectorRegSize;
7809 #endif // FEATURE_SIMD
7811 return TARGET_POINTER_SIZE;
7816 // These routines need not be enclosed under FEATURE_SIMD since lvIsSIMDType()
7817 // is defined for both FEATURE_SIMD and !FEATURE_SIMD apropriately. The use
7818 // of this routines also avoids the need of #ifdef FEATURE_SIMD specific code.
7820 // Is this var is of type simd struct?
7821 bool lclVarIsSIMDType(unsigned varNum)
7823 LclVarDsc* varDsc = lvaTable + varNum;
7824 return varDsc->lvIsSIMDType();
7827 // Is this Local node a SIMD local?
7828 bool lclVarIsSIMDType(GenTreeLclVarCommon* lclVarTree)
7830 return lclVarIsSIMDType(lclVarTree->gtLclNum);
7833 // Returns true if the TYP_SIMD locals on stack are aligned at their
7834 // preferred byte boundary specified by getSIMDTypeAlignment().
7836 // As per the Intel manual, the preferred alignment for AVX vectors is 32-bytes. On Amd64,
7837 // RSP/EBP is aligned at 16-bytes, therefore to align SIMD types at 32-bytes we need even
7838 // RSP/EBP to be 32-byte aligned. It is not clear whether additional stack space used in
7839 // aligning stack is worth the benefit and for now will use 16-byte alignment for AVX
7840 // 256-bit vectors with unaligned load/stores to/from memory. On x86, the stack frame
7841 // is aligned to 4 bytes. We need to extend existing support for double (8-byte) alignment
7842 // to 16 or 32 byte alignment for frames with local SIMD vars, if that is determined to be
7845 bool isSIMDTypeLocalAligned(unsigned varNum)
7847 #if defined(FEATURE_SIMD) && ALIGN_SIMD_TYPES
7848 if (lclVarIsSIMDType(varNum) && lvaTable[varNum].lvType != TYP_BYREF)
7851 int off = lvaFrameAddress(varNum, &ebpBased);
7852 // TODO-Cleanup: Can't this use the lvExactSize on the varDsc?
7853 int alignment = getSIMDTypeAlignment(lvaTable[varNum].lvType);
7854 bool isAligned = (alignment <= STACK_ALIGN) && ((off % alignment) == 0);
7857 #endif // FEATURE_SIMD
7862 // Whether SSE2 is available
7863 bool canUseSSE2() const
7865 #ifdef _TARGET_XARCH_
7866 return opts.compCanUseSSE2;
7872 // Whether SSE3, SSE3, SSE4.1 and SSE4.2 is available
7873 bool CanUseSSE4() const
7875 #ifdef _TARGET_XARCH_
7876 return opts.compCanUseSSE4;
7882 bool compSupports(InstructionSet isa) const
7884 #ifdef _TARGET_XARCH_
7885 return (opts.compSupportsISA & (1ULL << isa)) != 0;
7891 bool canUseVexEncoding() const
7893 #ifdef _TARGET_XARCH_
7894 return compSupports(InstructionSet_AVX);
7901 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7902 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7906 XX Generic info about the compilation and the method being compiled. XX
7907 XX It is responsible for driving the other phases. XX
7908 XX It is also responsible for all the memory management. XX
7910 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7911 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7915 Compiler* InlineeCompiler; // The Compiler instance for the inlinee
7917 InlineResult* compInlineResult; // The result of importing the inlinee method.
7919 bool compDoAggressiveInlining; // If true, mark every method as CORINFO_FLG_FORCEINLINE
7920 bool compJmpOpUsed; // Does the method do a JMP
7921 bool compLongUsed; // Does the method use TYP_LONG
7922 bool compFloatingPointUsed; // Does the method use TYP_FLOAT or TYP_DOUBLE
7923 bool compTailCallUsed; // Does the method do a tailcall
7924 bool compLocallocUsed; // Does the method use localloc.
7925 bool compLocallocOptimized; // Does the method have an optimized localloc
7926 bool compQmarkUsed; // Does the method use GT_QMARK/GT_COLON
7927 bool compQmarkRationalized; // Is it allowed to use a GT_QMARK/GT_COLON node.
7928 bool compUnsafeCastUsed; // Does the method use LDIND/STIND to cast between scalar/refernce types
7930 // NOTE: These values are only reliable after
7931 // the importing is completely finished.
7933 #ifdef LEGACY_BACKEND
7934 JitExpandArrayStack<GenTreePtr>* compQMarks; // The set of QMark nodes created in the current compilation, so
7935 // we can iterate over these efficiently.
7938 #if CPU_USES_BLOCK_MOVE
7939 bool compBlkOpUsed; // Does the method do a COPYBLK or INITBLK
7943 // State information - which phases have completed?
7944 // These are kept together for easy discoverability
7946 bool bRangeAllowStress;
7947 bool compCodeGenDone;
7948 int64_t compNumStatementLinksTraversed; // # of links traversed while doing debug checks
7949 bool fgNormalizeEHDone; // Has the flowgraph EH normalization phase been done?
7950 size_t compSizeEstimate; // The estimated size of the method as per `gtSetEvalOrder`.
7951 size_t compCycleEstimate; // The estimated cycle count of the method as per `gtSetEvalOrder`
7954 bool fgLocalVarLivenessDone; // Note that this one is used outside of debug.
7955 bool fgLocalVarLivenessChanged;
7957 bool compStackProbePrologDone;
7959 #ifndef LEGACY_BACKEND
7961 #endif // !LEGACY_BACKEND
7962 bool compRationalIRForm;
7964 bool compUsesThrowHelper; // There is a call to a THOROW_HELPER for the compiled method.
7966 bool compGeneratingProlog;
7967 bool compGeneratingEpilog;
7968 bool compNeedsGSSecurityCookie; // There is an unsafe buffer (or localloc) on the stack.
7969 // Insert cookie on frame and code to check the cookie, like VC++ -GS.
7970 bool compGSReorderStackLayout; // There is an unsafe buffer on the stack, reorder locals and make local
7971 // copies of susceptible parameters to avoid buffer overrun attacks through locals/params
7972 bool getNeedsGSSecurityCookie() const
7974 return compNeedsGSSecurityCookie;
7976 void setNeedsGSSecurityCookie()
7978 compNeedsGSSecurityCookie = true;
7981 FrameLayoutState lvaDoneFrameLayout; // The highest frame layout state that we've completed. During
7982 // frame layout calculations, this is the level we are currently
7985 //---------------------------- JITing options -----------------------------
7998 JitFlags* jitFlags; // all flags passed from the EE
7999 unsigned compFlags; // method attributes
8001 codeOptimize compCodeOpt; // what type of code optimizations
8005 #ifdef _TARGET_XARCH_
8006 bool compCanUseSSE2; // Allow CodeGen to use "movq XMM" instructions
8007 bool compCanUseSSE4; // Allow CodeGen to use SSE3, SSSE3, SSE4.1 and SSE4.2 instructions
8008 #endif // _TARGET_XARCH_
8010 #ifdef _TARGET_XARCH_
8011 uint64_t compSupportsISA;
8012 void setSupportedISA(InstructionSet isa)
8014 compSupportsISA |= 1ULL << isa;
8018 // optimize maximally and/or favor speed over size?
8020 #define DEFAULT_MIN_OPTS_CODE_SIZE 60000
8021 #define DEFAULT_MIN_OPTS_INSTR_COUNT 20000
8022 #define DEFAULT_MIN_OPTS_BB_COUNT 2000
8023 #define DEFAULT_MIN_OPTS_LV_NUM_COUNT 2000
8024 #define DEFAULT_MIN_OPTS_LV_REF_COUNT 8000
8026 // Maximun number of locals before turning off the inlining
8027 #define MAX_LV_NUM_COUNT_FOR_INLINING 512
8030 unsigned instrCount;
8031 unsigned lvRefCount;
8032 bool compMinOptsIsSet;
8034 bool compMinOptsIsUsed;
8036 inline bool MinOpts()
8038 assert(compMinOptsIsSet);
8039 compMinOptsIsUsed = true;
8042 inline bool IsMinOptsSet()
8044 return compMinOptsIsSet;
8047 inline bool MinOpts()
8051 inline bool IsMinOptsSet()
8053 return compMinOptsIsSet;
8056 inline void SetMinOpts(bool val)
8058 assert(!compMinOptsIsUsed);
8059 assert(!compMinOptsIsSet || (compMinOpts == val));
8061 compMinOptsIsSet = true;
8064 // true if the CLFLG_* for an optimization is set.
8065 inline bool OptEnabled(unsigned optFlag)
8067 return !!(compFlags & optFlag);
8070 #ifdef FEATURE_READYTORUN_COMPILER
8071 inline bool IsReadyToRun()
8073 return jitFlags->IsSet(JitFlags::JIT_FLAG_READYTORUN);
8076 inline bool IsReadyToRun()
8082 // true if we should use the PINVOKE_{BEGIN,END} helpers instead of generating
8083 // PInvoke transitions inline (e.g. when targeting CoreRT).
8084 inline bool ShouldUsePInvokeHelpers()
8086 return jitFlags->IsSet(JitFlags::JIT_FLAG_USE_PINVOKE_HELPERS);
8089 // true if we should use insert the REVERSE_PINVOKE_{ENTER,EXIT} helpers in the method
8091 inline bool IsReversePInvoke()
8093 return jitFlags->IsSet(JitFlags::JIT_FLAG_REVERSE_PINVOKE);
8096 // true if we must generate code compatible with JIT32 quirks
8097 inline bool IsJit32Compat()
8099 #if defined(_TARGET_X86_)
8100 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
8106 // true if we must generate code compatible with Jit64 quirks
8107 inline bool IsJit64Compat()
8109 #if defined(_TARGET_AMD64_)
8110 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
8111 #elif !defined(FEATURE_CORECLR)
8118 bool compScopeInfo; // Generate the LocalVar info ?
8119 bool compDbgCode; // Generate debugger-friendly code?
8120 bool compDbgInfo; // Gather debugging info?
8123 #ifdef PROFILING_SUPPORTED
8124 bool compNoPInvokeInlineCB;
8126 static const bool compNoPInvokeInlineCB;
8130 bool compGcChecks; // Check arguments and return values to ensure they are sane
8131 bool compStackCheckOnRet; // Check ESP on return to ensure it is correct
8132 bool compStackCheckOnCall; // Check ESP after every call to ensure it is correct
8136 bool compNeedSecurityCheck; // This flag really means where or not a security object needs
8137 // to be allocated on the stack.
8138 // It will be set to true in the following cases:
8139 // 1. When the method being compiled has a declarative security
8140 // (i.e. when CORINFO_FLG_NOSECURITYWRAP is reset for the current method).
8141 // This is also the case when we inject a prolog and epilog in the method.
8143 // 2. When the method being compiled has imperative security (i.e. the method
8144 // calls into another method that has CORINFO_FLG_SECURITYCHECK flag set).
8146 // 3. When opts.compDbgEnC is true. (See also Compiler::compCompile).
8148 // When this flag is set, jit will allocate a gc-reference local variable (lvaSecurityObject),
8149 // which gets reported as a GC root to stackwalker.
8150 // (See also ICodeManager::GetAddrOfSecurityObject.)
8152 bool compReloc; // Generate relocs for pointers in code, true for all ngen/prejit codegen
8155 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
8156 bool compEnablePCRelAddr; // Whether absolute addr be encoded as PC-rel offset by RyuJIT where possible
8160 #ifdef UNIX_AMD64_ABI
8161 // This flag is indicating if there is a need to align the frame.
8162 // On AMD64-Windows, if there are calls, 4 slots for the outgoing ars are allocated, except for
8163 // FastTailCall. This slots makes the frame size non-zero, so alignment logic will be called.
8164 // On AMD64-Unix, there are no such slots. There is a possibility to have calls in the method with frame size of
8165 // 0. The frame alignment logic won't kick in. This flags takes care of the AMD64-Unix case by remembering that
8166 // there are calls and making sure the frame alignment logic is executed.
8167 bool compNeedToAlignFrame;
8168 #endif // UNIX_AMD64_ABI
8170 bool compProcedureSplitting; // Separate cold code from hot code
8172 bool genFPorder; // Preserve FP order (operations are non-commutative)
8173 bool genFPopt; // Can we do frame-pointer-omission optimization?
8174 bool altJit; // True if we are an altjit and are compiling this method
8177 bool optRepeat; // Repeat optimizer phases k times
8181 bool compProcedureSplittingEH; // Separate cold code from hot code for functions with EH
8182 bool dspCode; // Display native code generated
8183 bool dspEHTable; // Display the EH table reported to the VM
8184 bool dspInstrs; // Display the IL instructions intermixed with the native code output
8185 bool dspEmit; // Display emitter output
8186 bool dspLines; // Display source-code lines intermixed with native code output
8187 bool dmpHex; // Display raw bytes in hex of native code output
8188 bool varNames; // Display variables names in native code output
8189 bool disAsm; // Display native code as it is generated
8190 bool disAsmSpilled; // Display native code when any register spilling occurs
8191 bool disDiffable; // Makes the Disassembly code 'diff-able'
8192 bool disAsm2; // Display native code after it is generated using external disassembler
8193 bool dspOrder; // Display names of each of the methods that we ngen/jit
8194 bool dspUnwind; // Display the unwind info output
8195 bool dspDiffable; // Makes the Jit Dump 'diff-able' (currently uses same COMPlus_* flag as disDiffable)
8196 bool compLongAddress; // Force using large pseudo instructions for long address
8197 // (IF_LARGEJMP/IF_LARGEADR/IF_LARGLDC)
8198 bool dspGCtbls; // Display the GC tables
8202 bool doLateDisasm; // Run the late disassembler
8203 #endif // LATE_DISASM
8205 #if DUMP_GC_TABLES && !defined(DEBUG) && defined(JIT32_GCENCODER)
8206 // Only the JIT32_GCENCODER implements GC dumping in non-DEBUG code.
8207 #pragma message("NOTE: this non-debug build has GC ptr table dumping always enabled!")
8208 static const bool dspGCtbls = true;
8211 // We need stack probes to guarantee that we won't trigger a stack overflow
8212 // when calling unmanaged code until they get a chance to set up a frame, because
8213 // the EE will have no idea where it is.
8215 // We will only be doing this currently for hosted environments. Unfortunately
8216 // we need to take care of stubs, so potentially, we will have to do the probes
8217 // for any call. We have a plan for not needing for stubs though
8218 bool compNeedStackProbes;
8220 #ifdef PROFILING_SUPPORTED
8221 // Whether to emit Enter/Leave/TailCall hooks using a dummy stub (DummyProfilerELTStub()).
8222 // This option helps make the JIT behave as if it is running under a profiler.
8223 bool compJitELTHookEnabled;
8224 #endif // PROFILING_SUPPORTED
8226 #if FEATURE_TAILCALL_OPT
8227 // Whether opportunistic or implicit tail call optimization is enabled.
8228 bool compTailCallOpt;
8229 // Whether optimization of transforming a recursive tail call into a loop is enabled.
8230 bool compTailCallLoopOpt;
8234 static const bool compUseSoftFP = true;
8235 #else // !ARM_SOFTFP
8236 static const bool compUseSoftFP = false;
8239 GCPollType compGCPollType;
8243 static bool s_pAltJitExcludeAssembliesListInitialized;
8244 static AssemblyNamesList2* s_pAltJitExcludeAssembliesList;
8249 template <typename T>
8252 return (p == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : p);
8255 template <typename T>
8258 return (o == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : o);
8261 static int dspTreeID(GenTree* tree)
8263 return tree->gtTreeID;
8265 static void printTreeID(GenTree* tree)
8267 if (tree == nullptr)
8273 printf("[%06d]", dspTreeID(tree));
8280 #define STRESS_MODES \
8284 /* "Variations" stress areas which we try to mix up with each other. */ \
8285 /* These should not be exhaustively used as they might */ \
8286 /* hide/trivialize other areas */ \
8289 STRESS_MODE(DBL_ALN) \
8290 STRESS_MODE(LCL_FLDS) \
8291 STRESS_MODE(UNROLL_LOOPS) \
8292 STRESS_MODE(MAKE_CSE) \
8293 STRESS_MODE(LEGACY_INLINE) \
8294 STRESS_MODE(CLONE_EXPR) \
8295 STRESS_MODE(USE_FCOMI) \
8296 STRESS_MODE(USE_CMOV) \
8298 STRESS_MODE(BB_PROFILE) \
8299 STRESS_MODE(OPT_BOOLS_GC) \
8300 STRESS_MODE(REMORPH_TREES) \
8301 STRESS_MODE(64RSLT_MUL) \
8302 STRESS_MODE(DO_WHILE_LOOPS) \
8303 STRESS_MODE(MIN_OPTS) \
8304 STRESS_MODE(REVERSE_FLAG) /* Will set GTF_REVERSE_OPS whenever we can */ \
8305 STRESS_MODE(REVERSE_COMMA) /* Will reverse commas created with gtNewCommaNode */ \
8306 STRESS_MODE(TAILCALL) /* Will make the call as a tailcall whenever legal */ \
8307 STRESS_MODE(CATCH_ARG) /* Will spill catch arg */ \
8308 STRESS_MODE(UNSAFE_BUFFER_CHECKS) \
8309 STRESS_MODE(NULL_OBJECT_CHECK) \
8310 STRESS_MODE(PINVOKE_RESTORE_ESP) \
8311 STRESS_MODE(RANDOM_INLINE) \
8312 STRESS_MODE(SWITCH_CMP_BR_EXPANSION) \
8313 STRESS_MODE(GENERIC_VARN) \
8315 /* After COUNT_VARN, stress level 2 does all of these all the time */ \
8317 STRESS_MODE(COUNT_VARN) \
8319 /* "Check" stress areas that can be exhaustively used if we */ \
8320 /* dont care about performance at all */ \
8322 STRESS_MODE(FORCE_INLINE) /* Treat every method as AggressiveInlining */ \
8323 STRESS_MODE(CHK_FLOW_UPDATE) \
8324 STRESS_MODE(EMITTER) \
8325 STRESS_MODE(CHK_REIMPORT) \
8326 STRESS_MODE(FLATFP) \
8327 STRESS_MODE(GENERIC_CHECK) \
8332 #define STRESS_MODE(mode) STRESS_##mode,
8339 static const LPCWSTR s_compStressModeNames[STRESS_COUNT + 1];
8340 BYTE compActiveStressModes[STRESS_COUNT];
8343 #define MAX_STRESS_WEIGHT 100
8345 bool compStressCompile(compStressArea stressArea, unsigned weightPercentage);
8349 bool compInlineStress()
8351 return compStressCompile(STRESS_LEGACY_INLINE, 50);
8354 bool compRandomInlineStress()
8356 return compStressCompile(STRESS_RANDOM_INLINE, 50);
8361 bool compTailCallStress()
8364 return (JitConfig.TailcallStress() != 0 || compStressCompile(STRESS_TAILCALL, 5));
8370 codeOptimize compCodeOpt()
8373 // Switching between size & speed has measurable throughput impact
8374 // (3.5% on NGen mscorlib when measured). It used to be enabled for
8375 // DEBUG, but should generate identical code between CHK & RET builds,
8376 // so that's not acceptable.
8377 // TODO-Throughput: Figure out what to do about size vs. speed & throughput.
8378 // Investigate the cause of the throughput regression.
8380 return opts.compCodeOpt;
8382 return BLENDED_CODE;
8386 //--------------------- Info about the procedure --------------------------
8390 COMP_HANDLE compCompHnd;
8391 CORINFO_MODULE_HANDLE compScopeHnd;
8392 CORINFO_CLASS_HANDLE compClassHnd;
8393 CORINFO_METHOD_HANDLE compMethodHnd;
8394 CORINFO_METHOD_INFO* compMethodInfo;
8396 BOOL hasCircularClassConstraints;
8397 BOOL hasCircularMethodConstraints;
8399 #if defined(DEBUG) || defined(LATE_DISASM)
8400 const char* compMethodName;
8401 const char* compClassName;
8402 const char* compFullName;
8403 #endif // defined(DEBUG) || defined(LATE_DISASM)
8405 #if defined(DEBUG) || defined(INLINE_DATA)
8406 // Method hash is logcally const, but computed
8408 mutable unsigned compMethodHashPrivate;
8409 unsigned compMethodHash() const;
8410 #endif // defined(DEBUG) || defined(INLINE_DATA)
8412 #ifdef PSEUDORANDOM_NOP_INSERTION
8413 // things for pseudorandom nop insertion
8414 unsigned compChecksum;
8418 // The following holds the FLG_xxxx flags for the method we're compiling.
8421 // The following holds the class attributes for the method we're compiling.
8422 unsigned compClassAttr;
8424 const BYTE* compCode;
8425 IL_OFFSET compILCodeSize; // The IL code size
8426 UNATIVE_OFFSET compNativeCodeSize; // The native code size, after instructions are issued. This
8427 // is less than (compTotalHotCodeSize + compTotalColdCodeSize) only if:
8428 // (1) the code is not hot/cold split, and we issued less code than we expected, or
8429 // (2) the code is hot/cold split, and we issued less code than we expected
8430 // in the cold section (the hot section will always be padded out to compTotalHotCodeSize).
8432 bool compIsStatic : 1; // Is the method static (no 'this' pointer)?
8433 bool compIsVarArgs : 1; // Does the method have varargs parameters?
8434 bool compIsContextful : 1; // contextful method
8435 bool compInitMem : 1; // Is the CORINFO_OPT_INIT_LOCALS bit set in the method info options?
8436 bool compUnwrapContextful : 1; // JIT should unwrap proxies when possible
8437 bool compProfilerCallback : 1; // JIT inserted a profiler Enter callback
8438 bool compPublishStubParam : 1; // EAX captured in prolog will be available through an instrinsic
8439 bool compRetBuffDefStack : 1; // The ret buff argument definitely points into the stack.
8441 var_types compRetType; // Return type of the method as declared in IL
8442 var_types compRetNativeType; // Normalized return type as per target arch ABI
8443 unsigned compILargsCount; // Number of arguments (incl. implicit but not hidden)
8444 unsigned compArgsCount; // Number of arguments (incl. implicit and hidden)
8446 #if FEATURE_FASTTAILCALL
8447 size_t compArgStackSize; // Incoming argument stack size in bytes
8448 #endif // FEATURE_FASTTAILCALL
8450 unsigned compRetBuffArg; // position of hidden return param var (0, 1) (BAD_VAR_NUM means not present);
8451 int compTypeCtxtArg; // position of hidden param for type context for generic code (CORINFO_CALLCONV_PARAMTYPE)
8452 unsigned compThisArg; // position of implicit this pointer param (not to be confused with lvaArg0Var)
8453 unsigned compILlocalsCount; // Number of vars : args + locals (incl. implicit but not hidden)
8454 unsigned compLocalsCount; // Number of vars : args + locals (incl. implicit and hidden)
8455 unsigned compMaxStack;
8456 UNATIVE_OFFSET compTotalHotCodeSize; // Total number of bytes of Hot Code in the method
8457 UNATIVE_OFFSET compTotalColdCodeSize; // Total number of bytes of Cold Code in the method
8459 unsigned compCallUnmanaged; // count of unmanaged calls
8460 unsigned compLvFrameListRoot; // lclNum for the Frame root
8461 unsigned compXcptnsCount; // Number of exception-handling clauses read in the method's IL.
8462 // You should generally use compHndBBtabCount instead: it is the
8463 // current number of EH clauses (after additions like synchronized
8464 // methods and funclets, and removals like unreachable code deletion).
8466 bool compMatchedVM; // true if the VM is "matched": either the JIT is a cross-compiler
8467 // and the VM expects that, or the JIT is a "self-host" compiler
8468 // (e.g., x86 hosted targeting x86) and the VM expects that.
8470 /* The following holds IL scope information about local variables.
8473 unsigned compVarScopesCount;
8474 VarScopeDsc* compVarScopes;
8476 /* The following holds information about instr offsets for
8477 * which we need to report IP-mappings
8480 IL_OFFSET* compStmtOffsets; // sorted
8481 unsigned compStmtOffsetsCount;
8482 ICorDebugInfo::BoundaryTypes compStmtOffsetsImplicit;
8484 #define CPU_X86 0x0100 // The generic X86 CPU
8485 #define CPU_X86_PENTIUM_4 0x0110
8487 #define CPU_X64 0x0200 // The generic x64 CPU
8488 #define CPU_AMD_X64 0x0210 // AMD x64 CPU
8489 #define CPU_INTEL_X64 0x0240 // Intel x64 CPU
8491 #define CPU_ARM 0x0300 // The generic ARM CPU
8493 unsigned genCPU; // What CPU are we running on
8496 // Returns true if the method being compiled returns a non-void and non-struct value.
8497 // Note that lvaInitTypeRef() normalizes compRetNativeType for struct returns in a
8498 // single register as per target arch ABI (e.g on Amd64 Windows structs of size 1, 2,
8499 // 4 or 8 gets normalized to TYP_BYTE/TYP_SHORT/TYP_INT/TYP_LONG; On Arm HFA structs).
8500 // Methods returning such structs are considered to return non-struct return value and
8501 // this method returns true in that case.
8502 bool compMethodReturnsNativeScalarType()
8504 return (info.compRetType != TYP_VOID) && !varTypeIsStruct(info.compRetNativeType);
8507 // Returns true if the method being compiled returns RetBuf addr as its return value
8508 bool compMethodReturnsRetBufAddr()
8510 // There are cases where implicit RetBuf argument should be explicitly returned in a register.
8511 // In such cases the return type is changed to TYP_BYREF and appropriate IR is generated.
8513 // 1. Profiler Leave calllback expects the address of retbuf as return value for
8514 // methods with hidden RetBuf argument. impReturnInstruction() when profiler
8515 // callbacks are needed creates GT_RETURN(TYP_BYREF, op1 = Addr of RetBuf) for
8516 // methods with hidden RetBufArg.
8518 // 2. As per the System V ABI, the address of RetBuf needs to be returned by
8519 // methods with hidden RetBufArg in RAX. In such case GT_RETURN is of TYP_BYREF,
8520 // returning the address of RetBuf.
8522 // 3. Windows 64-bit native calling convention also requires the address of RetBuff
8523 // to be returned in RAX.
8524 CLANG_FORMAT_COMMENT_ANCHOR;
8526 #ifdef _TARGET_AMD64_
8527 return (info.compRetBuffArg != BAD_VAR_NUM);
8528 #else // !_TARGET_AMD64_
8529 return (compIsProfilerHookNeeded()) && (info.compRetBuffArg != BAD_VAR_NUM);
8530 #endif // !_TARGET_AMD64_
8533 // Returns true if the method returns a value in more than one return register
8534 // TODO-ARM-Bug: Deal with multi-register genReturnLocaled structs?
8535 // TODO-ARM64: Does this apply for ARM64 too?
8536 bool compMethodReturnsMultiRegRetType()
8538 #if FEATURE_MULTIREG_RET
8539 #if defined(_TARGET_X86_)
8540 // On x86 only 64-bit longs are returned in multiple registers
8541 return varTypeIsLong(info.compRetNativeType);
8542 #else // targets: X64-UNIX, ARM64 or ARM32
8543 // On all other targets that support multireg return values:
8544 // Methods returning a struct in multiple registers have a return value of TYP_STRUCT.
8545 // Such method's compRetNativeType is TYP_STRUCT without a hidden RetBufArg
8546 return varTypeIsStruct(info.compRetNativeType) && (info.compRetBuffArg == BAD_VAR_NUM);
8547 #endif // TARGET_XXX
8549 #else // not FEATURE_MULTIREG_RET
8551 // For this architecture there are no multireg returns
8554 #endif // FEATURE_MULTIREG_RET
8557 #if FEATURE_MULTIREG_ARGS
8558 // Given a GenTree node of TYP_STRUCT that represents a pass by value argument
8559 // return the gcPtr layout for the pointers sized fields
8560 void getStructGcPtrsFromOp(GenTreePtr op, BYTE* gcPtrsOut);
8561 #endif // FEATURE_MULTIREG_ARGS
8563 // Returns true if the method being compiled returns a value
8564 bool compMethodHasRetVal()
8566 return compMethodReturnsNativeScalarType() || compMethodReturnsRetBufAddr() ||
8567 compMethodReturnsMultiRegRetType();
8572 void compDispLocalVars();
8576 //-------------------------- Global Compiler Data ------------------------------------
8579 static unsigned s_compMethodsCount; // to produce unique label names
8580 unsigned compGenTreeID;
8581 unsigned compBasicBlockID;
8584 BasicBlock* compCurBB; // the current basic block in process
8585 GenTreePtr compCurStmt; // the current statement in process
8587 unsigned compCurStmtNum; // to give all statements an increasing StmtNum when printing dumps
8590 // The following is used to create the 'method JIT info' block.
8591 size_t compInfoBlkSize;
8592 BYTE* compInfoBlkAddr;
8594 EHblkDsc* compHndBBtab; // array of EH data
8595 unsigned compHndBBtabCount; // element count of used elements in EH data array
8596 unsigned compHndBBtabAllocCount; // element count of allocated elements in EH data array
8598 #if defined(_TARGET_X86_)
8600 //-------------------------------------------------------------------------
8601 // Tracking of region covered by the monitor in synchronized methods
8602 void* syncStartEmitCookie; // the emitter cookie for first instruction after the call to MON_ENTER
8603 void* syncEndEmitCookie; // the emitter cookie for first instruction after the call to MON_EXIT
8605 #endif // !_TARGET_X86_
8607 Phases previousCompletedPhase; // the most recently completed phase
8609 //-------------------------------------------------------------------------
8610 // The following keeps track of how many bytes of local frame space we've
8611 // grabbed so far in the current function, and how many argument bytes we
8612 // need to pop when we return.
8615 unsigned compLclFrameSize; // secObject+lclBlk+locals+temps
8617 // Count of callee-saved regs we pushed in the prolog.
8618 // Does not include EBP for isFramePointerUsed() and double-aligned frames.
8619 // In case of Amd64 this doesn't include float regs saved on stack.
8620 unsigned compCalleeRegsPushed;
8622 #if defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87
8623 // Mask of callee saved float regs on stack.
8624 regMaskTP compCalleeFPRegsSavedMask;
8626 #ifdef _TARGET_AMD64_
8627 // Quirk for VS debug-launch scenario to work:
8628 // Bytes of padding between save-reg area and locals.
8629 #define VSQUIRK_STACK_PAD (2 * REGSIZE_BYTES)
8630 unsigned compVSQuirkStackPaddingNeeded;
8631 bool compQuirkForPPPflag;
8634 unsigned compArgSize; // total size of arguments in bytes (including register args (lvIsRegArg))
8636 unsigned compMapILargNum(unsigned ILargNum); // map accounting for hidden args
8637 unsigned compMapILvarNum(unsigned ILvarNum); // map accounting for hidden args
8638 unsigned compMap2ILvarNum(unsigned varNum); // map accounting for hidden args
8640 //-------------------------------------------------------------------------
8642 static void compStartup(); // One-time initialization
8643 static void compShutdown(); // One-time finalization
8645 void compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo);
8648 static void compDisplayStaticSizes(FILE* fout);
8650 //------------ Some utility functions --------------
8652 void* compGetHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
8653 void** ppIndirection); /* OUT */
8655 // Several JIT/EE interface functions return a CorInfoType, and also return a
8656 // class handle as an out parameter if the type is a value class. Returns the
8657 // size of the type these describe.
8658 unsigned compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd);
8661 // Components used by the compiler may write unit test suites, and
8662 // have them run within this method. They will be run only once per process, and only
8663 // in debug. (Perhaps should be under the control of a COMPlus_ flag.)
8664 // These should fail by asserting.
8665 void compDoComponentUnitTestsOnce();
8668 int compCompile(CORINFO_METHOD_HANDLE methodHnd,
8669 CORINFO_MODULE_HANDLE classPtr,
8670 COMP_HANDLE compHnd,
8671 CORINFO_METHOD_INFO* methodInfo,
8672 void** methodCodePtr,
8673 ULONG* methodCodeSize,
8674 JitFlags* compileFlags);
8675 void compCompileFinish();
8676 int compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
8677 COMP_HANDLE compHnd,
8678 CORINFO_METHOD_INFO* methodInfo,
8679 void** methodCodePtr,
8680 ULONG* methodCodeSize,
8681 JitFlags* compileFlags,
8682 CorInfoInstantiationVerification instVerInfo);
8684 ArenaAllocator* compGetAllocator();
8686 #if MEASURE_MEM_ALLOC
8688 static bool s_dspMemStats; // Display per-phase memory statistics for every function
8692 unsigned allocCnt; // # of allocs
8693 UINT64 allocSz; // total size of those alloc.
8694 UINT64 allocSzMax; // Maximum single allocation.
8695 UINT64 allocSzByKind[CMK_Count]; // Classified by "kind".
8696 UINT64 nraTotalSizeAlloc;
8697 UINT64 nraTotalSizeUsed;
8699 static const char* s_CompMemKindNames[]; // Names of the kinds.
8701 MemStats() : allocCnt(0), allocSz(0), allocSzMax(0), nraTotalSizeAlloc(0), nraTotalSizeUsed(0)
8703 for (int i = 0; i < CMK_Count; i++)
8705 allocSzByKind[i] = 0;
8708 MemStats(const MemStats& ms)
8709 : allocCnt(ms.allocCnt)
8710 , allocSz(ms.allocSz)
8711 , allocSzMax(ms.allocSzMax)
8712 , nraTotalSizeAlloc(ms.nraTotalSizeAlloc)
8713 , nraTotalSizeUsed(ms.nraTotalSizeUsed)
8715 for (int i = 0; i < CMK_Count; i++)
8717 allocSzByKind[i] = ms.allocSzByKind[i];
8721 // Until we have ubiquitous constructors.
8724 this->MemStats::MemStats();
8727 void AddAlloc(size_t sz, CompMemKind cmk)
8731 if (sz > allocSzMax)
8735 allocSzByKind[cmk] += sz;
8738 void Print(FILE* f); // Print these stats to f.
8739 void PrintByKind(FILE* f); // Do just the by-kind histogram part.
8741 MemStats genMemStats;
8743 struct AggregateMemStats : public MemStats
8747 AggregateMemStats() : MemStats(), nMethods(0)
8751 void Add(const MemStats& ms)
8754 allocCnt += ms.allocCnt;
8755 allocSz += ms.allocSz;
8756 allocSzMax = max(allocSzMax, ms.allocSzMax);
8757 for (int i = 0; i < CMK_Count; i++)
8759 allocSzByKind[i] += ms.allocSzByKind[i];
8761 nraTotalSizeAlloc += ms.nraTotalSizeAlloc;
8762 nraTotalSizeUsed += ms.nraTotalSizeUsed;
8765 void Print(FILE* f); // Print these stats to jitstdout.
8768 static CritSecObject s_memStatsLock; // This lock protects the data structures below.
8769 static MemStats s_maxCompMemStats; // Stats for the compilation with the largest amount allocated.
8770 static AggregateMemStats s_aggMemStats; // Aggregates statistics for all compilations.
8772 #endif // MEASURE_MEM_ALLOC
8774 #if LOOP_HOIST_STATS
8775 unsigned m_loopsConsidered;
8776 bool m_curLoopHasHoistedExpression;
8777 unsigned m_loopsWithHoistedExpressions;
8778 unsigned m_totalHoistedExpressions;
8780 void AddLoopHoistStats();
8781 void PrintPerMethodLoopHoistStats();
8783 static CritSecObject s_loopHoistStatsLock; // This lock protects the data structures below.
8784 static unsigned s_loopsConsidered;
8785 static unsigned s_loopsWithHoistedExpressions;
8786 static unsigned s_totalHoistedExpressions;
8788 static void PrintAggregateLoopHoistStats(FILE* f);
8789 #endif // LOOP_HOIST_STATS
8791 void* compGetMemArray(size_t numElem, size_t elemSize, CompMemKind cmk = CMK_Unknown);
8792 void* compGetMem(size_t sz, CompMemKind cmk = CMK_Unknown);
8793 void compFreeMem(void*);
8795 bool compIsForImportOnly();
8796 bool compIsForInlining();
8797 bool compDonotInline();
8800 const char* compLocalVarName(unsigned varNum, unsigned offs);
8801 VarName compVarName(regNumber reg, bool isFloatReg = false);
8802 const char* compRegVarName(regNumber reg, bool displayVar = false, bool isFloatReg = false);
8803 const char* compRegPairName(regPairNo regPair);
8804 const char* compRegNameForSize(regNumber reg, size_t size);
8805 const char* compFPregVarName(unsigned fpReg, bool displayVar = false);
8806 void compDspSrcLinesByNativeIP(UNATIVE_OFFSET curIP);
8807 void compDspSrcLinesByLineNum(unsigned line, bool seek = false);
8810 //-------------------------------------------------------------------------
8812 struct VarScopeListNode
8815 VarScopeListNode* next;
8816 static VarScopeListNode* Create(VarScopeDsc* value, CompAllocator* alloc)
8818 VarScopeListNode* node = new (alloc) VarScopeListNode;
8820 node->next = nullptr;
8825 struct VarScopeMapInfo
8827 VarScopeListNode* head;
8828 VarScopeListNode* tail;
8829 static VarScopeMapInfo* Create(VarScopeListNode* node, CompAllocator* alloc)
8831 VarScopeMapInfo* info = new (alloc) VarScopeMapInfo;
8838 // Max value of scope count for which we would use linear search; for larger values we would use hashtable lookup.
8839 static const unsigned MAX_LINEAR_FIND_LCL_SCOPELIST = 32;
8841 typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, VarScopeMapInfo*> VarNumToScopeDscMap;
8843 // Map to keep variables' scope indexed by varNum containing it's scope dscs at the index.
8844 VarNumToScopeDscMap* compVarScopeMap;
8846 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned lifeBeg, unsigned lifeEnd);
8848 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned offs);
8850 VarScopeDsc* compFindLocalVarLinear(unsigned varNum, unsigned offs);
8852 void compInitVarScopeMap();
8854 VarScopeDsc** compEnterScopeList; // List has the offsets where variables
8855 // enter scope, sorted by instr offset
8856 unsigned compNextEnterScope;
8858 VarScopeDsc** compExitScopeList; // List has the offsets where variables
8859 // go out of scope, sorted by instr offset
8860 unsigned compNextExitScope;
8862 void compInitScopeLists();
8864 void compResetScopeLists();
8866 VarScopeDsc* compGetNextEnterScope(unsigned offs, bool scan = false);
8868 VarScopeDsc* compGetNextExitScope(unsigned offs, bool scan = false);
8870 void compProcessScopesUntil(unsigned offset,
8872 void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*),
8873 void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*));
8876 void compDispScopeLists();
8879 bool compIsProfilerHookNeeded();
8881 //-------------------------------------------------------------------------
8882 /* Statistical Data Gathering */
8884 void compJitStats(); // call this function and enable
8885 // various ifdef's below for statistical data
8888 void compCallArgStats();
8889 static void compDispCallArgStats(FILE* fout);
8892 //-------------------------------------------------------------------------
8899 ArenaAllocator* compAllocator;
8902 CompAllocator* compAllocatorGeneric; // An allocator that uses the CMK_Generic tracker.
8903 #if MEASURE_MEM_ALLOC
8904 CompAllocator* compAllocatorBitset; // An allocator that uses the CMK_bitset tracker.
8905 CompAllocator* compAllocatorGC; // An allocator that uses the CMK_GC tracker.
8906 CompAllocator* compAllocatorLoopHoist; // An allocator that uses the CMK_LoopHoist tracker.
8908 CompAllocator* compAllocatorDebugOnly; // An allocator that uses the CMK_DebugOnly tracker.
8910 #endif // MEASURE_MEM_ALLOC
8912 void compFunctionTraceStart();
8913 void compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, bool isNYI);
8916 size_t compMaxUncheckedOffsetForNullObject;
8918 void compInitOptions(JitFlags* compileFlags);
8920 void compSetProcessor();
8921 void compInitDebuggingInfo();
8922 void compSetOptimizationLevel();
8923 #ifdef _TARGET_ARMARCH_
8924 bool compRsvdRegCheck(FrameLayoutState curState);
8926 void compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags);
8928 // Clear annotations produced during optimizations; to be used between iterations when repeating opts.
8929 void ResetOptAnnotations();
8931 // Regenerate loop descriptors; to be used between iterations when repeating opts.
8932 void RecomputeLoopInfo();
8934 #ifdef PROFILING_SUPPORTED
8935 // Data required for generating profiler Enter/Leave/TailCall hooks
8937 bool compProfilerHookNeeded; // Whether profiler Enter/Leave/TailCall hook needs to be generated for the method
8938 void* compProfilerMethHnd; // Profiler handle of the method being compiled. Passed as param to ELT callbacks
8939 bool compProfilerMethHndIndirected; // Whether compProfilerHandle is pointer to the handle or is an actual handle
8942 #ifdef _TARGET_AMD64_
8943 bool compQuirkForPPP(); // Check if this method should be Quirked for the PPP issue
8946 // Assumes called as part of process shutdown; does any compiler-specific work associated with that.
8947 static void ProcessShutdownWork(ICorStaticInfo* statInfo);
8949 CompAllocator* getAllocator()
8951 return compAllocatorGeneric;
8954 #if MEASURE_MEM_ALLOC
8955 CompAllocator* getAllocatorBitset()
8957 return compAllocatorBitset;
8959 CompAllocator* getAllocatorGC()
8961 return compAllocatorGC;
8963 CompAllocator* getAllocatorLoopHoist()
8965 return compAllocatorLoopHoist;
8967 #else // !MEASURE_MEM_ALLOC
8968 CompAllocator* getAllocatorBitset()
8970 return compAllocatorGeneric;
8972 CompAllocator* getAllocatorGC()
8974 return compAllocatorGeneric;
8976 CompAllocator* getAllocatorLoopHoist()
8978 return compAllocatorGeneric;
8980 #endif // !MEASURE_MEM_ALLOC
8983 CompAllocator* getAllocatorDebugOnly()
8985 #if MEASURE_MEM_ALLOC
8986 return compAllocatorDebugOnly;
8987 #else // !MEASURE_MEM_ALLOC
8988 return compAllocatorGeneric;
8989 #endif // !MEASURE_MEM_ALLOC
8994 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8995 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8999 XX Checks for type compatibility and merges types XX
9001 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9002 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9006 // Set to TRUE if verification cannot be skipped for this method
9007 // If we detect unverifiable code, we will lazily check
9008 // canSkipMethodVerification() to see if verification is REALLY needed.
9009 BOOL tiVerificationNeeded;
9011 // It it initially TRUE, and it gets set to FALSE if we run into unverifiable code
9012 // Note that this is valid only if tiVerificationNeeded was ever TRUE.
9013 BOOL tiIsVerifiableCode;
9015 // Set to TRUE if runtime callout is needed for this method
9016 BOOL tiRuntimeCalloutNeeded;
9018 // Set to TRUE if security prolog/epilog callout is needed for this method
9019 // Note: This flag is different than compNeedSecurityCheck.
9020 // compNeedSecurityCheck means whether or not a security object needs
9021 // to be allocated on the stack, which is currently true for EnC as well.
9022 // tiSecurityCalloutNeeded means whether or not security callouts need
9023 // to be inserted in the jitted code.
9024 BOOL tiSecurityCalloutNeeded;
9026 // Returns TRUE if child is equal to or a subtype of parent for merge purposes
9027 // This support is necessary to suport attributes that are not described in
9028 // for example, signatures. For example, the permanent home byref (byref that
9029 // points to the gc heap), isn't a property of method signatures, therefore,
9030 // it is safe to have mismatches here (that tiCompatibleWith will not flag),
9031 // but when deciding if we need to reimport a block, we need to take these
9033 BOOL tiMergeCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
9035 // Returns TRUE if child is equal to or a subtype of parent.
9036 // normalisedForStack indicates that both types are normalised for the stack
9037 BOOL tiCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
9039 // Merges pDest and pSrc. Returns FALSE if merge is undefined.
9040 // *pDest is modified to represent the merged type. Sets "*changed" to true
9041 // if this changes "*pDest".
9042 BOOL tiMergeToCommonParent(typeInfo* pDest, const typeInfo* pSrc, bool* changed) const;
9044 // Set pDest from the primitive value type.
9045 // Eg. System.Int32 -> ELEMENT_TYPE_I4
9047 BOOL tiFromPrimitiveValueClass(typeInfo* pDest, const typeInfo* pVC) const;
9050 // <BUGNUM> VSW 471305
9051 // IJW allows assigning REF to BYREF. The following allows us to temporarily
9052 // bypass the assert check in gcMarkRegSetGCref and gcMarkRegSetByref
9053 // We use a "short" as we need to push/pop this scope.
9055 short compRegSetCheckLevel;
9059 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9060 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9062 XX IL verification stuff XX
9065 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9066 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9070 // The following is used to track liveness of local variables, initialization
9071 // of valueclass constructors, and type safe use of IL instructions.
9073 // dynamic state info needed for verification
9074 EntryState verCurrentState;
9076 // this ptr of object type .ctors are considered intited only after
9077 // the base class ctor is called, or an alternate ctor is called.
9078 // An uninited this ptr can be used to access fields, but cannot
9079 // be used to call a member function.
9080 BOOL verTrackObjCtorInitState;
9082 void verInitBBEntryState(BasicBlock* block, EntryState* currentState);
9084 // Requires that "tis" is not TIS_Bottom -- it's a definite init/uninit state.
9085 void verSetThisInit(BasicBlock* block, ThisInitState tis);
9086 void verInitCurrentState();
9087 void verResetCurrentState(BasicBlock* block, EntryState* currentState);
9089 // Merges the current verification state into the entry state of "block", return FALSE if that merge fails,
9090 // TRUE if it succeeds. Further sets "*changed" to true if this changes the entry state of "block".
9091 BOOL verMergeEntryStates(BasicBlock* block, bool* changed);
9093 void verConvertBBToThrowVerificationException(BasicBlock* block DEBUGARG(bool logMsg));
9094 void verHandleVerificationFailure(BasicBlock* block DEBUGARG(bool logMsg));
9095 typeInfo verMakeTypeInfo(CORINFO_CLASS_HANDLE clsHnd,
9096 bool bashStructToRef = false); // converts from jit type representation to typeInfo
9097 typeInfo verMakeTypeInfo(CorInfoType ciType,
9098 CORINFO_CLASS_HANDLE clsHnd); // converts from jit type representation to typeInfo
9099 BOOL verIsSDArray(typeInfo ti);
9100 typeInfo verGetArrayElemType(typeInfo ti);
9102 typeInfo verParseArgSigToTypeInfo(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args);
9103 BOOL verNeedsVerification();
9104 BOOL verIsByRefLike(const typeInfo& ti);
9105 BOOL verIsSafeToReturnByRef(const typeInfo& ti);
9107 // generic type variables range over types that satisfy IsBoxable
9108 BOOL verIsBoxable(const typeInfo& ti);
9110 void DECLSPEC_NORETURN verRaiseVerifyException(INDEBUG(const char* reason) DEBUGARG(const char* file)
9111 DEBUGARG(unsigned line));
9112 void verRaiseVerifyExceptionIfNeeded(INDEBUG(const char* reason) DEBUGARG(const char* file)
9113 DEBUGARG(unsigned line));
9114 bool verCheckTailCallConstraint(OPCODE opcode,
9115 CORINFO_RESOLVED_TOKEN* pResolvedToken,
9116 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call
9117 // on a type parameter?
9118 bool speculative // If true, won't throw if verificatoin fails. Instead it will
9119 // return false to the caller.
9120 // If false, it will throw.
9122 bool verIsBoxedValueType(typeInfo ti);
9124 void verVerifyCall(OPCODE opcode,
9125 CORINFO_RESOLVED_TOKEN* pResolvedToken,
9126 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
9128 bool readonlyCall, // is this a "readonly." call?
9129 const BYTE* delegateCreateStart,
9130 const BYTE* codeAddr,
9131 CORINFO_CALL_INFO* callInfo DEBUGARG(const char* methodName));
9133 BOOL verCheckDelegateCreation(const BYTE* delegateCreateStart, const BYTE* codeAddr, mdMemberRef& targetMemberRef);
9135 typeInfo verVerifySTIND(const typeInfo& ptr, const typeInfo& value, const typeInfo& instrType);
9136 typeInfo verVerifyLDIND(const typeInfo& ptr, const typeInfo& instrType);
9137 void verVerifyField(CORINFO_RESOLVED_TOKEN* pResolvedToken,
9138 const CORINFO_FIELD_INFO& fieldInfo,
9139 const typeInfo* tiThis,
9141 BOOL allowPlainStructAsThis = FALSE);
9142 void verVerifyCond(const typeInfo& tiOp1, const typeInfo& tiOp2, unsigned opcode);
9143 void verVerifyThisPtrInitialised();
9144 BOOL verIsCallToInitThisPtr(CORINFO_CLASS_HANDLE context, CORINFO_CLASS_HANDLE target);
9146 // Register allocator
9147 void raInitStackFP();
9148 void raEnregisterVarsPrePassStackFP();
9149 void raSetRegLclBirthDeath(GenTreePtr tree, VARSET_VALARG_TP lastlife, bool fromLDOBJ);
9150 void raEnregisterVarsPostPassStackFP();
9151 void raGenerateFPRefCounts();
9152 void raEnregisterVarsStackFP();
9153 void raUpdateHeightsForVarsStackFP(VARSET_VALARG_TP mask);
9155 regNumber raRegForVarStackFP(unsigned varTrackedIndex);
9156 void raAddPayloadStackFP(VARSET_VALARG_TP mask, unsigned weight);
9158 // returns true if enregistering v1 would save more mem accesses than v2
9159 bool raVarIsGreaterValueStackFP(LclVarDsc* lv1, LclVarDsc* lv2);
9162 void raDumpHeightsStackFP();
9163 void raDumpVariableRegIntfFloat();
9166 #if FEATURE_STACK_FP_X87
9168 // Currently, we use FP transition blocks in only 2 situations:
9170 // -conditional jump on longs where FP stack differs with target: it's not strictly
9171 // necessary, but its low frequency and the code would get complicated if we try to
9172 // inline the FP stack adjustment, as we have a lot of special casing going on to try
9173 // minimize the way we generate the jump code.
9174 // -case statements of switch where the FP stack differs with the one of evaluating the switch () statement
9175 // We do this as we want to codegen switch as a jumptable. Again, this is low frequency.
9177 // However, transition blocks have 2 problems
9179 // - Procedure splitting: current implementation of procedure splitting requires all basic blocks to
9180 // be known at codegen time, as it generates all hot blocks first and cold blocks later. This ties
9181 // us up in codegen and is a solvable problem (we could make procedure splitting generate blocks
9182 // in the right place without preordering them), this causes us to have to generate the transition
9183 // blocks in the cold area if we want procedure splitting.
9186 // - Thread abort exceptions and transition blocks. Transition blocks were designed under the assumption
9187 // that no exceptions can happen inside them. Unfortunately Thread.Abort can happen in any instruction,
9188 // and if we have handlers we will have to try to call them. Fixing this the right way would imply
9189 // having multiple try native code regions for a single try il region. This is doable and shouldnt be
9190 // a big change in the exception.
9192 // Given the low frequency of the cases where we have transition blocks, I've decided to dumb down
9193 // optimizations. For these 2 cases:
9195 // - When there is a chance that we will have FP transition blocks, we won't do procedure splitting.
9196 // - When a method has a handler, it won't enregister any FP variables that go thru a conditional long or
9197 // a switch statement.
9199 // If at any point we find we need to optimize this, we should throw work at unblocking the restrictions our
9200 // current procedure splitting and exception code have.
9201 bool compMayHaveTransitionBlocks;
9203 VARSET_TP raMaskDontEnregFloat; // mask for additional restrictions
9205 VARSET_TP raLclRegIntfFloat[REG_FPCOUNT];
9207 unsigned raCntStkStackFP;
9208 unsigned raCntWtdStkDblStackFP;
9209 unsigned raCntStkParamDblStackFP;
9211 // Payload in mem accesses for enregistering a variable (we dont want to mix with refcounts)
9212 // TODO: Do we want to put this in LclVarDsc?
9213 unsigned raPayloadStackFP[lclMAX_TRACKED];
9214 unsigned raHeightsStackFP[lclMAX_TRACKED][FP_VIRTUALREGISTERS + 1];
9216 // Useful for debugging
9217 unsigned raHeightsNonWeightedStackFP[lclMAX_TRACKED][FP_VIRTUALREGISTERS + 1];
9219 #endif // FEATURE_STACK_FP_X87
9222 // One line log function. Default level is 0. Increasing it gives you
9223 // more log information
9225 // levels are currently unused: #define JITDUMP(level,...) ();
9226 void JitLogEE(unsigned level, const char* fmt, ...);
9228 bool compDebugBreak;
9230 bool compJitHaltMethod();
9235 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9236 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9238 XX GS Security checks for unsafe buffers XX
9240 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9241 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9244 struct ShadowParamVarInfo
9246 FixedBitVect* assignGroup; // the closure set of variables whose values depend on each other
9247 unsigned shadowCopy; // Lcl var num, valid only if not set to NO_SHADOW_COPY
9249 static bool mayNeedShadowCopy(LclVarDsc* varDsc)
9251 #if defined(_TARGET_AMD64_) && !defined(LEGACY_BACKEND)
9252 // GS cookie logic to create shadow slots, create trees to copy reg args to shadow
9253 // slots and update all trees to refer to shadow slots is done immediately after
9254 // fgMorph(). Lsra could potentially mark a param as DoNotEnregister after JIT determines
9255 // not to shadow a parameter. Also, LSRA could potentially spill a param which is passed
9256 // in register. Therefore, conservatively all params may need a shadow copy. Note that
9257 // GS cookie logic further checks whether the param is a ptr or an unsafe buffer before
9258 // creating a shadow slot even though this routine returns true.
9260 // TODO-AMD64-CQ: Revisit this conservative approach as it could create more shadow slots than
9261 // required. There are two cases under which a reg arg could potentially be used from its
9263 // a) LSRA marks it as DoNotEnregister (see LinearScan::identifyCandidates())
9264 // b) LSRA spills it
9266 // Possible solution to address case (a)
9267 // - The conditions under which LSRA marks a varDsc as DoNotEnregister could be checked
9268 // in this routine. Note that live out of exception handler is something we may not be
9269 // able to do it here since GS cookie logic is invoked ahead of liveness computation.
9270 // Therefore, for methods with exception handling and need GS cookie check we might have
9271 // to take conservative approach.
9273 // Possible solution to address case (b)
9274 // - Whenver a parameter passed in an argument register needs to be spilled by LSRA, we
9275 // create a new spill temp if the method needs GS cookie check.
9276 return varDsc->lvIsParam;
9277 #else // !(defined(_TARGET_AMD64_) && defined(LEGACY_BACKEND))
9278 return varDsc->lvIsParam && !varDsc->lvIsRegArg;
9285 printf("assignGroup [%p]; shadowCopy: [%d];\n", assignGroup, shadowCopy);
9290 GSCookie* gsGlobalSecurityCookieAddr; // Address of global cookie for unsafe buffer checks
9291 GSCookie gsGlobalSecurityCookieVal; // Value of global cookie if addr is NULL
9292 ShadowParamVarInfo* gsShadowVarInfo; // Table used by shadow param analysis code
9294 void gsGSChecksInitCookie(); // Grabs cookie variable
9295 void gsCopyShadowParams(); // Identify vulnerable params and create dhadow copies
9296 bool gsFindVulnerableParams(); // Shadow param analysis code
9297 void gsParamsToShadows(); // Insert copy code and replave param uses by shadow
9299 static fgWalkPreFn gsMarkPtrsAndAssignGroups; // Shadow param analysis tree-walk
9300 static fgWalkPreFn gsReplaceShadowParams; // Shadow param replacement tree-walk
9302 #define DEFAULT_MAX_INLINE_SIZE 100 // Methods with > DEFAULT_MAX_INLINE_SIZE IL bytes will never be inlined.
9303 // This can be overwritten by setting complus_JITInlineSize env variable.
9305 #define DEFAULT_MAX_INLINE_DEPTH 20 // Methods at more than this level deep will not be inlined
9307 #define DEFAULT_MAX_LOCALLOC_TO_LOCAL_SIZE 32 // fixed locallocs of this size or smaller will convert to local buffers
9310 #ifdef FEATURE_JIT_METHOD_PERF
9311 JitTimer* pCompJitTimer; // Timer data structure (by phases) for current compilation.
9312 static CompTimeSummaryInfo s_compJitTimerSummary; // Summary of the Timer information for the whole run.
9314 static LPCWSTR JitTimeLogCsv(); // Retrieve the file name for CSV from ConfigDWORD.
9315 static LPCWSTR compJitTimeLogFilename; // If a log file for JIT time is desired, filename to write it to.
9317 inline void EndPhase(Phases phase); // Indicate the end of the given phase.
9319 #if MEASURE_CLRAPI_CALLS
9320 // Thin wrappers that call into JitTimer (if present).
9321 inline void CLRApiCallEnter(unsigned apix);
9322 inline void CLRApiCallLeave(unsigned apix);
9325 inline void CLR_API_Enter(API_ICorJitInfo_Names ename);
9326 inline void CLR_API_Leave(API_ICorJitInfo_Names ename);
9331 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9332 // These variables are associated with maintaining SQM data about compile time.
9333 unsigned __int64 m_compCyclesAtEndOfInlining; // The thread-virtualized cycle count at the end of the inlining phase
9334 // in the current compilation.
9335 unsigned __int64 m_compCycles; // Net cycle count for current compilation
9336 DWORD m_compTickCountAtEndOfInlining; // The result of GetTickCount() (# ms since some epoch marker) at the end of
9337 // the inlining phase in the current compilation.
9338 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9340 // Records the SQM-relevant (cycles and tick count). Should be called after inlining is complete.
9341 // (We do this after inlining because this marks the last point at which the JIT is likely to cause
9342 // type-loading and class initialization).
9343 void RecordStateAtEndOfInlining();
9344 // Assumes being called at the end of compilation. Update the SQM state.
9345 void RecordStateAtEndOfCompilation();
9347 #ifdef FEATURE_CLRSQM
9348 // Does anything SQM related necessary at process shutdown time.
9349 static void ProcessShutdownSQMWork(ICorStaticInfo* statInfo);
9350 #endif // FEATURE_CLRSQM
9353 #if FUNC_INFO_LOGGING
9354 static LPCWSTR compJitFuncInfoFilename; // If a log file for per-function information is required, this is the
9355 // filename to write it to.
9356 static FILE* compJitFuncInfoFile; // And this is the actual FILE* to write to.
9357 #endif // FUNC_INFO_LOGGING
9359 Compiler* prevCompiler; // Previous compiler on stack for TLS Compiler* linked list for reentrant compilers.
9361 // Is the compilation in a full trust context?
9362 bool compIsFullTrust();
9365 void RecordNowayAssert(const char* filename, unsigned line, const char* condStr);
9366 #endif // MEASURE_NOWAY
9368 #ifndef FEATURE_TRACELOGGING
9369 // Should we actually fire the noway assert body and the exception handler?
9370 bool compShouldThrowOnNoway();
9371 #else // FEATURE_TRACELOGGING
9372 // Should we actually fire the noway assert body and the exception handler?
9373 bool compShouldThrowOnNoway(const char* filename, unsigned line);
9375 // Telemetry instance to use per method compilation.
9376 JitTelemetry compJitTelemetry;
9378 // Get common parameters that have to be logged with most telemetry data.
9379 void compGetTelemetryDefaults(const char** assemblyName,
9380 const char** scopeName,
9381 const char** methodName,
9382 unsigned* methodHash);
9383 #endif // !FEATURE_TRACELOGGING
9387 NodeToTestDataMap* m_nodeTestData;
9389 static const unsigned FIRST_LOOP_HOIST_CSE_CLASS = 1000;
9390 unsigned m_loopHoistCSEClass; // LoopHoist test annotations turn into CSE requirements; we
9391 // label them with CSE Class #'s starting at FIRST_LOOP_HOIST_CSE_CLASS.
9392 // Current kept in this.
9394 NodeToTestDataMap* GetNodeTestData()
9396 Compiler* compRoot = impInlineRoot();
9397 if (compRoot->m_nodeTestData == nullptr)
9399 compRoot->m_nodeTestData = new (getAllocatorDebugOnly()) NodeToTestDataMap(getAllocatorDebugOnly());
9401 return compRoot->m_nodeTestData;
9404 typedef JitHashTable<GenTreePtr, JitPtrKeyFuncs<GenTree>, int> NodeToIntMap;
9406 // Returns the set (i.e., the domain of the result map) of nodes that are keys in m_nodeTestData, and
9407 // currently occur in the AST graph.
9408 NodeToIntMap* FindReachableNodesInNodeTestData();
9410 // Node "from" is being eliminated, and being replaced by node "to". If "from" had any associated
9411 // test data, associate that data with "to".
9412 void TransferTestDataToNode(GenTreePtr from, GenTreePtr to);
9414 // Requires that "to" is a clone of "from". If any nodes in the "from" tree
9415 // have annotations, attach similar annotations to the corresponding nodes in "to".
9416 void CopyTestDataToCloneTree(GenTreePtr from, GenTreePtr to);
9418 // These are the methods that test that the various conditions implied by the
9419 // test attributes are satisfied.
9420 void JitTestCheckSSA(); // SSA builder tests.
9421 void JitTestCheckVN(); // Value numbering tests.
9424 // The "FieldSeqStore", for canonicalizing field sequences. See the definition of FieldSeqStore for
9426 FieldSeqStore* m_fieldSeqStore;
9428 FieldSeqStore* GetFieldSeqStore()
9430 Compiler* compRoot = impInlineRoot();
9431 if (compRoot->m_fieldSeqStore == nullptr)
9433 // Create a CompAllocator that labels sub-structure with CMK_FieldSeqStore, and use that for allocation.
9434 CompAllocator* ialloc = new (this, CMK_FieldSeqStore) CompAllocator(this, CMK_FieldSeqStore);
9435 compRoot->m_fieldSeqStore = new (ialloc) FieldSeqStore(ialloc);
9437 return compRoot->m_fieldSeqStore;
9440 typedef JitHashTable<GenTreePtr, JitPtrKeyFuncs<GenTree>, FieldSeqNode*> NodeToFieldSeqMap;
9442 // Some nodes of "TYP_BYREF" or "TYP_I_IMPL" actually represent the address of a field within a struct, but since
9443 // the offset of the field is zero, there's no "GT_ADD" node. We normally attach a field sequence to the constant
9444 // that is added, but what do we do when that constant is zero, and is thus not present? We use this mechanism to
9445 // attach the field sequence directly to the address node.
9446 NodeToFieldSeqMap* m_zeroOffsetFieldMap;
9448 NodeToFieldSeqMap* GetZeroOffsetFieldMap()
9450 // Don't need to worry about inlining here
9451 if (m_zeroOffsetFieldMap == nullptr)
9453 // Create a CompAllocator that labels sub-structure with CMK_ZeroOffsetFieldMap, and use that for
9455 CompAllocator* ialloc = new (this, CMK_ZeroOffsetFieldMap) CompAllocator(this, CMK_ZeroOffsetFieldMap);
9456 m_zeroOffsetFieldMap = new (ialloc) NodeToFieldSeqMap(ialloc);
9458 return m_zeroOffsetFieldMap;
9461 // Requires that "op1" is a node of type "TYP_BYREF" or "TYP_I_IMPL". We are dereferencing this with the fields in
9462 // "fieldSeq", whose offsets are required all to be zero. Ensures that any field sequence annotation currently on
9463 // "op1" or its components is augmented by appending "fieldSeq". In practice, if "op1" is a GT_LCL_FLD, it has
9464 // a field sequence as a member; otherwise, it may be the addition of an a byref and a constant, where the const
9465 // has a field sequence -- in this case "fieldSeq" is appended to that of the constant; otherwise, we
9466 // record the the field sequence using the ZeroOffsetFieldMap described above.
9468 // One exception above is that "op1" is a node of type "TYP_REF" where "op1" is a GT_LCL_VAR.
9469 // This happens when System.Object vtable pointer is a regular field at offset 0 in System.Private.CoreLib in
9470 // CoreRT. Such case is handled same as the default case.
9471 void fgAddFieldSeqForZeroOffset(GenTreePtr op1, FieldSeqNode* fieldSeq);
9473 typedef JitHashTable<const GenTree*, JitPtrKeyFuncs<GenTree>, ArrayInfo> NodeToArrayInfoMap;
9474 NodeToArrayInfoMap* m_arrayInfoMap;
9476 NodeToArrayInfoMap* GetArrayInfoMap()
9478 Compiler* compRoot = impInlineRoot();
9479 if (compRoot->m_arrayInfoMap == nullptr)
9481 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9482 CompAllocator* ialloc = new (this, CMK_ArrayInfoMap) CompAllocator(this, CMK_ArrayInfoMap);
9483 compRoot->m_arrayInfoMap = new (ialloc) NodeToArrayInfoMap(ialloc);
9485 return compRoot->m_arrayInfoMap;
9488 //-----------------------------------------------------------------------------------------------------------------
9489 // Compiler::TryGetArrayInfo:
9490 // Given an indirection node, checks to see whether or not that indirection represents an array access, and
9491 // if so returns information about the array.
9494 // indir - The `GT_IND` node.
9495 // arrayInfo (out) - Information about the accessed array if this function returns true. Undefined otherwise.
9498 // True if the `GT_IND` node represents an array access; false otherwise.
9499 inline bool TryGetArrayInfo(GenTreeIndir* indir, ArrayInfo* arrayInfo)
9501 if ((indir->gtFlags & GTF_IND_ARR_INDEX) == 0)
9506 if (indir->gtOp1->OperIs(GT_INDEX_ADDR))
9508 GenTreeIndexAddr* const indexAddr = indir->gtOp1->AsIndexAddr();
9509 *arrayInfo = ArrayInfo(indexAddr->gtElemType, indexAddr->gtElemSize, indexAddr->gtElemOffset,
9510 indexAddr->gtStructElemClass);
9514 bool found = GetArrayInfoMap()->Lookup(indir, arrayInfo);
9519 NodeToUnsignedMap* m_memorySsaMap[MemoryKindCount];
9521 // In some cases, we want to assign intermediate SSA #'s to memory states, and know what nodes create those memory
9522 // states. (We do this for try blocks, where, if the try block doesn't do a call that loses track of the memory
9523 // state, all the possible memory states are possible initial states of the corresponding catch block(s).)
9524 NodeToUnsignedMap* GetMemorySsaMap(MemoryKind memoryKind)
9526 if (memoryKind == GcHeap && byrefStatesMatchGcHeapStates)
9528 // Use the same map for GCHeap and ByrefExposed when their states match.
9529 memoryKind = ByrefExposed;
9532 assert(memoryKind < MemoryKindCount);
9533 Compiler* compRoot = impInlineRoot();
9534 if (compRoot->m_memorySsaMap[memoryKind] == nullptr)
9536 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9537 CompAllocator* ialloc = new (this, CMK_ArrayInfoMap) CompAllocator(this, CMK_ArrayInfoMap);
9538 compRoot->m_memorySsaMap[memoryKind] = new (ialloc) NodeToUnsignedMap(ialloc);
9540 return compRoot->m_memorySsaMap[memoryKind];
9543 // The Refany type is the only struct type whose structure is implicitly assumed by IL. We need its fields.
9544 CORINFO_CLASS_HANDLE m_refAnyClass;
9545 CORINFO_FIELD_HANDLE GetRefanyDataField()
9547 if (m_refAnyClass == nullptr)
9549 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9551 return info.compCompHnd->getFieldInClass(m_refAnyClass, 0);
9553 CORINFO_FIELD_HANDLE GetRefanyTypeField()
9555 if (m_refAnyClass == nullptr)
9557 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9559 return info.compCompHnd->getFieldInClass(m_refAnyClass, 1);
9563 static BitSetSupport::BitSetOpCounter m_varsetOpCounter;
9565 #if ALLVARSET_COUNTOPS
9566 static BitSetSupport::BitSetOpCounter m_allvarsetOpCounter;
9569 static HelperCallProperties s_helperCallProperties;
9571 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
9572 static var_types GetTypeFromClassificationAndSizes(SystemVClassificationType classType, int size);
9573 static var_types GetEightByteType(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9576 static void GetStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9579 unsigned __int8* offset0,
9580 unsigned __int8* offset1);
9582 void GetStructTypeOffset(CORINFO_CLASS_HANDLE typeHnd,
9585 unsigned __int8* offset0,
9586 unsigned __int8* offset1);
9588 void fgMorphSystemVStructArgs(GenTreeCall* call, bool hasStructArgument);
9589 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
9591 void fgMorphMultiregStructArgs(GenTreeCall* call);
9592 GenTreePtr fgMorphMultiregStructArg(GenTreePtr arg, fgArgTabEntryPtr fgEntryPtr);
9594 bool killGCRefs(GenTreePtr tree);
9596 }; // end of class Compiler
9598 // Inline methods of CompAllocator.
9599 void* CompAllocator::Alloc(size_t sz)
9601 #if MEASURE_MEM_ALLOC
9602 return m_comp->compGetMem(sz, m_cmk);
9604 return m_comp->compGetMem(sz);
9608 void* CompAllocator::ArrayAlloc(size_t elems, size_t elemSize)
9610 #if MEASURE_MEM_ALLOC
9611 return m_comp->compGetMemArray(elems, elemSize, m_cmk);
9613 return m_comp->compGetMemArray(elems, elemSize);
9617 // LclVarDsc constructor. Uses Compiler, so must come after Compiler definition.
9618 inline LclVarDsc::LclVarDsc(Compiler* comp)
9619 : // Initialize the ArgRegs to REG_STK.
9620 // The morph will do the right thing to change
9621 // to the right register if passed in register.
9624 #if FEATURE_MULTIREG_ARGS
9625 _lvOtherArgReg(REG_STK)
9627 #endif // FEATURE_MULTIREG_ARGS
9629 lvRefBlks(BlockSetOps::UninitVal())
9631 #endif // ASSERTION_PROP
9632 lvPerSsaData(comp->getAllocator())
9636 //---------------------------------------------------------------------------------------------------------------------
9637 // GenTreeVisitor: a flexible tree walker implemented using the curiosly-recurring-template pattern.
9639 // This class implements a configurable walker for IR trees. There are five configuration options (defaults values are
9640 // shown in parentheses):
9642 // - ComputeStack (false): when true, the walker will push each node onto the `m_ancestors` stack. "Ancestors" is a bit
9643 // of a misnomer, as the first entry will always be the current node.
9645 // - DoPreOrder (false): when true, the walker will invoke `TVisitor::PreOrderVisit` with the current node as an
9646 // argument before visiting the node's operands.
9648 // - DoPostOrder (false): when true, the walker will invoke `TVisitor::PostOrderVisit` with the current node as an
9649 // argument after visiting the node's operands.
9651 // - DoLclVarsOnly (false): when true, the walker will only invoke `TVisitor::PreOrderVisit` for lclVar nodes.
9652 // `DoPreOrder` must be true if this option is true.
9654 // - UseExecutionOrder (false): when true, then walker will visit a node's operands in execution order (e.g. if a
9655 // binary operator has the `GTF_REVERSE_OPS` flag set, the second operand will be
9656 // visited before the first).
9658 // At least one of `DoPreOrder` and `DoPostOrder` must be specified.
9660 // A simple pre-order visitor might look something like the following:
9662 // class CountingVisitor final : public GenTreeVisitor<CountingVisitor>
9667 // DoPreOrder = true
9670 // unsigned m_count;
9672 // CountingVisitor(Compiler* compiler)
9673 // : GenTreeVisitor<CountingVisitor>(compiler), m_count(0)
9677 // Compiler::fgWalkResult PreOrderVisit(GenTree* node)
9683 // This visitor would then be used like so:
9685 // CountingVisitor countingVisitor(compiler);
9686 // countingVisitor.WalkTree(root);
9688 template <typename TVisitor>
9689 class GenTreeVisitor
9692 typedef Compiler::fgWalkResult fgWalkResult;
9696 ComputeStack = false,
9698 DoPostOrder = false,
9699 DoLclVarsOnly = false,
9700 UseExecutionOrder = false,
9703 Compiler* m_compiler;
9704 ArrayStack<GenTree*> m_ancestors;
9706 GenTreeVisitor(Compiler* compiler) : m_compiler(compiler), m_ancestors(compiler)
9708 assert(compiler != nullptr);
9710 static_assert_no_msg(TVisitor::DoPreOrder || TVisitor::DoPostOrder);
9711 static_assert_no_msg(!TVisitor::DoLclVarsOnly || TVisitor::DoPreOrder);
9714 fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
9716 return fgWalkResult::WALK_CONTINUE;
9719 fgWalkResult PostOrderVisit(GenTree** use, GenTree* user)
9721 return fgWalkResult::WALK_CONTINUE;
9725 fgWalkResult WalkTree(GenTree** use, GenTree* user)
9727 assert(use != nullptr);
9729 GenTree* node = *use;
9731 if (TVisitor::ComputeStack)
9733 m_ancestors.Push(node);
9736 fgWalkResult result = fgWalkResult::WALK_CONTINUE;
9737 if (TVisitor::DoPreOrder && !TVisitor::DoLclVarsOnly)
9739 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9740 if (result == fgWalkResult::WALK_ABORT)
9746 if ((node == nullptr) || (result == fgWalkResult::WALK_SKIP_SUBTREES))
9752 switch (node->OperGet())
9757 case GT_LCL_VAR_ADDR:
9758 case GT_LCL_FLD_ADDR:
9759 if (TVisitor::DoLclVarsOnly)
9761 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9762 if (result == fgWalkResult::WALK_ABORT)
9778 case GT_MEMORYBARRIER:
9783 case GT_START_NONGC:
9785 #if !FEATURE_EH_FUNCLETS
9787 #endif // !FEATURE_EH_FUNCLETS
9789 #ifndef LEGACY_BACKEND
9791 #endif // LEGACY_BACKEND
9794 case GT_CLS_VAR_ADDR:
9798 case GT_PINVOKE_PROLOG:
9799 case GT_PINVOKE_EPILOG:
9803 // Lclvar unary operators
9804 case GT_STORE_LCL_VAR:
9805 case GT_STORE_LCL_FLD:
9806 if (TVisitor::DoLclVarsOnly)
9808 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9809 if (result == fgWalkResult::WALK_ABORT)
9816 // Standard unary operators
9843 case GT_RUNTIMELOOKUP:
9845 GenTreeUnOp* const unOp = node->AsUnOp();
9846 if (unOp->gtOp1 != nullptr)
9848 result = WalkTree(&unOp->gtOp1, unOp);
9849 if (result == fgWalkResult::WALK_ABORT)
9860 GenTreeCmpXchg* const cmpXchg = node->AsCmpXchg();
9862 result = WalkTree(&cmpXchg->gtOpComparand, cmpXchg);
9863 if (result == fgWalkResult::WALK_ABORT)
9867 result = WalkTree(&cmpXchg->gtOpValue, cmpXchg);
9868 if (result == fgWalkResult::WALK_ABORT)
9872 result = WalkTree(&cmpXchg->gtOpLocation, cmpXchg);
9873 if (result == fgWalkResult::WALK_ABORT)
9880 case GT_ARR_BOUNDS_CHECK:
9883 #endif // FEATURE_SIMD
9885 GenTreeBoundsChk* const boundsChk = node->AsBoundsChk();
9887 result = WalkTree(&boundsChk->gtIndex, boundsChk);
9888 if (result == fgWalkResult::WALK_ABORT)
9892 result = WalkTree(&boundsChk->gtArrLen, boundsChk);
9893 if (result == fgWalkResult::WALK_ABORT)
9902 GenTreeField* const field = node->AsField();
9904 if (field->gtFldObj != nullptr)
9906 result = WalkTree(&field->gtFldObj, field);
9907 if (result == fgWalkResult::WALK_ABORT)
9917 GenTreeArrElem* const arrElem = node->AsArrElem();
9919 result = WalkTree(&arrElem->gtArrObj, arrElem);
9920 if (result == fgWalkResult::WALK_ABORT)
9925 const unsigned rank = arrElem->gtArrRank;
9926 for (unsigned dim = 0; dim < rank; dim++)
9928 result = WalkTree(&arrElem->gtArrInds[dim], arrElem);
9929 if (result == fgWalkResult::WALK_ABORT)
9939 GenTreeArrOffs* const arrOffs = node->AsArrOffs();
9941 result = WalkTree(&arrOffs->gtOffset, arrOffs);
9942 if (result == fgWalkResult::WALK_ABORT)
9946 result = WalkTree(&arrOffs->gtIndex, arrOffs);
9947 if (result == fgWalkResult::WALK_ABORT)
9951 result = WalkTree(&arrOffs->gtArrObj, arrOffs);
9952 if (result == fgWalkResult::WALK_ABORT)
9961 GenTreeDynBlk* const dynBlock = node->AsDynBlk();
9963 GenTree** op1Use = &dynBlock->gtOp1;
9964 GenTree** op2Use = &dynBlock->gtDynamicSize;
9966 if (TVisitor::UseExecutionOrder && dynBlock->gtEvalSizeFirst)
9968 std::swap(op1Use, op2Use);
9971 result = WalkTree(op1Use, dynBlock);
9972 if (result == fgWalkResult::WALK_ABORT)
9976 result = WalkTree(op2Use, dynBlock);
9977 if (result == fgWalkResult::WALK_ABORT)
9984 case GT_STORE_DYN_BLK:
9986 GenTreeDynBlk* const dynBlock = node->AsDynBlk();
9988 GenTree** op1Use = &dynBlock->gtOp1;
9989 GenTree** op2Use = &dynBlock->gtOp2;
9990 GenTree** op3Use = &dynBlock->gtDynamicSize;
9992 if (TVisitor::UseExecutionOrder)
9994 if (dynBlock->IsReverseOp())
9996 std::swap(op1Use, op2Use);
9998 if (dynBlock->gtEvalSizeFirst)
10000 std::swap(op3Use, op2Use);
10001 std::swap(op2Use, op1Use);
10005 result = WalkTree(op1Use, dynBlock);
10006 if (result == fgWalkResult::WALK_ABORT)
10010 result = WalkTree(op2Use, dynBlock);
10011 if (result == fgWalkResult::WALK_ABORT)
10015 result = WalkTree(op3Use, dynBlock);
10016 if (result == fgWalkResult::WALK_ABORT)
10025 GenTreeCall* const call = node->AsCall();
10027 if (call->gtCallObjp != nullptr)
10029 result = WalkTree(&call->gtCallObjp, call);
10030 if (result == fgWalkResult::WALK_ABORT)
10036 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
10038 result = WalkTree(args->pCurrent(), call);
10039 if (result == fgWalkResult::WALK_ABORT)
10045 for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
10047 result = WalkTree(args->pCurrent(), call);
10048 if (result == fgWalkResult::WALK_ABORT)
10054 if (call->gtCallType == CT_INDIRECT)
10056 if (call->gtCallCookie != nullptr)
10058 result = WalkTree(&call->gtCallCookie, call);
10059 if (result == fgWalkResult::WALK_ABORT)
10065 result = WalkTree(&call->gtCallAddr, call);
10066 if (result == fgWalkResult::WALK_ABORT)
10072 if (call->gtControlExpr != nullptr)
10074 result = WalkTree(&call->gtControlExpr, call);
10075 if (result == fgWalkResult::WALK_ABORT)
10087 assert(node->OperIsBinary());
10089 GenTreeOp* const op = node->AsOp();
10091 GenTree** op1Use = &op->gtOp1;
10092 GenTree** op2Use = &op->gtOp2;
10094 if (TVisitor::UseExecutionOrder && node->IsReverseOp())
10096 std::swap(op1Use, op2Use);
10099 if (*op1Use != nullptr)
10101 result = WalkTree(op1Use, op);
10102 if (result == fgWalkResult::WALK_ABORT)
10108 if (*op2Use != nullptr)
10110 result = WalkTree(op2Use, op);
10111 if (result == fgWalkResult::WALK_ABORT)
10121 // Finally, visit the current node
10122 if (TVisitor::DoPostOrder)
10124 result = reinterpret_cast<TVisitor*>(this)->PostOrderVisit(use, user);
10127 if (TVisitor::ComputeStack)
10136 template <bool computeStack, bool doPreOrder, bool doPostOrder, bool doLclVarsOnly, bool useExecutionOrder>
10137 class GenericTreeWalker final
10138 : public GenTreeVisitor<GenericTreeWalker<computeStack, doPreOrder, doPostOrder, doLclVarsOnly, useExecutionOrder>>
10143 ComputeStack = computeStack,
10144 DoPreOrder = doPreOrder,
10145 DoPostOrder = doPostOrder,
10146 DoLclVarsOnly = doLclVarsOnly,
10147 UseExecutionOrder = useExecutionOrder,
10151 Compiler::fgWalkData* m_walkData;
10154 GenericTreeWalker(Compiler::fgWalkData* walkData)
10155 : GenTreeVisitor<GenericTreeWalker<computeStack, doPreOrder, doPostOrder, doLclVarsOnly, useExecutionOrder>>(
10156 walkData->compiler)
10157 , m_walkData(walkData)
10159 assert(walkData != nullptr);
10163 walkData->parentStack = &this->m_ancestors;
10167 Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
10169 m_walkData->parent = user;
10170 return m_walkData->wtprVisitorFn(use, m_walkData);
10173 Compiler::fgWalkResult PostOrderVisit(GenTree** use, GenTree* user)
10175 m_walkData->parent = user;
10176 return m_walkData->wtpoVisitorFn(use, m_walkData);
10180 class IncLclVarRefCountsVisitor final : public GenTreeVisitor<IncLclVarRefCountsVisitor>
10186 DoLclVarsOnly = true
10189 IncLclVarRefCountsVisitor(Compiler* compiler);
10190 Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user);
10192 static Compiler::fgWalkResult WalkTree(Compiler* compiler, GenTree* tree);
10195 class DecLclVarRefCountsVisitor final : public GenTreeVisitor<DecLclVarRefCountsVisitor>
10201 DoLclVarsOnly = true
10204 DecLclVarRefCountsVisitor(Compiler* compiler);
10205 Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user);
10207 static Compiler::fgWalkResult WalkTree(Compiler* compiler, GenTree* tree);
10211 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10212 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10214 XX Miscellaneous Compiler stuff XX
10216 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10217 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10220 // Values used to mark the types a stack slot is used for
10222 const unsigned TYPE_REF_INT = 0x01; // slot used as a 32-bit int
10223 const unsigned TYPE_REF_LNG = 0x02; // slot used as a 64-bit long
10224 const unsigned TYPE_REF_FLT = 0x04; // slot used as a 32-bit float
10225 const unsigned TYPE_REF_DBL = 0x08; // slot used as a 64-bit float
10226 const unsigned TYPE_REF_PTR = 0x10; // slot used as a 32-bit pointer
10227 const unsigned TYPE_REF_BYR = 0x20; // slot used as a byref pointer
10228 const unsigned TYPE_REF_STC = 0x40; // slot used as a struct
10229 const unsigned TYPE_REF_TYPEMASK = 0x7F; // bits that represent the type
10231 // const unsigned TYPE_REF_ADDR_TAKEN = 0x80; // slots address was taken
10233 /*****************************************************************************
10235 * Variables to keep track of total code amounts.
10240 extern size_t grossVMsize;
10241 extern size_t grossNCsize;
10242 extern size_t totalNCsize;
10244 extern unsigned genMethodICnt;
10245 extern unsigned genMethodNCnt;
10246 extern size_t gcHeaderISize;
10247 extern size_t gcPtrMapISize;
10248 extern size_t gcHeaderNSize;
10249 extern size_t gcPtrMapNSize;
10251 #endif // DISPLAY_SIZES
10253 /*****************************************************************************
10255 * Variables to keep track of basic block counts (more data on 1 BB methods)
10258 #if COUNT_BASIC_BLOCKS
10259 extern Histogram bbCntTable;
10260 extern Histogram bbOneBBSizeTable;
10263 /*****************************************************************************
10265 * Used by optFindNaturalLoops to gather statistical information such as
10266 * - total number of natural loops
10267 * - number of loops with 1, 2, ... exit conditions
10268 * - number of loops that have an iterator (for like)
10269 * - number of loops that have a constant iterator
10274 extern unsigned totalLoopMethods; // counts the total number of methods that have natural loops
10275 extern unsigned maxLoopsPerMethod; // counts the maximum number of loops a method has
10276 extern unsigned totalLoopOverflows; // # of methods that identified more loops than we can represent
10277 extern unsigned totalLoopCount; // counts the total number of natural loops
10278 extern unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
10279 extern unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
10280 extern unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
10281 extern unsigned simpleTestLoopCount; // counts the # of loops with an iterator and a simple loop condition (iter <
10283 extern unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
10284 extern bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
10285 extern unsigned loopsThisMethod; // counts the number of loops in the current method
10286 extern bool loopOverflowThisMethod; // True if we exceeded the max # of loops in the method.
10287 extern Histogram loopCountTable; // Histogram of loop counts
10288 extern Histogram loopExitCountTable; // Histogram of loop exit counts
10290 #endif // COUNT_LOOPS
10292 /*****************************************************************************
10293 * variables to keep track of how many iterations we go in a dataflow pass
10298 extern unsigned CSEiterCount; // counts the # of iteration for the CSE dataflow
10299 extern unsigned CFiterCount; // counts the # of iteration for the Const Folding dataflow
10301 #endif // DATAFLOW_ITER
10303 #if MEASURE_BLOCK_SIZE
10304 extern size_t genFlowNodeSize;
10305 extern size_t genFlowNodeCnt;
10306 #endif // MEASURE_BLOCK_SIZE
10308 #if MEASURE_NODE_SIZE
10309 struct NodeSizeStats
10313 genTreeNodeCnt = 0;
10314 genTreeNodeSize = 0;
10315 genTreeNodeActualSize = 0;
10318 // Count of tree nodes allocated.
10319 unsigned __int64 genTreeNodeCnt;
10321 // The size we allocate.
10322 unsigned __int64 genTreeNodeSize;
10324 // The actual size of the node. Note that the actual size will likely be smaller
10325 // than the allocated size, but we sometimes use SetOper()/ChangeOper() to change
10326 // a smaller node to a larger one. TODO-Cleanup: add stats on
10327 // SetOper()/ChangeOper() usage to quantify this.
10328 unsigned __int64 genTreeNodeActualSize;
10330 extern NodeSizeStats genNodeSizeStats; // Total node size stats
10331 extern NodeSizeStats genNodeSizeStatsPerFunc; // Per-function node size stats
10332 extern Histogram genTreeNcntHist;
10333 extern Histogram genTreeNsizHist;
10334 #endif // MEASURE_NODE_SIZE
10336 /*****************************************************************************
10337 * Count fatal errors (including noway_asserts).
10341 extern unsigned fatal_badCode;
10342 extern unsigned fatal_noWay;
10343 extern unsigned fatal_NOMEM;
10344 extern unsigned fatal_noWayAssertBody;
10346 extern unsigned fatal_noWayAssertBodyArgs;
10348 extern unsigned fatal_NYI;
10349 #endif // MEASURE_FATAL
10351 /*****************************************************************************
10355 #ifdef _TARGET_XARCH_
10357 const instruction INS_SHIFT_LEFT_LOGICAL = INS_shl;
10358 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_shr;
10359 const instruction INS_SHIFT_RIGHT_ARITHM = INS_sar;
10361 const instruction INS_AND = INS_and;
10362 const instruction INS_OR = INS_or;
10363 const instruction INS_XOR = INS_xor;
10364 const instruction INS_NEG = INS_neg;
10365 const instruction INS_TEST = INS_test;
10366 const instruction INS_MUL = INS_imul;
10367 const instruction INS_SIGNED_DIVIDE = INS_idiv;
10368 const instruction INS_UNSIGNED_DIVIDE = INS_div;
10369 const instruction INS_BREAKPOINT = INS_int3;
10370 const instruction INS_ADDC = INS_adc;
10371 const instruction INS_SUBC = INS_sbb;
10372 const instruction INS_NOT = INS_not;
10376 #ifdef _TARGET_ARM_
10378 const instruction INS_SHIFT_LEFT_LOGICAL = INS_lsl;
10379 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_lsr;
10380 const instruction INS_SHIFT_RIGHT_ARITHM = INS_asr;
10382 const instruction INS_AND = INS_and;
10383 const instruction INS_OR = INS_orr;
10384 const instruction INS_XOR = INS_eor;
10385 const instruction INS_NEG = INS_rsb;
10386 const instruction INS_TEST = INS_tst;
10387 const instruction INS_MUL = INS_mul;
10388 const instruction INS_MULADD = INS_mla;
10389 const instruction INS_SIGNED_DIVIDE = INS_sdiv;
10390 const instruction INS_UNSIGNED_DIVIDE = INS_udiv;
10391 const instruction INS_BREAKPOINT = INS_bkpt;
10392 const instruction INS_ADDC = INS_adc;
10393 const instruction INS_SUBC = INS_sbc;
10394 const instruction INS_NOT = INS_mvn;
10396 const instruction INS_ABS = INS_vabs;
10397 const instruction INS_ROUND = INS_invalid;
10398 const instruction INS_SQRT = INS_vsqrt;
10402 #ifdef _TARGET_ARM64_
10404 const instruction INS_MULADD = INS_madd;
10405 const instruction INS_BREAKPOINT = INS_bkpt;
10407 const instruction INS_ABS = INS_fabs;
10408 const instruction INS_ROUND = INS_frintn;
10409 const instruction INS_SQRT = INS_fsqrt;
10413 /*****************************************************************************/
10415 extern const BYTE genTypeSizes[];
10416 extern const BYTE genTypeAlignments[];
10417 extern const BYTE genTypeStSzs[];
10418 extern const BYTE genActualTypes[];
10420 /*****************************************************************************/
10422 // VERY_LARGE_FRAME_SIZE_REG_MASK is the set of registers we need to use for
10423 // the probing loop generated for very large stack frames (see `getVeryLargeFrameSize`).
10425 #ifdef _TARGET_ARM_
10426 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R4 | RBM_R5 | RBM_R6)
10427 #elif defined(_TARGET_ARM64_)
10428 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R9 | RBM_R10 | RBM_R11)
10431 /*****************************************************************************/
10433 #define REG_CORRUPT regNumber(REG_NA + 1)
10434 #define RBM_CORRUPT (RBM_ILLEGAL | regMaskTP(1))
10435 #define REG_PAIR_CORRUPT regPairNo(REG_PAIR_NONE + 1)
10437 /*****************************************************************************/
10439 extern BasicBlock dummyBB;
10441 /*****************************************************************************/
10442 /*****************************************************************************/
10444 // foreach_treenode_execution_order: An iterator that iterates through all the tree
10445 // nodes of a statement in execution order.
10446 // __stmt: a GT_STMT type GenTree*
10447 // __node: a GenTree*, already declared, that gets updated with each node in the statement, in execution order
10449 #define foreach_treenode_execution_order(__node, __stmt) \
10450 for ((__node) = (__stmt)->gtStmt.gtStmtList; (__node); (__node) = (__node)->gtNext)
10452 // foreach_block: An iterator over all blocks in the function.
10453 // __compiler: the Compiler* object
10454 // __block : a BasicBlock*, already declared, that gets updated each iteration.
10456 #define foreach_block(__compiler, __block) \
10457 for ((__block) = (__compiler)->fgFirstBB; (__block); (__block) = (__block)->bbNext)
10459 /*****************************************************************************/
10460 /*****************************************************************************/
10464 void dumpConvertedVarSet(Compiler* comp, VARSET_VALARG_TP vars);
10466 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10467 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10469 XX Debugging helpers XX
10471 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10472 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10475 /*****************************************************************************/
10476 /* The following functions are intended to be called from the debugger, to dump
10477 * various data structures. The can be used in the debugger Watch or Quick Watch
10478 * windows. They are designed to be short to type and take as few arguments as
10479 * possible. The 'c' versions take a Compiler*, whereas the 'd' versions use the TlsCompiler.
10480 * See the function definition comment for more details.
10483 void cBlock(Compiler* comp, BasicBlock* block);
10484 void cBlocks(Compiler* comp);
10485 void cBlocksV(Compiler* comp);
10486 void cTree(Compiler* comp, GenTree* tree);
10487 void cTrees(Compiler* comp);
10488 void cEH(Compiler* comp);
10489 void cVar(Compiler* comp, unsigned lclNum);
10490 void cVarDsc(Compiler* comp, LclVarDsc* varDsc);
10491 void cVars(Compiler* comp);
10492 void cVarsFinal(Compiler* comp);
10493 void cBlockPreds(Compiler* comp, BasicBlock* block);
10494 void cReach(Compiler* comp);
10495 void cDoms(Compiler* comp);
10496 void cLiveness(Compiler* comp);
10497 void cCVarSet(Compiler* comp, VARSET_VALARG_TP vars);
10499 void cFuncIR(Compiler* comp);
10500 void cBlockIR(Compiler* comp, BasicBlock* block);
10501 void cLoopIR(Compiler* comp, Compiler::LoopDsc* loop);
10502 void cTreeIR(Compiler* comp, GenTree* tree);
10503 int cTreeTypeIR(Compiler* comp, GenTree* tree);
10504 int cTreeKindsIR(Compiler* comp, GenTree* tree);
10505 int cTreeFlagsIR(Compiler* comp, GenTree* tree);
10506 int cOperandIR(Compiler* comp, GenTree* operand);
10507 int cLeafIR(Compiler* comp, GenTree* tree);
10508 int cIndirIR(Compiler* comp, GenTree* tree);
10509 int cListIR(Compiler* comp, GenTree* list);
10510 int cSsaNumIR(Compiler* comp, GenTree* tree);
10511 int cValNumIR(Compiler* comp, GenTree* tree);
10512 int cDependsIR(Compiler* comp, GenTree* comma, bool* first);
10514 void dBlock(BasicBlock* block);
10517 void dTree(GenTree* tree);
10520 void dVar(unsigned lclNum);
10521 void dVarDsc(LclVarDsc* varDsc);
10524 void dBlockPreds(BasicBlock* block);
10528 void dCVarSet(VARSET_VALARG_TP vars);
10530 void dVarSet(VARSET_VALARG_TP vars);
10531 void dRegMask(regMaskTP mask);
10534 void dBlockIR(BasicBlock* block);
10535 void dTreeIR(GenTree* tree);
10536 void dLoopIR(Compiler::LoopDsc* loop);
10537 void dLoopNumIR(unsigned loopNum);
10538 int dTabStopIR(int curr, int tabstop);
10539 int dTreeTypeIR(GenTree* tree);
10540 int dTreeKindsIR(GenTree* tree);
10541 int dTreeFlagsIR(GenTree* tree);
10542 int dOperandIR(GenTree* operand);
10543 int dLeafIR(GenTree* tree);
10544 int dIndirIR(GenTree* tree);
10545 int dListIR(GenTree* list);
10546 int dSsaNumIR(GenTree* tree);
10547 int dValNumIR(GenTree* tree);
10548 int dDependsIR(GenTree* comma);
10551 GenTree* dFindTree(GenTree* tree, unsigned id);
10552 GenTree* dFindTree(unsigned id);
10553 GenTreeStmt* dFindStmt(unsigned id);
10554 BasicBlock* dFindBlock(unsigned bbNum);
10558 #include "compiler.hpp" // All the shared inline functions
10560 /*****************************************************************************/
10561 #endif //_COMPILER_H_
10562 /*****************************************************************************/