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 /*****************************************************************************/
36 #include "simplerhash.h"
37 #include "cycletimer.h"
40 #include "arraystack.h"
43 #include "expandarray.h"
44 #include "tinyarray.h"
47 #include "jittelemetry.h"
52 #include "codegeninterface.h"
54 #include "jitgcinfo.h"
56 #if DUMP_GC_TABLES && defined(JIT32_GCENCODER)
64 // This is only used locally in the JIT to indicate that
65 // a verification block should be inserted
66 #define SEH_VERIFICATION_EXCEPTION 0xe0564552 // VER
68 /*****************************************************************************
69 * Forward declarations
72 struct InfoHdr; // defined in GCInfo.h
73 struct escapeMapping_t; // defined in flowgraph.cpp
74 class emitter; // defined in emit.h
75 struct ShadowParamVarInfo; // defined in GSChecks.cpp
76 struct InitVarDscInfo; // defined in register_arg_convention.h
77 class FgStack; // defined in flowgraph.cpp
78 #if FEATURE_STACK_FP_X87
79 struct FlatFPStateX87; // defined in fp.h
82 class CSE_DataFlow; // defined in OptCSE.cpp
88 // The following are defined in this file, Compiler.h
92 /*****************************************************************************
98 /*****************************************************************************/
101 // Declare global operator new overloads that use the Compiler::compGetMem() function for allocation.
104 // Or the more-general IAllocator interface.
105 void* __cdecl operator new(size_t n, IAllocator* alloc);
106 void* __cdecl operator new[](size_t n, IAllocator* alloc);
108 // I wanted to make the second argument optional, with default = CMK_Unknown, but that
109 // caused these to be ambiguous with the global placement new operators.
110 void* __cdecl operator new(size_t n, Compiler* context, CompMemKind cmk);
111 void* __cdecl operator new[](size_t n, Compiler* context, CompMemKind cmk);
112 void* __cdecl operator new(size_t n, void* p, const jitstd::placement_t& syntax_difference);
114 // Requires the definitions of "operator new" so including "LoopCloning.h" after the definitions.
115 #include "loopcloning.h"
117 /*****************************************************************************/
119 /* This is included here and not earlier as it needs the definition of "CSE"
120 * which is defined in the section above */
122 /*****************************************************************************/
124 unsigned genLog2(unsigned value);
125 unsigned genLog2(unsigned __int64 value);
127 var_types genActualType(var_types type);
128 var_types genUnsignedType(var_types type);
129 var_types genSignedType(var_types type);
131 unsigned ReinterpretHexAsDecimal(unsigned);
133 /*****************************************************************************/
136 #ifdef FEATURE_AVX_SUPPORT
137 const unsigned TEMP_MAX_SIZE = YMM_REGSIZE_BYTES;
138 #else // !FEATURE_AVX_SUPPORT
139 const unsigned TEMP_MAX_SIZE = XMM_REGSIZE_BYTES;
140 #endif // !FEATURE_AVX_SUPPORT
141 #else // !FEATURE_SIMD
142 const unsigned TEMP_MAX_SIZE = sizeof(double);
143 #endif // !FEATURE_SIMD
144 const unsigned TEMP_SLOT_COUNT = (TEMP_MAX_SIZE / sizeof(int));
146 const unsigned FLG_CCTOR = (CORINFO_FLG_CONSTRUCTOR | CORINFO_FLG_STATIC);
149 const int BAD_STK_OFFS = 0xBAADF00D; // for LclVarDsc::lvStkOffs
152 // The following holds the Local var info (scope information)
153 typedef const char* VarName; // Actual ASCII string
156 IL_OFFSET vsdLifeBeg; // instr offset of beg of life
157 IL_OFFSET vsdLifeEnd; // instr offset of end of life
158 unsigned vsdVarNum; // (remapped) LclVarDsc number
161 VarName vsdName; // name of the var
164 unsigned vsdLVnum; // 'which' in eeGetLVinfo().
165 // Also, it is the index of this entry in the info.compVarScopes array,
166 // which is useful since the array is also accessed via the
167 // compEnterScopeList and compExitScopeList sorted arrays.
170 /*****************************************************************************
172 * The following holds the local variable counts and the descriptor table.
175 // This is the location of a definition.
181 DefLoc() : m_blk(nullptr), m_tree(nullptr)
186 // This class encapsulates all info about a local variable that may vary for different SSA names
191 ValueNumPair m_vnPair;
199 typedef ExpandArray<LclSsaVarDsc> PerSsaArray;
204 // The constructor. Most things can just be zero'ed.
205 LclVarDsc(Compiler* comp);
207 // note this only packs because var_types is a typedef of unsigned char
208 var_types lvType : 5; // TYP_INT/LONG/FLOAT/DOUBLE/REF
210 unsigned char lvIsParam : 1; // is this a parameter?
211 unsigned char lvIsRegArg : 1; // is this a register argument?
212 unsigned char lvFramePointerBased : 1; // 0 = off of REG_SPBASE (e.g., ESP), 1 = off of REG_FPBASE (e.g., EBP)
214 unsigned char lvStructGcCount : 3; // if struct, how many GC pointer (stop counting at 7). The only use of values >1
215 // is to help determine whether to use block init in the prolog.
216 unsigned char lvOnFrame : 1; // (part of) the variable lives on the frame
217 unsigned char lvDependReg : 1; // did the predictor depend upon this being enregistered
218 unsigned char lvRegister : 1; // assigned to live in a register? For RyuJIT backend, this is only set if the
219 // variable is in the same register for the entire function.
220 unsigned char lvTracked : 1; // is this a tracked variable?
221 bool lvTrackedNonStruct()
223 return lvTracked && lvType != TYP_STRUCT;
225 unsigned char lvPinned : 1; // is this a pinned variable?
227 unsigned char lvMustInit : 1; // must be initialized
228 unsigned char lvAddrExposed : 1; // The address of this variable is "exposed" -- passed as an argument, stored in a
229 // global location, etc.
230 // We cannot reason reliably about the value of the variable.
231 unsigned char lvDoNotEnregister : 1; // Do not enregister this variable.
232 unsigned char lvFieldAccessed : 1; // The var is a struct local, and a field of the variable is accessed. Affects
236 // These further document the reasons for setting "lvDoNotEnregister". (Note that "lvAddrExposed" is one of the
238 // also, lvType == TYP_STRUCT prevents enregistration. At least one of the reasons should be true.
239 unsigned char lvVMNeedsStackAddr : 1; // The VM may have access to a stack-relative address of the variable, and
240 // read/write its value.
241 unsigned char lvLiveInOutOfHndlr : 1; // The variable was live in or out of an exception handler, and this required
242 // the variable to be
243 // in the stack (at least at those boundaries.)
244 unsigned char lvLclFieldExpr : 1; // The variable is not a struct, but was accessed like one (e.g., reading a
245 // particular byte from an int).
246 unsigned char lvLclBlockOpAddr : 1; // The variable was written to via a block operation that took its address.
247 unsigned char lvLiveAcrossUCall : 1; // The variable is live across an unmanaged call.
249 unsigned char lvIsCSE : 1; // Indicates if this LclVar is a CSE variable.
250 unsigned char lvRefAssign : 1; // involved in pointer assignment
251 unsigned char lvHasLdAddrOp : 1; // has ldloca or ldarga opcode on this local.
252 unsigned char lvStackByref : 1; // This is a compiler temporary of TYP_BYREF that is known to point into our local
255 unsigned char lvHasILStoreOp : 1; // there is at least one STLOC or STARG on this local
256 unsigned char lvHasMultipleILStoreOp : 1; // there is more than one STLOC on this local
258 unsigned char lvIsTemp : 1; // Short-lifetime compiler temp
260 unsigned char lvIsBoolean : 1; // set if variable is boolean
262 unsigned char lvRngOptDone : 1; // considered for range check opt?
263 unsigned char lvLoopInc : 1; // incremented in the loop?
264 unsigned char lvLoopAsg : 1; // reassigned in the loop (other than a monotonic inc/dec for the index var)?
265 unsigned char lvArrIndx : 1; // used as an array index?
266 unsigned char lvArrIndxOff : 1; // used as an array index with an offset?
267 unsigned char lvArrIndxDom : 1; // index dominates loop exit
269 unsigned char lvSingleDef : 1; // variable has a single def
270 unsigned char lvDisqualify : 1; // variable is no longer OK for add copy optimization
271 unsigned char lvVolatileHint : 1; // hint for AssertionProp
274 unsigned char lvSpilled : 1; // enregistered variable was spilled
275 #ifndef _TARGET_64BIT_
276 unsigned char lvStructDoubleAlign : 1; // Must we double align this struct?
277 #endif // !_TARGET_64BIT_
278 #ifdef _TARGET_64BIT_
279 unsigned char lvQuirkToLong : 1; // Quirk to allocate this LclVar as a 64-bit long
282 unsigned char lvKeepType : 1; // Don't change the type of this variable
283 unsigned char lvNoLclFldStress : 1; // Can't apply local field stress on this one
285 unsigned char lvIsPtr : 1; // Might this be used in an address computation? (used by buffer overflow security
287 unsigned char lvIsUnsafeBuffer : 1; // Does this contain an unsafe buffer requiring buffer overflow security checks?
288 unsigned char lvPromoted : 1; // True when this local is a promoted struct, a normed struct, or a "split" long on a
290 unsigned char lvIsStructField : 1; // Is this local var a field of a promoted struct local?
291 unsigned char lvContainsFloatingFields : 1; // Does this struct contains floating point fields?
292 unsigned char lvOverlappingFields : 1; // True when we have a struct with possibly overlapping fields
293 unsigned char lvContainsHoles : 1; // True when we have a promoted struct that contains holes
294 unsigned char lvCustomLayout : 1; // True when this struct has "CustomLayout"
296 unsigned char lvIsMultiRegArg : 1; // true if this is a multireg LclVar struct used in an argument context
297 unsigned char lvIsMultiRegRet : 1; // true if this is a multireg LclVar struct assigned from a multireg call
300 unsigned char _lvIsHfa : 1; // Is this a struct variable who's class handle is an HFA type
301 unsigned char _lvIsHfaRegArg : 1; // Is this a HFA argument variable? // TODO-CLEANUP: Remove this and replace
302 // with (lvIsRegArg && lvIsHfa())
303 unsigned char _lvHfaTypeIsFloat : 1; // Is the HFA type float or double?
304 #endif // FEATURE_HFA
307 // TODO-Cleanup: See the note on lvSize() - this flag is only in use by asserts that are checking for struct
308 // types, and is needed because of cases where TYP_STRUCT is bashed to an integral type.
309 // Consider cleaning this up so this workaround is not required.
310 unsigned char lvUnusedStruct : 1; // All references to this promoted struct are through its field locals.
311 // I.e. there is no longer any reference to the struct directly.
312 // In this case we can simply remove this struct local.
314 #ifndef LEGACY_BACKEND
315 unsigned char lvLRACandidate : 1; // Tracked for linear scan register allocation purposes
316 #endif // !LEGACY_BACKEND
319 // Note that both SIMD vector args and locals are marked as lvSIMDType = true, but the
320 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD*.
321 unsigned char lvSIMDType : 1; // This is a SIMD struct
322 unsigned char lvUsedInSIMDIntrinsic : 1; // This tells lclvar is used for simd intrinsic
323 var_types lvBaseType : 5; // Note: this only packs because var_types is a typedef of unsigned char
324 #endif // FEATURE_SIMD
325 unsigned char lvRegStruct : 1; // This is a reg-sized non-field-addressed struct.
327 unsigned char lvClassIsExact : 1; // lvClassHandle is the exact type
330 unsigned char lvClassInfoUpdated : 1; // true if this var has updated class handle or exactness
334 unsigned lvFieldLclStart; // The index of the local var representing the first field in the promoted struct
336 unsigned lvParentLcl; // The index of the local var representing the parent (i.e. the promoted struct local).
337 // Valid on promoted struct local fields.
340 unsigned char lvFieldCnt; // Number of fields in the promoted VarDsc.
341 unsigned char lvFldOffset;
342 unsigned char lvFldOrdinal;
344 #if FEATURE_MULTIREG_ARGS
345 regNumber lvRegNumForSlot(unsigned slotNum)
351 else if (slotNum == 1)
353 return lvOtherArgReg;
357 assert(false && "Invalid slotNum!");
362 #endif // FEATURE_MULTIREG_ARGS
380 bool lvIsHfaRegArg() const
383 return _lvIsHfaRegArg;
389 void lvSetIsHfaRegArg()
392 _lvIsHfaRegArg = true;
396 bool lvHfaTypeIsFloat() const
399 return _lvHfaTypeIsFloat;
405 void lvSetHfaTypeIsFloat(bool value)
408 _lvHfaTypeIsFloat = value;
412 // on Arm64 - Returns 1-4 indicating the number of register slots used by the HFA
413 // on Arm32 - Returns the total number of single FP register slots used by the HFA, max is 8
415 unsigned lvHfaSlots() const
418 assert(lvType == TYP_STRUCT);
420 return lvExactSize / sizeof(float);
421 #else // _TARGET_ARM64_
422 if (lvHfaTypeIsFloat())
424 return lvExactSize / sizeof(float);
428 return lvExactSize / sizeof(double);
430 #endif // _TARGET_ARM64_
433 // lvIsMultiRegArgOrRet()
434 // returns true if this is a multireg LclVar struct used in an argument context
435 // or if this is a multireg LclVar struct assigned from a multireg call
436 bool lvIsMultiRegArgOrRet()
438 return lvIsMultiRegArg || lvIsMultiRegRet;
442 regNumberSmall _lvRegNum; // Used to store the register this variable is in (or, the low register of a
443 // register pair). For LEGACY_BACKEND, this is only set if lvRegister is
444 // non-zero. For non-LEGACY_BACKEND, it is set during codegen any time the
445 // variable is enregistered (in non-LEGACY_BACKEND, lvRegister is only set
446 // to non-zero if the variable gets the same register assignment for its entire
448 #if !defined(_TARGET_64BIT_)
449 regNumberSmall _lvOtherReg; // Used for "upper half" of long var.
450 #endif // !defined(_TARGET_64BIT_)
452 regNumberSmall _lvArgReg; // The register in which this argument is passed.
454 #if FEATURE_MULTIREG_ARGS
455 regNumberSmall _lvOtherArgReg; // Used for the second part of the struct passed in a register.
456 // Note this is defined but not used by ARM32
457 #endif // FEATURE_MULTIREG_ARGS
459 #ifndef LEGACY_BACKEND
461 regNumberSmall _lvArgInitReg; // the register into which the argument is moved at entry
462 regPairNoSmall _lvArgInitRegPair; // the register pair into which the argument is moved at entry
464 #endif // !LEGACY_BACKEND
467 // The register number is stored in a small format (8 bits), but the getters return and the setters take
468 // a full-size (unsigned) format, to localize the casts here.
470 /////////////////////
472 __declspec(property(get = GetRegNum, put = SetRegNum)) regNumber lvRegNum;
474 regNumber GetRegNum() const
476 return (regNumber)_lvRegNum;
479 void SetRegNum(regNumber reg)
481 _lvRegNum = (regNumberSmall)reg;
482 assert(_lvRegNum == reg);
485 /////////////////////
487 #if defined(_TARGET_64BIT_)
488 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
490 regNumber GetOtherReg() const
492 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
493 // "unreachable code" warnings
497 void SetOtherReg(regNumber reg)
499 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
500 // "unreachable code" warnings
502 #else // !_TARGET_64BIT_
503 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
505 regNumber GetOtherReg() const
507 return (regNumber)_lvOtherReg;
510 void SetOtherReg(regNumber reg)
512 _lvOtherReg = (regNumberSmall)reg;
513 assert(_lvOtherReg == reg);
515 #endif // !_TARGET_64BIT_
517 /////////////////////
519 __declspec(property(get = GetArgReg, put = SetArgReg)) regNumber lvArgReg;
521 regNumber GetArgReg() const
523 return (regNumber)_lvArgReg;
526 void SetArgReg(regNumber reg)
528 _lvArgReg = (regNumberSmall)reg;
529 assert(_lvArgReg == reg);
532 #if FEATURE_MULTIREG_ARGS
533 __declspec(property(get = GetOtherArgReg, put = SetOtherArgReg)) regNumber lvOtherArgReg;
535 regNumber GetOtherArgReg() const
537 return (regNumber)_lvOtherArgReg;
540 void SetOtherArgReg(regNumber reg)
542 _lvOtherArgReg = (regNumberSmall)reg;
543 assert(_lvOtherArgReg == reg);
545 #endif // FEATURE_MULTIREG_ARGS
548 // Is this is a SIMD struct?
549 bool lvIsSIMDType() const
554 // Is this is a SIMD struct which is used for SIMD intrinsic?
555 bool lvIsUsedInSIMDIntrinsic() const
557 return lvUsedInSIMDIntrinsic;
560 // If feature_simd not enabled, return false
561 bool lvIsSIMDType() const
565 bool lvIsUsedInSIMDIntrinsic() const
571 /////////////////////
573 #ifndef LEGACY_BACKEND
574 __declspec(property(get = GetArgInitReg, put = SetArgInitReg)) regNumber lvArgInitReg;
576 regNumber GetArgInitReg() const
578 return (regNumber)_lvArgInitReg;
581 void SetArgInitReg(regNumber reg)
583 _lvArgInitReg = (regNumberSmall)reg;
584 assert(_lvArgInitReg == reg);
587 /////////////////////
589 __declspec(property(get = GetArgInitRegPair, put = SetArgInitRegPair)) regPairNo lvArgInitRegPair;
591 regPairNo GetArgInitRegPair() const
593 regPairNo regPair = (regPairNo)_lvArgInitRegPair;
594 assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
598 void SetArgInitRegPair(regPairNo regPair)
600 assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
601 _lvArgInitRegPair = (regPairNoSmall)regPair;
602 assert(_lvArgInitRegPair == regPair);
605 /////////////////////
607 bool lvIsRegCandidate() const
609 return lvLRACandidate != 0;
612 bool lvIsInReg() const
614 return lvIsRegCandidate() && (lvRegNum != REG_STK);
617 #else // LEGACY_BACKEND
619 bool lvIsRegCandidate() const
621 return lvTracked != 0;
624 bool lvIsInReg() const
626 return lvRegister != 0;
629 #endif // LEGACY_BACKEND
631 regMaskTP lvRegMask() const
633 regMaskTP regMask = RBM_NONE;
634 if (varTypeIsFloating(TypeGet()))
636 if (lvRegNum != REG_STK)
638 regMask = genRegMaskFloat(lvRegNum, TypeGet());
643 if (lvRegNum != REG_STK)
645 regMask = genRegMask(lvRegNum);
648 // For longs we may have two regs
649 if (isRegPairType(lvType) && lvOtherReg != REG_STK)
651 regMask |= genRegMask(lvOtherReg);
657 regMaskSmall lvPrefReg; // set of regs it prefers to live in
659 unsigned short lvVarIndex; // variable tracking index
660 unsigned short lvRefCnt; // unweighted (real) reference count
661 unsigned lvRefCntWtd; // weighted reference count
662 int lvStkOffs; // stack offset of home
663 unsigned lvExactSize; // (exact) size of the type in bytes
665 // Is this a promoted struct?
666 // This method returns true only for structs (including SIMD structs), not for
667 // locals that are split on a 32-bit target.
668 // It is only necessary to use this:
669 // 1) if only structs are wanted, and
670 // 2) if Lowering has already been done.
671 // Otherwise lvPromoted is valid.
672 bool lvPromotedStruct()
674 #if !defined(_TARGET_64BIT_)
675 return (lvPromoted && !varTypeIsLong(lvType));
676 #else // defined(_TARGET_64BIT_)
678 #endif // defined(_TARGET_64BIT_)
681 unsigned lvSize() const // Size needed for storage representation. Only used for structs or TYP_BLK.
683 // TODO-Review: Sometimes we get called on ARM with HFA struct variables that have been promoted,
684 // where the struct itself is no longer used because all access is via its member fields.
685 // When that happens, the struct is marked as unused and its type has been changed to
686 // TYP_INT (to keep the GC tracking code from looking at it).
687 // See Compiler::raAssignVars() for details. For example:
688 // N002 ( 4, 3) [00EA067C] ------------- return struct $346
689 // N001 ( 3, 2) [00EA0628] ------------- lclVar struct(U) V03 loc2
690 // float V03.f1 (offs=0x00) -> V12 tmp7
691 // f8 (last use) (last use) $345
692 // Here, the "struct(U)" shows that the "V03 loc2" variable is unused. Not shown is that V03
693 // is now TYP_INT in the local variable table. It's not really unused, because it's in the tree.
695 assert(varTypeIsStruct(lvType) || (lvType == TYP_BLK) || (lvPromoted && lvUnusedStruct));
697 #if defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
698 // For 32-bit architectures, we make local variable SIMD12 types 16 bytes instead of just 12. We can't do
699 // this for arguments, which must be passed according the defined ABI. We don't want to do this for
700 // dependently promoted struct fields, but we don't know that here. See lvaMapSimd12ToSimd16().
701 if ((lvType == TYP_SIMD12) && !lvIsParam)
703 assert(lvExactSize == 12);
706 #endif // defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
708 return (unsigned)(roundUp(lvExactSize, TARGET_POINTER_SIZE));
711 unsigned lvSlotNum; // original slot # (if remapped)
713 typeInfo lvVerTypeInfo; // type info needed for verification
715 CORINFO_CLASS_HANDLE lvClassHnd; // class handle for the local, or null if not known
717 BYTE* lvGcLayout; // GC layout info for structs
720 BlockSet lvRefBlks; // Set of blocks that contain refs
721 GenTreePtr lvDefStmt; // Pointer to the statement with the single definition
722 void lvaDisqualifyVar(); // Call to disqualify a local variable from use in optAddCopies
724 var_types TypeGet() const
726 return (var_types)lvType;
728 bool lvStackAligned() const
730 assert(lvIsStructField);
731 return ((lvFldOffset % sizeof(void*)) == 0);
733 bool lvNormalizeOnLoad() const
735 return varTypeIsSmall(TypeGet()) &&
736 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
737 (lvIsParam || lvAddrExposed || lvIsStructField);
740 bool lvNormalizeOnStore()
742 return varTypeIsSmall(TypeGet()) &&
743 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
744 !(lvIsParam || lvAddrExposed || lvIsStructField);
747 void lvaResetSortAgainFlag(Compiler* pComp);
748 void decRefCnts(BasicBlock::weight_t weight, Compiler* pComp, bool propagate = true);
749 void incRefCnts(BasicBlock::weight_t weight, Compiler* pComp, bool propagate = true);
750 void setPrefReg(regNumber regNum, Compiler* pComp);
751 void addPrefReg(regMaskTP regMask, Compiler* pComp);
752 bool IsFloatRegType() const
754 return isFloatRegType(lvType) || lvIsHfaRegArg();
756 var_types GetHfaType() const
758 return lvIsHfa() ? (lvHfaTypeIsFloat() ? TYP_FLOAT : TYP_DOUBLE) : TYP_UNDEF;
760 void SetHfaType(var_types type)
762 assert(varTypeIsFloating(type));
763 lvSetHfaTypeIsFloat(type == TYP_FLOAT);
766 #ifndef LEGACY_BACKEND
767 var_types lvaArgType();
770 PerSsaArray lvPerSsaData;
773 // Keep track of the # of SsaNames, for a bounds check.
774 unsigned lvNumSsaNames;
777 // Returns the address of the per-Ssa data for the given ssaNum (which is required
778 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
779 // not an SSA variable).
780 LclSsaVarDsc* GetPerSsaData(unsigned ssaNum)
782 assert(ssaNum != SsaConfig::RESERVED_SSA_NUM);
783 assert(SsaConfig::RESERVED_SSA_NUM == 0);
784 unsigned zeroBased = ssaNum - SsaConfig::UNINIT_SSA_NUM;
785 assert(zeroBased < lvNumSsaNames);
786 return &lvPerSsaData.GetRef(zeroBased);
791 void PrintVarReg() const
793 if (isRegPairType(TypeGet()))
795 printf("%s:%s", getRegName(lvOtherReg), // hi32
796 getRegName(lvRegNum)); // lo32
800 printf("%s", getRegName(lvRegNum));
805 }; // class LclVarDsc
808 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
809 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
813 XX The temporary lclVars allocated by the compiler for code generation XX
815 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
816 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
819 /*****************************************************************************
821 * The following keeps track of temporaries allocated in the stack frame
822 * during code-generation (after register allocation). These spill-temps are
823 * only used if we run out of registers while evaluating a tree.
825 * These are different from the more common temps allocated by lvaGrabTemp().
836 static const int BAD_TEMP_OFFSET = 0xDDDDDDDD; // used as a sentinel "bad value" for tdOffs in DEBUG
844 TempDsc(int _tdNum, unsigned _tdSize, var_types _tdType) : tdNum(_tdNum), tdSize((BYTE)_tdSize), tdType(_tdType)
848 0); // temps must have a negative number (so they have a different number from all local variables)
849 tdOffs = BAD_TEMP_OFFSET;
853 IMPL_LIMITATION("too many spill temps");
858 bool tdLegalOffset() const
860 return tdOffs != BAD_TEMP_OFFSET;
864 int tdTempOffs() const
866 assert(tdLegalOffset());
869 void tdSetTempOffs(int offs)
872 assert(tdLegalOffset());
874 void tdAdjustTempOffs(int offs)
877 assert(tdLegalOffset());
880 int tdTempNum() const
885 unsigned tdTempSize() const
889 var_types tdTempType() const
895 // interface to hide linearscan implementation from rest of compiler
896 class LinearScanInterface
899 virtual void doLinearScan() = 0;
900 virtual void recordVarLocationsAtStartOfBB(BasicBlock* bb) = 0;
903 LinearScanInterface* getLinearScanAllocator(Compiler* comp);
905 // Information about arrays: their element type and size, and the offset of the first element.
906 // We label GT_IND's that are array indices with GTF_IND_ARR_INDEX, and, for such nodes,
907 // associate an array info via the map retrieved by GetArrayInfoMap(). This information is used,
908 // for example, in value numbering of array index expressions.
911 var_types m_elemType;
912 CORINFO_CLASS_HANDLE m_elemStructType;
914 unsigned m_elemOffset;
916 ArrayInfo() : m_elemType(TYP_UNDEF), m_elemStructType(nullptr), m_elemSize(0), m_elemOffset(0)
920 ArrayInfo(var_types elemType, unsigned elemSize, unsigned elemOffset, CORINFO_CLASS_HANDLE elemStructType)
921 : m_elemType(elemType), m_elemStructType(elemStructType), m_elemSize(elemSize), m_elemOffset(elemOffset)
926 // This enumeration names the phases into which we divide compilation. The phases should completely
927 // partition a compilation.
930 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) enum_nm,
931 #include "compphases.h"
935 extern const char* PhaseNames[];
936 extern const char* PhaseEnums[];
937 extern const LPCWSTR PhaseShortNames[];
939 // The following enum provides a simple 1:1 mapping to CLR API's
940 enum API_ICorJitInfo_Names
942 #define DEF_CLR_API(name) API_##name,
943 #include "ICorJitInfo_API_names.h"
947 //---------------------------------------------------------------
951 // A "CompTimeInfo" is a structure for tracking the compilation time of one or more methods.
952 // We divide a compilation into a sequence of contiguous phases, and track the total (per-thread) cycles
953 // of the compilation, as well as the cycles for each phase. We also track the number of bytecodes.
954 // If there is a failure in reading a timer at any point, the "CompTimeInfo" becomes invalid, as indicated
955 // by "m_timerFailure" being true.
956 // If FEATURE_JIT_METHOD_PERF is not set, we define a minimal form of this, enough to let other code compile.
959 #ifdef FEATURE_JIT_METHOD_PERF
960 // The string names of the phases.
961 static const char* PhaseNames[];
963 static bool PhaseHasChildren[];
964 static int PhaseParent[];
965 static bool PhaseReportsIRSize[];
967 unsigned m_byteCodeBytes;
968 unsigned __int64 m_totalCycles;
969 unsigned __int64 m_invokesByPhase[PHASE_NUMBER_OF];
970 unsigned __int64 m_cyclesByPhase[PHASE_NUMBER_OF];
971 #if MEASURE_CLRAPI_CALLS
972 unsigned __int64 m_CLRinvokesByPhase[PHASE_NUMBER_OF];
973 unsigned __int64 m_CLRcyclesByPhase[PHASE_NUMBER_OF];
976 unsigned m_nodeCountAfterPhase[PHASE_NUMBER_OF];
978 // For better documentation, we call EndPhase on
979 // non-leaf phases. We should also call EndPhase on the
980 // last leaf subphase; obviously, the elapsed cycles between the EndPhase
981 // for the last leaf subphase and the EndPhase for an ancestor should be very small.
982 // We add all such "redundant end phase" intervals to this variable below; we print
983 // it out in a report, so we can verify that it is, indeed, very small. If it ever
984 // isn't, this means that we're doing something significant between the end of the last
985 // declared subphase and the end of its parent.
986 unsigned __int64 m_parentPhaseEndSlop;
989 #if MEASURE_CLRAPI_CALLS
990 // The following measures the time spent inside each individual CLR API call.
991 unsigned m_allClrAPIcalls;
992 unsigned m_perClrAPIcalls[API_ICorJitInfo_Names::API_COUNT];
993 unsigned __int64 m_allClrAPIcycles;
994 unsigned __int64 m_perClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
995 unsigned __int32 m_maxClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
996 #endif // MEASURE_CLRAPI_CALLS
998 CompTimeInfo(unsigned byteCodeBytes);
1002 #ifdef FEATURE_JIT_METHOD_PERF
1004 #if MEASURE_CLRAPI_CALLS
1005 struct WrapICorJitInfo;
1008 // This class summarizes the JIT time information over the course of a run: the number of methods compiled,
1009 // and the total and maximum timings. (These are instances of the "CompTimeInfo" type described above).
1010 // The operation of adding a single method's timing to the summary may be performed concurrently by several
1011 // threads, so it is protected by a lock.
1012 // This class is intended to be used as a singleton type, with only a single instance.
1013 class CompTimeSummaryInfo
1015 // This lock protects the fields of all CompTimeSummaryInfo(s) (of which we expect there to be one).
1016 static CritSecObject s_compTimeSummaryLock;
1020 CompTimeInfo m_total;
1021 CompTimeInfo m_maximum;
1023 int m_numFilteredMethods;
1024 CompTimeInfo m_filtered;
1026 // This method computes the number of cycles/sec for the current machine. The cycles are those counted
1027 // by GetThreadCycleTime; we assume that these are of equal duration, though that is not necessarily true.
1028 // If any OS interaction fails, returns 0.0.
1029 double CyclesPerSecond();
1031 // This can use what ever data you want to determine if the value to be added
1032 // belongs in the filtered section (it's always included in the unfiltered section)
1033 bool IncludedInFilteredData(CompTimeInfo& info);
1036 // This is the unique CompTimeSummaryInfo object for this instance of the runtime.
1037 static CompTimeSummaryInfo s_compTimeSummary;
1039 CompTimeSummaryInfo()
1040 : m_numMethods(0), m_totMethods(0), m_total(0), m_maximum(0), m_numFilteredMethods(0), m_filtered(0)
1044 // Assumes that "info" is a completed CompTimeInfo for a compilation; adds it to the summary.
1045 // This is thread safe.
1046 void AddInfo(CompTimeInfo& info, bool includePhases);
1048 // Print the summary information to "f".
1049 // This is not thread-safe; assumed to be called by only one thread.
1050 void Print(FILE* f);
1053 // A JitTimer encapsulates a CompTimeInfo for a single compilation. It also tracks the start of compilation,
1054 // and when the current phase started. This is intended to be part of a Compilation object. This is
1055 // disabled (FEATURE_JIT_METHOD_PERF not defined) when FEATURE_CORECLR is set, or on non-windows platforms.
1059 unsigned __int64 m_start; // Start of the compilation.
1060 unsigned __int64 m_curPhaseStart; // Start of the current phase.
1061 #if MEASURE_CLRAPI_CALLS
1062 unsigned __int64 m_CLRcallStart; // Start of the current CLR API call (if any).
1063 unsigned __int64 m_CLRcallInvokes; // CLR API invokes under current outer so far
1064 unsigned __int64 m_CLRcallCycles; // CLR API cycles under current outer so far.
1065 int m_CLRcallAPInum; // The enum/index of the current CLR API call (or -1).
1066 static double s_cyclesPerSec; // Cached for speedier measurements
1069 Phases m_lastPhase; // The last phase that was completed (or (Phases)-1 to start).
1071 CompTimeInfo m_info; // The CompTimeInfo for this compilation.
1073 static CritSecObject s_csvLock; // Lock to protect the time log file.
1074 void PrintCsvMethodStats(Compiler* comp);
1077 void* operator new(size_t);
1078 void* operator new[](size_t);
1079 void operator delete(void*);
1080 void operator delete[](void*);
1083 // Initialized the timer instance
1084 JitTimer(unsigned byteCodeSize);
1086 static JitTimer* Create(Compiler* comp, unsigned byteCodeSize)
1088 return ::new (comp, CMK_Unknown) JitTimer(byteCodeSize);
1091 static void PrintCsvHeader();
1093 // Ends the current phase (argument is for a redundant check).
1094 void EndPhase(Compiler* compiler, Phases phase);
1096 #if MEASURE_CLRAPI_CALLS
1097 // Start and end a timed CLR API call.
1098 void CLRApiCallEnter(unsigned apix);
1099 void CLRApiCallLeave(unsigned apix);
1100 #endif // MEASURE_CLRAPI_CALLS
1102 // Completes the timing of the current method, which is assumed to have "byteCodeBytes" bytes of bytecode,
1103 // and adds it to "sum".
1104 void Terminate(Compiler* comp, CompTimeSummaryInfo& sum, bool includePhases);
1106 // Attempts to query the cycle counter of the current thread. If successful, returns "true" and sets
1107 // *cycles to the cycle counter value. Otherwise, returns false and sets the "m_timerFailure" flag of
1108 // "m_info" to true.
1109 bool GetThreadCycles(unsigned __int64* cycles)
1111 bool res = CycleTimer::GetThreadCyclesS(cycles);
1114 m_info.m_timerFailure = true;
1119 #endif // FEATURE_JIT_METHOD_PERF
1121 //------------------- Function/Funclet info -------------------------------
1122 DECLARE_TYPED_ENUM(FuncKind, BYTE)
1124 FUNC_ROOT, // The main/root function (always id==0)
1125 FUNC_HANDLER, // a funclet associated with an EH handler (finally, fault, catch, filter handler)
1126 FUNC_FILTER, // a funclet associated with an EH filter
1129 END_DECLARE_TYPED_ENUM(FuncKind, BYTE)
1136 BYTE funFlags; // Currently unused, just here for padding
1137 unsigned short funEHIndex; // index, into the ebd table, of innermost EH clause corresponding to this
1138 // funclet. It is only valid if funKind field indicates this is a
1139 // EH-related funclet: FUNC_HANDLER or FUNC_FILTER
1141 #if defined(_TARGET_AMD64_)
1143 // TODO-AMD64-Throughput: make the AMD64 info more like the ARM info to avoid having this large static array.
1144 emitLocation* startLoc;
1145 emitLocation* endLoc;
1146 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1147 emitLocation* coldEndLoc;
1148 UNWIND_INFO unwindHeader;
1149 // Maximum of 255 UNWIND_CODE 'nodes' and then the unwind header. If there are an odd
1150 // number of codes, the VM or Zapper will 4-byte align the whole thing.
1151 BYTE unwindCodes[offsetof(UNWIND_INFO, UnwindCode) + (0xFF * sizeof(UNWIND_CODE))];
1152 unsigned unwindCodeSlot;
1154 #ifdef UNIX_AMD64_ABI
1155 jitstd::vector<CFI_CODE>* cfiCodes;
1156 #endif // UNIX_AMD64_ABI
1158 #elif defined(_TARGET_ARMARCH_)
1160 UnwindInfo uwi; // Unwind information for this function/funclet's hot section
1161 UnwindInfo* uwiCold; // Unwind information for this function/funclet's cold section
1162 // Note: we only have a pointer here instead of the actual object,
1163 // to save memory in the JIT case (compared to the NGEN case),
1164 // where we don't have any cold section.
1165 // Note 2: we currently don't support hot/cold splitting in functions
1166 // with EH, so uwiCold will be NULL for all funclets.
1168 #endif // _TARGET_ARMARCH_
1170 // Eventually we may want to move rsModifiedRegsMask, lvaOutgoingArgSize, and anything else
1171 // that isn't shared between the main function body and funclets.
1174 struct fgArgTabEntry
1177 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1180 otherRegNum = REG_NA;
1181 isStruct = false; // is this a struct arg
1183 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1185 GenTreePtr node; // Initially points at the Op1 field of 'parent', but if the argument is replaced with an GT_ASG or
1187 // it will point at the actual argument in the gtCallLateArgs list.
1188 GenTreePtr parent; // Points at the GT_LIST node in the gtCallArgs for this argument
1190 unsigned argNum; // The original argument number, also specifies the required argument evaluation order from the IL
1192 regNumber regNum; // The (first) register to use when passing this argument, set to REG_STK for arguments passed on
1194 unsigned numRegs; // Count of number of registers that this argument uses
1196 // A slot is a pointer sized region in the OutArg area.
1197 unsigned slotNum; // When an argument is passed in the OutArg area this is the slot number in the OutArg area
1198 unsigned numSlots; // Count of number of slots that this argument uses
1200 unsigned alignment; // 1 or 2 (slots/registers)
1201 unsigned lateArgInx; // index into gtCallLateArgs list
1202 unsigned tmpNum; // the LclVar number if we had to force evaluation of this arg
1204 bool isSplit : 1; // True when this argument is split between the registers and OutArg area
1205 bool needTmp : 1; // True when we force this argument's evaluation into a temp LclVar
1206 bool needPlace : 1; // True when we must replace this argument with a placeholder node
1207 bool isTmp : 1; // True when we setup a temp LclVar for this argument due to size issues with the struct
1208 bool processed : 1; // True when we have decided the evaluation order for this argument in the gtCallLateArgs
1209 bool isHfaRegArg : 1; // True when the argument is passed as a HFA in FP registers.
1210 bool isBackFilled : 1; // True when the argument fills a register slot skipped due to alignment requirements of
1211 // previous arguments.
1212 bool isNonStandard : 1; // True if it is an arg that is passed in a reg other than a standard arg reg, or is forced
1213 // to be on the stack despite its arg list position.
1215 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1216 bool isStruct : 1; // True if this is a struct arg
1218 regNumber otherRegNum; // The (second) register to use when passing this argument.
1220 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
1221 #elif defined(_TARGET_X86_)
1222 __declspec(property(get = getIsStruct)) bool isStruct;
1225 return varTypeIsStruct(node);
1227 #endif // _TARGET_X86_
1230 void SetIsHfaRegArg(bool hfaRegArg)
1232 isHfaRegArg = hfaRegArg;
1235 void SetIsBackFilled(bool backFilled)
1237 isBackFilled = backFilled;
1240 bool IsBackFilled() const
1242 return isBackFilled;
1244 #else // !_TARGET_ARM_
1245 // To make the callers easier, we allow these calls (and the isHfaRegArg and isBackFilled data members) for all
1247 void SetIsHfaRegArg(bool hfaRegArg)
1251 void SetIsBackFilled(bool backFilled)
1255 bool IsBackFilled() const
1259 #endif // !_TARGET_ARM_
1265 typedef struct fgArgTabEntry* fgArgTabEntryPtr;
1267 //-------------------------------------------------------------------------
1269 // The class fgArgInfo is used to handle the arguments
1270 // when morphing a GT_CALL node.
1275 Compiler* compiler; // Back pointer to the compiler instance so that we can allocate memory
1276 GenTreeCall* callTree; // Back pointer to the GT_CALL node for this fgArgInfo
1277 unsigned argCount; // Updatable arg count value
1278 unsigned nextSlotNum; // Updatable slot count value
1279 unsigned stkLevel; // Stack depth when we make this call (for x86)
1281 #if defined(UNIX_X86_ABI)
1282 bool alignmentDone; // Updateable flag, set to 'true' after we've done any required alignment.
1283 unsigned stkSizeBytes; // Size of stack used by this call, in bytes. Calculated during fgMorphArgs().
1284 unsigned padStkAlign; // Stack alignment in bytes required before arguments are pushed for this call.
1285 // Computed dynamically during codegen, based on stkSizeBytes and the current
1286 // stack level (genStackLevel) when the first stack adjustment is made for
1290 #if FEATURE_FIXED_OUT_ARGS
1291 unsigned outArgSize; // Size of the out arg area for the call, will be at least MIN_ARG_AREA_FOR_CALL
1294 unsigned argTableSize; // size of argTable array (equal to the argCount when done with fgMorphArgs)
1295 bool hasRegArgs; // true if we have one or more register arguments
1296 bool hasStackArgs; // true if we have one or more stack arguments
1297 bool argsComplete; // marker for state
1298 bool argsSorted; // marker for state
1299 fgArgTabEntryPtr* argTable; // variable sized array of per argument descrption: (i.e. argTable[argTableSize])
1302 void AddArg(fgArgTabEntryPtr curArgTabEntry);
1305 fgArgInfo(Compiler* comp, GenTreeCall* call, unsigned argCount);
1306 fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall);
1308 fgArgTabEntryPtr AddRegArg(
1309 unsigned argNum, GenTreePtr node, GenTreePtr parent, regNumber regNum, unsigned numRegs, unsigned alignment);
1311 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
1312 fgArgTabEntryPtr AddRegArg(
1319 const bool isStruct,
1320 const regNumber otherRegNum = REG_NA,
1321 const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* const structDescPtr = nullptr);
1322 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
1324 fgArgTabEntryPtr AddStkArg(unsigned argNum,
1328 unsigned alignment FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(const bool isStruct));
1330 void RemorphReset();
1331 fgArgTabEntryPtr RemorphRegArg(
1332 unsigned argNum, GenTreePtr node, GenTreePtr parent, regNumber regNum, unsigned numRegs, unsigned alignment);
1334 void RemorphStkArg(unsigned argNum, GenTreePtr node, GenTreePtr parent, unsigned numSlots, unsigned alignment);
1336 void SplitArg(unsigned argNum, unsigned numRegs, unsigned numSlots);
1338 void EvalToTmp(unsigned argNum, unsigned tmpNum, GenTreePtr newNode);
1340 void ArgsComplete();
1344 void EvalArgsToTemps();
1346 void RecordStkLevel(unsigned stkLvl);
1347 unsigned RetrieveStkLevel();
1353 fgArgTabEntryPtr* ArgTable()
1357 unsigned GetNextSlotNum()
1367 return hasStackArgs;
1369 bool AreArgsComplete() const
1371 return argsComplete;
1373 #if FEATURE_FIXED_OUT_ARGS
1374 unsigned GetOutArgSize() const
1378 void SetOutArgSize(unsigned newVal)
1380 outArgSize = newVal;
1382 #endif // FEATURE_FIXED_OUT_ARGS
1384 void ComputeStackAlignment(unsigned curStackLevelInBytes)
1386 #if defined(UNIX_X86_ABI)
1387 padStkAlign = AlignmentPad(curStackLevelInBytes, STACK_ALIGN);
1388 #endif // defined(UNIX_X86_ABI)
1391 void SetStkSizeBytes(unsigned newStkSizeBytes)
1393 #if defined(UNIX_X86_ABI)
1394 stkSizeBytes = newStkSizeBytes;
1395 #endif // defined(UNIX_X86_ABI)
1398 #if defined(UNIX_X86_ABI)
1399 unsigned GetStkAlign()
1403 unsigned GetStkSizeBytes() const
1405 return stkSizeBytes;
1407 bool IsStkAlignmentDone() const
1409 return alignmentDone;
1411 void SetStkAlignmentDone()
1413 alignmentDone = true;
1415 #endif // defined(UNIX_X86_ABI)
1417 // Get the late arg for arg at position argIndex. Caller must ensure this position has a late arg.
1418 GenTreePtr GetLateArg(unsigned argIndex);
1422 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1423 // We have the ability to mark source expressions with "Test Labels."
1424 // These drive assertions within the JIT, or internal JIT testing. For example, we could label expressions
1425 // that should be CSE defs, and other expressions that should uses of those defs, with a shared label.
1427 enum TestLabel // This must be kept identical to System.Runtime.CompilerServices.JitTestLabel.TestLabel.
1430 TL_VN, // Defines a "VN equivalence class". (For full VN, including exceptions thrown).
1431 TL_VNNorm, // Like above, but uses the non-exceptional value of the expression.
1432 TL_CSE_Def, // This must be identified in the JIT as a CSE def
1433 TL_CSE_Use, // This must be identified in the JIT as a CSE use
1434 TL_LoopHoist, // Expression must (or must not) be hoisted out of the loop.
1437 struct TestLabelAndNum
1442 TestLabelAndNum() : m_tl(TestLabel(0)), m_num(0)
1447 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, TestLabelAndNum, JitSimplerHashBehavior> NodeToTestDataMap;
1449 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1452 // This class implements the "IAllocator" interface, so that we can use
1453 // utilcode collection classes in the JIT, and have them use the JIT's allocator.
1455 class CompAllocator : public IAllocator
1458 #if MEASURE_MEM_ALLOC
1462 CompAllocator(Compiler* comp, CompMemKind cmk)
1464 #if MEASURE_MEM_ALLOC
1470 inline void* Alloc(size_t sz);
1472 inline void* ArrayAlloc(size_t elems, size_t elemSize);
1474 // For the compiler's no-release allocator, free operations are no-ops.
1481 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1482 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1484 XX The big guy. The sections are currently organized as : XX
1486 XX o GenTree and BasicBlock XX
1498 XX o PrologScopeInfo XX
1499 XX o CodeGenerator XX
1504 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1505 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1510 friend class emitter;
1511 friend class UnwindInfo;
1512 friend class UnwindFragmentInfo;
1513 friend class UnwindEpilogInfo;
1514 friend class JitTimer;
1515 friend class LinearScan;
1516 friend class fgArgInfo;
1517 friend class Rationalizer;
1519 friend class Lowering;
1520 friend class CSE_DataFlow;
1521 friend class CSE_Heuristic;
1522 friend class CodeGenInterface;
1523 friend class CodeGen;
1524 friend class LclVarDsc;
1525 friend class TempDsc;
1527 friend class ObjectAllocator;
1529 #ifndef _TARGET_64BIT_
1530 friend class DecomposeLongs;
1531 #endif // !_TARGET_64BIT_
1534 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1535 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1537 XX Misc structs definitions XX
1539 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1540 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1544 hashBvGlobalData hbvGlobalData; // Used by the hashBv bitvector package.
1563 bool dumpIRDataflow;
1564 bool dumpIRBlockHeaders;
1566 LPCWSTR dumpIRPhase;
1567 LPCWSTR dumpIRFormat;
1569 bool shouldUseVerboseTrees();
1570 bool asciiTrees; // If true, dump trees using only ASCII characters
1571 bool shouldDumpASCIITrees();
1572 bool verboseSsa; // If true, produce especially verbose dump output in SSA construction.
1573 bool shouldUseVerboseSsa();
1574 bool treesBeforeAfterMorph; // If true, print trees before/after morphing (paired by an intra-compilation id:
1575 int morphNum; // This counts the the trees that have been morphed, allowing us to label each uniquely.
1577 const char* VarNameToStr(VarName name)
1582 DWORD expensiveDebugCheckLevel;
1585 #if FEATURE_MULTIREG_RET
1586 GenTreePtr impAssignMultiRegTypeToVar(GenTreePtr op, CORINFO_CLASS_HANDLE hClass);
1587 #endif // FEATURE_MULTIREG_RET
1590 bool isSingleFloat32Struct(CORINFO_CLASS_HANDLE hClass);
1591 #endif // ARM_SOFTFP
1593 //-------------------------------------------------------------------------
1594 // Functions to handle homogeneous floating-point aggregates (HFAs) in ARM.
1595 // HFAs are one to four element structs where each element is the same
1596 // type, either all float or all double. They are treated specially
1597 // in the ARM Procedure Call Standard, specifically, they are passed in
1598 // floating-point registers instead of the general purpose registers.
1601 bool IsHfa(CORINFO_CLASS_HANDLE hClass);
1602 bool IsHfa(GenTreePtr tree);
1604 var_types GetHfaType(GenTreePtr tree);
1605 unsigned GetHfaCount(GenTreePtr tree);
1607 var_types GetHfaType(CORINFO_CLASS_HANDLE hClass);
1608 unsigned GetHfaCount(CORINFO_CLASS_HANDLE hClass);
1610 bool IsMultiRegPassedType(CORINFO_CLASS_HANDLE hClass);
1611 bool IsMultiRegReturnedType(CORINFO_CLASS_HANDLE hClass);
1613 //-------------------------------------------------------------------------
1614 // The following is used for validating format of EH table
1618 typedef struct EHNodeDsc* pEHNodeDsc;
1620 EHNodeDsc* ehnTree; // root of the tree comprising the EHnodes.
1621 EHNodeDsc* ehnNext; // root of the tree comprising the EHnodes.
1634 EHBlockType ehnBlockType; // kind of EH block
1635 IL_OFFSET ehnStartOffset; // IL offset of start of the EH block
1636 IL_OFFSET ehnEndOffset; // IL offset past end of the EH block. (TODO: looks like verInsertEhNode() sets this to
1637 // the last IL offset, not "one past the last one", i.e., the range Start to End is
1639 pEHNodeDsc ehnNext; // next (non-nested) block in sequential order
1640 pEHNodeDsc ehnChild; // leftmost nested block
1642 pEHNodeDsc ehnTryNode; // for filters and handlers, the corresponding try node
1643 pEHNodeDsc ehnHandlerNode; // for a try node, the corresponding handler node
1645 pEHNodeDsc ehnFilterNode; // if this is a try node and has a filter, otherwise 0
1646 pEHNodeDsc ehnEquivalent; // if blockType=tryNode, start offset and end offset is same,
1648 inline void ehnSetTryNodeType()
1650 ehnBlockType = TryNode;
1652 inline void ehnSetFilterNodeType()
1654 ehnBlockType = FilterNode;
1656 inline void ehnSetHandlerNodeType()
1658 ehnBlockType = HandlerNode;
1660 inline void ehnSetFinallyNodeType()
1662 ehnBlockType = FinallyNode;
1664 inline void ehnSetFaultNodeType()
1666 ehnBlockType = FaultNode;
1669 inline BOOL ehnIsTryBlock()
1671 return ehnBlockType == TryNode;
1673 inline BOOL ehnIsFilterBlock()
1675 return ehnBlockType == FilterNode;
1677 inline BOOL ehnIsHandlerBlock()
1679 return ehnBlockType == HandlerNode;
1681 inline BOOL ehnIsFinallyBlock()
1683 return ehnBlockType == FinallyNode;
1685 inline BOOL ehnIsFaultBlock()
1687 return ehnBlockType == FaultNode;
1690 // returns true if there is any overlap between the two nodes
1691 static inline BOOL ehnIsOverlap(pEHNodeDsc node1, pEHNodeDsc node2)
1693 if (node1->ehnStartOffset < node2->ehnStartOffset)
1695 return (node1->ehnEndOffset >= node2->ehnStartOffset);
1699 return (node1->ehnStartOffset <= node2->ehnEndOffset);
1703 // fails with BADCODE if inner is not completely nested inside outer
1704 static inline BOOL ehnIsNested(pEHNodeDsc inner, pEHNodeDsc outer)
1706 return ((inner->ehnStartOffset >= outer->ehnStartOffset) && (inner->ehnEndOffset <= outer->ehnEndOffset));
1710 //-------------------------------------------------------------------------
1711 // Exception handling functions
1714 #if !FEATURE_EH_FUNCLETS
1716 bool ehNeedsShadowSPslots()
1718 return (info.compXcptnsCount || opts.compDbgEnC);
1721 // 0 for methods with no EH
1722 // 1 for methods with non-nested EH, or where only the try blocks are nested
1723 // 2 for a method with a catch within a catch
1725 unsigned ehMaxHndNestingCount;
1727 #endif // !FEATURE_EH_FUNCLETS
1729 static bool jitIsBetween(unsigned value, unsigned start, unsigned end);
1730 static bool jitIsBetweenInclusive(unsigned value, unsigned start, unsigned end);
1732 bool bbInCatchHandlerILRange(BasicBlock* blk);
1733 bool bbInFilterILRange(BasicBlock* blk);
1734 bool bbInTryRegions(unsigned regionIndex, BasicBlock* blk);
1735 bool bbInExnFlowRegions(unsigned regionIndex, BasicBlock* blk);
1736 bool bbInHandlerRegions(unsigned regionIndex, BasicBlock* blk);
1737 bool bbInCatchHandlerRegions(BasicBlock* tryBlk, BasicBlock* hndBlk);
1738 unsigned short bbFindInnermostCommonTryRegion(BasicBlock* bbOne, BasicBlock* bbTwo);
1740 unsigned short bbFindInnermostTryRegionContainingHandlerRegion(unsigned handlerIndex);
1741 unsigned short bbFindInnermostHandlerRegionContainingTryRegion(unsigned tryIndex);
1743 // Returns true if "block" is the start of a try region.
1744 bool bbIsTryBeg(BasicBlock* block);
1746 // Returns true if "block" is the start of a handler or filter region.
1747 bool bbIsHandlerBeg(BasicBlock* block);
1749 // Returns true iff "block" is where control flows if an exception is raised in the
1750 // try region, and sets "*regionIndex" to the index of the try for the handler.
1751 // Differs from "IsHandlerBeg" in the case of filters, where this is true for the first
1752 // block of the filter, but not for the filter's handler.
1753 bool bbIsExFlowBlock(BasicBlock* block, unsigned* regionIndex);
1755 bool ehHasCallableHandlers();
1757 // Return the EH descriptor for the given region index.
1758 EHblkDsc* ehGetDsc(unsigned regionIndex);
1760 // Return the EH index given a region descriptor.
1761 unsigned ehGetIndex(EHblkDsc* ehDsc);
1763 // Return the EH descriptor index of the enclosing try, for the given region index.
1764 unsigned ehGetEnclosingTryIndex(unsigned regionIndex);
1766 // Return the EH descriptor index of the enclosing handler, for the given region index.
1767 unsigned ehGetEnclosingHndIndex(unsigned regionIndex);
1769 // Return the EH descriptor for the most nested 'try' region this BasicBlock is a member of (or nullptr if this
1770 // block is not in a 'try' region).
1771 EHblkDsc* ehGetBlockTryDsc(BasicBlock* block);
1773 // Return the EH descriptor for the most nested filter or handler region this BasicBlock is a member of (or nullptr
1774 // if this block is not in a filter or handler region).
1775 EHblkDsc* ehGetBlockHndDsc(BasicBlock* block);
1777 // Return the EH descriptor for the most nested region that may handle exceptions raised in this BasicBlock (or
1778 // nullptr if this block's exceptions propagate to caller).
1779 EHblkDsc* ehGetBlockExnFlowDsc(BasicBlock* block);
1781 EHblkDsc* ehIsBlockTryLast(BasicBlock* block);
1782 EHblkDsc* ehIsBlockHndLast(BasicBlock* block);
1783 bool ehIsBlockEHLast(BasicBlock* block);
1785 bool ehBlockHasExnFlowDsc(BasicBlock* block);
1787 // Return the region index of the most nested EH region this block is in.
1788 unsigned ehGetMostNestedRegionIndex(BasicBlock* block, bool* inTryRegion);
1790 // Find the true enclosing try index, ignoring 'mutual protect' try. Uses IL ranges to check.
1791 unsigned ehTrueEnclosingTryIndexIL(unsigned regionIndex);
1793 // Return the index of the most nested enclosing region for a particular EH region. Returns NO_ENCLOSING_INDEX
1794 // if there is no enclosing region. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion'
1795 // is set to 'true' if the enclosing region is a 'try', or 'false' if the enclosing region is a handler.
1796 // (It can never be a filter.)
1797 unsigned ehGetEnclosingRegionIndex(unsigned regionIndex, bool* inTryRegion);
1799 // A block has been deleted. Update the EH table appropriately.
1800 void ehUpdateForDeletedBlock(BasicBlock* block);
1802 // Determine whether a block can be deleted while preserving the EH normalization rules.
1803 bool ehCanDeleteEmptyBlock(BasicBlock* block);
1805 // Update the 'last' pointers in the EH table to reflect new or deleted blocks in an EH region.
1806 void ehUpdateLastBlocks(BasicBlock* oldLast, BasicBlock* newLast);
1808 // For a finally handler, find the region index that the BBJ_CALLFINALLY lives in that calls the handler,
1809 // or NO_ENCLOSING_INDEX if the BBJ_CALLFINALLY lives in the main function body. Normally, the index
1810 // is the same index as the handler (and the BBJ_CALLFINALLY lives in the 'try' region), but for AMD64 the
1811 // BBJ_CALLFINALLY lives in the enclosing try or handler region, whichever is more nested, or the main function
1812 // body. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion' is set to 'true' if the
1813 // BBJ_CALLFINALLY lives in the returned index's 'try' region, or 'false' if lives in the handler region. (It never
1814 // lives in a filter.)
1815 unsigned ehGetCallFinallyRegionIndex(unsigned finallyIndex, bool* inTryRegion);
1817 // Find the range of basic blocks in which all BBJ_CALLFINALLY will be found that target the 'finallyIndex' region's
1818 // handler. Set begBlk to the first block, and endBlk to the block after the last block of the range
1819 // (nullptr if the last block is the last block in the program).
1820 // Precondition: 'finallyIndex' is the EH region of a try/finally clause.
1821 void ehGetCallFinallyBlockRange(unsigned finallyIndex, BasicBlock** begBlk, BasicBlock** endBlk);
1824 // Given a BBJ_CALLFINALLY block and the EH region index of the finally it is calling, return
1825 // 'true' if the BBJ_CALLFINALLY is in the correct EH region.
1826 bool ehCallFinallyInCorrectRegion(BasicBlock* blockCallFinally, unsigned finallyIndex);
1829 #if FEATURE_EH_FUNCLETS
1830 // Do we need a PSPSym in the main function? For codegen purposes, we only need one
1831 // if there is a filter that protects a region with a nested EH clause (such as a
1832 // try/catch nested in the 'try' body of a try/filter/filter-handler). See
1833 // genFuncletProlog() for more details. However, the VM seems to use it for more
1834 // purposes, maybe including debugging. Until we are sure otherwise, always create
1835 // a PSPSym for functions with any EH.
1836 bool ehNeedsPSPSym() const
1840 #else // _TARGET_X86_
1841 return compHndBBtabCount > 0;
1842 #endif // _TARGET_X86_
1845 bool ehAnyFunclets(); // Are there any funclets in this function?
1846 unsigned ehFuncletCount(); // Return the count of funclets in the function
1848 unsigned bbThrowIndex(BasicBlock* blk); // Get the index to use as the cache key for sharing throw blocks
1849 #else // !FEATURE_EH_FUNCLETS
1850 bool ehAnyFunclets()
1854 unsigned ehFuncletCount()
1859 unsigned bbThrowIndex(BasicBlock* blk)
1861 return blk->bbTryIndex;
1862 } // Get the index to use as the cache key for sharing throw blocks
1863 #endif // !FEATURE_EH_FUNCLETS
1865 // Returns a flowList representing the "EH predecessors" of "blk". These are the normal predecessors of
1866 // "blk", plus one special case: if "blk" is the first block of a handler, considers the predecessor(s) of the first
1867 // first block of the corresponding try region to be "EH predecessors". (If there is a single such predecessor,
1868 // for example, we want to consider that the immediate dominator of the catch clause start block, so it's
1869 // convenient to also consider it a predecessor.)
1870 flowList* BlockPredsWithEH(BasicBlock* blk);
1872 // This table is useful for memoization of the method above.
1873 typedef SimplerHashTable<BasicBlock*, PtrKeyFuncs<BasicBlock>, flowList*, JitSimplerHashBehavior>
1875 BlockToFlowListMap* m_blockToEHPreds;
1876 BlockToFlowListMap* GetBlockToEHPreds()
1878 if (m_blockToEHPreds == nullptr)
1880 m_blockToEHPreds = new (getAllocator()) BlockToFlowListMap(getAllocator());
1882 return m_blockToEHPreds;
1885 void* ehEmitCookie(BasicBlock* block);
1886 UNATIVE_OFFSET ehCodeOffset(BasicBlock* block);
1888 EHblkDsc* ehInitHndRange(BasicBlock* src, IL_OFFSET* hndBeg, IL_OFFSET* hndEnd, bool* inFilter);
1890 EHblkDsc* ehInitTryRange(BasicBlock* src, IL_OFFSET* tryBeg, IL_OFFSET* tryEnd);
1892 EHblkDsc* ehInitHndBlockRange(BasicBlock* blk, BasicBlock** hndBeg, BasicBlock** hndLast, bool* inFilter);
1894 EHblkDsc* ehInitTryBlockRange(BasicBlock* blk, BasicBlock** tryBeg, BasicBlock** tryLast);
1896 void fgSetTryEnd(EHblkDsc* handlerTab, BasicBlock* newTryLast);
1898 void fgSetHndEnd(EHblkDsc* handlerTab, BasicBlock* newHndLast);
1900 void fgSkipRmvdBlocks(EHblkDsc* handlerTab);
1902 void fgAllocEHTable();
1904 void fgRemoveEHTableEntry(unsigned XTnum);
1906 #if FEATURE_EH_FUNCLETS
1908 EHblkDsc* fgAddEHTableEntry(unsigned XTnum);
1910 #endif // FEATURE_EH_FUNCLETS
1914 #endif // !FEATURE_EH
1916 void fgSortEHTable();
1918 // Causes the EH table to obey some well-formedness conditions, by inserting
1919 // empty BB's when necessary:
1920 // * No block is both the first block of a handler and the first block of a try.
1921 // * No block is the first block of multiple 'try' regions.
1922 // * No block is the last block of multiple EH regions.
1923 void fgNormalizeEH();
1924 bool fgNormalizeEHCase1();
1925 bool fgNormalizeEHCase2();
1926 bool fgNormalizeEHCase3();
1929 void dispIncomingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
1930 void dispOutgoingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
1931 void fgVerifyHandlerTab();
1932 void fgDispHandlerTab();
1935 bool fgNeedToSortEHTable;
1937 void verInitEHTree(unsigned numEHClauses);
1938 void verInsertEhNode(CORINFO_EH_CLAUSE* clause, EHblkDsc* handlerTab);
1939 void verInsertEhNodeInTree(EHNodeDsc** ppRoot, EHNodeDsc* node);
1940 void verInsertEhNodeParent(EHNodeDsc** ppRoot, EHNodeDsc* node);
1941 void verCheckNestingLevel(EHNodeDsc* initRoot);
1944 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1945 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1947 XX GenTree and BasicBlock XX
1949 XX Functions to allocate and display the GenTrees and BasicBlocks XX
1951 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1952 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1955 // Functions to create nodes
1956 GenTreeStmt* gtNewStmt(GenTreePtr expr = nullptr, IL_OFFSETX offset = BAD_IL_OFFSET);
1959 GenTreePtr gtNewOperNode(genTreeOps oper, var_types type, GenTreePtr op1, bool doSimplifications = TRUE);
1961 // For binary opers.
1962 GenTreePtr gtNewOperNode(genTreeOps oper, var_types type, GenTreePtr op1, GenTreePtr op2);
1964 GenTreePtr gtNewQmarkNode(var_types type, GenTreePtr cond, GenTreePtr colon);
1966 GenTreePtr gtNewLargeOperNode(genTreeOps oper,
1967 var_types type = TYP_I_IMPL,
1968 GenTreePtr op1 = nullptr,
1969 GenTreePtr op2 = nullptr);
1971 GenTreeIntCon* gtNewIconNode(ssize_t value, var_types type = TYP_INT);
1973 GenTree* gtNewPhysRegNode(regNumber reg, var_types type);
1975 GenTree* gtNewPhysRegNode(regNumber reg, GenTree* src);
1977 GenTreePtr gtNewJmpTableNode();
1978 GenTreePtr gtNewIconHandleNode(
1979 size_t value, unsigned flags, FieldSeqNode* fields = nullptr, unsigned handle1 = 0, void* handle2 = nullptr);
1981 unsigned gtTokenToIconFlags(unsigned token);
1983 GenTreePtr gtNewIconEmbHndNode(void* value,
1986 unsigned handle1 = 0,
1987 void* handle2 = nullptr,
1988 void* compileTimeHandle = nullptr);
1990 GenTreePtr gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
1991 GenTreePtr gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
1992 GenTreePtr gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
1993 GenTreePtr gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
1995 GenTreePtr gtNewStringLiteralNode(InfoAccessType iat, void* pValue);
1997 GenTreePtr gtNewLconNode(__int64 value);
1999 GenTreePtr gtNewDconNode(double value);
2001 GenTreePtr gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle);
2003 GenTreePtr gtNewZeroConNode(var_types type);
2005 GenTreePtr gtNewOneConNode(var_types type);
2008 GenTreePtr gtNewSIMDVectorZero(var_types simdType, var_types baseType, unsigned size);
2009 GenTreePtr gtNewSIMDVectorOne(var_types simdType, var_types baseType, unsigned size);
2012 GenTreeBlk* gtNewBlkOpNode(
2013 genTreeOps oper, GenTreePtr dst, GenTreePtr srcOrFillVal, GenTreePtr sizeOrClsTok, bool isVolatile);
2015 GenTree* gtNewBlkOpNode(GenTreePtr dst, GenTreePtr srcOrFillVal, unsigned size, bool isVolatile, bool isCopyBlock);
2018 void gtBlockOpInit(GenTreePtr result, GenTreePtr dst, GenTreePtr srcOrFillVal, bool isVolatile);
2021 GenTree* gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTreePtr addr);
2022 void gtSetObjGcInfo(GenTreeObj* objNode);
2023 GenTree* gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTreePtr addr);
2024 GenTree* gtNewBlockVal(GenTreePtr addr, unsigned size);
2026 GenTree* gtNewCpObjNode(GenTreePtr dst, GenTreePtr src, CORINFO_CLASS_HANDLE structHnd, bool isVolatile);
2028 GenTreeArgList* gtNewListNode(GenTreePtr op1, GenTreeArgList* op2);
2030 GenTreeCall* gtNewCallNode(gtCallTypes callType,
2031 CORINFO_METHOD_HANDLE handle,
2033 GenTreeArgList* args,
2034 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2036 GenTreeCall* gtNewIndCallNode(GenTreePtr addr,
2038 GenTreeArgList* args,
2039 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2041 GenTreeCall* gtNewHelperCallNode(unsigned helper,
2044 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 GenTreePtr gtNewLclLNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs = BAD_IL_OFFSET);
2061 GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset);
2062 GenTreePtr gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate, var_types type);
2064 GenTreePtr gtNewCodeRef(BasicBlock* block);
2066 GenTreePtr gtNewFieldRef(
2067 var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTreePtr obj = nullptr, DWORD offset = 0, bool nullcheck = false);
2069 GenTreePtr gtNewIndexRef(var_types typ, GenTreePtr arrayOp, GenTreePtr indexOp);
2071 GenTreeArgList* gtNewArgList(GenTreePtr op);
2072 GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2);
2073 GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2, GenTreePtr op3);
2075 static fgArgTabEntryPtr gtArgEntryByArgNum(GenTreeCall* call, unsigned argNum);
2076 static fgArgTabEntryPtr gtArgEntryByNode(GenTreeCall* call, GenTreePtr node);
2077 fgArgTabEntryPtr gtArgEntryByLateArgIndex(GenTreeCall* call, unsigned lateArgInx);
2078 bool gtArgIsThisPtr(fgArgTabEntryPtr argEntry);
2080 GenTreePtr gtNewAssignNode(GenTreePtr dst, GenTreePtr src);
2082 GenTreePtr gtNewTempAssign(unsigned tmp, GenTreePtr val);
2084 GenTreePtr gtNewRefCOMfield(GenTreePtr objPtr,
2085 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2086 CORINFO_ACCESS_FLAGS access,
2087 CORINFO_FIELD_INFO* pFieldInfo,
2089 CORINFO_CLASS_HANDLE structType,
2092 GenTreePtr gtNewNothingNode();
2094 GenTreePtr gtNewArgPlaceHolderNode(var_types type, CORINFO_CLASS_HANDLE clsHnd);
2096 GenTreePtr gtUnusedValNode(GenTreePtr expr);
2098 GenTreePtr gtNewCastNode(var_types typ, GenTreePtr op1, var_types castType);
2100 GenTreePtr gtNewCastNodeL(var_types typ, GenTreePtr op1, var_types castType);
2102 GenTreePtr gtNewAllocObjNode(unsigned int helper, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTreePtr op1);
2104 //------------------------------------------------------------------------
2105 // Other GenTree functions
2107 GenTreePtr gtClone(GenTree* tree, bool complexOK = false);
2109 // If `tree` is a lclVar with lclNum `varNum`, return an IntCns with value `varVal`; otherwise,
2110 // create a copy of `tree`, adding specified flags, replacing uses of lclVar `deepVarNum` with
2111 // IntCnses with value `deepVarVal`.
2112 GenTreePtr gtCloneExpr(
2113 GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal);
2115 // Create a copy of `tree`, optionally adding specifed flags, and optionally mapping uses of local
2116 // `varNum` to int constants with value `varVal`.
2117 GenTreePtr gtCloneExpr(GenTree* tree, unsigned addFlags = 0, unsigned varNum = (unsigned)-1, int varVal = 0)
2119 return gtCloneExpr(tree, addFlags, varNum, varVal, varNum, varVal);
2122 GenTreePtr gtReplaceTree(GenTreePtr stmt, GenTreePtr tree, GenTreePtr replacementTree);
2124 void gtUpdateSideEffects(GenTreePtr tree, unsigned oldGtFlags, unsigned newGtFlags);
2126 // Returns "true" iff the complexity (not formally defined, but first interpretation
2127 // is #of nodes in subtree) of "tree" is greater than "limit".
2128 // (This is somewhat redundant with the "gtCostEx/gtCostSz" fields, but can be used
2129 // before they have been set.)
2130 bool gtComplexityExceeds(GenTreePtr* tree, unsigned limit);
2132 bool gtCompareTree(GenTree* op1, GenTree* op2);
2134 GenTreePtr gtReverseCond(GenTree* tree);
2136 bool gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly);
2138 bool gtHasLocalsWithAddrOp(GenTreePtr tree);
2140 unsigned gtSetListOrder(GenTree* list, bool regs, bool isListCallArgs);
2142 void gtWalkOp(GenTree** op1, GenTree** op2, GenTree* adr, bool constOnly);
2145 unsigned gtHashValue(GenTree* tree);
2147 GenTreePtr gtWalkOpEffectiveVal(GenTreePtr op);
2150 void gtPrepareCost(GenTree* tree);
2151 bool gtIsLikelyRegVar(GenTree* tree);
2153 unsigned gtSetEvalOrderAndRestoreFPstkLevel(GenTree* tree);
2155 // Returns true iff the secondNode can be swapped with firstNode.
2156 bool gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode);
2158 unsigned gtSetEvalOrder(GenTree* tree);
2160 #if FEATURE_STACK_FP_X87
2162 void gtComputeFPlvls(GenTreePtr tree);
2163 #endif // FEATURE_STACK_FP_X87
2165 void gtSetStmtInfo(GenTree* stmt);
2167 // Returns "true" iff "node" has any of the side effects in "flags".
2168 bool gtNodeHasSideEffects(GenTreePtr node, unsigned flags);
2170 // Returns "true" iff "tree" or its (transitive) children have any of the side effects in "flags".
2171 bool gtTreeHasSideEffects(GenTreePtr tree, unsigned flags);
2173 // Appends 'expr' in front of 'list'
2174 // 'list' will typically start off as 'nullptr'
2175 // when 'list' is non-null a GT_COMMA node is used to insert 'expr'
2176 GenTreePtr gtBuildCommaList(GenTreePtr list, GenTreePtr expr);
2178 void gtExtractSideEffList(GenTreePtr expr,
2180 unsigned flags = GTF_SIDE_EFFECT,
2181 bool ignoreRoot = false);
2183 GenTreePtr gtGetThisArg(GenTreeCall* call);
2185 // Static fields of struct types (and sometimes the types that those are reduced to) are represented by having the
2186 // static field contain an object pointer to the boxed struct. This simplifies the GC implementation...but
2187 // complicates the JIT somewhat. This predicate returns "true" iff a node with type "fieldNodeType", representing
2188 // the given "fldHnd", is such an object pointer.
2189 bool gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd);
2191 // Return true if call is a recursive call; return false otherwise.
2192 // Note when inlining, this looks for calls back to the root method.
2193 bool gtIsRecursiveCall(GenTreeCall* call)
2195 return (call->gtCallMethHnd == impInlineRoot()->info.compMethodHnd);
2198 //-------------------------------------------------------------------------
2200 GenTreePtr gtFoldExpr(GenTreePtr tree);
2203 // TODO-Amd64-Unix: Remove this when the clang optimizer is fixed and/or the method implementation is
2204 // refactored in a simpler code. This is a workaround for a bug in the clang-3.5 optimizer. The issue is that in
2205 // release build the optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner case
2206 // of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div operation instead of 64 bit) - see
2207 // the implementation of the method in gentree.cpp. For the case of lval1 and lval2 equal to MIN_LONG
2208 // (0x8000000000000000) this results in raising a SIGFPE. The method implementation is rather complex. Disable
2209 // optimizations for now.
2210 __attribute__((optnone))
2212 gtFoldExprConst(GenTreePtr tree);
2213 GenTreePtr gtFoldExprSpecial(GenTreePtr tree);
2214 GenTreePtr gtFoldExprCompare(GenTreePtr tree);
2216 //-------------------------------------------------------------------------
2217 // Get the handle, if any.
2218 CORINFO_CLASS_HANDLE gtGetStructHandleIfPresent(GenTreePtr tree);
2219 // Get the handle, and assert if not found.
2220 CORINFO_CLASS_HANDLE gtGetStructHandle(GenTreePtr tree);
2221 // Get the handle for a ref type.
2222 CORINFO_CLASS_HANDLE gtGetClassHandle(GenTreePtr tree, bool* isExact, bool* isNonNull);
2224 //-------------------------------------------------------------------------
2225 // Functions to display the trees
2228 void gtDispNode(GenTreePtr tree, IndentStack* indentStack, __in_z const char* msg, bool isLIR);
2230 void gtDispVN(GenTreePtr tree);
2231 void gtDispConst(GenTreePtr tree);
2232 void gtDispLeaf(GenTreePtr tree, IndentStack* indentStack);
2233 void gtDispNodeName(GenTreePtr tree);
2234 void gtDispRegVal(GenTreePtr tree);
2246 void gtDispChild(GenTreePtr child,
2247 IndentStack* indentStack,
2249 __in_opt const char* msg = nullptr,
2250 bool topOnly = false);
2251 void gtDispTree(GenTreePtr tree,
2252 IndentStack* indentStack = nullptr,
2253 __in_opt const char* msg = nullptr,
2254 bool topOnly = false,
2255 bool isLIR = false);
2256 void gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut);
2257 int gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining);
2258 char* gtGetLclVarName(unsigned lclNum);
2259 void gtDispLclVar(unsigned varNum, bool padForBiggestDisp = true);
2260 void gtDispTreeList(GenTreePtr tree, IndentStack* indentStack = nullptr);
2261 void gtGetArgMsg(GenTreeCall* call, GenTreePtr arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength);
2262 void gtGetLateArgMsg(GenTreeCall* call, GenTreePtr arg, int argNum, int listCount, char* bufp, unsigned bufLength);
2263 void gtDispArgList(GenTreeCall* call, IndentStack* indentStack);
2264 void gtDispFieldSeq(FieldSeqNode* pfsn);
2266 void gtDispRange(LIR::ReadOnlyRange const& range);
2268 void gtDispTreeRange(LIR::Range& containingRange, GenTree* tree);
2270 void gtDispLIRNode(GenTree* node, const char* prefixMsg = nullptr);
2282 typedef fgWalkResult(fgWalkPreFn)(GenTreePtr* pTree, fgWalkData* data);
2283 typedef fgWalkResult(fgWalkPostFn)(GenTreePtr* pTree, fgWalkData* data);
2286 static fgWalkPreFn gtAssertColonCond;
2288 static fgWalkPreFn gtMarkColonCond;
2289 static fgWalkPreFn gtClearColonCond;
2291 GenTreePtr* gtFindLink(GenTreePtr stmt, GenTreePtr node);
2292 bool gtHasCatchArg(GenTreePtr tree);
2293 bool gtHasUnmanagedCall(GenTreePtr tree);
2295 typedef ArrayStack<GenTree*> GenTreeStack;
2297 static bool gtHasCallOnStack(GenTreeStack* parentStack);
2298 void gtCheckQuirkAddrExposedLclVar(GenTreePtr argTree, GenTreeStack* parentStack);
2300 //=========================================================================
2301 // BasicBlock functions
2303 // This is a debug flag we will use to assert when creating block during codegen
2304 // as this interferes with procedure splitting. If you know what you're doing, set
2305 // it to true before creating the block. (DEBUG only)
2306 bool fgSafeBasicBlockCreation;
2309 BasicBlock* bbNewBasicBlock(BBjumpKinds jumpKind);
2312 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2313 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2317 XX The variables to be used by the code generator. XX
2319 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2320 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2324 // For both PROMOTION_TYPE_NONE and PROMOTION_TYPE_DEPENDENT the struct will
2325 // be placed in the stack frame and it's fields must be laid out sequentially.
2327 // For PROMOTION_TYPE_INDEPENDENT each of the struct's fields is replaced by
2328 // a local variable that can be enregistered or placed in the stack frame.
2329 // The fields do not need to be laid out sequentially
2331 enum lvaPromotionType
2333 PROMOTION_TYPE_NONE, // The struct local is not promoted
2334 PROMOTION_TYPE_INDEPENDENT, // The struct local is promoted,
2335 // and its field locals are independent of its parent struct local.
2336 PROMOTION_TYPE_DEPENDENT // The struct local is promoted,
2337 // but its field locals depend on its parent struct local.
2340 static int __cdecl RefCntCmp(const void* op1, const void* op2);
2341 static int __cdecl WtdRefCntCmp(const void* op1, const void* op2);
2343 /*****************************************************************************/
2345 enum FrameLayoutState
2348 INITIAL_FRAME_LAYOUT,
2349 PRE_REGALLOC_FRAME_LAYOUT,
2350 REGALLOC_FRAME_LAYOUT,
2351 TENTATIVE_FRAME_LAYOUT,
2356 bool lvaRefCountingStarted; // Set to true when we have started counting the local vars
2357 bool lvaLocalVarRefCounted; // Set to true after we have called lvaMarkLocalVars()
2358 bool lvaSortAgain; // true: We need to sort the lvaTable
2359 bool lvaTrackedFixed; // true: We cannot add new 'tracked' variable
2360 unsigned lvaCount; // total number of locals
2362 unsigned lvaRefCount; // total number of references to locals
2363 LclVarDsc* lvaTable; // variable descriptor table
2364 unsigned lvaTableCnt; // lvaTable size (>= lvaCount)
2366 LclVarDsc** lvaRefSorted; // table sorted by refcount
2368 unsigned short lvaTrackedCount; // actual # of locals being tracked
2369 unsigned lvaTrackedCountInSizeTUnits; // min # of size_t's sufficient to hold a bit for all the locals being tracked
2371 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
2372 // Only for AMD64 System V cache the first caller stack homed argument.
2373 unsigned lvaFirstStackIncomingArgNum; // First argument with stack slot in the caller.
2374 #endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
2377 VARSET_TP lvaTrackedVars; // set of tracked variables
2379 #ifndef _TARGET_64BIT_
2380 VARSET_TP lvaLongVars; // set of long (64-bit) variables
2382 VARSET_TP lvaFloatVars; // set of floating-point (32-bit and 64-bit) variables
2384 unsigned lvaCurEpoch; // VarSets are relative to a specific set of tracked var indices.
2385 // It that changes, this changes. VarSets from different epochs
2386 // cannot be meaningfully combined.
2388 unsigned GetCurLVEpoch()
2393 // reverse map of tracked number to var number
2394 unsigned lvaTrackedToVarNum[lclMAX_TRACKED];
2396 #ifdef LEGACY_BACKEND
2397 // variable interference graph
2398 VARSET_TP lvaVarIntf[lclMAX_TRACKED];
2401 // variable preference graph
2402 VARSET_TP lvaVarPref[lclMAX_TRACKED];
2406 // # of procs compiled a with double-aligned stack
2407 static unsigned s_lvaDoubleAlignedProcsCount;
2411 // Getters and setters for address-exposed and do-not-enregister local var properties.
2412 bool lvaVarAddrExposed(unsigned varNum);
2413 void lvaSetVarAddrExposed(unsigned varNum);
2414 bool lvaVarDoNotEnregister(unsigned varNum);
2416 // Reasons why we can't enregister. Some of these correspond to debug properties of local vars.
2417 enum DoNotEnregisterReason
2422 DNER_VMNeedsStackAddr,
2423 DNER_LiveInOutOfHandler,
2424 DNER_LiveAcrossUnmanagedCall,
2425 DNER_BlockOp, // Is read or written via a block operation that explicitly takes the address.
2426 DNER_IsStructArg, // Is a struct passed as an argument in a way that requires a stack location.
2427 #ifdef JIT32_GCENCODER
2432 void lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregisterReason reason));
2434 unsigned lvaVarargsHandleArg;
2436 unsigned lvaVarargsBaseOfStkArgs; // Pointer (computed based on incoming varargs handle) to the start of the stack
2438 #endif // _TARGET_X86_
2440 unsigned lvaInlinedPInvokeFrameVar; // variable representing the InlinedCallFrame
2441 unsigned lvaReversePInvokeFrameVar; // variable representing the reverse PInvoke frame
2442 #if FEATURE_FIXED_OUT_ARGS
2443 unsigned lvaPInvokeFrameRegSaveVar; // variable representing the RegSave for PInvoke inlining.
2445 unsigned lvaMonAcquired; // boolean variable introduced into in synchronized methods
2446 // that tracks whether the lock has been taken
2448 unsigned lvaArg0Var; // The lclNum of arg0. Normally this will be info.compThisArg.
2449 // However, if there is a "ldarga 0" or "starg 0" in the IL,
2450 // we will redirect all "ldarg(a) 0" and "starg 0" to this temp.
2452 unsigned lvaInlineeReturnSpillTemp; // The temp to spill the non-VOID return expression
2453 // in case there are multiple BBJ_RETURN blocks in the inlinee.
2455 #if FEATURE_FIXED_OUT_ARGS
2456 unsigned lvaOutgoingArgSpaceVar; // dummy TYP_LCLBLK var for fixed outgoing argument space
2457 PhasedVar<unsigned> lvaOutgoingArgSpaceSize; // size of fixed outgoing argument space
2458 #endif // FEATURE_FIXED_OUT_ARGS
2461 // On architectures whose ABIs allow structs to be passed in registers, struct promotion will sometimes
2462 // require us to "rematerialize" a struct from it's separate constituent field variables. Packing several sub-word
2463 // field variables into an argument register is a hard problem. It's easier to reserve a word of memory into which
2464 // such field can be copied, after which the assembled memory word can be read into the register. We will allocate
2465 // this variable to be this scratch word whenever struct promotion occurs.
2466 unsigned lvaPromotedStructAssemblyScratchVar;
2467 #endif // _TARGET_ARM_
2470 unsigned lvaReturnEspCheck; // confirms ESP not corrupted on return
2471 unsigned lvaCallEspCheck; // confirms ESP not corrupted after a call
2474 unsigned lvaGenericsContextUseCount;
2476 bool lvaKeepAliveAndReportThis(); // Synchronized instance method of a reference type, or
2477 // CORINFO_GENERICS_CTXT_FROM_THIS?
2478 bool lvaReportParamTypeArg(); // Exceptions and CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG?
2480 //-------------------------------------------------------------------------
2481 // All these frame offsets are inter-related and must be kept in sync
2483 #if !FEATURE_EH_FUNCLETS
2484 // This is used for the callable handlers
2485 unsigned lvaShadowSPslotsVar; // TYP_BLK variable for all the shadow SP slots
2486 #endif // FEATURE_EH_FUNCLETS
2488 unsigned lvaCachedGenericContextArgOffs;
2489 unsigned lvaCachedGenericContextArgOffset(); // For CORINFO_CALLCONV_PARAMTYPE and if generic context is passed as
2492 unsigned lvaLocAllocSPvar; // variable which has the result of the last alloca/localloc
2494 unsigned lvaNewObjArrayArgs; // variable with arguments for new MD array helper
2496 // TODO-Review: Prior to reg predict we reserve 24 bytes for Spill temps.
2497 // after the reg predict we will use a computed maxTmpSize
2498 // which is based upon the number of spill temps predicted by reg predict
2499 // All this is necessary because if we under-estimate the size of the spill
2500 // temps we could fail when encoding instructions that reference stack offsets for ARM.
2502 // Pre codegen max spill temp size.
2503 static const unsigned MAX_SPILL_TEMP_SIZE = 24;
2505 //-------------------------------------------------------------------------
2507 unsigned lvaGetMaxSpillTempSize();
2509 bool lvaIsPreSpilled(unsigned lclNum, regMaskTP preSpillMask);
2510 #endif // _TARGET_ARM_
2511 void lvaAssignFrameOffsets(FrameLayoutState curState);
2512 void lvaFixVirtualFrameOffsets();
2514 #ifndef LEGACY_BACKEND
2515 void lvaUpdateArgsWithInitialReg();
2516 #endif // !LEGACY_BACKEND
2518 void lvaAssignVirtualFrameOffsetsToArgs();
2519 #ifdef UNIX_AMD64_ABI
2520 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs, int* callerArgOffset);
2521 #else // !UNIX_AMD64_ABI
2522 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs);
2523 #endif // !UNIX_AMD64_ABI
2524 void lvaAssignVirtualFrameOffsetsToLocals();
2525 int lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, int stkOffs);
2526 #ifdef _TARGET_AMD64_
2527 // Returns true if compCalleeRegsPushed (including RBP if used as frame pointer) is even.
2528 bool lvaIsCalleeSavedIntRegCountEven();
2530 void lvaAlignFrame();
2531 void lvaAssignFrameOffsetsToPromotedStructs();
2532 int lvaAllocateTemps(int stkOffs, bool mustDoubleAlign);
2535 void lvaDumpRegLocation(unsigned lclNum);
2536 void lvaDumpFrameLocation(unsigned lclNum);
2537 void lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t refCntWtdWidth = 6);
2538 void lvaTableDump(FrameLayoutState curState = NO_FRAME_LAYOUT); // NO_FRAME_LAYOUT means use the current frame
2539 // layout state defined by lvaDoneFrameLayout
2542 // Limit frames size to 1GB. The maximum is 2GB in theory - make it intentionally smaller
2543 // to avoid bugs from borderline cases.
2544 #define MAX_FrameSize 0x3FFFFFFF
2545 void lvaIncrementFrameSize(unsigned size);
2547 unsigned lvaFrameSize(FrameLayoutState curState);
2549 // Returns the caller-SP-relative offset for the SP/FP relative offset determined by FP based.
2550 int lvaToCallerSPRelativeOffset(int offs, bool isFpBased);
2552 // Returns the caller-SP-relative offset for the local variable "varNum."
2553 int lvaGetCallerSPRelativeOffset(unsigned varNum);
2555 // Returns the SP-relative offset for the local variable "varNum". Illegal to ask this for functions with localloc.
2556 int lvaGetSPRelativeOffset(unsigned varNum);
2558 int lvaToInitialSPRelativeOffset(unsigned offset, bool isFpBased);
2559 int lvaGetInitialSPRelativeOffset(unsigned varNum);
2561 //------------------------ For splitting types ----------------------------
2563 void lvaInitTypeRef();
2565 void lvaInitArgs(InitVarDscInfo* varDscInfo);
2566 void lvaInitThisPtr(InitVarDscInfo* varDscInfo);
2567 void lvaInitRetBuffArg(InitVarDscInfo* varDscInfo);
2568 void lvaInitUserArgs(InitVarDscInfo* varDscInfo);
2569 void lvaInitGenericsCtxt(InitVarDscInfo* varDscInfo);
2570 void lvaInitVarArgsHandle(InitVarDscInfo* varDscInfo);
2572 void lvaInitVarDsc(LclVarDsc* varDsc,
2574 CorInfoType corInfoType,
2575 CORINFO_CLASS_HANDLE typeHnd,
2576 CORINFO_ARG_LIST_HANDLE varList,
2577 CORINFO_SIG_INFO* varSig);
2579 static unsigned lvaTypeRefMask(var_types type);
2581 var_types lvaGetActualType(unsigned lclNum);
2582 var_types lvaGetRealType(unsigned lclNum);
2584 //-------------------------------------------------------------------------
2588 unsigned lvaLclSize(unsigned varNum);
2589 unsigned lvaLclExactSize(unsigned varNum);
2591 bool lvaLclVarRefs(GenTreePtr tree, GenTreePtr* findPtr, varRefKinds* refsPtr, void* result);
2593 // Call lvaLclVarRefs on "true"; accumulate "*result" into whichever of
2594 // "allVars" and "trkdVars" is indiated by the nullness of "findPtr"; return
2595 // the return result.
2596 bool lvaLclVarRefsAccum(
2597 GenTreePtr tree, GenTreePtr* findPtr, varRefKinds* refsPtr, ALLVARSET_TP* allVars, VARSET_TP* trkdVars);
2599 // If "findPtr" is non-NULL, assumes "result" is an "ALLVARSET_TP*", and
2600 // (destructively) unions "allVars" into "*result". Otherwise, assumes "result" is a "VARSET_TP*",
2601 // and (destructively) unions "trkedVars" into "*result".
2602 void lvaLclVarRefsAccumIntoRes(GenTreePtr* findPtr,
2604 ALLVARSET_VALARG_TP allVars,
2605 VARSET_VALARG_TP trkdVars);
2607 bool lvaHaveManyLocals() const;
2609 unsigned lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason));
2610 unsigned lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason));
2611 unsigned lvaGrabTempWithImplicitUse(bool shortLifetime DEBUGARG(const char* reason));
2614 void lvaSortByRefCount();
2615 void lvaDumpRefCounts();
2617 void lvaMarkLocalVars(BasicBlock* block);
2619 void lvaMarkLocalVars(); // Local variable ref-counting
2621 void lvaAllocOutgoingArgSpaceVar(); // Set up lvaOutgoingArgSpaceVar
2623 VARSET_VALRET_TP lvaStmtLclMask(GenTreePtr stmt);
2625 static fgWalkPreFn lvaIncRefCntsCB;
2626 void lvaIncRefCnts(GenTreePtr tree);
2628 static fgWalkPreFn lvaDecRefCntsCB;
2629 void lvaDecRefCnts(GenTreePtr tree);
2630 void lvaDecRefCnts(BasicBlock* basicBlock, GenTreePtr tree);
2631 void lvaRecursiveDecRefCounts(GenTreePtr tree);
2632 void lvaRecursiveIncRefCounts(GenTreePtr tree);
2635 struct lvaStressLclFldArgs
2637 Compiler* m_pCompiler;
2641 static fgWalkPreFn lvaStressLclFldCB;
2642 void lvaStressLclFld();
2644 void lvaDispVarSet(VARSET_VALARG_TP set, VARSET_VALARG_TP allVars);
2645 void lvaDispVarSet(VARSET_VALARG_TP set);
2650 int lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset);
2652 int lvaFrameAddress(int varNum, bool* pFPbased);
2655 bool lvaIsParameter(unsigned varNum);
2656 bool lvaIsRegArgument(unsigned varNum);
2657 BOOL lvaIsOriginalThisArg(unsigned varNum); // Is this varNum the original this argument?
2658 BOOL lvaIsOriginalThisReadOnly(); // return TRUE if there is no place in the code
2659 // that writes to arg0
2661 // Struct parameters that are passed by reference are marked as both lvIsParam and lvIsTemp
2662 // (this is an overload of lvIsTemp because there are no temp parameters).
2663 // For x64 this is 3, 5, 6, 7, >8 byte structs that are passed by reference.
2664 // For ARM64, this is structs larger than 16 bytes that are passed by reference.
2665 bool lvaIsImplicitByRefLocal(unsigned varNum)
2667 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
2668 LclVarDsc* varDsc = &(lvaTable[varNum]);
2669 if (varDsc->lvIsParam && varDsc->lvIsTemp)
2671 assert((varDsc->lvType == TYP_STRUCT) || (varDsc->lvType == TYP_BYREF));
2674 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
2678 // Returns true if this local var is a multireg struct
2679 bool lvaIsMultiregStruct(LclVarDsc* varDsc);
2681 // If the local is a TYP_STRUCT, get/set a class handle describing it
2682 CORINFO_CLASS_HANDLE lvaGetStruct(unsigned varNum);
2683 void lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool unsafeValueClsCheck, bool setTypeInfo = true);
2685 // If the local is TYP_REF, set or update the associated class information.
2686 void lvaSetClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
2687 void lvaSetClass(unsigned varNum, GenTreePtr tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
2688 void lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
2689 void lvaUpdateClass(unsigned varNum, GenTreePtr tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
2691 #define MAX_NumOfFieldsInPromotableStruct 4 // Maximum number of fields in promotable struct
2693 // Info about struct fields
2694 struct lvaStructFieldInfo
2696 CORINFO_FIELD_HANDLE fldHnd;
2697 unsigned char fldOffset;
2698 unsigned char fldOrdinal;
2701 CORINFO_CLASS_HANDLE fldTypeHnd;
2704 // Info about struct to be promoted.
2705 struct lvaStructPromotionInfo
2707 CORINFO_CLASS_HANDLE typeHnd;
2709 bool requiresScratchVar;
2712 unsigned char fieldCnt;
2713 lvaStructFieldInfo fields[MAX_NumOfFieldsInPromotableStruct];
2715 lvaStructPromotionInfo()
2716 : typeHnd(nullptr), canPromote(false), requiresScratchVar(false), containsHoles(false), customLayout(false)
2721 static int __cdecl lvaFieldOffsetCmp(const void* field1, const void* field2);
2722 void lvaCanPromoteStructType(CORINFO_CLASS_HANDLE typeHnd,
2723 lvaStructPromotionInfo* StructPromotionInfo,
2725 void lvaCanPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo);
2726 bool lvaShouldPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* structPromotionInfo);
2727 void lvaPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo);
2728 #if !defined(_TARGET_64BIT_)
2729 void lvaPromoteLongVars();
2730 #endif // !defined(_TARGET_64BIT_)
2731 unsigned lvaGetFieldLocal(LclVarDsc* varDsc, unsigned int fldOffset);
2732 lvaPromotionType lvaGetPromotionType(const LclVarDsc* varDsc);
2733 lvaPromotionType lvaGetPromotionType(unsigned varNum);
2734 lvaPromotionType lvaGetParentPromotionType(const LclVarDsc* varDsc);
2735 lvaPromotionType lvaGetParentPromotionType(unsigned varNum);
2736 bool lvaIsFieldOfDependentlyPromotedStruct(const LclVarDsc* varDsc);
2737 bool lvaIsGCTracked(const LclVarDsc* varDsc);
2739 #if defined(FEATURE_SIMD)
2740 bool lvaMapSimd12ToSimd16(const LclVarDsc* varDsc)
2742 assert(varDsc->lvType == TYP_SIMD12);
2743 assert(varDsc->lvExactSize == 12);
2745 #if defined(_TARGET_64BIT_)
2746 assert(varDsc->lvSize() == 16);
2748 #else // !defined(_TARGET_64BIT_)
2750 // For 32-bit architectures, we make local variable SIMD12 types 16 bytes instead of just 12. lvSize()
2751 // already does this calculation. However, we also need to prevent mapping types if the var is a
2752 // depenendently promoted struct field, which must remain its exact size within its parent struct.
2753 // However, we don't know this until late, so we may have already pretended the field is bigger
2755 if ((varDsc->lvSize() == 16) && !lvaIsFieldOfDependentlyPromotedStruct(varDsc))
2764 #endif // !defined(_TARGET_64BIT_)
2766 #endif // defined(FEATURE_SIMD)
2768 BYTE* lvaGetGcLayout(unsigned varNum);
2769 bool lvaTypeIsGC(unsigned varNum);
2770 unsigned lvaGSSecurityCookie; // LclVar number
2771 bool lvaTempsHaveLargerOffsetThanVars();
2773 unsigned lvaSecurityObject; // variable representing the security object on the stack
2774 unsigned lvaStubArgumentVar; // variable representing the secret stub argument coming in EAX
2776 #if FEATURE_EH_FUNCLETS
2777 unsigned lvaPSPSym; // variable representing the PSPSym
2780 InlineInfo* impInlineInfo;
2781 InlineStrategy* m_inlineStrategy;
2783 // The Compiler* that is the root of the inlining tree of which "this" is a member.
2784 Compiler* impInlineRoot();
2786 #if defined(DEBUG) || defined(INLINE_DATA)
2787 unsigned __int64 getInlineCycleCount()
2789 return m_compCycles;
2791 #endif // defined(DEBUG) || defined(INLINE_DATA)
2793 bool fgNoStructPromotion; // Set to TRUE to turn off struct promotion for this method.
2794 bool fgNoStructParamPromotion; // Set to TRUE to turn off struct promotion for parameters this method.
2796 //=========================================================================
2798 //=========================================================================
2801 //---------------- Local variable ref-counting ----------------------------
2804 BasicBlock* lvaMarkRefsCurBlock;
2805 GenTreePtr lvaMarkRefsCurStmt;
2807 BasicBlock::weight_t lvaMarkRefsWeight;
2809 static fgWalkPreFn lvaMarkLclRefsCallback;
2810 void lvaMarkLclRefs(GenTreePtr tree);
2812 bool IsDominatedByExceptionalEntry(BasicBlock* block);
2813 void SetVolatileHint(LclVarDsc* varDsc);
2815 // Keeps the mapping from SSA #'s to VN's for the implicit memory variables.
2816 PerSsaArray lvMemoryPerSsaData;
2817 unsigned lvMemoryNumSsaNames;
2820 // Returns the address of the per-Ssa data for memory at the given ssaNum (which is required
2821 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
2822 // not an SSA variable).
2823 LclSsaVarDsc* GetMemoryPerSsaData(unsigned ssaNum)
2825 assert(ssaNum != SsaConfig::RESERVED_SSA_NUM);
2826 assert(SsaConfig::RESERVED_SSA_NUM == 0);
2828 assert(ssaNum < lvMemoryNumSsaNames);
2829 return &lvMemoryPerSsaData.GetRef(ssaNum);
2833 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2834 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2838 XX Imports the given method and converts it to semantic trees XX
2840 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2841 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2847 void impImport(BasicBlock* method);
2849 CORINFO_CLASS_HANDLE impGetRefAnyClass();
2850 CORINFO_CLASS_HANDLE impGetRuntimeArgumentHandle();
2851 CORINFO_CLASS_HANDLE impGetTypeHandleClass();
2852 CORINFO_CLASS_HANDLE impGetStringClass();
2853 CORINFO_CLASS_HANDLE impGetObjectClass();
2855 //=========================================================================
2857 //=========================================================================
2860 //-------------------- Stack manipulation ---------------------------------
2862 unsigned impStkSize; // Size of the full stack
2864 #define SMALL_STACK_SIZE 16 // number of elements in impSmallStack
2866 StackEntry impSmallStack[SMALL_STACK_SIZE]; // Use this array if possible
2868 struct SavedStack // used to save/restore stack contents.
2870 unsigned ssDepth; // number of values on stack
2871 StackEntry* ssTrees; // saved tree values
2874 bool impIsPrimitive(CorInfoType type);
2875 bool impILConsumesAddr(const BYTE* codeAddr, CORINFO_METHOD_HANDLE fncHandle, CORINFO_MODULE_HANDLE scpHandle);
2877 void impResolveToken(const BYTE* addr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CorInfoTokenKind kind);
2878 void impPushOnStackNoType(GenTreePtr tree);
2880 void impPushOnStack(GenTreePtr tree, typeInfo ti);
2881 void impPushNullObjRefOnStack();
2882 StackEntry impPopStack();
2883 StackEntry impPopStack(CORINFO_CLASS_HANDLE& structTypeRet);
2884 GenTreePtr impPopStack(typeInfo& ti);
2885 StackEntry& impStackTop(unsigned n = 0);
2886 unsigned impStackHeight();
2888 void impSaveStackState(SavedStack* savePtr, bool copy);
2889 void impRestoreStackState(SavedStack* savePtr);
2891 GenTreePtr impImportLdvirtftn(GenTreePtr thisPtr,
2892 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2893 CORINFO_CALL_INFO* pCallInfo);
2895 void impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken);
2897 void impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
2899 bool impCanPInvokeInline();
2900 bool impCanPInvokeInlineCallSite(BasicBlock* block);
2901 void impCheckForPInvokeCall(
2902 GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block);
2903 GenTreeCall* impImportIndirectCall(CORINFO_SIG_INFO* sig, IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2904 void impPopArgsForUnmanagedCall(GenTreePtr call, CORINFO_SIG_INFO* sig);
2906 void impInsertHelperCall(CORINFO_HELPER_DESC* helperCall);
2907 void impHandleAccessAllowed(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
2908 void impHandleAccessAllowedInternal(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
2910 var_types impImportCall(OPCODE opcode,
2911 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2912 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call on a
2914 GenTreePtr newobjThis,
2916 CORINFO_CALL_INFO* callInfo,
2917 IL_OFFSET rawILOffset);
2919 void impDevirtualizeCall(GenTreeCall* call,
2921 CORINFO_CALL_INFO* callInfo,
2922 CORINFO_CONTEXT_HANDLE* exactContextHnd);
2924 bool impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo);
2926 GenTreePtr impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HANDLE retClsHnd);
2928 GenTreePtr impFixupStructReturnType(GenTreePtr op, CORINFO_CLASS_HANDLE retClsHnd);
2931 var_types impImportJitTestLabelMark(int numArgs);
2934 GenTreePtr impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken);
2936 GenTreePtr impImportStaticReadOnlyField(void* fldAddr, var_types lclTyp);
2938 GenTreePtr impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken,
2939 CORINFO_ACCESS_FLAGS access,
2940 CORINFO_FIELD_INFO* pFieldInfo,
2943 static void impBashVarAddrsToI(GenTreePtr tree1, GenTreePtr tree2 = nullptr);
2945 GenTreePtr impImplicitIorI4Cast(GenTreePtr tree, var_types dstTyp);
2947 GenTreePtr impImplicitR4orR8Cast(GenTreePtr tree, var_types dstTyp);
2949 void impImportLeave(BasicBlock* block);
2950 void impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr);
2951 GenTreePtr impIntrinsic(GenTreePtr newobjThis,
2952 CORINFO_CLASS_HANDLE clsHnd,
2953 CORINFO_METHOD_HANDLE method,
2954 CORINFO_SIG_INFO* sig,
2958 CorInfoIntrinsics* pIntrinsicID);
2959 GenTreePtr impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
2960 CORINFO_SIG_INFO* sig,
2963 CorInfoIntrinsics intrinsicID);
2964 GenTreePtr impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig);
2966 GenTreePtr impMethodPointer(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
2968 GenTreePtr impTransformThis(GenTreePtr thisPtr,
2969 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
2970 CORINFO_THIS_TRANSFORM transform);
2972 //----------------- Manipulating the trees and stmts ----------------------
2974 GenTreePtr impTreeList; // Trees for the BB being imported
2975 GenTreePtr impTreeLast; // The last tree for the current BB
2979 CHECK_SPILL_ALL = -1,
2980 CHECK_SPILL_NONE = -2
2984 void impBeginTreeList();
2985 void impEndTreeList(BasicBlock* block, GenTreePtr firstStmt, GenTreePtr lastStmt);
2986 void impEndTreeList(BasicBlock* block);
2987 void impAppendStmtCheck(GenTreePtr stmt, unsigned chkLevel);
2988 void impAppendStmt(GenTreePtr stmt, unsigned chkLevel);
2989 void impInsertStmtBefore(GenTreePtr stmt, GenTreePtr stmtBefore);
2990 GenTreePtr impAppendTree(GenTreePtr tree, unsigned chkLevel, IL_OFFSETX offset);
2991 void impInsertTreeBefore(GenTreePtr tree, IL_OFFSETX offset, GenTreePtr stmtBefore);
2992 void impAssignTempGen(unsigned tmp,
2995 GenTreePtr* pAfterStmt = nullptr,
2996 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
2997 BasicBlock* block = nullptr);
2998 void impAssignTempGen(unsigned tmpNum,
3000 CORINFO_CLASS_HANDLE structHnd,
3002 GenTreePtr* pAfterStmt = nullptr,
3003 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3004 BasicBlock* block = nullptr);
3005 GenTreePtr impCloneExpr(GenTreePtr tree,
3007 CORINFO_CLASS_HANDLE structHnd,
3009 GenTreePtr* pAfterStmt DEBUGARG(const char* reason));
3010 GenTreePtr impAssignStruct(GenTreePtr dest,
3012 CORINFO_CLASS_HANDLE structHnd,
3014 GenTreePtr* pAfterStmt = nullptr,
3015 BasicBlock* block = nullptr);
3016 GenTreePtr impAssignStructPtr(GenTreePtr dest,
3018 CORINFO_CLASS_HANDLE structHnd,
3020 GenTreePtr* pAfterStmt = nullptr,
3021 BasicBlock* block = nullptr);
3023 GenTreePtr impGetStructAddr(GenTreePtr structVal,
3024 CORINFO_CLASS_HANDLE structHnd,
3028 var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd,
3029 BYTE* gcLayout = nullptr,
3030 unsigned* numGCVars = nullptr,
3031 var_types* simdBaseType = nullptr);
3033 GenTreePtr impNormStructVal(GenTreePtr structVal,
3034 CORINFO_CLASS_HANDLE structHnd,
3036 bool forceNormalization = false);
3038 GenTreePtr impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3039 BOOL* pRuntimeLookup = nullptr,
3040 BOOL mustRestoreHandle = FALSE,
3041 BOOL importParent = FALSE);
3043 GenTreePtr impParentClassTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3044 BOOL* pRuntimeLookup = nullptr,
3045 BOOL mustRestoreHandle = FALSE)
3047 return impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, TRUE);
3050 GenTreePtr impLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3051 CORINFO_LOOKUP* pLookup,
3053 void* compileTimeHandle);
3055 GenTreePtr getRuntimeContextTree(CORINFO_RUNTIME_LOOKUP_KIND kind);
3057 GenTreePtr impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3058 CORINFO_LOOKUP* pLookup,
3059 void* compileTimeHandle);
3061 GenTreePtr impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP* pLookup, unsigned flags, void* compileTimeHandle);
3063 GenTreeCall* impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3064 CorInfoHelpFunc helper,
3066 GenTreeArgList* arg = nullptr,
3067 CORINFO_LOOKUP_KIND* pGenericLookupKind = nullptr);
3069 GenTreePtr impCastClassOrIsInstToTree(GenTreePtr op1,
3071 CORINFO_RESOLVED_TOKEN* pResolvedToken,
3074 bool VarTypeIsMultiByteAndCanEnreg(var_types type,
3075 CORINFO_CLASS_HANDLE typeClass,
3079 static bool IsIntrinsicImplementedByUserCall(CorInfoIntrinsics intrinsicId);
3080 static bool IsTargetIntrinsic(CorInfoIntrinsics intrinsicId);
3081 static bool IsMathIntrinsic(CorInfoIntrinsics intrinsicId);
3082 static bool IsMathIntrinsic(GenTreePtr tree);
3085 //----------------- Importing the method ----------------------------------
3087 CORINFO_CONTEXT_HANDLE impTokenLookupContextHandle; // The context used for looking up tokens.
3090 unsigned impCurOpcOffs;
3091 const char* impCurOpcName;
3092 bool impNestedStackSpill;
3094 // For displaying instrs with generated native code (-n:B)
3095 GenTreePtr impLastILoffsStmt; // oldest stmt added for which we did not gtStmtLastILoffs
3096 void impNoteLastILoffs();
3099 /* IL offset of the stmt currently being imported. It gets set to
3100 BAD_IL_OFFSET after it has been set in the appended trees. Then it gets
3101 updated at IL offsets for which we have to report mapping info.
3102 It also includes flag bits, so use jitGetILoffs()
3103 to get the actual IL offset value.
3106 IL_OFFSETX impCurStmtOffs;
3107 void impCurStmtOffsSet(IL_OFFSET offs);
3109 void impNoteBranchOffs();
3111 unsigned impInitBlockLineInfo();
3113 GenTreePtr impCheckForNullPointer(GenTreePtr obj);
3114 bool impIsThis(GenTreePtr obj);
3115 bool impIsLDFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3116 bool impIsDUP_LDVIRTFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3117 bool impIsAnySTLOC(OPCODE opcode)
3119 return ((opcode == CEE_STLOC) || (opcode == CEE_STLOC_S) ||
3120 ((opcode >= CEE_STLOC_0) && (opcode <= CEE_STLOC_3)));
3123 GenTreeArgList* impPopList(unsigned count,
3125 CORINFO_SIG_INFO* sig,
3126 GenTreeArgList* prefixTree = nullptr);
3128 GenTreeArgList* impPopRevList(unsigned count,
3130 CORINFO_SIG_INFO* sig,
3131 unsigned skipReverseCount = 0);
3134 * Get current IL offset with stack-empty info incoporated
3136 IL_OFFSETX impCurILOffset(IL_OFFSET offs, bool callInstruction = false);
3138 //---------------- Spilling the importer stack ----------------------------
3140 // The maximum number of bytes of IL processed without clean stack state.
3141 // It allows to limit the maximum tree size and depth.
3142 static const unsigned MAX_TREE_SIZE = 200;
3143 bool impCanSpillNow(OPCODE prevOpcode);
3149 SavedStack pdSavedStack;
3150 ThisInitState pdThisPtrInit;
3153 PendingDsc* impPendingList; // list of BBs currently waiting to be imported.
3154 PendingDsc* impPendingFree; // Freed up dscs that can be reused
3156 // We keep a byte-per-block map (dynamically extended) in the top-level Compiler object of a compilation.
3157 ExpandArray<BYTE> impPendingBlockMembers;
3159 // Return the byte for "b" (allocating/extending impPendingBlockMembers if necessary.)
3160 // Operates on the map in the top-level ancestor.
3161 BYTE impGetPendingBlockMember(BasicBlock* blk)
3163 return impInlineRoot()->impPendingBlockMembers.Get(blk->bbInd());
3166 // Set the byte for "b" to "val" (allocating/extending impPendingBlockMembers if necessary.)
3167 // Operates on the map in the top-level ancestor.
3168 void impSetPendingBlockMember(BasicBlock* blk, BYTE val)
3170 impInlineRoot()->impPendingBlockMembers.Set(blk->bbInd(), val);
3173 bool impCanReimport;
3175 bool impSpillStackEntry(unsigned level,
3179 bool bAssertOnRecursion,
3184 void impSpillStackEnsure(bool spillLeaves = false);
3185 void impEvalSideEffects();
3186 void impSpillSpecialSideEff();
3187 void impSpillSideEffects(bool spillGlobEffects, unsigned chkLevel DEBUGARG(const char* reason));
3188 void impSpillValueClasses();
3189 void impSpillEvalStack();
3190 static fgWalkPreFn impFindValueClasses;
3191 void impSpillLclRefs(ssize_t lclNum);
3193 BasicBlock* impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_HANDLE clsHnd);
3195 void impImportBlockCode(BasicBlock* block);
3197 void impReimportMarkBlock(BasicBlock* block);
3198 void impReimportMarkSuccessors(BasicBlock* block);
3200 void impVerifyEHBlock(BasicBlock* block, bool isTryStart);
3202 void impImportBlockPending(BasicBlock* block);
3204 // Similar to impImportBlockPending, but assumes that block has already been imported once and is being
3205 // reimported for some reason. It specifically does *not* look at verCurrentState to set the EntryState
3206 // for the block, but instead, just re-uses the block's existing EntryState.
3207 void impReimportBlockPending(BasicBlock* block);
3209 var_types impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTreePtr* pOp1, GenTreePtr* pOp2);
3211 void impImportBlock(BasicBlock* block);
3213 // Assumes that "block" is a basic block that completes with a non-empty stack. We will assign the values
3214 // on the stack to local variables (the "spill temp" variables). The successor blocks will assume that
3215 // its incoming stack contents are in those locals. This requires "block" and its successors to agree on
3216 // the variables that will be used -- and for all the predecessors of those successors, and the
3217 // successors of those predecessors, etc. Call such a set of blocks closed under alternating
3218 // successor/predecessor edges a "spill clique." A block is a "predecessor" or "successor" member of the
3219 // clique (or, conceivably, both). Each block has a specified sequence of incoming and outgoing spill
3220 // temps. If "block" already has its outgoing spill temps assigned (they are always a contiguous series
3221 // of local variable numbers, so we represent them with the base local variable number), returns that.
3222 // Otherwise, picks a set of spill temps, and propagates this choice to all blocks in the spill clique of
3223 // which "block" is a member (asserting, in debug mode, that no block in this clique had its spill temps
3224 // chosen already. More precisely, that the incoming or outgoing spill temps are not chosen, depending
3225 // on which kind of member of the clique the block is).
3226 unsigned impGetSpillTmpBase(BasicBlock* block);
3228 // Assumes that "block" is a basic block that completes with a non-empty stack. We have previously
3229 // assigned the values on the stack to local variables (the "spill temp" variables). The successor blocks
3230 // will assume that its incoming stack contents are in those locals. This requires "block" and its
3231 // successors to agree on the variables and their types that will be used. The CLI spec allows implicit
3232 // conversions between 'int' and 'native int' or 'float' and 'double' stack types. So one predecessor can
3233 // push an int and another can push a native int. For 64-bit we have chosen to implement this by typing
3234 // the "spill temp" as native int, and then importing (or re-importing as needed) so that all the
3235 // predecessors in the "spill clique" push a native int (sign-extending if needed), and all the
3236 // successors receive a native int. Similarly float and double are unified to double.
3237 // This routine is called after a type-mismatch is detected, and it will walk the spill clique to mark
3238 // blocks for re-importation as appropriate (both successors, so they get the right incoming type, and
3239 // predecessors, so they insert an upcast if needed).
3240 void impReimportSpillClique(BasicBlock* block);
3242 // When we compute a "spill clique" (see above) these byte-maps are allocated to have a byte per basic
3243 // block, and represent the predecessor and successor members of the clique currently being computed.
3244 // *** Access to these will need to be locked in a parallel compiler.
3245 ExpandArray<BYTE> impSpillCliquePredMembers;
3246 ExpandArray<BYTE> impSpillCliqueSuccMembers;
3254 // Abstract class for receiving a callback while walking a spill clique
3255 class SpillCliqueWalker
3258 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk) = 0;
3261 // This class is used for setting the bbStkTempsIn and bbStkTempsOut on the blocks within a spill clique
3262 class SetSpillTempsBase : public SpillCliqueWalker
3267 SetSpillTempsBase(unsigned baseTmp) : m_baseTmp(baseTmp)
3270 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3273 // This class is used for implementing impReimportSpillClique part on each block within the spill clique
3274 class ReimportSpillClique : public SpillCliqueWalker
3279 ReimportSpillClique(Compiler* pComp) : m_pComp(pComp)
3282 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3285 // This is the heart of the algorithm for walking spill cliques. It invokes callback->Visit for each
3286 // predecessor or successor within the spill clique
3287 void impWalkSpillCliqueFromPred(BasicBlock* pred, SpillCliqueWalker* callback);
3289 // For a BasicBlock that has already been imported, the EntryState has an array of GenTrees for the
3290 // incoming locals. This walks that list an resets the types of the GenTrees to match the types of
3291 // the VarDscs. They get out of sync when we have int/native int issues (see impReimportSpillClique).
3292 void impRetypeEntryStateTemps(BasicBlock* blk);
3294 BYTE impSpillCliqueGetMember(SpillCliqueDir predOrSucc, BasicBlock* blk);
3295 void impSpillCliqueSetMember(SpillCliqueDir predOrSucc, BasicBlock* blk, BYTE val);
3297 void impPushVar(GenTree* op, typeInfo tiRetVal);
3298 void impLoadVar(unsigned lclNum, IL_OFFSET offset, typeInfo tiRetVal);
3299 void impLoadVar(unsigned lclNum, IL_OFFSET offset)
3301 impLoadVar(lclNum, offset, lvaTable[lclNum].lvVerTypeInfo);
3303 void impLoadArg(unsigned ilArgNum, IL_OFFSET offset);
3304 void impLoadLoc(unsigned ilLclNum, IL_OFFSET offset);
3305 bool impReturnInstruction(BasicBlock* block, int prefixFlags, OPCODE& opcode);
3308 void impMarkLclDstNotPromotable(unsigned tmpNum, GenTreePtr op, CORINFO_CLASS_HANDLE hClass);
3311 // A free list of linked list nodes used to represent to-do stacks of basic blocks.
3312 struct BlockListNode
3315 BlockListNode* m_next;
3316 BlockListNode(BasicBlock* blk, BlockListNode* next = nullptr) : m_blk(blk), m_next(next)
3319 void* operator new(size_t sz, Compiler* comp);
3321 BlockListNode* impBlockListNodeFreeList;
3323 BlockListNode* AllocBlockListNode();
3324 void FreeBlockListNode(BlockListNode* node);
3326 bool impIsValueType(typeInfo* pTypeInfo);
3327 var_types mangleVarArgsType(var_types type);
3330 regNumber getCallArgIntRegister(regNumber floatReg);
3331 regNumber getCallArgFloatRegister(regNumber intReg);
3332 #endif // FEATURE_VARARG
3335 static unsigned jitTotalMethodCompiled;
3339 static LONG jitNestingLevel;
3342 static BOOL impIsAddressInLocal(GenTreePtr tree, GenTreePtr* lclVarTreeOut);
3344 void impMakeDiscretionaryInlineObservations(InlineInfo* pInlineInfo, InlineResult* inlineResult);
3346 // STATIC inlining decision based on the IL code.
3347 void impCanInlineIL(CORINFO_METHOD_HANDLE fncHandle,
3348 CORINFO_METHOD_INFO* methInfo,
3350 InlineResult* inlineResult);
3352 void impCheckCanInline(GenTreePtr call,
3353 CORINFO_METHOD_HANDLE fncHandle,
3355 CORINFO_CONTEXT_HANDLE exactContextHnd,
3356 InlineCandidateInfo** ppInlineCandidateInfo,
3357 InlineResult* inlineResult);
3359 void impInlineRecordArgInfo(InlineInfo* pInlineInfo,
3360 GenTreePtr curArgVal,
3362 InlineResult* inlineResult);
3364 void impInlineInitVars(InlineInfo* pInlineInfo);
3366 unsigned impInlineFetchLocal(unsigned lclNum DEBUGARG(const char* reason));
3368 GenTreePtr impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, InlLclVarInfo* lclTypeInfo);
3370 BOOL impInlineIsThis(GenTreePtr tree, InlArgInfo* inlArgInfo);
3372 BOOL impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTreePtr additionalTreesToBeEvaluatedBefore,
3373 GenTreePtr variableBeingDereferenced,
3374 InlArgInfo* inlArgInfo);
3376 void impMarkInlineCandidate(GenTreePtr call,
3377 CORINFO_CONTEXT_HANDLE exactContextHnd,
3378 bool exactContextNeedsRuntimeLookup,
3379 CORINFO_CALL_INFO* callInfo);
3381 bool impTailCallRetTypeCompatible(var_types callerRetType,
3382 CORINFO_CLASS_HANDLE callerRetTypeClass,
3383 var_types calleeRetType,
3384 CORINFO_CLASS_HANDLE calleeRetTypeClass);
3386 bool impIsTailCallILPattern(bool tailPrefixed,
3388 const BYTE* codeAddrOfNextOpcode,
3389 const BYTE* codeEnd,
3391 bool* IsCallPopRet = nullptr);
3393 bool impIsImplicitTailCallCandidate(
3394 OPCODE curOpcode, const BYTE* codeAddrOfNextOpcode, const BYTE* codeEnd, int prefixFlags, bool isRecursive);
3396 CORINFO_RESOLVED_TOKEN* impAllocateToken(CORINFO_RESOLVED_TOKEN token);
3399 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3400 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3404 XX Info about the basic-blocks, their contents and the flow analysis XX
3406 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3407 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3411 BasicBlock* fgFirstBB; // Beginning of the basic block list
3412 BasicBlock* fgLastBB; // End of the basic block list
3413 BasicBlock* fgFirstColdBlock; // First block to be placed in the cold section
3414 #if FEATURE_EH_FUNCLETS
3415 BasicBlock* fgFirstFuncletBB; // First block of outlined funclets (to allow block insertion before the funclets)
3417 BasicBlock* fgFirstBBScratch; // Block inserted for initialization stuff. Is nullptr if no such block has been
3419 BasicBlockList* fgReturnBlocks; // list of BBJ_RETURN blocks
3420 unsigned fgEdgeCount; // # of control flow edges between the BBs
3421 unsigned fgBBcount; // # of BBs in the method
3423 unsigned fgBBcountAtCodegen; // # of BBs in the method at the start of codegen
3425 unsigned fgBBNumMax; // The max bbNum that has been assigned to basic blocks
3426 unsigned fgDomBBcount; // # of BBs for which we have dominator and reachability information
3427 BasicBlock** fgBBInvPostOrder; // The flow graph stored in an array sorted in topological order, needed to compute
3428 // dominance. Indexed by block number. Size: fgBBNumMax + 1.
3430 // After the dominance tree is computed, we cache a DFS preorder number and DFS postorder number to compute
3431 // dominance queries in O(1). fgDomTreePreOrder and fgDomTreePostOrder are arrays giving the block's preorder and
3432 // postorder number, respectively. The arrays are indexed by basic block number. (Note that blocks are numbered
3433 // starting from one. Thus, we always waste element zero. This makes debugging easier and makes the code less likely
3434 // to suffer from bugs stemming from forgetting to add or subtract one from the block number to form an array
3435 // index). The arrays are of size fgBBNumMax + 1.
3436 unsigned* fgDomTreePreOrder;
3437 unsigned* fgDomTreePostOrder;
3439 bool fgBBVarSetsInited;
3441 // Allocate array like T* a = new T[fgBBNumMax + 1];
3442 // Using helper so we don't keep forgetting +1.
3443 template <typename T>
3444 T* fgAllocateTypeForEachBlk(CompMemKind cmk = CMK_Unknown)
3446 return (T*)compGetMem((fgBBNumMax + 1) * sizeof(T), cmk);
3449 // BlockSets are relative to a specific set of BasicBlock numbers. If that changes
3450 // (if the blocks are renumbered), this changes. BlockSets from different epochs
3451 // cannot be meaningfully combined. Note that new blocks can be created with higher
3452 // block numbers without changing the basic block epoch. These blocks *cannot*
3453 // participate in a block set until the blocks are all renumbered, causing the epoch
3454 // to change. This is useful if continuing to use previous block sets is valuable.
3455 // If the epoch is zero, then it is uninitialized, and block sets can't be used.
3456 unsigned fgCurBBEpoch;
3458 unsigned GetCurBasicBlockEpoch()
3460 return fgCurBBEpoch;
3463 // The number of basic blocks in the current epoch. When the blocks are renumbered,
3464 // this is fgBBcount. As blocks are added, fgBBcount increases, fgCurBBEpochSize remains
3465 // the same, until a new BasicBlock epoch is created, such as when the blocks are all renumbered.
3466 unsigned fgCurBBEpochSize;
3468 // The number of "size_t" elements required to hold a bitset large enough for fgCurBBEpochSize
3469 // bits. This is precomputed to avoid doing math every time BasicBlockBitSetTraits::GetArrSize() is called.
3470 unsigned fgBBSetCountInSizeTUnits;
3472 void NewBasicBlockEpoch()
3474 INDEBUG(unsigned oldEpochArrSize = fgBBSetCountInSizeTUnits);
3476 // We have a new epoch. Compute and cache the size needed for new BlockSets.
3478 fgCurBBEpochSize = fgBBNumMax + 1;
3479 fgBBSetCountInSizeTUnits =
3480 unsigned(roundUp(fgCurBBEpochSize, sizeof(size_t) * 8)) / unsigned(sizeof(size_t) * 8);
3483 // All BlockSet objects are now invalid!
3484 fgReachabilitySetsValid = false; // the bbReach sets are now invalid!
3485 fgEnterBlksSetValid = false; // the fgEnterBlks set is now invalid!
3489 unsigned epochArrSize = BasicBlockBitSetTraits::GetArrSize(this, sizeof(size_t));
3490 printf("\nNew BlockSet epoch %d, # of blocks (including unused BB00): %u, bitset array size: %u (%s)",
3491 fgCurBBEpoch, fgCurBBEpochSize, epochArrSize, (epochArrSize <= 1) ? "short" : "long");
3492 if ((fgCurBBEpoch != 1) && ((oldEpochArrSize <= 1) != (epochArrSize <= 1)))
3494 // If we're not just establishing the first epoch, and the epoch array size has changed such that we're
3495 // going to change our bitset representation from short (just a size_t bitset) to long (a pointer to an
3496 // array of size_t bitsets), then print that out.
3497 printf("; NOTE: BlockSet size was previously %s!", (oldEpochArrSize <= 1) ? "short" : "long");
3504 void EnsureBasicBlockEpoch()
3506 if (fgCurBBEpochSize != fgBBNumMax + 1)
3508 NewBasicBlockEpoch();
3512 BasicBlock* fgNewBasicBlock(BBjumpKinds jumpKind);
3513 void fgEnsureFirstBBisScratch();
3514 bool fgFirstBBisScratch();
3515 bool fgBBisScratch(BasicBlock* block);
3517 void fgExtendEHRegionBefore(BasicBlock* block);
3518 void fgExtendEHRegionAfter(BasicBlock* block);
3520 BasicBlock* fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
3522 BasicBlock* fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
3524 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
3527 BasicBlock* nearBlk,
3528 bool putInFilter = false,
3529 bool runRarely = false,
3530 bool insertAtEnd = false);
3532 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
3534 bool runRarely = false,
3535 bool insertAtEnd = false);
3537 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind);
3539 BasicBlock* fgNewBBinRegionWorker(BBjumpKinds jumpKind,
3540 BasicBlock* afterBlk,
3541 unsigned xcptnIndex,
3542 bool putInTryRegion);
3544 void fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk);
3545 void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk);
3546 void fgUnlinkBlock(BasicBlock* block);
3548 unsigned fgMeasureIR();
3550 #if OPT_BOOL_OPS // Used to detect multiple logical "not" assignments.
3551 bool fgMultipleNots;
3554 bool fgModified; // True if the flow graph has been modified recently
3555 bool fgComputePredsDone; // Have we computed the bbPreds list
3556 bool fgCheapPredsValid; // Is the bbCheapPreds list valid?
3557 bool fgDomsComputed; // Have we computed the dominator sets?
3558 bool fgOptimizedFinally; // Did we optimize any try-finallys?
3560 bool fgHasSwitch; // any BBJ_SWITCH jumps?
3561 bool fgHasPostfix; // any postfix ++/-- found?
3562 unsigned fgIncrCount; // number of increment nodes found
3564 BlockSet fgEnterBlks; // Set of blocks which have a special transfer of control; the "entry" blocks plus EH handler
3568 bool fgReachabilitySetsValid; // Are the bbReach sets valid?
3569 bool fgEnterBlksSetValid; // Is the fgEnterBlks set valid?
3572 bool fgRemoveRestOfBlock; // true if we know that we will throw
3573 bool fgStmtRemoved; // true if we remove statements -> need new DFA
3575 // There are two modes for ordering of the trees.
3576 // - In FGOrderTree, the dominant ordering is the tree order, and the nodes contained in
3577 // each tree and sub-tree are contiguous, and can be traversed (in gtNext/gtPrev order)
3578 // by traversing the tree according to the order of the operands.
3579 // - In FGOrderLinear, the dominant ordering is the linear order.
3586 FlowGraphOrder fgOrder;
3588 // The following are boolean flags that keep track of the state of internal data structures
3590 bool fgStmtListThreaded;
3591 bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
3592 bool fgEdgeWeightsComputed; // true after we have called fgComputeEdgeWeights
3593 bool fgHaveValidEdgeWeights; // true if we were successful in computing all of the edge weights
3594 bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
3595 bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
3596 bool fgNeedsUpdateFlowGraph; // true if we need to run fgUpdateFlowGraph
3597 BasicBlock::weight_t fgCalledCount; // count of the number of times this method was called
3598 // This is derived from the profile data
3599 // or is BB_UNITY_WEIGHT when we don't have profile data
3601 #if FEATURE_EH_FUNCLETS
3602 bool fgFuncletsCreated; // true if the funclet creation phase has been run
3603 #endif // FEATURE_EH_FUNCLETS
3605 bool fgGlobalMorph; // indicates if we are during the global morphing phase
3606 // since fgMorphTree can be called from several places
3607 bool fgExpandInline; // indicates that we are creating tree for the inliner
3609 bool impBoxTempInUse; // the temp below is valid and available
3610 unsigned impBoxTemp; // a temporary that is used for boxing
3613 bool jitFallbackCompile; // Are we doing a fallback compile? That is, have we executed a NO_WAY assert,
3614 // and we are trying to compile again in a "safer", minopts mode?
3618 unsigned impInlinedCodeSize;
3621 //-------------------------------------------------------------------------
3627 void fgTransformFatCalli();
3631 void fgRemoveEmptyTry();
3633 void fgRemoveEmptyFinally();
3635 void fgMergeFinallyChains();
3637 void fgCloneFinally();
3639 void fgCleanupContinuation(BasicBlock* continuation);
3641 void fgUpdateFinallyTargetFlags();
3643 bool fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block,
3644 BasicBlock* handler,
3645 BlockToBlockMap& continuationMap);
3647 GenTreePtr fgGetCritSectOfStaticMethod();
3649 #if FEATURE_EH_FUNCLETS
3651 void fgAddSyncMethodEnterExit();
3653 GenTree* fgCreateMonitorTree(unsigned lvaMonitorBool, unsigned lvaThisVar, BasicBlock* block, bool enter);
3655 void fgConvertSyncReturnToLeave(BasicBlock* block);
3657 #endif // FEATURE_EH_FUNCLETS
3659 void fgAddReversePInvokeEnterExit();
3661 bool fgMoreThanOneReturnBlock();
3663 // The number of separate return points in the method.
3664 unsigned fgReturnCount;
3666 void fgAddInternal();
3668 bool fgFoldConditional(BasicBlock* block);
3670 void fgMorphStmts(BasicBlock* block, bool* mult, bool* lnot, bool* loadw);
3671 void fgMorphBlocks();
3673 bool fgMorphBlockStmt(BasicBlock* block, GenTreeStmt* stmt DEBUGARG(const char* msg));
3675 void fgCheckArgCnt();
3676 void fgSetOptions();
3679 static fgWalkPreFn fgAssertNoQmark;
3680 void fgPreExpandQmarkChecks(GenTreePtr expr);
3681 void fgPostExpandQmarkChecks();
3682 static void fgCheckQmarkAllowedForm(GenTreePtr tree);
3685 IL_OFFSET fgFindBlockILOffset(BasicBlock* block);
3687 BasicBlock* fgSplitBlockAtBeginning(BasicBlock* curr);
3688 BasicBlock* fgSplitBlockAtEnd(BasicBlock* curr);
3689 BasicBlock* fgSplitBlockAfterStatement(BasicBlock* curr, GenTree* stmt);
3690 BasicBlock* fgSplitBlockAfterNode(BasicBlock* curr, GenTree* node); // for LIR
3691 BasicBlock* fgSplitEdge(BasicBlock* curr, BasicBlock* succ);
3693 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree, BasicBlock* block, IL_OFFSETX offs);
3694 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree);
3695 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree, BasicBlock* block);
3696 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree, IL_OFFSETX offs);
3698 GenTreePtr fgGetTopLevelQmark(GenTreePtr expr, GenTreePtr* ppDst = nullptr);
3699 void fgExpandQmarkForCastInstOf(BasicBlock* block, GenTreePtr stmt);
3700 void fgExpandQmarkStmt(BasicBlock* block, GenTreePtr expr);
3701 void fgExpandQmarkNodes();
3705 // Do "simple lowering." This functionality is (conceptually) part of "general"
3706 // lowering that is distributed between fgMorph and the lowering phase of LSRA.
3707 void fgSimpleLowering();
3709 bool fgShouldCreateAssignOp(GenTreePtr tree, bool* bReverse);
3711 GenTreePtr fgInitThisClass();
3713 GenTreeCall* fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper);
3715 GenTreeCall* fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls);
3717 void fgLocalVarLiveness();
3719 void fgLocalVarLivenessInit();
3721 #ifdef LEGACY_BACKEND
3722 GenTreePtr fgLegacyPerStatementLocalVarLiveness(GenTreePtr startNode, GenTreePtr relopNode);
3724 void fgPerNodeLocalVarLiveness(GenTree* node);
3726 void fgPerBlockLocalVarLiveness();
3728 VARSET_VALRET_TP fgGetHandlerLiveVars(BasicBlock* block);
3730 void fgLiveVarAnalysis(bool updateInternalOnly = false);
3732 // This is used in the liveness computation, as a temporary. When we use the
3733 // arbitrary-length VarSet representation, it is better not to allocate a new one
3735 VARSET_TP fgMarkIntfUnionVS;
3737 bool fgMarkIntf(VARSET_VALARG_TP varSet);
3739 bool fgMarkIntf(VARSET_VALARG_TP varSet1, VARSET_VALARG_TP varSet2);
3741 void fgUpdateRefCntForClone(BasicBlock* addedToBlock, GenTreePtr clonedTree);
3743 void fgUpdateRefCntForExtract(GenTreePtr wholeTree, GenTreePtr keptTree);
3745 void fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call);
3747 bool fgComputeLifeLocal(VARSET_TP& life, VARSET_TP& keepAliveVars, GenTree* lclVarNode, GenTree* node);
3749 VARSET_VALRET_TP fgComputeLife(VARSET_VALARG_TP life,
3750 GenTreePtr startNode,
3752 VARSET_VALARG_TP volatileVars,
3753 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
3755 VARSET_VALRET_TP fgComputeLifeLIR(VARSET_VALARG_TP life, BasicBlock* block, VARSET_VALARG_TP volatileVars);
3757 bool fgRemoveDeadStore(GenTree** pTree,
3761 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
3763 bool fgTryRemoveDeadLIRStore(LIR::Range& blockRange, GenTree* node, GenTree** next);
3765 // For updating liveset during traversal AFTER fgComputeLife has completed
3766 VARSET_VALRET_TP fgGetVarBits(GenTreePtr tree);
3767 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTreePtr tree);
3769 // Returns the set of live variables after endTree,
3770 // assuming that liveSet is the set of live variables BEFORE tree.
3771 // Requires that fgComputeLife has completed, and that tree is in the same
3772 // statement as endTree, and that it comes before endTree in execution order
3774 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTreePtr tree, GenTreePtr endTree)
3776 VARSET_TP VARSET_INIT(this, newLiveSet, liveSet);
3777 while (tree != nullptr && tree != endTree->gtNext)
3779 VarSetOps::AssignNoCopy(this, newLiveSet, fgUpdateLiveSet(newLiveSet, tree));
3780 tree = tree->gtNext;
3782 assert(tree == endTree->gtNext);
3786 void fgInterBlockLocalVarLiveness();
3788 // The presence of "x op= y" operations presents some difficulties for SSA: this is both a use of some SSA name of
3789 // "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
3790 // whether to treat that as the use or def. It chooses the "use", and thus the old SSA name. This map allows us
3791 // to record/recover the "def" SSA number, given the lcl var node for "x" in such a tree.
3792 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, unsigned, JitSimplerHashBehavior> NodeToUnsignedMap;
3793 NodeToUnsignedMap* m_opAsgnVarDefSsaNums;
3794 NodeToUnsignedMap* GetOpAsgnVarDefSsaNums()
3796 if (m_opAsgnVarDefSsaNums == nullptr)
3798 m_opAsgnVarDefSsaNums = new (getAllocator()) NodeToUnsignedMap(getAllocator());
3800 return m_opAsgnVarDefSsaNums;
3803 // Requires value numbering phase to have completed. Returns the value number ("gtVN") of the
3804 // "tree," EXCEPT in the case of GTF_VAR_USEASG, because the tree node's gtVN member is the
3805 // "use" VN. Performs a lookup into the map of (use asg tree -> def VN.) to return the "def's"
3807 inline ValueNum GetUseAsgDefVNOrTreeVN(GenTreePtr tree);
3809 // Requires that "lcl" has the GTF_VAR_DEF flag set. Returns the SSA number of "lcl".
3810 // Except: assumes that lcl is a def, and if it is
3811 // a def appearing in "lcl op= rhs" (GTF_VAR_USEASG), looks up and returns the SSA number for the "def",
3812 // rather than the "use" SSA number recorded in the tree "lcl".
3813 inline unsigned GetSsaNumForLocalVarDef(GenTreePtr lcl);
3815 // Some assignments assign to a local "indirectly": they are part of a comma expression that takes the address
3816 // of the local (or a field thereof), assigns this address to a temp, and uses an indirection of this temp as
3817 // the LHS of the assignment. This actually arises in exactly one situation. At the source level we assign one
3818 // struct local to another: "s1 = s2". This becomes a copyblk. If "s2" is promoted into field variables "s2f0",
3819 // ..."s2fn", then the copyblk will morph to a comma expression that takes the address of "s1" and does field-wise
3821 // (byref addrS1 = &s1,
3822 // *(addrS1 * offsetof(f0)) = s2f0,
3824 // *(addrS1 * offsetof(fn)) = s2fn)
3826 // It would be a shame, given the simple form at the source level, to be unable to track the values in the
3827 // fields of "s1" after this. But "s1" does not appear in the assignments that modify it. How, then, to
3828 // give it SSA names and value numbers?
3830 // The solution is to use the side table described below to annotate each of the field-wise assignments at the
3831 // end with an instance of the structure below, whose fields are described in the declaration.
3832 struct IndirectAssignmentAnnotation
3834 unsigned m_lclNum; // The local num that is being indirectly assigned.
3835 FieldSeqNode* m_fieldSeq; // If the LHS of the struct assignment is itself a struct field dereference,
3836 // as in "s0.g = s2", then "m_lclNum" would be "s0", and "m_fieldSeq" would
3837 // be the singleton field sequence "g". The individual assignments would
3838 // further append the fields of "s.g" to that.
3839 bool m_isEntire; // True iff this assignment writes all of m_lclNum. (This can occur if the
3840 // structure has a single field).
3841 unsigned m_defSsaNum; // The new SSA number of "m_lclNum" after the assignment.
3842 unsigned m_useSsaNum; // Only valid if "m_isEntire" is false; if so, the SSA number of "m_lclNum" before the
3845 IndirectAssignmentAnnotation(unsigned lclNum,
3846 FieldSeqNode* fldSeq,
3848 unsigned defSsaNum = SsaConfig::RESERVED_SSA_NUM,
3849 unsigned useSsaNum = SsaConfig::RESERVED_SSA_NUM)
3850 : m_lclNum(lclNum), m_fieldSeq(fldSeq), m_isEntire(isEntire), m_defSsaNum(defSsaNum), m_useSsaNum(useSsaNum)
3854 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, IndirectAssignmentAnnotation*, JitSimplerHashBehavior>
3855 NodeToIndirAssignMap;
3856 NodeToIndirAssignMap* m_indirAssignMap;
3857 NodeToIndirAssignMap* GetIndirAssignMap()
3859 if (m_indirAssignMap == nullptr)
3861 // Create a CompAllocator that labels sub-structure with CMK_IndirAssignMap, and use that for allocation.
3862 IAllocator* ialloc = new (this, CMK_IndirAssignMap) CompAllocator(this, CMK_IndirAssignMap);
3863 m_indirAssignMap = new (ialloc) NodeToIndirAssignMap(ialloc);
3865 return m_indirAssignMap;
3868 // Performs SSA conversion.
3871 // Reset any data structures to the state expected by "fgSsaBuild", so it can be run again.
3872 void fgResetForSsa();
3874 unsigned fgSsaPassesCompleted; // Number of times fgSsaBuild has been run.
3876 // Returns "true" iff lcl "lclNum" should be excluded from SSA.
3877 inline bool fgExcludeFromSsa(unsigned lclNum);
3879 // The value numbers for this compilation.
3880 ValueNumStore* vnStore;
3883 ValueNumStore* GetValueNumStore()
3888 // Do value numbering (assign a value number to each
3890 void fgValueNumber();
3892 // Computes new GcHeap VN via the assignment H[elemTypeEq][arrVN][inx][fldSeq] = rhsVN.
3893 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
3894 // The 'indType' is the indirection type of the lhs of the assignment and will typically
3895 // match the element type of the array or fldSeq. When this type doesn't match
3896 // or if the fldSeq is 'NotAField' we invalidate the array contents H[elemTypeEq][arrVN]
3898 ValueNum fgValueNumberArrIndexAssign(CORINFO_CLASS_HANDLE elemTypeEq,
3901 FieldSeqNode* fldSeq,
3905 // Requires that "tree" is a GT_IND marked as an array index, and that its address argument
3906 // has been parsed to yield the other input arguments. If evaluation of the address
3907 // can raise exceptions, those should be captured in the exception set "excVN."
3908 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
3909 // Marks "tree" with the VN for H[elemTypeEq][arrVN][inx][fldSeq] (for the liberal VN; a new unique
3910 // VN for the conservative VN.) Also marks the tree's argument as the address of an array element.
3911 // The type tree->TypeGet() will typically match the element type of the array or fldSeq.
3912 // When this type doesn't match or if the fldSeq is 'NotAField' we return a new unique VN
3914 ValueNum fgValueNumberArrIndexVal(GenTreePtr tree,
3915 CORINFO_CLASS_HANDLE elemTypeEq,
3919 FieldSeqNode* fldSeq);
3921 // Requires "funcApp" to be a VNF_PtrToArrElem, and "addrXvn" to represent the exception set thrown
3922 // by evaluating the array index expression "tree". Returns the value number resulting from
3923 // dereferencing the array in the current GcHeap state. If "tree" is non-null, it must be the
3924 // "GT_IND" that does the dereference, and it is given the returned value number.
3925 ValueNum fgValueNumberArrIndexVal(GenTreePtr tree, struct VNFuncApp* funcApp, ValueNum addrXvn);
3927 // Compute the value number for a byref-exposed load of the given type via the given pointerVN.
3928 ValueNum fgValueNumberByrefExposedLoad(var_types type, ValueNum pointerVN);
3930 unsigned fgVNPassesCompleted; // Number of times fgValueNumber has been run.
3932 // Utility functions for fgValueNumber.
3934 // Perform value-numbering for the trees in "blk".
3935 void fgValueNumberBlock(BasicBlock* blk);
3937 // Requires that "entryBlock" is the entry block of loop "loopNum", and that "loopNum" is the
3938 // innermost loop of which "entryBlock" is the entry. Returns the value number that should be
3939 // assumed for the memoryKind at the start "entryBlk".
3940 ValueNum fgMemoryVNForLoopSideEffects(MemoryKind memoryKind, BasicBlock* entryBlock, unsigned loopNum);
3942 // Called when an operation (performed by "tree", described by "msg") may cause the GcHeap to be mutated.
3943 // As GcHeap is a subset of ByrefExposed, this will also annotate the ByrefExposed mutation.
3944 void fgMutateGcHeap(GenTreePtr tree DEBUGARG(const char* msg));
3946 // Called when an operation (performed by "tree", described by "msg") may cause an address-exposed local to be
3948 void fgMutateAddressExposedLocal(GenTreePtr tree DEBUGARG(const char* msg));
3950 // For a GC heap store at curTree, record the new curMemoryVN's and update curTree's MemorySsaMap.
3951 // As GcHeap is a subset of ByrefExposed, this will also record the ByrefExposed store.
3952 void recordGcHeapStore(GenTreePtr curTree, ValueNum gcHeapVN DEBUGARG(const char* msg));
3954 // For a store to an address-exposed local at curTree, record the new curMemoryVN and update curTree's MemorySsaMap.
3955 void recordAddressExposedLocalStore(GenTreePtr curTree, ValueNum memoryVN DEBUGARG(const char* msg));
3957 // Tree caused an update in the current memory VN. If "tree" has an associated heap SSA #, record that
3958 // value in that SSA #.
3959 void fgValueNumberRecordMemorySsa(MemoryKind memoryKind, GenTreePtr tree);
3961 // The input 'tree' is a leaf node that is a constant
3962 // Assign the proper value number to the tree
3963 void fgValueNumberTreeConst(GenTreePtr tree);
3965 // Assumes that all inputs to "tree" have had value numbers assigned; assigns a VN to tree.
3966 // (With some exceptions: the VN of the lhs of an assignment is assigned as part of the
3968 // If "evalAsgLhsInd" is true, evaluate a GT_IND node, even if it's labeled as the LHS of
3970 void fgValueNumberTree(GenTreePtr tree, bool evalAsgLhsInd = false);
3972 // Does value-numbering for a block assignment.
3973 void fgValueNumberBlockAssignment(GenTreePtr tree, bool evalAsgLhsInd);
3975 // Does value-numbering for a cast tree.
3976 void fgValueNumberCastTree(GenTreePtr tree);
3978 // Does value-numbering for an intrinsic tree.
3979 void fgValueNumberIntrinsic(GenTreePtr tree);
3981 // Does value-numbering for a call. We interpret some helper calls.
3982 void fgValueNumberCall(GenTreeCall* call);
3984 // The VN of some nodes in "args" may have changed -- reassign VNs to the arg list nodes.
3985 void fgUpdateArgListVNs(GenTreeArgList* args);
3987 // Does value-numbering for a helper "call" that has a VN function symbol "vnf".
3988 void fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc);
3990 // Requires "helpCall" to be a helper call. Assigns it a value number;
3991 // we understand the semantics of some of the calls. Returns "true" if
3992 // the call may modify the heap (we assume arbitrary memory side effects if so).
3993 bool fgValueNumberHelperCall(GenTreeCall* helpCall);
3995 // Requires "helpFunc" to be pure. Returns the corresponding VNFunc.
3996 VNFunc fgValueNumberHelperMethVNFunc(CorInfoHelpFunc helpFunc);
3998 // These are the current value number for the memory implicit variables while
3999 // doing value numbering. These are the value numbers under the "liberal" interpretation
4000 // of memory values; the "conservative" interpretation needs no VN, since every access of
4001 // memory yields an unknown value.
4002 ValueNum fgCurMemoryVN[MemoryKindCount];
4004 // Return a "pseudo"-class handle for an array element type. If "elemType" is TYP_STRUCT,
4005 // requires "elemStructType" to be non-null (and to have a low-order zero). Otherwise, low order bit
4006 // is 1, and the rest is an encoding of "elemTyp".
4007 static CORINFO_CLASS_HANDLE EncodeElemType(var_types elemTyp, CORINFO_CLASS_HANDLE elemStructType)
4009 if (elemStructType != nullptr)
4011 assert(varTypeIsStruct(elemTyp) || elemTyp == TYP_REF || elemTyp == TYP_BYREF ||
4012 varTypeIsIntegral(elemTyp));
4013 assert((size_t(elemStructType) & 0x1) == 0x0); // Make sure the encoding below is valid.
4014 return elemStructType;
4018 elemTyp = varTypeUnsignedToSigned(elemTyp);
4019 return CORINFO_CLASS_HANDLE(size_t(elemTyp) << 1 | 0x1);
4022 // If "clsHnd" is the result of an "EncodePrim" call, returns true and sets "*pPrimType" to the
4023 // var_types it represents. Otherwise, returns TYP_STRUCT (on the assumption that "clsHnd" is
4024 // the struct type of the element).
4025 static var_types DecodeElemType(CORINFO_CLASS_HANDLE clsHnd)
4027 size_t clsHndVal = size_t(clsHnd);
4028 if (clsHndVal & 0x1)
4030 return var_types(clsHndVal >> 1);
4038 // Convert a BYTE which represents the VM's CorInfoGCtype to the JIT's var_types
4039 var_types getJitGCType(BYTE gcType);
4041 enum structPassingKind
4043 SPK_Unknown, // Invalid value, never returned
4044 SPK_PrimitiveType, // The struct is passed/returned using a primitive type.
4045 SPK_ByValue, // The struct is passed/returned by value (using the ABI rules)
4046 // for ARM64 and UNIX_X64 in multiple registers. (when all of the
4047 // parameters registers are used, then the stack will be used)
4048 // for X86 passed on the stack, for ARM32 passed in registers
4049 // or the stack or split between registers and the stack.
4050 SPK_ByValueAsHfa, // The struct is passed/returned as an HFA in multiple registers.
4052 }; // The struct is passed/returned by reference to a copy/buffer.
4054 // Get the "primitive" type that is is used when we are given a struct of size 'structSize'.
4055 // For pointer sized structs the 'clsHnd' is used to determine if the struct contains GC ref.
4056 // A "primitive" type is one of the scalar types: byte, short, int, long, ref, float, double
4057 // If we can't or shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
4059 var_types getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS_HANDLE clsHnd);
4061 // Get the type that is used to pass values of the given struct type.
4062 // If you have already retrieved the struct size then pass it as the optional third argument
4064 var_types getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4065 structPassingKind* wbPassStruct,
4066 unsigned structSize = 0);
4068 // Get the type that is used to return values of the given struct type.
4069 // If you have already retrieved the struct size then pass it as the optional third argument
4071 var_types getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4072 structPassingKind* wbPassStruct = nullptr,
4073 unsigned structSize = 0);
4076 // Print a representation of "vnp" or "vn" on standard output.
4077 // If "level" is non-zero, we also print out a partial expansion of the value.
4078 void vnpPrint(ValueNumPair vnp, unsigned level);
4079 void vnPrint(ValueNum vn, unsigned level);
4082 // Dominator computation member functions
4083 // Not exposed outside Compiler
4085 bool fgDominate(BasicBlock* b1, BasicBlock* b2); // Return true if b1 dominates b2
4087 bool fgReachable(BasicBlock* b1, BasicBlock* b2); // Returns true if block b1 can reach block b2
4089 void fgComputeDoms(); // Computes the immediate dominators for each basic block in the
4090 // flow graph. We first assume the fields bbIDom on each
4091 // basic block are invalid. This computation is needed later
4092 // by fgBuildDomTree to build the dominance tree structure.
4093 // Based on: A Simple, Fast Dominance Algorithm
4094 // by Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
4096 void fgCompDominatedByExceptionalEntryBlocks();
4098 BlockSet_ValRet_T fgGetDominatorSet(BasicBlock* block); // Returns a set of blocks that dominate the given block.
4099 // Note: this is relatively slow compared to calling fgDominate(),
4100 // especially if dealing with a single block versus block check.
4102 void fgComputeReachabilitySets(); // Compute bbReach sets. (Also sets BBF_GC_SAFE_POINT flag on blocks.)
4104 void fgComputeEnterBlocksSet(); // Compute the set of entry blocks, 'fgEnterBlks'.
4106 bool fgRemoveUnreachableBlocks(); // Remove blocks determined to be unreachable by the bbReach sets.
4108 void fgComputeReachability(); // Perform flow graph node reachability analysis.
4110 BasicBlock* fgIntersectDom(BasicBlock* a, BasicBlock* b); // Intersect two immediate dominator sets.
4112 void fgDfsInvPostOrder(); // In order to compute dominance using fgIntersectDom, the flow graph nodes must be
4113 // processed in topological sort, this function takes care of that.
4115 void fgDfsInvPostOrderHelper(BasicBlock* block, BlockSet& visited, unsigned* count);
4117 BlockSet_ValRet_T fgDomFindStartNodes(); // Computes which basic blocks don't have incoming edges in the flow graph.
4118 // Returns this as a set.
4120 BlockSet_ValRet_T fgDomTreeEntryNodes(BasicBlockList** domTree); // Computes which nodes in the dominance forest are
4121 // root nodes. Returns this as a set.
4124 void fgDispDomTree(BasicBlockList** domTree); // Helper that prints out the Dominator Tree in debug builds.
4127 void fgBuildDomTree(); // Once we compute all the immediate dominator sets for each node in the flow graph
4128 // (performed by fgComputeDoms), this procedure builds the dominance tree represented
4131 // In order to speed up the queries of the form 'Does A dominates B', we can perform a DFS preorder and postorder
4132 // traversal of the dominance tree and the dominance query will become A dominates B iif preOrder(A) <= preOrder(B)
4133 // && postOrder(A) >= postOrder(B) making the computation O(1).
4134 void fgTraverseDomTree(unsigned bbNum, BasicBlockList** domTree, unsigned* preNum, unsigned* postNum);
4136 // When the flow graph changes, we need to update the block numbers, predecessor lists, reachability sets, and
4138 void fgUpdateChangedFlowGraph();
4141 // Compute the predecessors of the blocks in the control flow graph.
4142 void fgComputePreds();
4144 // Remove all predecessor information.
4145 void fgRemovePreds();
4147 // Compute the cheap flow graph predecessors lists. This is used in some early phases
4148 // before the full predecessors lists are computed.
4149 void fgComputeCheapPreds();
4152 void fgAddCheapPred(BasicBlock* block, BasicBlock* blockPred);
4154 void fgRemoveCheapPred(BasicBlock* block, BasicBlock* blockPred);
4164 // Initialize the per-block variable sets (used for liveness analysis).
4165 void fgInitBlockVarSets();
4167 // true if we've gone through and created GC Poll calls.
4168 bool fgGCPollsCreated;
4169 void fgMarkGCPollBlocks();
4170 void fgCreateGCPolls();
4171 bool fgCreateGCPoll(GCPollType pollType, BasicBlock* block);
4173 // Requires that "block" is a block that returns from
4174 // a finally. Returns the number of successors (jump targets of
4175 // of blocks in the covered "try" that did a "LEAVE".)
4176 unsigned fgNSuccsOfFinallyRet(BasicBlock* block);
4178 // Requires that "block" is a block that returns (in the sense of BBJ_EHFINALLYRET) from
4179 // a finally. Returns its "i"th successor (jump targets of
4180 // of blocks in the covered "try" that did a "LEAVE".)
4181 // Requires that "i" < fgNSuccsOfFinallyRet(block).
4182 BasicBlock* fgSuccOfFinallyRet(BasicBlock* block, unsigned i);
4185 // Factor out common portions of the impls of the methods above.
4186 void fgSuccOfFinallyRetWork(BasicBlock* block, unsigned i, BasicBlock** bres, unsigned* nres);
4189 // For many purposes, it is desirable to be able to enumerate the *distinct* targets of a switch statement,
4190 // skipping duplicate targets. (E.g., in flow analyses that are only interested in the set of possible targets.)
4191 // SwitchUniqueSuccSet contains the non-duplicated switch targets.
4192 // (Code that modifies the jump table of a switch has an obligation to call Compiler::UpdateSwitchTableTarget,
4193 // which in turn will call the "UpdateTarget" method of this type if a SwitchUniqueSuccSet has already
4194 // been computed for the switch block. If a switch block is deleted or is transformed into a non-switch,
4195 // we leave the entry associated with the block, but it will no longer be accessed.)
4196 struct SwitchUniqueSuccSet
4198 unsigned numDistinctSuccs; // Number of distinct targets of the switch.
4199 BasicBlock** nonDuplicates; // Array of "numDistinctSuccs", containing all the distinct switch target
4202 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4203 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4204 // remove it from "this", and ensure that "to" is a member. Use "alloc" to do any required allocation.
4205 void UpdateTarget(IAllocator* alloc, BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4208 typedef SimplerHashTable<BasicBlock*, PtrKeyFuncs<BasicBlock>, SwitchUniqueSuccSet, JitSimplerHashBehavior>
4209 BlockToSwitchDescMap;
4212 // Maps BasicBlock*'s that end in switch statements to SwitchUniqueSuccSets that allow
4213 // iteration over only the distinct successors.
4214 BlockToSwitchDescMap* m_switchDescMap;
4217 BlockToSwitchDescMap* GetSwitchDescMap()
4219 if (m_switchDescMap == nullptr)
4221 m_switchDescMap = new (getAllocator()) BlockToSwitchDescMap(getAllocator());
4223 return m_switchDescMap;
4226 // Invalidate the map of unique switch block successors. For example, since the hash key of the map
4227 // depends on block numbers, we must invalidate the map when the blocks are renumbered, to ensure that
4228 // we don't accidentally look up and return the wrong switch data.
4229 void InvalidateUniqueSwitchSuccMap()
4231 m_switchDescMap = nullptr;
4234 // Requires "switchBlock" to be a block that ends in a switch. Returns
4235 // the corresponding SwitchUniqueSuccSet.
4236 SwitchUniqueSuccSet GetDescriptorForSwitch(BasicBlock* switchBlk);
4238 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4239 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4240 // remove it from "this", and ensure that "to" is a member.
4241 void UpdateSwitchTableTarget(BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4243 // Remove the "SwitchUniqueSuccSet" of "switchBlk" in the BlockToSwitchDescMap.
4244 void fgInvalidateSwitchDescMapEntry(BasicBlock* switchBlk);
4246 BasicBlock* fgFirstBlockOfHandler(BasicBlock* block);
4248 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred);
4250 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred, flowList*** ptrToPred);
4252 flowList* fgSpliceOutPred(BasicBlock* block, BasicBlock* blockPred);
4254 flowList* fgRemoveRefPred(BasicBlock* block, BasicBlock* blockPred);
4256 flowList* fgRemoveAllRefPreds(BasicBlock* block, BasicBlock* blockPred);
4258 flowList* fgRemoveAllRefPreds(BasicBlock* block, flowList** ptrToPred);
4260 void fgRemoveBlockAsPred(BasicBlock* block);
4262 void fgChangeSwitchBlock(BasicBlock* oldSwitchBlock, BasicBlock* newSwitchBlock);
4264 void fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* newTarget, BasicBlock* oldTarget);
4266 void fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, BasicBlock* oldTarget);
4268 void fgReplacePred(BasicBlock* block, BasicBlock* oldPred, BasicBlock* newPred);
4270 flowList* fgAddRefPred(BasicBlock* block,
4271 BasicBlock* blockPred,
4272 flowList* oldEdge = nullptr,
4273 bool initializingPreds = false); // Only set to 'true' when we are computing preds in
4276 void fgFindBasicBlocks();
4278 bool fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt);
4280 bool fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionIndex, bool putInTryRegion);
4282 BasicBlock* fgFindInsertPoint(unsigned regionIndex,
4283 bool putInTryRegion,
4284 BasicBlock* startBlk,
4286 BasicBlock* nearBlk,
4287 BasicBlock* jumpBlk,
4290 unsigned fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNesting = nullptr);
4292 void fgRemoveEmptyBlocks();
4294 void fgRemoveStmt(BasicBlock* block, GenTreePtr stmt, bool updateRefCnt = true);
4296 bool fgCheckRemoveStmt(BasicBlock* block, GenTreePtr stmt);
4298 void fgCreateLoopPreHeader(unsigned lnum);
4300 void fgUnreachableBlock(BasicBlock* block);
4302 void fgRemoveConditionalJump(BasicBlock* block);
4304 BasicBlock* fgLastBBInMainFunction();
4306 BasicBlock* fgEndBBAfterMainFunction();
4308 void fgUnlinkRange(BasicBlock* bBeg, BasicBlock* bEnd);
4310 void fgRemoveBlock(BasicBlock* block, bool unreachable);
4312 bool fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4314 void fgCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4316 void fgUpdateLoopsAfterCompacting(BasicBlock* block, BasicBlock* bNext);
4318 BasicBlock* fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst);
4320 bool fgRenumberBlocks();
4322 bool fgExpandRarelyRunBlocks();
4324 bool fgEhAllowsMoveBlock(BasicBlock* bBefore, BasicBlock* bAfter);
4326 void fgMoveBlocksAfter(BasicBlock* bStart, BasicBlock* bEnd, BasicBlock* insertAfterBlk);
4328 enum FG_RELOCATE_TYPE
4330 FG_RELOCATE_TRY, // relocate the 'try' region
4331 FG_RELOCATE_HANDLER // relocate the handler region (including the filter if necessary)
4333 BasicBlock* fgRelocateEHRange(unsigned regionIndex, FG_RELOCATE_TYPE relocateType);
4335 #if FEATURE_EH_FUNCLETS
4336 #if defined(_TARGET_ARM_)
4337 void fgClearFinallyTargetBit(BasicBlock* block);
4338 #endif // defined(_TARGET_ARM_)
4339 bool fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block);
4340 bool fgAnyIntraHandlerPreds(BasicBlock* block);
4341 void fgInsertFuncletPrologBlock(BasicBlock* block);
4342 void fgCreateFuncletPrologBlocks();
4343 void fgCreateFunclets();
4344 #else // !FEATURE_EH_FUNCLETS
4345 bool fgRelocateEHRegions();
4346 #endif // !FEATURE_EH_FUNCLETS
4348 bool fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* target);
4350 bool fgBlockEndFavorsTailDuplication(BasicBlock* block);
4352 bool fgBlockIsGoodTailDuplicationCandidate(BasicBlock* block);
4354 bool fgOptimizeFallthroughTailDup(BasicBlock* block, BasicBlock* target);
4356 bool fgOptimizeEmptyBlock(BasicBlock* block);
4358 bool fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBlock* bDest);
4360 bool fgOptimizeBranch(BasicBlock* bJump);
4362 bool fgOptimizeSwitchBranches(BasicBlock* block);
4364 bool fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev);
4366 bool fgOptimizeSwitchJumps();
4368 void fgPrintEdgeWeights();
4370 void fgComputeEdgeWeights();
4372 void fgReorderBlocks();
4374 void fgDetermineFirstColdBlock();
4376 bool fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc = nullptr);
4378 bool fgUpdateFlowGraph(bool doTailDup = false);
4380 void fgFindOperOrder();
4382 // method that returns if you should split here
4383 typedef bool(fgSplitPredicate)(GenTree* tree, GenTree* parent, fgWalkData* data);
4385 void fgSetBlockOrder();
4387 void fgRemoveReturnBlock(BasicBlock* block);
4389 /* Helper code that has been factored out */
4390 inline void fgConvertBBToThrowBB(BasicBlock* block);
4392 bool fgCastNeeded(GenTreePtr tree, var_types toType);
4393 GenTreePtr fgDoNormalizeOnStore(GenTreePtr tree);
4394 GenTreePtr fgMakeTmpArgNode(
4395 unsigned tmpVarNum FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(const bool passedInRegisters));
4397 // The following check for loops that don't execute calls
4398 bool fgLoopCallMarked;
4400 void fgLoopCallTest(BasicBlock* srcBB, BasicBlock* dstBB);
4401 void fgLoopCallMark();
4403 void fgMarkLoopHead(BasicBlock* block);
4405 unsigned fgGetCodeEstimate(BasicBlock* block);
4408 const char* fgProcessEscapes(const char* nameIn, escapeMapping_t* map);
4409 FILE* fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, LPCWSTR type);
4410 bool fgDumpFlowGraph(Phases phase);
4412 #endif // DUMP_FLOWGRAPHS
4417 void fgDispBBLiveness(BasicBlock* block);
4418 void fgDispBBLiveness();
4419 void fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth = 0);
4420 void fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, bool dumpTrees);
4421 void fgDispBasicBlocks(bool dumpTrees = false);
4422 void fgDumpStmtTree(GenTreePtr stmt, unsigned blkNum);
4423 void fgDumpBlock(BasicBlock* block);
4424 void fgDumpTrees(BasicBlock* firstBlock, BasicBlock* lastBlock);
4426 static fgWalkPreFn fgStress64RsltMulCB;
4427 void fgStress64RsltMul();
4428 void fgDebugCheckUpdate();
4429 void fgDebugCheckBBlist(bool checkBBNum = false, bool checkBBRefs = true);
4430 void fgDebugCheckBlockLinks();
4431 void fgDebugCheckLinks(bool morphTrees = false);
4432 void fgDebugCheckNodeLinks(BasicBlock* block, GenTreePtr stmt);
4433 void fgDebugCheckFlags(GenTreePtr tree);
4434 void fgDebugCheckFlagsHelper(GenTreePtr tree, unsigned treeFlags, unsigned chkFlags);
4435 void fgDebugCheckTryFinallyExits();
4438 #ifdef LEGACY_BACKEND
4439 static void fgOrderBlockOps(GenTreePtr tree,
4443 GenTreePtr* opsPtr, // OUT
4444 regMaskTP* regsPtr); // OUT
4445 #endif // LEGACY_BACKEND
4447 static GenTreePtr fgGetFirstNode(GenTreePtr tree);
4448 static bool fgTreeIsInStmt(GenTree* tree, GenTreeStmt* stmt);
4450 inline bool fgIsInlining()
4452 return fgExpandInline;
4455 void fgTraverseRPO();
4457 //--------------------- Walking the trees in the IR -----------------------
4462 fgWalkPreFn* wtprVisitorFn;
4463 fgWalkPostFn* wtpoVisitorFn;
4464 void* pCallbackData; // user-provided data
4465 bool wtprLclsOnly; // whether to only visit lclvar nodes
4466 GenTreePtr parent; // parent of current node, provided to callback
4467 GenTreeStack* parentStack; // stack of parent nodes, if asked for
4469 bool printModified; // callback can use this
4473 template <bool computeStack>
4474 static fgWalkResult fgWalkTreePreRec(GenTreePtr* pTree, fgWalkData* fgWalkPre);
4476 // general purpose tree-walker that is capable of doing pre- and post- order
4477 // callbacks at the same time
4478 template <bool doPreOrder, bool doPostOrder>
4479 static fgWalkResult fgWalkTreeRec(GenTreePtr* pTree, fgWalkData* fgWalkPre);
4481 fgWalkResult fgWalkTreePre(GenTreePtr* pTree,
4482 fgWalkPreFn* visitor,
4483 void* pCallBackData = nullptr,
4484 bool lclVarsOnly = false,
4485 bool computeStack = false);
4487 fgWalkResult fgWalkTree(GenTreePtr* pTree,
4488 fgWalkPreFn* preVisitor,
4489 fgWalkPostFn* postVisitor,
4490 void* pCallBackData = nullptr);
4492 void fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData);
4496 template <bool computeStack>
4497 static fgWalkResult fgWalkTreePostRec(GenTreePtr* pTree, fgWalkData* fgWalkPre);
4499 fgWalkResult fgWalkTreePost(GenTreePtr* pTree,
4500 fgWalkPostFn* visitor,
4501 void* pCallBackData = nullptr,
4502 bool computeStack = false);
4504 // An fgWalkPreFn that looks for expressions that have inline throws in
4505 // minopts mode. Basically it looks for tress with gtOverflowEx() or
4506 // GTF_IND_RNGCHK. It returns WALK_ABORT if one is found. It
4507 // returns WALK_SKIP_SUBTREES if GTF_EXCEPT is not set (assumes flags
4508 // properly propagated to parent trees). It returns WALK_CONTINUE
4510 static fgWalkResult fgChkThrowCB(GenTreePtr* pTree, Compiler::fgWalkData* data);
4511 static fgWalkResult fgChkLocAllocCB(GenTreePtr* pTree, Compiler::fgWalkData* data);
4512 static fgWalkResult fgChkQmarkCB(GenTreePtr* pTree, Compiler::fgWalkData* data);
4514 /**************************************************************************
4516 *************************************************************************/
4519 friend class SsaBuilder;
4520 friend struct ValueNumberState;
4522 //--------------------- Detect the basic blocks ---------------------------
4524 BasicBlock** fgBBs; // Table of pointers to the BBs
4526 void fgInitBBLookup();
4527 BasicBlock* fgLookupBB(unsigned addr);
4529 void fgMarkJumpTarget(BYTE* jumpTarget, IL_OFFSET offs);
4531 void fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget);
4533 void fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock);
4535 void fgLinkBasicBlocks();
4537 unsigned fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget);
4539 void fgCheckBasicBlockControlFlow();
4541 void fgControlFlowPermitted(BasicBlock* blkSrc,
4542 BasicBlock* blkDest,
4543 BOOL IsLeave = false /* is the src a leave block */);
4545 bool fgFlowToFirstBlockOfInnerTry(BasicBlock* blkSrc, BasicBlock* blkDest, bool sibling);
4547 void fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, bool isInlining);
4549 void fgAdjustForAddressExposedOrWrittenThis();
4551 bool fgProfileData_ILSizeMismatch;
4552 ICorJitInfo::ProfileBuffer* fgProfileBuffer;
4553 ULONG fgProfileBufferCount;
4554 ULONG fgNumProfileRuns;
4556 unsigned fgStressBBProf()
4559 unsigned result = JitConfig.JitStressBBProf();
4562 if (compStressCompile(STRESS_BB_PROFILE, 15))
4573 bool fgHaveProfileData();
4574 bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weight);
4575 void fgInstrumentMethod();
4578 // fgIsUsingProfileWeights - returns true if we have real profile data for this method
4579 // or if we have some fake profile data for the stress mode
4580 bool fgIsUsingProfileWeights()
4582 return (fgHaveProfileData() || fgStressBBProf());
4585 // fgProfileRunsCount - returns total number of scenario runs for the profile data
4586 // or BB_UNITY_WEIGHT when we aren't using profile data.
4587 unsigned fgProfileRunsCount()
4589 return fgIsUsingProfileWeights() ? fgNumProfileRuns : BB_UNITY_WEIGHT;
4592 //-------- Insert a statement at the start or end of a basic block --------
4596 static bool fgBlockContainsStatementBounded(BasicBlock* block, GenTree* stmt, bool answerOnBoundExceeded = true);
4600 GenTreeStmt* fgInsertStmtAtEnd(BasicBlock* block, GenTreePtr node);
4602 public: // Used by linear scan register allocation
4603 GenTreeStmt* fgInsertStmtNearEnd(BasicBlock* block, GenTreePtr node);
4606 GenTreePtr fgInsertStmtAtBeg(BasicBlock* block, GenTreePtr stmt);
4607 GenTreePtr fgInsertStmtAfter(BasicBlock* block, GenTreePtr insertionPoint, GenTreePtr stmt);
4609 public: // Used by linear scan register allocation
4610 GenTreePtr fgInsertStmtBefore(BasicBlock* block, GenTreePtr insertionPoint, GenTreePtr stmt);
4613 GenTreePtr fgInsertStmtListAfter(BasicBlock* block, GenTreePtr stmtAfter, GenTreePtr stmtList);
4615 GenTreePtr fgMorphSplitTree(GenTree** splitPoint, GenTree* stmt, BasicBlock* blk);
4617 // Create a new temporary variable to hold the result of *ppTree,
4618 // and transform the graph accordingly.
4619 GenTree* fgInsertCommaFormTemp(GenTree** ppTree, CORINFO_CLASS_HANDLE structType = nullptr);
4620 GenTree* fgMakeMultiUse(GenTree** ppTree);
4623 // Recognize a bitwise rotation pattern and convert into a GT_ROL or a GT_ROR node.
4624 GenTreePtr fgRecognizeAndMorphBitwiseRotation(GenTreePtr tree);
4625 bool fgOperIsBitwiseRotationRoot(genTreeOps oper);
4627 //-------- Determine the order in which the trees will be evaluated -------
4629 unsigned fgTreeSeqNum;
4630 GenTree* fgTreeSeqLst;
4631 GenTree* fgTreeSeqBeg;
4633 GenTree* fgSetTreeSeq(GenTree* tree, GenTree* prev = nullptr, bool isLIR = false);
4634 void fgSetTreeSeqHelper(GenTree* tree, bool isLIR);
4635 void fgSetTreeSeqFinish(GenTreePtr tree, bool isLIR);
4636 void fgSetStmtSeq(GenTree* tree);
4637 void fgSetBlockOrder(BasicBlock* block);
4639 //------------------------- Morphing --------------------------------------
4641 unsigned fgPtrArgCntCur;
4642 unsigned fgPtrArgCntMax;
4643 hashBv* fgOutgoingArgTemps;
4644 hashBv* fgCurrentlyInUseArgTemps;
4646 bool compCanEncodePtrArgCntMax();
4648 void fgSetRngChkTarget(GenTreePtr tree, bool delay = true);
4651 void fgMoveOpsLeft(GenTreePtr tree);
4654 bool fgIsCommaThrow(GenTreePtr tree, bool forFolding = false);
4656 bool fgIsThrow(GenTreePtr tree);
4658 bool fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2);
4659 bool fgIsBlockCold(BasicBlock* block);
4661 GenTreePtr fgMorphCastIntoHelper(GenTreePtr tree, int helper, GenTreePtr oper);
4663 GenTreePtr fgMorphIntoHelperCall(GenTreePtr tree, int helper, GenTreeArgList* args);
4665 GenTreePtr fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType, unsigned lclOffs);
4667 bool fgMorphRelopToQmark(GenTreePtr tree);
4669 // A "MorphAddrContext" carries information from the surrounding context. If we are evaluating a byref address,
4670 // it is useful to know whether the address will be immediately dereferenced, or whether the address value will
4671 // be used, perhaps by passing it as an argument to a called method. This affects how null checking is done:
4672 // for sufficiently small offsets, we can rely on OS page protection to implicitly null-check addresses that we
4673 // know will be dereferenced. To know that reliance on implicit null checking is sound, we must further know that
4674 // all offsets between the top-level indirection and the bottom are constant, and that their sum is sufficiently
4675 // small; hence the other fields of MorphAddrContext.
4676 enum MorphAddrContextKind
4681 struct MorphAddrContext
4683 MorphAddrContextKind m_kind;
4684 bool m_allConstantOffsets; // Valid only for "m_kind == MACK_Ind". True iff all offsets between
4685 // top-level indirection and here have been constants.
4686 size_t m_totalOffset; // Valid only for "m_kind == MACK_Ind", and if "m_allConstantOffsets" is true.
4687 // In that case, is the sum of those constant offsets.
4689 MorphAddrContext(MorphAddrContextKind kind) : m_kind(kind), m_allConstantOffsets(true), m_totalOffset(0)
4694 // A MACK_CopyBlock context is immutable, so we can just make one of these and share it.
4695 static MorphAddrContext s_CopyBlockMAC;
4698 GenTreePtr getSIMDStructFromField(GenTreePtr tree,
4699 var_types* baseTypeOut,
4701 unsigned* simdSizeOut,
4702 bool ignoreUsedInSIMDIntrinsic = false);
4703 GenTreePtr fgMorphFieldAssignToSIMDIntrinsicSet(GenTreePtr tree);
4704 GenTreePtr fgMorphFieldToSIMDIntrinsicGet(GenTreePtr tree);
4705 bool fgMorphCombineSIMDFieldAssignments(BasicBlock* block, GenTreePtr stmt);
4706 void impMarkContiguousSIMDFieldAssignments(GenTreePtr stmt);
4708 // fgPreviousCandidateSIMDFieldAsgStmt is only used for tracking previous simd field assignment
4709 // in function: Complier::impMarkContiguousSIMDFieldAssignments.
4710 GenTreePtr fgPreviousCandidateSIMDFieldAsgStmt;
4712 #endif // FEATURE_SIMD
4713 GenTreePtr fgMorphArrayIndex(GenTreePtr tree);
4714 GenTreePtr fgMorphCast(GenTreePtr tree);
4715 GenTreePtr fgUnwrapProxy(GenTreePtr objRef);
4716 GenTreeCall* fgMorphArgs(GenTreeCall* call);
4718 void fgMakeOutgoingStructArgCopy(GenTreeCall* call,
4721 CORINFO_CLASS_HANDLE copyBlkClass FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(
4722 const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structDescPtr));
4724 void fgFixupStructReturn(GenTreePtr call);
4725 GenTreePtr fgMorphLocalVar(GenTreePtr tree);
4726 bool fgAddrCouldBeNull(GenTreePtr addr);
4727 GenTreePtr fgMorphField(GenTreePtr tree, MorphAddrContext* mac);
4728 bool fgCanFastTailCall(GenTreeCall* call);
4729 void fgMorphTailCall(GenTreeCall* call);
4730 void fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCall* recursiveTailCall);
4731 GenTreePtr fgAssignRecursiveCallArgToCallerParam(GenTreePtr arg,
4732 fgArgTabEntryPtr argTabEntry,
4734 IL_OFFSETX callILOffset,
4735 GenTreePtr tmpAssignmentInsertionPoint,
4736 GenTreePtr paramAssignmentInsertionPoint);
4737 static int fgEstimateCallStackSize(GenTreeCall* call);
4738 GenTreePtr fgMorphCall(GenTreeCall* call);
4739 void fgMorphCallInline(GenTreeCall* call, InlineResult* result);
4740 void fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result);
4742 void fgNoteNonInlineCandidate(GenTreeStmt* stmt, GenTreeCall* call);
4743 static fgWalkPreFn fgFindNonInlineCandidate;
4745 GenTreePtr fgOptimizeDelegateConstructor(GenTreeCall* call,
4746 CORINFO_CONTEXT_HANDLE* ExactContextHnd,
4747 CORINFO_RESOLVED_TOKEN* ldftnToken);
4748 GenTreePtr fgMorphLeaf(GenTreePtr tree);
4749 void fgAssignSetVarDef(GenTreePtr tree);
4750 GenTreePtr fgMorphOneAsgBlockOp(GenTreePtr tree);
4751 GenTreePtr fgMorphInitBlock(GenTreePtr tree);
4752 GenTreePtr fgMorphBlkToInd(GenTreeBlk* tree, var_types type);
4753 GenTreePtr fgMorphGetStructAddr(GenTreePtr* pTree, CORINFO_CLASS_HANDLE clsHnd, bool isRValue = false);
4754 GenTreePtr fgMorphBlkNode(GenTreePtr tree, bool isDest);
4755 GenTreePtr fgMorphBlockOperand(GenTreePtr tree, var_types asgType, unsigned blockWidth, bool isDest);
4756 void fgMorphUnsafeBlk(GenTreeObj* obj);
4757 GenTreePtr fgMorphCopyBlock(GenTreePtr tree);
4758 GenTreePtr fgMorphForRegisterFP(GenTreePtr tree);
4759 GenTreePtr fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac = nullptr);
4760 GenTreePtr fgMorphSmpOpPre(GenTreePtr tree);
4761 GenTreePtr fgMorphModToSubMulDiv(GenTreeOp* tree);
4762 GenTreePtr fgMorphSmpOpOptional(GenTreeOp* tree);
4763 GenTreePtr fgMorphRecognizeBoxNullable(GenTree* compare);
4765 GenTreePtr fgMorphToEmulatedFP(GenTreePtr tree);
4766 GenTreePtr fgMorphConst(GenTreePtr tree);
4769 GenTreePtr fgMorphTree(GenTreePtr tree, MorphAddrContext* mac = nullptr);
4772 #if LOCAL_ASSERTION_PROP
4773 void fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTreePtr tree));
4774 void fgKillDependentAssertions(unsigned lclNum DEBUGARG(GenTreePtr tree));
4776 void fgMorphTreeDone(GenTreePtr tree, GenTreePtr oldTree = nullptr DEBUGARG(int morphNum = 0));
4778 GenTreeStmt* fgMorphStmt;
4780 unsigned fgGetBigOffsetMorphingTemp(var_types type); // We cache one temp per type to be
4781 // used when morphing big offset.
4783 //----------------------- Liveness analysis -------------------------------
4785 VARSET_TP fgCurUseSet; // vars used by block (before an assignment)
4786 VARSET_TP fgCurDefSet; // vars assigned by block (before a use)
4788 MemoryKindSet fgCurMemoryUse; // True iff the current basic block uses memory.
4789 MemoryKindSet fgCurMemoryDef; // True iff the current basic block modifies memory.
4790 MemoryKindSet fgCurMemoryHavoc; // True if the current basic block is known to set memory to a "havoc" value.
4792 bool byrefStatesMatchGcHeapStates; // True iff GcHeap and ByrefExposed memory have all the same def points.
4794 void fgMarkUseDef(GenTreeLclVarCommon* tree);
4796 void fgBeginScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
4797 void fgEndScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
4799 void fgMarkInScope(BasicBlock* block, VARSET_VALARG_TP inScope);
4800 void fgUnmarkInScope(BasicBlock* block, VARSET_VALARG_TP unmarkScope);
4802 void fgExtendDbgScopes();
4803 void fgExtendDbgLifetimes();
4806 void fgDispDebugScopes();
4809 //-------------------------------------------------------------------------
4811 // The following keeps track of any code we've added for things like array
4812 // range checking or explicit calls to enable GC, and so on.
4817 AddCodeDsc* acdNext;
4818 BasicBlock* acdDstBlk; // block to which we jump
4820 SpecialCodeKind acdKind; // what kind of a special block is this?
4821 unsigned short acdStkLvl;
4825 static unsigned acdHelper(SpecialCodeKind codeKind);
4827 AddCodeDsc* fgAddCodeList;
4829 bool fgRngChkThrowAdded;
4830 AddCodeDsc* fgExcptnTargetCache[SCK_COUNT];
4832 BasicBlock* fgRngChkTarget(BasicBlock* block, unsigned stkDepth, SpecialCodeKind kind);
4834 BasicBlock* fgAddCodeRef(BasicBlock* srcBlk, unsigned refData, SpecialCodeKind kind, unsigned stkDepth = 0);
4837 AddCodeDsc* fgFindExcptnTarget(SpecialCodeKind kind, unsigned refData);
4840 bool fgIsCodeAdded();
4842 bool fgIsThrowHlpBlk(BasicBlock* block);
4843 unsigned fgThrowHlpBlkStkLevel(BasicBlock* block);
4845 unsigned fgBigOffsetMorphingTemps[TYP_COUNT];
4847 unsigned fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo);
4848 void fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* result);
4849 void fgInsertInlineeBlocks(InlineInfo* pInlineInfo);
4850 GenTreePtr fgInlinePrependStatements(InlineInfo* inlineInfo);
4851 void fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, GenTreePtr stmt);
4853 #if FEATURE_MULTIREG_RET
4854 GenTreePtr fgGetStructAsStructPtr(GenTreePtr tree);
4855 GenTreePtr fgAssignStructInlineeToVar(GenTreePtr child, CORINFO_CLASS_HANDLE retClsHnd);
4856 void fgAttachStructInlineeToAsg(GenTreePtr tree, GenTreePtr child, CORINFO_CLASS_HANDLE retClsHnd);
4857 #endif // FEATURE_MULTIREG_RET
4859 static fgWalkPreFn fgUpdateInlineReturnExpressionPlaceHolder;
4862 static fgWalkPreFn fgDebugCheckInlineCandidates;
4864 void CheckNoFatPointerCandidatesLeft();
4865 static fgWalkPreFn fgDebugCheckFatPointerCandidates;
4868 void fgPromoteStructs();
4869 fgWalkResult fgMorphStructField(GenTreePtr tree, fgWalkData* fgWalkPre);
4870 fgWalkResult fgMorphLocalField(GenTreePtr tree, fgWalkData* fgWalkPre);
4871 void fgMarkImplicitByRefArgs();
4872 bool fgMorphImplicitByRefArgs(GenTree** pTree, fgWalkData* fgWalkPre);
4873 static fgWalkPreFn fgMarkAddrTakenLocalsPreCB;
4874 static fgWalkPostFn fgMarkAddrTakenLocalsPostCB;
4875 void fgMarkAddressExposedLocals();
4876 bool fgNodesMayInterfere(GenTree* store, GenTree* load);
4878 // Returns true if the type of tree is of size at least "width", or if "tree" is not a
4880 bool fgFitsInOrNotLoc(GenTreePtr tree, unsigned width);
4882 // The given local variable, required to be a struct variable, is being assigned via
4883 // a "lclField", to make it masquerade as an integral type in the ABI. Make sure that
4884 // the variable is not enregistered, and is therefore not promoted independently.
4885 void fgLclFldAssign(unsigned lclNum);
4887 static fgWalkPreFn gtHasLocalsWithAddrOpCB;
4888 bool gtCanOptimizeTypeEquality(GenTreePtr tree);
4889 bool gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call);
4890 bool gtIsActiveCSE_Candidate(GenTreePtr tree);
4893 bool fgPrintInlinedMethods;
4896 bool fgIsBigOffset(size_t offset);
4898 // The following are used when morphing special cases of integer div/mod operations and also by codegen
4899 bool fgIsSignedDivOptimizable(GenTreePtr divisor);
4900 bool fgIsUnsignedDivOptimizable(GenTreePtr divisor);
4901 bool fgIsSignedModOptimizable(GenTreePtr divisor);
4902 bool fgIsUnsignedModOptimizable(GenTreePtr divisor);
4905 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4906 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4910 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4911 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4918 LclVarDsc* optIsTrackedLocal(GenTreePtr tree);
4921 void optRemoveRangeCheck(
4922 GenTreePtr tree, GenTreePtr stmt, bool updateCSEcounts, unsigned sideEffFlags = 0, bool forceRemove = false);
4923 bool optIsRangeCheckRemovable(GenTreePtr tree);
4926 static fgWalkPreFn optValidRangeCheckIndex;
4927 static fgWalkPreFn optRemoveTreeVisitor; // Helper passed to Compiler::fgWalkAllTreesPre() to decrement the LclVar
4930 void optRemoveTree(GenTreePtr deadTree, GenTreePtr keepList);
4932 /**************************************************************************
4934 *************************************************************************/
4937 // Do hoisting for all loops.
4938 void optHoistLoopCode();
4940 // To represent sets of VN's that have already been hoisted in outer loops.
4941 typedef SimplerHashTable<ValueNum, SmallPrimitiveKeyFuncs<ValueNum>, bool, JitSimplerHashBehavior> VNToBoolMap;
4942 typedef VNToBoolMap VNSet;
4944 struct LoopHoistContext
4947 // The set of variables hoisted in the current loop (or nullptr if there are none).
4948 VNSet* m_pHoistedInCurLoop;
4951 // Value numbers of expressions that have been hoisted in parent loops in the loop nest.
4952 VNSet m_hoistedInParentLoops;
4953 // Value numbers of expressions that have been hoisted in the current (or most recent) loop in the nest.
4954 // Previous decisions on loop-invariance of value numbers in the current loop.
4955 VNToBoolMap m_curLoopVnInvariantCache;
4957 VNSet* GetHoistedInCurLoop(Compiler* comp)
4959 if (m_pHoistedInCurLoop == nullptr)
4961 m_pHoistedInCurLoop = new (comp->getAllocatorLoopHoist()) VNSet(comp->getAllocatorLoopHoist());
4963 return m_pHoistedInCurLoop;
4966 VNSet* ExtractHoistedInCurLoop()
4968 VNSet* res = m_pHoistedInCurLoop;
4969 m_pHoistedInCurLoop = nullptr;
4973 LoopHoistContext(Compiler* comp)
4974 : m_pHoistedInCurLoop(nullptr)
4975 , m_hoistedInParentLoops(comp->getAllocatorLoopHoist())
4976 , m_curLoopVnInvariantCache(comp->getAllocatorLoopHoist())
4981 // Do hoisting for loop "lnum" (an index into the optLoopTable), and all loops nested within it.
4982 // Tracks the expressions that have been hoisted by containing loops by temporary recording their
4983 // value numbers in "m_hoistedInParentLoops". This set is not modified by the call.
4984 void optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);
4986 // Do hoisting for a particular loop ("lnum" is an index into the optLoopTable.)
4987 // Assumes that expressions have been hoisted in containing loops if their value numbers are in
4988 // "m_hoistedInParentLoops".
4990 void optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt);
4992 // Hoist all expressions in "blk" that are invariant in loop "lnum" (an index into the optLoopTable)
4993 // outside of that loop. Exempt expressions whose value number is in "m_hoistedInParentLoops"; add VN's of hoisted
4994 // expressions to "hoistInLoop".
4995 void optHoistLoopExprsForBlock(BasicBlock* blk, unsigned lnum, LoopHoistContext* hoistCtxt);
4997 // Return true if the tree looks profitable to hoist out of loop 'lnum'.
4998 bool optIsProfitableToHoistableTree(GenTreePtr tree, unsigned lnum);
5000 // Hoist all proper sub-expressions of "tree" (which occurs in "stmt", which occurs in "blk")
5001 // that are invariant in loop "lnum" (an index into the optLoopTable)
5002 // outside of that loop. Exempt expressions whose value number is in "hoistedInParents"; add VN's of hoisted
5003 // expressions to "hoistInLoop".
5004 // Returns "true" iff "tree" is loop-invariant (wrt "lnum").
5005 // Assumes that the value of "*firstBlockAndBeforeSideEffect" indicates that we're in the first block, and before
5006 // any possible globally visible side effects. Assume is called in evaluation order, and updates this.
5007 bool optHoistLoopExprsForTree(GenTreePtr tree,
5009 LoopHoistContext* hoistCtxt,
5010 bool* firstBlockAndBeforeSideEffect,
5013 // Performs the hoisting 'tree' into the PreHeader for loop 'lnum'
5014 void optHoistCandidate(GenTreePtr tree, unsigned lnum, LoopHoistContext* hoistCtxt);
5016 // Returns true iff the ValueNum "vn" represents a value that is loop-invariant in "lnum".
5017 // Constants and init values are always loop invariant.
5018 // VNPhi's connect VN's to the SSA definition, so we can know if the SSA def occurs in the loop.
5019 bool optVNIsLoopInvariant(ValueNum vn, unsigned lnum, VNToBoolMap* recordedVNs);
5021 // Returns "true" iff "tree" is valid at the head of loop "lnum", in the context of the hoist substitution
5022 // "subst". If "tree" is a local SSA var, it is valid if its SSA definition occurs outside of the loop, or
5023 // if it is in the domain of "subst" (meaning that it's definition has been previously hoisted, with a "standin"
5024 // local.) If tree is a constant, it is valid. Otherwise, if it is an operator, it is valid iff its children are.
5025 bool optTreeIsValidAtLoopHead(GenTreePtr tree, unsigned lnum);
5027 // If "blk" is the entry block of a natural loop, returns true and sets "*pLnum" to the index of the loop
5028 // in the loop table.
5029 bool optBlockIsLoopEntry(BasicBlock* blk, unsigned* pLnum);
5031 // Records the set of "side effects" of all loops: fields (object instance and static)
5032 // written to, and SZ-array element type equivalence classes updated.
5033 void optComputeLoopSideEffects();
5036 // Requires "lnum" to be the index of an outermost loop in the loop table. Traverses the body of that loop,
5037 // including all nested loops, and records the set of "side effects" of the loop: fields (object instance and
5038 // static) written to, and SZ-array element type equivalence classes updated.
5039 void optComputeLoopNestSideEffects(unsigned lnum);
5041 // Add the side effects of "blk" (which is required to be within a loop) to all loops of which it is a part.
5042 void optComputeLoopSideEffectsOfBlock(BasicBlock* blk);
5044 // Hoist the expression "expr" out of loop "lnum".
5045 void optPerformHoistExpr(GenTreePtr expr, unsigned lnum);
5048 void optOptimizeBools();
5051 GenTree* optIsBoolCond(GenTree* condBranch, GenTree** compPtr, bool* boolPtr);
5053 void optOptimizeBoolsGcStress(BasicBlock* condBlock);
5056 void optOptimizeLayout(); // Optimize the BasicBlock layout of the method
5058 void optOptimizeLoops(); // for "while-do" loops duplicates simple loop conditions and transforms
5059 // the loop into a "do-while" loop
5060 // Also finds all natural loops and records them in the loop table
5062 // Optionally clone loops in the loop table.
5063 void optCloneLoops();
5065 // Clone loop "loopInd" in the loop table.
5066 void optCloneLoop(unsigned loopInd, LoopCloneContext* context);
5068 // Ensure that loop "loopInd" has a unique head block. (If the existing entry has
5069 // non-loop predecessors other than the head entry, create a new, empty block that goes (only) to the entry,
5070 // and redirects the preds of the entry to this new block.) Sets the weight of the newly created block to
5072 void optEnsureUniqueHead(unsigned loopInd, unsigned ambientWeight);
5074 void optUnrollLoops(); // Unrolls loops (needs to have cost info)
5077 // This enumeration describes what is killed by a call.
5081 CALLINT_NONE, // no interference (most helpers)
5082 CALLINT_REF_INDIRS, // kills GC ref indirections (SETFIELD OBJ)
5083 CALLINT_SCL_INDIRS, // kills non GC ref indirections (SETFIELD non-OBJ)
5084 CALLINT_ALL_INDIRS, // kills both GC ref and non GC ref indirections (SETFIELD STRUCT)
5085 CALLINT_ALL, // kills everything (normal method call)
5089 // A "LoopDsc" describes a ("natural") loop. We (currently) require the body of a loop to be a contiguous (in
5090 // bbNext order) sequence of basic blocks. (At times, we may require the blocks in a loop to be "properly numbered"
5091 // in bbNext order; we use comparisons on the bbNum to decide order.)
5092 // The blocks that define the body are
5093 // first <= top <= entry <= bottom .
5094 // The "head" of the loop is a block outside the loop that has "entry" as a successor. We only support loops with a
5095 // single 'head' block. The meanings of these blocks are given in the definitions below. Also see the picture at
5096 // Compiler::optFindNaturalLoops().
5099 BasicBlock* lpHead; // HEAD of the loop (not part of the looping of the loop) -- has ENTRY as a successor.
5100 BasicBlock* lpFirst; // FIRST block (in bbNext order) reachable within this loop. (May be part of a nested
5101 // loop, but not the outer loop.)
5102 BasicBlock* lpTop; // loop TOP (the back edge from lpBottom reaches here) (in most cases FIRST and TOP are the
5104 BasicBlock* lpEntry; // the ENTRY in the loop (in most cases TOP or BOTTOM)
5105 BasicBlock* lpBottom; // loop BOTTOM (from here we have a back edge to the TOP)
5106 BasicBlock* lpExit; // if a single exit loop this is the EXIT (in most cases BOTTOM)
5108 callInterf lpAsgCall; // "callInterf" for calls in the loop
5109 ALLVARSET_TP lpAsgVars; // set of vars assigned within the loop (all vars, not just tracked)
5110 varRefKinds lpAsgInds : 8; // set of inds modified within the loop
5112 unsigned short lpFlags; // Mask of the LPFLG_* constants
5114 unsigned char lpExitCnt; // number of exits from the loop
5116 unsigned char lpParent; // The index of the most-nested loop that completely contains this one,
5117 // or else BasicBlock::NOT_IN_LOOP if no such loop exists.
5118 unsigned char lpChild; // The index of a nested loop, or else BasicBlock::NOT_IN_LOOP if no child exists.
5119 // (Actually, an "immediately" nested loop --
5120 // no other child of this loop is a parent of lpChild.)
5121 unsigned char lpSibling; // The index of another loop that is an immediate child of lpParent,
5122 // or else BasicBlock::NOT_IN_LOOP. One can enumerate all the children of a loop
5123 // by following "lpChild" then "lpSibling" links.
5125 #define LPFLG_DO_WHILE 0x0001 // it's a do-while loop (i.e ENTRY is at the TOP)
5126 #define LPFLG_ONE_EXIT 0x0002 // the loop has only one exit
5128 #define LPFLG_ITER 0x0004 // for (i = icon or lclVar; test_condition(); i++)
5129 #define LPFLG_HOISTABLE 0x0008 // the loop is in a form that is suitable for hoisting expressions
5130 #define LPFLG_CONST 0x0010 // for (i=icon;i<icon;i++){ ... } - constant loop
5132 #define LPFLG_VAR_INIT 0x0020 // iterator is initialized with a local var (var # found in lpVarInit)
5133 #define LPFLG_CONST_INIT 0x0040 // iterator is initialized with a constant (found in lpConstInit)
5135 #define LPFLG_VAR_LIMIT 0x0100 // iterator is compared with a local var (var # found in lpVarLimit)
5136 #define LPFLG_CONST_LIMIT 0x0200 // iterator is compared with a constant (found in lpConstLimit)
5137 #define LPFLG_ARRLEN_LIMIT 0x0400 // iterator is compared with a.len or a[i].len (found in lpArrLenLimit)
5138 #define LPFLG_SIMD_LIMIT 0x0080 // iterator is compared with Vector<T>.Count (found in lpConstLimit)
5140 #define LPFLG_HAS_PREHEAD 0x0800 // lpHead is known to be a preHead for this loop
5141 #define LPFLG_REMOVED 0x1000 // has been removed from the loop table (unrolled or optimized away)
5142 #define LPFLG_DONT_UNROLL 0x2000 // do not unroll this loop
5144 #define LPFLG_ASGVARS_YES 0x4000 // "lpAsgVars" has been computed
5145 #define LPFLG_ASGVARS_INC 0x8000 // "lpAsgVars" is incomplete -- vars beyond those representable in an AllVarSet
5146 // type are assigned to.
5148 bool lpLoopHasMemoryHavoc[MemoryKindCount]; // The loop contains an operation that we assume has arbitrary
5149 // memory side effects. If this is set, the fields below
5150 // may not be accurate (since they become irrelevant.)
5151 bool lpContainsCall; // True if executing the loop body *may* execute a call
5153 VARSET_TP lpVarInOut; // The set of variables that are IN or OUT during the execution of this loop
5154 VARSET_TP lpVarUseDef; // The set of variables that are USE or DEF during the execution of this loop
5156 int lpHoistedExprCount; // The register count for the non-FP expressions from inside this loop that have been
5158 int lpLoopVarCount; // The register count for the non-FP LclVars that are read/written inside this loop
5159 int lpVarInOutCount; // The register count for the non-FP LclVars that are alive inside or accross this loop
5161 int lpHoistedFPExprCount; // The register count for the FP expressions from inside this loop that have been
5163 int lpLoopVarFPCount; // The register count for the FP LclVars that are read/written inside this loop
5164 int lpVarInOutFPCount; // The register count for the FP LclVars that are alive inside or accross this loop
5166 typedef SimplerHashTable<CORINFO_FIELD_HANDLE,
5167 PtrKeyFuncs<struct CORINFO_FIELD_STRUCT_>,
5169 JitSimplerHashBehavior>
5171 FieldHandleSet* lpFieldsModified; // This has entries (mappings to "true") for all static field and object
5172 // instance fields modified
5175 typedef SimplerHashTable<CORINFO_CLASS_HANDLE,
5176 PtrKeyFuncs<struct CORINFO_CLASS_STRUCT_>,
5178 JitSimplerHashBehavior>
5180 ClassHandleSet* lpArrayElemTypesModified; // Bits set indicate the set of sz array element types such that
5181 // arrays of that type are modified
5184 // Adds the variable liveness information for 'blk' to 'this' LoopDsc
5185 void AddVariableLiveness(Compiler* comp, BasicBlock* blk);
5187 inline void AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd);
5188 // This doesn't *always* take a class handle -- it can also take primitive types, encoded as class handles
5189 // (shifted left, with a low-order bit set to distinguish.)
5190 // Use the {Encode/Decode}ElemType methods to construct/destruct these.
5191 inline void AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd);
5193 /* The following values are set only for iterator loops, i.e. has the flag LPFLG_ITER set */
5195 GenTreePtr lpIterTree; // The "i <op>= const" tree
5196 unsigned lpIterVar(); // iterator variable #
5197 int lpIterConst(); // the constant with which the iterator is incremented
5198 genTreeOps lpIterOper(); // the type of the operation on the iterator (ASG_ADD, ASG_SUB, etc.)
5199 void VERIFY_lpIterTree();
5201 var_types lpIterOperType(); // For overflow instructions
5204 int lpConstInit; // initial constant value of iterator : Valid if LPFLG_CONST_INIT
5205 unsigned lpVarInit; // initial local var number to which we initialize the iterator : Valid if
5209 /* The following is for LPFLG_ITER loops only (i.e. the loop condition is "i RELOP const or var" */
5211 GenTreePtr lpTestTree; // pointer to the node containing the loop test
5212 genTreeOps lpTestOper(); // the type of the comparison between the iterator and the limit (GT_LE, GT_GE, etc.)
5213 void VERIFY_lpTestTree();
5215 bool lpIsReversed(); // true if the iterator node is the second operand in the loop condition
5216 GenTreePtr lpIterator(); // the iterator node in the loop test
5217 GenTreePtr lpLimit(); // the limit node in the loop test
5219 int lpConstLimit(); // limit constant value of iterator - loop condition is "i RELOP const" : Valid if
5220 // LPFLG_CONST_LIMIT
5221 unsigned lpVarLimit(); // the lclVar # in the loop condition ( "i RELOP lclVar" ) : Valid if
5223 bool lpArrLenLimit(Compiler* comp, ArrIndex* index); // The array length in the loop condition ( "i RELOP
5224 // arr.len" or "i RELOP arr[i][j].len" ) : Valid if
5225 // LPFLG_ARRLEN_LIMIT
5227 // Returns "true" iff "*this" contains the blk.
5228 bool lpContains(BasicBlock* blk)
5230 return lpFirst->bbNum <= blk->bbNum && blk->bbNum <= lpBottom->bbNum;
5232 // Returns "true" iff "*this" (properly) contains the range [first, bottom] (allowing firsts
5233 // to be equal, but requiring bottoms to be different.)
5234 bool lpContains(BasicBlock* first, BasicBlock* bottom)
5236 return lpFirst->bbNum <= first->bbNum && bottom->bbNum < lpBottom->bbNum;
5239 // Returns "true" iff "*this" (properly) contains "lp2" (allowing firsts to be equal, but requiring
5240 // bottoms to be different.)
5241 bool lpContains(const LoopDsc& lp2)
5243 return lpContains(lp2.lpFirst, lp2.lpBottom);
5246 // Returns "true" iff "*this" is (properly) contained by the range [first, bottom]
5247 // (allowing firsts to be equal, but requiring bottoms to be different.)
5248 bool lpContainedBy(BasicBlock* first, BasicBlock* bottom)
5250 return first->bbNum <= lpFirst->bbNum && lpBottom->bbNum < bottom->bbNum;
5253 // Returns "true" iff "*this" is (properly) contained by "lp2"
5254 // (allowing firsts to be equal, but requiring bottoms to be different.)
5255 bool lpContainedBy(const LoopDsc& lp2)
5257 return lpContains(lp2.lpFirst, lp2.lpBottom);
5260 // Returns "true" iff "*this" is disjoint from the range [top, bottom].
5261 bool lpDisjoint(BasicBlock* first, BasicBlock* bottom)
5263 return bottom->bbNum < lpFirst->bbNum || lpBottom->bbNum < first->bbNum;
5265 // Returns "true" iff "*this" is disjoint from "lp2".
5266 bool lpDisjoint(const LoopDsc& lp2)
5268 return lpDisjoint(lp2.lpFirst, lp2.lpBottom);
5270 // Returns "true" iff the loop is well-formed (see code for defn).
5273 return lpFirst->bbNum <= lpTop->bbNum && lpTop->bbNum <= lpEntry->bbNum &&
5274 lpEntry->bbNum <= lpBottom->bbNum &&
5275 (lpHead->bbNum < lpTop->bbNum || lpHead->bbNum > lpBottom->bbNum);
5280 bool fgMightHaveLoop(); // returns true if there are any backedges
5281 bool fgHasLoops; // True if this method has any loops, set in fgComputeReachability
5284 LoopDsc optLoopTable[MAX_LOOP_NUM]; // loop descriptor table
5285 unsigned char optLoopCount; // number of tracked loops
5288 unsigned optCallCount; // number of calls made in the method
5289 unsigned optIndirectCallCount; // number of virtual, interface and indirect calls made in the method
5290 unsigned optNativeCallCount; // number of Pinvoke/Native calls made in the method
5291 unsigned optLoopsCloned; // number of loops cloned in the current method.
5294 unsigned optFindLoopNumberFromBeginBlock(BasicBlock* begBlk);
5295 void optPrintLoopInfo(unsigned loopNum,
5297 BasicBlock* lpFirst,
5299 BasicBlock* lpEntry,
5300 BasicBlock* lpBottom,
5301 unsigned char lpExitCnt,
5303 unsigned parentLoop = BasicBlock::NOT_IN_LOOP);
5304 void optPrintLoopInfo(unsigned lnum);
5305 void optPrintLoopRecording(unsigned lnum);
5307 void optCheckPreds();
5310 void optSetBlockWeights();
5312 void optMarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk, bool excludeEndBlk);
5314 void optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk);
5316 void optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmarkLoop = false);
5318 bool optIsLoopTestEvalIntoTemp(GenTreePtr test, GenTreePtr* newTest);
5319 unsigned optIsLoopIncrTree(GenTreePtr incr);
5320 bool optCheckIterInLoopTest(unsigned loopInd, GenTreePtr test, BasicBlock* from, BasicBlock* to, unsigned iterVar);
5321 bool optComputeIterInfo(GenTreePtr incr, BasicBlock* from, BasicBlock* to, unsigned* pIterVar);
5322 bool optPopulateInitInfo(unsigned loopInd, GenTreePtr init, unsigned iterVar);
5323 bool optExtractInitTestIncr(BasicBlock* head,
5328 GenTreePtr* ppIncr);
5330 void optRecordLoop(BasicBlock* head,
5336 unsigned char exitCnt);
5338 void optFindNaturalLoops();
5340 // Ensures that all the loops in the loop nest rooted at "loopInd" (an index into the loop table) are 'canonical' --
5341 // each loop has a unique "top." Returns "true" iff the flowgraph has been modified.
5342 bool optCanonicalizeLoopNest(unsigned char loopInd);
5344 // Ensures that the loop "loopInd" (an index into the loop table) is 'canonical' -- it has a unique "top,"
5345 // unshared with any other loop. Returns "true" iff the flowgraph has been modified
5346 bool optCanonicalizeLoop(unsigned char loopInd);
5348 // Requires "l1" to be a valid loop table index, and not "BasicBlock::NOT_IN_LOOP". Requires "l2" to be
5349 // a valid loop table index, or else "BasicBlock::NOT_IN_LOOP". Returns true
5350 // iff "l2" is not NOT_IN_LOOP, and "l1" contains "l2".
5351 bool optLoopContains(unsigned l1, unsigned l2);
5353 // Requires "loopInd" to be a valid index into the loop table.
5354 // Updates the loop table by changing loop "loopInd", whose head is required
5355 // to be "from", to be "to". Also performs this transformation for any
5356 // loop nested in "loopInd" that shares the same head as "loopInd".
5357 void optUpdateLoopHead(unsigned loopInd, BasicBlock* from, BasicBlock* to);
5359 // Updates the successors of "blk": if "blk2" is a successor of "blk", and there is a mapping for "blk2->blk3" in
5360 // "redirectMap", change "blk" so that "blk3" is this successor. Note that the predecessor lists are not updated.
5361 void optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap);
5363 // Marks the containsCall information to "lnum" and any parent loops.
5364 void AddContainsCallAllContainingLoops(unsigned lnum);
5365 // Adds the variable liveness information from 'blk' to "lnum" and any parent loops.
5366 void AddVariableLivenessAllContainingLoops(unsigned lnum, BasicBlock* blk);
5367 // Adds "fldHnd" to the set of modified fields of "lnum" and any parent loops.
5368 void AddModifiedFieldAllContainingLoops(unsigned lnum, CORINFO_FIELD_HANDLE fldHnd);
5369 // Adds "elemType" to the set of modified array element types of "lnum" and any parent loops.
5370 void AddModifiedElemTypeAllContainingLoops(unsigned lnum, CORINFO_CLASS_HANDLE elemType);
5372 // Requires that "from" and "to" have the same "bbJumpKind" (perhaps because "to" is a clone
5373 // of "from".) Copies the jump destination from "from" to "to".
5374 void optCopyBlkDest(BasicBlock* from, BasicBlock* to);
5376 // The depth of the loop described by "lnum" (an index into the loop table.) (0 == top level)
5377 unsigned optLoopDepth(unsigned lnum)
5379 unsigned par = optLoopTable[lnum].lpParent;
5380 if (par == BasicBlock::NOT_IN_LOOP)
5386 return 1 + optLoopDepth(par);
5390 void fgOptWhileLoop(BasicBlock* block);
5392 bool optComputeLoopRep(int constInit,
5395 genTreeOps iterOper,
5397 genTreeOps testOper,
5400 unsigned* iterCount);
5401 #if FEATURE_STACK_FP_X87
5404 VARSET_TP optAllFloatVars; // mask of all tracked FP variables
5405 VARSET_TP optAllFPregVars; // mask of all enregistered FP variables
5406 VARSET_TP optAllNonFPvars; // mask of all tracked non-FP variables
5407 #endif // FEATURE_STACK_FP_X87
5410 static fgWalkPreFn optIsVarAssgCB;
5413 bool optIsVarAssigned(BasicBlock* beg, BasicBlock* end, GenTreePtr skip, unsigned var);
5415 bool optIsVarAssgLoop(unsigned lnum, unsigned var);
5417 int optIsSetAssgLoop(unsigned lnum, ALLVARSET_VALARG_TP vars, varRefKinds inds = VR_NONE);
5419 bool optNarrowTree(GenTreePtr tree, var_types srct, var_types dstt, ValueNumPair vnpNarrow, bool doit);
5421 /**************************************************************************
5422 * Optimization conditions
5423 *************************************************************************/
5425 bool optFastCodeOrBlendedLoop(BasicBlock::weight_t bbWeight);
5426 bool optPentium4(void);
5427 bool optAvoidIncDec(BasicBlock::weight_t bbWeight);
5428 bool optAvoidIntMult(void);
5433 // The following is the upper limit on how many expressions we'll keep track
5434 // of for the CSE analysis.
5436 static const unsigned MAX_CSE_CNT = EXPSET_SZ;
5438 static const int MIN_CSE_COST = 2;
5440 // Keeps tracked cse indices
5441 BitVecTraits* cseTraits;
5444 /* Generic list of nodes - used by the CSE logic */
5452 typedef struct treeLst* treeLstPtr;
5456 treeStmtLst* tslNext;
5457 GenTreePtr tslTree; // tree node
5458 GenTreePtr tslStmt; // statement containing the tree
5459 BasicBlock* tslBlock; // block containing the statement
5462 typedef struct treeStmtLst* treeStmtLstPtr;
5464 // The following logic keeps track of expressions via a simple hash table.
5468 CSEdsc* csdNextInBucket; // used by the hash table
5470 unsigned csdHashValue; // the orginal hashkey
5472 unsigned csdIndex; // 1..optCSECandidateCount
5473 char csdLiveAcrossCall; // 0 or 1
5475 unsigned short csdDefCount; // definition count
5476 unsigned short csdUseCount; // use count (excluding the implicit uses at defs)
5478 unsigned csdDefWtCnt; // weighted def count
5479 unsigned csdUseWtCnt; // weighted use count (excluding the implicit uses at defs)
5481 GenTreePtr csdTree; // treenode containing the 1st occurance
5482 GenTreePtr csdStmt; // stmt containing the 1st occurance
5483 BasicBlock* csdBlock; // block containing the 1st occurance
5485 treeStmtLstPtr csdTreeList; // list of matching tree nodes: head
5486 treeStmtLstPtr csdTreeLast; // list of matching tree nodes: tail
5488 ValueNum defConservativeVN; // if all def occurrences share the same conservative value
5489 // number, this will reflect it; otherwise, NoVN.
5492 static const size_t s_optCSEhashSize;
5493 CSEdsc** optCSEhash;
5496 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, GenTreePtr, JitSimplerHashBehavior> NodeToNodeMap;
5498 NodeToNodeMap* optCseArrLenMap; // Maps array length nodes to ancestor compares that should be
5499 // re-numbered with the array length to improve range check elimination
5501 // Given a compare, look for a cse candidate arrlen feeding it and add a map entry if found.
5502 void optCseUpdateArrLenMap(GenTreePtr compare);
5506 CSEdsc* optCSEfindDsc(unsigned index);
5507 void optUnmarkCSE(GenTreePtr tree);
5509 // user defined callback data for the tree walk function optCSE_MaskHelper()
5510 struct optCSE_MaskData
5512 EXPSET_TP CSE_defMask;
5513 EXPSET_TP CSE_useMask;
5516 // Treewalk helper for optCSE_DefMask and optCSE_UseMask
5517 static fgWalkPreFn optCSE_MaskHelper;
5519 // This function walks all the node for an given tree
5520 // and return the mask of CSE definitions and uses for the tree
5522 void optCSE_GetMaskData(GenTreePtr tree, optCSE_MaskData* pMaskData);
5524 // Given a binary tree node return true if it is safe to swap the order of evaluation for op1 and op2.
5525 bool optCSE_canSwap(GenTree* firstNode, GenTree* secondNode);
5526 bool optCSE_canSwap(GenTree* tree);
5528 static fgWalkPostFn optPropagateNonCSE;
5529 static fgWalkPreFn optHasNonCSEChild;
5531 static fgWalkPreFn optUnmarkCSEs;
5533 static int __cdecl optCSEcostCmpEx(const void* op1, const void* op2);
5534 static int __cdecl optCSEcostCmpSz(const void* op1, const void* op2);
5536 void optCleanupCSEs();
5539 void optEnsureClearCSEInfo();
5542 #endif // FEATURE_ANYCSE
5544 #if FEATURE_VALNUM_CSE
5545 /**************************************************************************
5546 * Value Number based CSEs
5547 *************************************************************************/
5550 void optOptimizeValnumCSEs();
5553 void optValnumCSE_Init();
5554 unsigned optValnumCSE_Index(GenTreePtr tree, GenTreePtr stmt);
5555 unsigned optValnumCSE_Locate();
5556 void optValnumCSE_InitDataFlow();
5557 void optValnumCSE_DataFlow();
5558 void optValnumCSE_Availablity();
5559 void optValnumCSE_Heuristic();
5560 void optValnumCSE_UnmarkCSEs(GenTreePtr deadTree, GenTreePtr keepList);
5562 #endif // FEATURE_VALNUM_CSE
5565 bool optDoCSE; // True when we have found a duplicate CSE tree
5566 bool optValnumCSE_phase; // True when we are executing the optValnumCSE_phase
5567 unsigned optCSECandidateTotal; // Grand total of CSE candidates for both Lexical and ValNum
5568 unsigned optCSECandidateCount; // Count of CSE's candidates, reset for Lexical and ValNum CSE's
5569 unsigned optCSEstart; // The first local variable number that is a CSE
5570 unsigned optCSEcount; // The total count of CSE's introduced.
5571 unsigned optCSEweight; // The weight of the current block when we are
5572 // scanning for CSE expressions
5574 bool optIsCSEcandidate(GenTreePtr tree);
5576 // lclNumIsTrueCSE returns true if the LclVar was introduced by the CSE phase of the compiler
5578 bool lclNumIsTrueCSE(unsigned lclNum) const
5580 return ((optCSEcount > 0) && (lclNum >= optCSEstart) && (lclNum < optCSEstart + optCSEcount));
5583 // lclNumIsCSE returns true if the LclVar should be treated like a CSE with regards to constant prop.
5585 bool lclNumIsCSE(unsigned lclNum) const
5587 return lvaTable[lclNum].lvIsCSE;
5591 bool optConfigDisableCSE();
5592 bool optConfigDisableCSE2();
5594 void optOptimizeCSEs();
5596 #endif // FEATURE_ANYCSE
5604 unsigned ivaVar; // Variable we are interested in, or -1
5605 ALLVARSET_TP ivaMaskVal; // Set of variables assigned to. This is a set of all vars, not tracked vars.
5606 bool ivaMaskIncomplete; // Variables not representable in ivaMaskVal were assigned to.
5607 varRefKinds ivaMaskInd; // What kind of indirect assignments are there?
5608 callInterf ivaMaskCall; // What kind of calls are there?
5611 static callInterf optCallInterf(GenTreeCall* call);
5614 // VN based copy propagation.
5615 typedef ArrayStack<GenTreePtr> GenTreePtrStack;
5616 typedef SimplerHashTable<unsigned, SmallPrimitiveKeyFuncs<unsigned>, GenTreePtrStack*, JitSimplerHashBehavior>
5617 LclNumToGenTreePtrStack;
5619 // Kill set to track variables with intervening definitions.
5620 VARSET_TP optCopyPropKillSet;
5622 // Copy propagation functions.
5623 void optCopyProp(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree, LclNumToGenTreePtrStack* curSsaName);
5624 void optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
5625 void optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
5626 bool optIsSsaLocal(GenTreePtr tree);
5627 int optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2);
5628 void optVnCopyProp();
5630 /**************************************************************************
5631 * Early value propagation
5632 *************************************************************************/
5638 SSAName(unsigned lvNum, unsigned ssaNum) : m_lvNum(lvNum), m_ssaNum(ssaNum)
5642 static unsigned GetHashCode(SSAName ssaNm)
5644 return (ssaNm.m_lvNum << 16) | (ssaNm.m_ssaNum);
5647 static bool Equals(SSAName ssaNm1, SSAName ssaNm2)
5649 return (ssaNm1.m_lvNum == ssaNm2.m_lvNum) && (ssaNm1.m_ssaNum == ssaNm2.m_ssaNum);
5653 #define OMF_HAS_NEWARRAY 0x00000001 // Method contains 'new' of an array
5654 #define OMF_HAS_NEWOBJ 0x00000002 // Method contains 'new' of an object type.
5655 #define OMF_HAS_ARRAYREF 0x00000004 // Method contains array element loads or stores.
5656 #define OMF_HAS_VTABLEREF 0x00000008 // Method contains method table reference.
5657 #define OMF_HAS_NULLCHECK 0x00000010 // Method contains null check.
5658 #define OMF_HAS_FATPOINTER 0x00000020 // Method contains call, that needs fat pointer transformation.
5660 bool doesMethodHaveFatPointer()
5662 return (optMethodFlags & OMF_HAS_FATPOINTER) != 0;
5665 void setMethodHasFatPointer()
5667 optMethodFlags |= OMF_HAS_FATPOINTER;
5670 void clearMethodHasFatPointer()
5672 optMethodFlags &= ~OMF_HAS_FATPOINTER;
5675 void addFatPointerCandidate(GenTreeCall* call)
5677 setMethodHasFatPointer();
5678 call->SetFatPointerCandidate();
5681 unsigned optMethodFlags;
5683 // Recursion bound controls how far we can go backwards tracking for a SSA value.
5684 // No throughput diff was found with backward walk bound between 3-8.
5685 static const int optEarlyPropRecurBound = 5;
5687 enum class optPropKind
5695 bool gtIsVtableRef(GenTreePtr tree);
5696 GenTreePtr getArrayLengthFromAllocation(GenTreePtr tree);
5697 GenTreePtr getObjectHandleNodeFromAllocation(GenTreePtr tree);
5698 GenTreePtr optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropKind valueKind, int walkDepth);
5699 GenTreePtr optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind);
5700 bool optEarlyPropRewriteTree(GenTreePtr tree);
5701 bool optDoEarlyPropForBlock(BasicBlock* block);
5702 bool optDoEarlyPropForFunc();
5703 void optEarlyProp();
5704 void optFoldNullCheck(GenTreePtr tree);
5705 bool optCanMoveNullCheckPastTree(GenTreePtr tree, bool isInsideTry);
5708 /**************************************************************************
5709 * Value/Assertion propagation
5710 *************************************************************************/
5712 // Data structures for assertion prop
5713 BitVecTraits* apTraits;
5716 enum optAssertionKind
5731 O1K_ARRLEN_OPER_BND,
5732 O1K_ARRLEN_LOOP_BND,
5733 O1K_CONSTANT_LOOP_BND,
5754 optAssertionKind assertionKind;
5757 unsigned lclNum; // assigned to or property of this local var number
5765 struct AssertionDscOp1
5767 optOp1Kind kind; // a normal LclVar, or Exact-type or Subtype
5774 struct AssertionDscOp2
5776 optOp2Kind kind; // a const or copy assignment
5780 ssize_t iconVal; // integer
5781 unsigned iconFlags; // gtFlags
5783 struct Range // integer subrange
5797 bool IsArrLenArithBound()
5799 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_ARRLEN_OPER_BND);
5801 bool IsArrLenBound()
5803 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_ARRLEN_LOOP_BND);
5805 bool IsConstantBound()
5807 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) &&
5808 op1.kind == O1K_CONSTANT_LOOP_BND);
5810 bool IsBoundsCheckNoThrow()
5812 return ((assertionKind == OAK_NO_THROW) && (op1.kind == O1K_ARR_BND));
5815 bool IsCopyAssertion()
5817 return ((assertionKind == OAK_EQUAL) && (op1.kind == O1K_LCLVAR) && (op2.kind == O2K_LCLVAR_COPY));
5820 static bool SameKind(AssertionDsc* a1, AssertionDsc* a2)
5822 return a1->assertionKind == a2->assertionKind && a1->op1.kind == a2->op1.kind &&
5823 a1->op2.kind == a2->op2.kind;
5826 static bool ComplementaryKind(optAssertionKind kind, optAssertionKind kind2)
5828 if (kind == OAK_EQUAL)
5830 return kind2 == OAK_NOT_EQUAL;
5832 else if (kind == OAK_NOT_EQUAL)
5834 return kind2 == OAK_EQUAL;
5839 static ssize_t GetLowerBoundForIntegralType(var_types type)
5859 static ssize_t GetUpperBoundForIntegralType(var_types type)
5883 bool HasSameOp1(AssertionDsc* that, bool vnBased)
5885 if (op1.kind != that->op1.kind)
5889 else if (op1.kind == O1K_ARR_BND)
5892 return (op1.bnd.vnIdx == that->op1.bnd.vnIdx) && (op1.bnd.vnLen == that->op1.bnd.vnLen);
5896 return ((vnBased && (op1.vn == that->op1.vn)) ||
5897 (!vnBased && (op1.lcl.lclNum == that->op1.lcl.lclNum)));
5901 bool HasSameOp2(AssertionDsc* that, bool vnBased)
5903 if (op2.kind != that->op2.kind)
5909 case O2K_IND_CNS_INT:
5911 return ((op2.u1.iconVal == that->op2.u1.iconVal) && (op2.u1.iconFlags == that->op2.u1.iconFlags));
5913 case O2K_CONST_LONG:
5914 return (op2.lconVal == that->op2.lconVal);
5916 case O2K_CONST_DOUBLE:
5917 // exact match because of positive and negative zero.
5918 return (memcmp(&op2.dconVal, &that->op2.dconVal, sizeof(double)) == 0);
5920 case O2K_LCLVAR_COPY:
5922 return (op2.lcl.lclNum == that->op2.lcl.lclNum) &&
5923 (!vnBased || op2.lcl.ssaNum == that->op2.lcl.ssaNum);
5926 return ((op2.u2.loBound == that->op2.u2.loBound) && (op2.u2.hiBound == that->op2.u2.hiBound));
5929 // we will return false
5933 assert(!"Unexpected value for op2.kind in AssertionDsc.");
5939 bool Complementary(AssertionDsc* that, bool vnBased)
5941 return ComplementaryKind(assertionKind, that->assertionKind) && HasSameOp1(that, vnBased) &&
5942 HasSameOp2(that, vnBased);
5945 bool Equals(AssertionDsc* that, bool vnBased)
5947 if (assertionKind != that->assertionKind)
5951 else if (assertionKind == OAK_NO_THROW)
5953 assert(op2.kind == O2K_INVALID);
5954 return HasSameOp1(that, vnBased);
5958 return HasSameOp1(that, vnBased) && HasSameOp2(that, vnBased);
5964 static fgWalkPreFn optAddCopiesCallback;
5965 static fgWalkPreFn optVNAssertionPropCurStmtVisitor;
5966 unsigned optAddCopyLclNum;
5967 GenTreePtr optAddCopyAsgnNode;
5969 bool optLocalAssertionProp; // indicates that we are performing local assertion prop
5970 bool optAssertionPropagated; // set to true if we modified the trees
5971 bool optAssertionPropagatedCurrentStmt;
5973 GenTreePtr optAssertionPropCurrentTree;
5975 AssertionIndex* optComplementaryAssertionMap;
5976 ExpandArray<ASSERT_TP>* optAssertionDep; // table that holds dependent assertions (assertions
5977 // using the value of a local var) for each local var
5978 AssertionDsc* optAssertionTabPrivate; // table that holds info about value assignments
5979 AssertionIndex optAssertionCount; // total number of assertions in the assertion table
5980 AssertionIndex optMaxAssertionCount;
5983 void optVnNonNullPropCurStmt(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree);
5984 fgWalkResult optVNConstantPropCurStmt(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree);
5985 GenTreePtr optVNConstantPropOnRelOp(GenTreePtr tree);
5986 GenTreePtr optVNConstantPropOnJTrue(BasicBlock* block, GenTreePtr stmt, GenTreePtr test);
5987 GenTreePtr optVNConstantPropOnTree(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree);
5988 GenTreePtr optPrepareTreeForReplacement(GenTreePtr extractTree, GenTreePtr replaceTree);
5990 AssertionIndex GetAssertionCount()
5992 return optAssertionCount;
5994 ASSERT_TP* bbJtrueAssertionOut;
5995 typedef SimplerHashTable<ValueNum, SmallPrimitiveKeyFuncs<ValueNum>, ASSERT_TP, JitSimplerHashBehavior>
5996 ValueNumToAssertsMap;
5997 ValueNumToAssertsMap* optValueNumToAsserts;
5999 // Assertion prop helpers.
6000 ASSERT_TP& GetAssertionDep(unsigned lclNum);
6001 AssertionDsc* optGetAssertion(AssertionIndex assertIndex);
6002 void optAssertionInit(bool isLocalProp);
6003 void optAssertionTraitsInit(AssertionIndex assertionCount);
6004 #if LOCAL_ASSERTION_PROP
6005 void optAssertionReset(AssertionIndex limit);
6006 void optAssertionRemove(AssertionIndex index);
6009 // Assertion prop data flow functions.
6010 void optAssertionPropMain();
6011 GenTreePtr optVNAssertionPropCurStmt(BasicBlock* block, GenTreePtr stmt);
6012 bool optIsTreeKnownIntValue(bool vnBased, GenTreePtr tree, ssize_t* pConstant, unsigned* pIconFlags);
6013 ASSERT_TP* optInitAssertionDataflowFlags();
6014 ASSERT_TP* optComputeAssertionGen();
6016 // Assertion Gen functions.
6017 void optAssertionGen(GenTreePtr tree);
6018 AssertionIndex optAssertionGenPhiDefn(GenTreePtr tree);
6019 AssertionInfo optCreateJTrueBoundsAssertion(GenTreePtr tree);
6020 AssertionInfo optAssertionGenJtrue(GenTreePtr tree);
6021 AssertionIndex optCreateJtrueAssertions(GenTreePtr op1, GenTreePtr op2, Compiler::optAssertionKind assertionKind);
6022 AssertionIndex optFindComplementary(AssertionIndex assertionIndex);
6023 void optMapComplementary(AssertionIndex assertionIndex, AssertionIndex index);
6025 // Assertion creation functions.
6026 AssertionIndex optCreateAssertion(GenTreePtr op1, GenTreePtr op2, optAssertionKind assertionKind);
6027 AssertionIndex optCreateAssertion(GenTreePtr op1,
6029 optAssertionKind assertionKind,
6030 AssertionDsc* assertion);
6031 void optCreateComplementaryAssertion(AssertionIndex assertionIndex, GenTreePtr op1, GenTreePtr op2);
6033 bool optAssertionVnInvolvesNan(AssertionDsc* assertion);
6034 AssertionIndex optAddAssertion(AssertionDsc* assertion);
6035 void optAddVnAssertionMapping(ValueNum vn, AssertionIndex index);
6037 void optPrintVnAssertionMapping();
6039 ASSERT_TP optGetVnMappedAssertions(ValueNum vn);
6041 // Used for respective assertion propagations.
6042 AssertionIndex optAssertionIsSubrange(GenTreePtr tree, var_types toType, ASSERT_VALARG_TP assertions);
6043 AssertionIndex optAssertionIsSubtype(GenTreePtr tree, GenTreePtr methodTableArg, ASSERT_VALARG_TP assertions);
6044 AssertionIndex optAssertionIsNonNullInternal(GenTreePtr op, ASSERT_VALARG_TP assertions);
6045 bool optAssertionIsNonNull(GenTreePtr op,
6046 ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased) DEBUGARG(AssertionIndex* pIndex));
6048 // Used for Relop propagation.
6049 AssertionIndex optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP assertions, GenTreePtr op1, GenTreePtr op2);
6050 AssertionIndex optLocalAssertionIsEqualOrNotEqual(
6051 optOp1Kind op1Kind, unsigned lclNum, optOp2Kind op2Kind, ssize_t cnsVal, ASSERT_VALARG_TP assertions);
6053 // Assertion prop for lcl var functions.
6054 bool optAssertionProp_LclVarTypeCheck(GenTreePtr tree, LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc);
6055 GenTreePtr optCopyAssertionProp(AssertionDsc* curAssertion,
6057 GenTreePtr stmt DEBUGARG(AssertionIndex index));
6058 GenTreePtr optConstantAssertionProp(AssertionDsc* curAssertion,
6059 const GenTreePtr tree,
6060 const GenTreePtr stmt DEBUGARG(AssertionIndex index));
6061 GenTreePtr optVnConstantAssertionProp(const GenTreePtr tree, const GenTreePtr stmt);
6063 // Assertion propagation functions.
6064 GenTreePtr optAssertionProp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6065 GenTreePtr optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6066 GenTreePtr optAssertionProp_Ind(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6067 GenTreePtr optAssertionProp_Cast(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6068 GenTreePtr optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, const GenTreePtr stmt);
6069 GenTreePtr optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6070 GenTreePtr optAssertionProp_Comma(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6071 GenTreePtr optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6072 GenTreePtr optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6073 GenTreePtr optAssertionPropLocal_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
6074 GenTreePtr optAssertionProp_Update(const GenTreePtr newTree, const GenTreePtr tree, const GenTreePtr stmt);
6075 GenTreePtr optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, const GenTreePtr stmt);
6077 // Implied assertion functions.
6078 void optImpliedAssertions(AssertionIndex assertionIndex, ASSERT_TP& activeAssertions);
6079 void optImpliedByTypeOfAssertions(ASSERT_TP& activeAssertions);
6080 void optImpliedByCopyAssertion(AssertionDsc* copyAssertion, AssertionDsc* depAssertion, ASSERT_TP& result);
6081 void optImpliedByConstAssertion(AssertionDsc* curAssertion, ASSERT_TP& result);
6084 void optPrintAssertion(AssertionDsc* newAssertion, AssertionIndex assertionIndex = 0);
6085 void optDebugCheckAssertion(AssertionDsc* assertion);
6086 void optDebugCheckAssertions(AssertionIndex AssertionIndex);
6088 void optAddCopies();
6089 #endif // ASSERTION_PROP
6091 /**************************************************************************
6093 *************************************************************************/
6096 struct LoopCloneVisitorInfo
6098 LoopCloneContext* context;
6101 LoopCloneVisitorInfo(LoopCloneContext* context, unsigned loopNum, GenTreePtr stmt)
6102 : context(context), loopNum(loopNum), stmt(nullptr)
6107 bool optIsStackLocalInvariant(unsigned loopNum, unsigned lclNum);
6108 bool optExtractArrIndex(GenTreePtr tree, ArrIndex* result, unsigned lhsNum);
6109 bool optReconstructArrIndex(GenTreePtr tree, ArrIndex* result, unsigned lhsNum);
6110 bool optIdentifyLoopOptInfo(unsigned loopNum, LoopCloneContext* context);
6111 static fgWalkPreFn optCanOptimizeByLoopCloningVisitor;
6112 fgWalkResult optCanOptimizeByLoopCloning(GenTreePtr tree, LoopCloneVisitorInfo* info);
6113 void optObtainLoopCloningOpts(LoopCloneContext* context);
6114 bool optIsLoopClonable(unsigned loopInd);
6116 bool optCanCloneLoops();
6119 void optDebugLogLoopCloning(BasicBlock* block, GenTreePtr insertBefore);
6121 void optPerformStaticOptimizations(unsigned loopNum, LoopCloneContext* context DEBUGARG(bool fastPath));
6122 bool optComputeDerefConditions(unsigned loopNum, LoopCloneContext* context);
6123 bool optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext* context);
6124 BasicBlock* optInsertLoopChoiceConditions(LoopCloneContext* context,
6128 void optInsertLoopCloningStress(BasicBlock* head);
6130 #if COUNT_RANGECHECKS
6131 static unsigned optRangeChkRmv;
6132 static unsigned optRangeChkAll;
6141 #define MAX_ARRAYS 4 // a magic max number of arrays tracked for bounds check elimination
6146 RngChkDsc* rcdNextInBucket; // used by the hash table
6148 unsigned short rcdHashValue; // to make matching faster
6149 unsigned short rcdIndex; // 0..optRngChkCount-1
6151 GenTreePtr rcdTree; // the array index tree
6154 unsigned optRngChkCount;
6155 static const size_t optRngChkHashSize;
6157 ssize_t optGetArrayRefScaleAndIndex(GenTreePtr mul, GenTreePtr* pIndex DEBUGARG(bool bRngChk));
6158 GenTreePtr optFindLocalInit(BasicBlock* block, GenTreePtr local, VARSET_TP* pKilledInOut, bool* isKilledAfterInit);
6160 bool optReachWithoutCall(BasicBlock* srcBB, BasicBlock* dstBB);
6163 bool optLoopsMarked;
6166 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6167 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6171 XX Does the register allocation and puts the remaining lclVars on the stack XX
6173 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6174 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6178 #ifndef LEGACY_BACKEND
6183 #else // LEGACY_BACKEND
6188 #endif // LEGACY_BACKEND
6190 #ifdef LEGACY_BACKEND
6192 void raAssignVars(); // register allocation
6193 #endif // LEGACY_BACKEND
6195 VARSET_TP raRegVarsMask; // Set of all enregistered variables (not including FEATURE_STACK_FP_X87 enregistered
6197 regNumber raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc);
6199 void raMarkStkVars();
6202 // Some things are used by both LSRA and regpredict allocators.
6204 FrameType rpFrameType;
6205 bool rpMustCreateEBPCalled; // Set to true after we have called rpMustCreateEBPFrame once
6207 #ifdef LEGACY_BACKEND
6208 regMaskTP rpMaskPInvokeEpilogIntf; // pinvoke epilog trashes esi/edi holding stack args needed to setup tail call's
6210 #endif // LEGACY_BACKEND
6212 bool rpMustCreateEBPFrame(INDEBUG(const char** wbReason));
6214 #if FEATURE_FP_REGALLOC
6215 enum enumConfigRegisterFP
6217 CONFIG_REGISTER_FP_NONE = 0x0,
6218 CONFIG_REGISTER_FP_CALLEE_TRASH = 0x1,
6219 CONFIG_REGISTER_FP_CALLEE_SAVED = 0x2,
6220 CONFIG_REGISTER_FP_FULL = 0x3,
6222 enumConfigRegisterFP raConfigRegisterFP();
6223 #endif // FEATURE_FP_REGALLOC
6226 regMaskTP raConfigRestrictMaskFP();
6229 #ifndef LEGACY_BACKEND
6230 LinearScanInterface* m_pLinearScan; // Linear Scan allocator
6231 #else // LEGACY_BACKEND
6232 unsigned raAvoidArgRegMask; // Mask of incoming argument registers that we may need to avoid
6233 VARSET_TP raLclRegIntf[REG_COUNT]; // variable to register interference graph
6234 bool raNewBlocks; // True is we added killing blocks for FPU registers
6235 unsigned rpPasses; // Number of passes made by the register predicter
6236 unsigned rpPassesMax; // Maximum number of passes made by the register predicter
6237 unsigned rpPassesPessimize; // Number of passes non-pessimizing made by the register predicter
6238 unsigned rpStkPredict; // Weighted count of variables were predicted STK (lower means register allocation is better)
6239 unsigned rpPredictSpillCnt; // Predicted number of integer spill tmps for the current tree
6240 regMaskTP rpPredictAssignMask; // Mask of registers to consider in rpPredictAssignRegVars()
6241 VARSET_TP rpLastUseVars; // Set of last use variables in rpPredictTreeRegUse
6242 VARSET_TP rpUseInPlace; // Set of variables that we used in place
6243 int rpAsgVarNum; // VarNum for the target of GT_ASG node
6244 bool rpPredictAssignAgain; // Must rerun the rpPredictAssignRegVars()
6245 bool rpAddedVarIntf; // Set to true if we need to add a new var intf
6246 bool rpLostEnreg; // Set to true if we lost an enregister var that had lvDependReg set
6247 bool rpReverseEBPenreg; // Decided to reverse the enregistration of EBP
6249 bool rpRegAllocDone; // Set to true after we have completed register allocation
6251 regMaskTP rpPredictMap[PREDICT_COUNT]; // Holds the regMaskTP for each of the enum values
6253 void raSetupArgMasks(RegState* r);
6255 const regNumber* raGetRegVarOrder(var_types regType, unsigned* wbVarOrderSize);
6257 void raDumpVarIntf(); // Dump the variable to variable interference graph
6258 void raDumpRegIntf(); // Dump the variable to register interference graph
6260 void raAdjustVarIntf();
6262 regMaskTP rpPredictRegMask(rpPredictReg predictReg, var_types type);
6264 bool rpRecordRegIntf(regMaskTP regMask, VARSET_VALARG_TP life DEBUGARG(const char* msg));
6266 bool rpRecordVarIntf(unsigned varNum, VARSET_VALARG_TP intfVar DEBUGARG(const char* msg));
6267 regMaskTP rpPredictRegPick(var_types type, rpPredictReg predictReg, regMaskTP lockedRegs);
6269 regMaskTP rpPredictGrabReg(var_types type, rpPredictReg predictReg, regMaskTP lockedRegs);
6271 static fgWalkPreFn rpMarkRegIntf;
6273 regMaskTP rpPredictAddressMode(
6274 GenTreePtr tree, var_types type, regMaskTP lockedRegs, regMaskTP rsvdRegs, GenTreePtr lenCSE);
6276 void rpPredictRefAssign(unsigned lclNum);
6278 regMaskTP rpPredictBlkAsgRegUse(GenTreePtr tree, rpPredictReg predictReg, regMaskTP lockedRegs, regMaskTP rsvdRegs);
6280 regMaskTP rpPredictTreeRegUse(GenTreePtr tree, rpPredictReg predictReg, regMaskTP lockedRegs, regMaskTP rsvdRegs);
6282 regMaskTP rpPredictAssignRegVars(regMaskTP regAvail);
6284 void rpPredictRegUse(); // Entry point
6286 unsigned raPredictTreeRegUse(GenTreePtr tree);
6287 unsigned raPredictListRegUse(GenTreePtr list);
6289 void raSetRegVarOrder(var_types regType,
6290 regNumber* customVarOrder,
6291 unsigned* customVarOrderSize,
6293 regMaskTP avoidReg);
6295 // We use (unsigned)-1 as an uninitialized sentinel for rpStkPredict and
6296 // also as the maximum value of lvRefCntWtd. Don't allow overflow, and
6297 // saturate at UINT_MAX - 1, to avoid using the sentinel.
6298 void raAddToStkPredict(unsigned val)
6300 unsigned newStkPredict = rpStkPredict + val;
6301 if ((newStkPredict < rpStkPredict) || (newStkPredict == UINT_MAX))
6302 rpStkPredict = UINT_MAX - 1;
6304 rpStkPredict = newStkPredict;
6308 #if !FEATURE_FP_REGALLOC
6309 void raDispFPlifeInfo();
6313 regMaskTP genReturnRegForTree(GenTreePtr tree);
6314 #endif // LEGACY_BACKEND
6316 /* raIsVarargsStackArg is called by raMaskStkVars and by
6317 lvaSortByRefCount. It identifies the special case
6318 where a varargs function has a parameter passed on the
6319 stack, other than the special varargs handle. Such parameters
6320 require special treatment, because they cannot be tracked
6321 by the GC (their offsets in the stack are not known
6325 bool raIsVarargsStackArg(unsigned lclNum)
6329 LclVarDsc* varDsc = &lvaTable[lclNum];
6331 assert(varDsc->lvIsParam);
6333 return (info.compIsVarArgs && !varDsc->lvIsRegArg && (lclNum != lvaVarargsHandleArg));
6335 #else // _TARGET_X86_
6339 #endif // _TARGET_X86_
6342 #ifdef LEGACY_BACKEND
6343 // Records the current prediction, if it's better than any previous recorded prediction.
6344 void rpRecordPrediction();
6345 // Applies the best recorded prediction, if one exists and is better than the current prediction.
6346 void rpUseRecordedPredictionIfBetter();
6348 // Data members used in the methods above.
6349 unsigned rpBestRecordedStkPredict;
6350 struct VarRegPrediction
6352 bool m_isEnregistered;
6353 regNumberSmall m_regNum;
6354 regNumberSmall m_otherReg;
6356 VarRegPrediction* rpBestRecordedPrediction;
6357 #endif // LEGACY_BACKEND
6360 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6361 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6365 XX Get to the class and method info from the Execution Engine given XX
6366 XX tokens for the class and method XX
6368 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6369 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6373 /* These are the different addressing modes used to access a local var.
6374 * The JIT has to report the location of the locals back to the EE
6375 * for debugging purposes.
6381 VLT_REG_BYREF, // this type is currently only used for value types on X64
6384 VLT_STK_BYREF, // this type is currently only used for value types on X64
6398 siVarLocType vlType;
6401 // VLT_REG/VLT_REG_FP -- Any pointer-sized enregistered value (TYP_INT, TYP_REF, etc)
6403 // VLT_REG_BYREF -- the specified register contains the address of the variable
6411 // VLT_STK -- Any 32 bit value which is on the stack
6412 // eg. [ESP+0x20], or [EBP-0x28]
6413 // VLT_STK_BYREF -- the specified stack location contains the address of the variable
6414 // eg. mov EAX, [ESP+0x20]; [EAX]
6418 regNumber vlsBaseReg;
6419 NATIVE_OFFSET vlsOffset;
6422 // VLT_REG_REG -- TYP_LONG/TYP_DOUBLE with both DWords enregistered
6431 // VLT_REG_STK -- Partly enregistered TYP_LONG/TYP_DOUBLE
6432 // eg { LowerDWord=EAX UpperDWord=[ESP+0x8] }
6440 regNumber vlrssBaseReg;
6441 NATIVE_OFFSET vlrssOffset;
6445 // VLT_STK_REG -- Partly enregistered TYP_LONG/TYP_DOUBLE
6446 // eg { LowerDWord=[ESP+0x8] UpperDWord=EAX }
6452 regNumber vlsrsBaseReg;
6453 NATIVE_OFFSET vlsrsOffset;
6459 // VLT_STK2 -- Any 64 bit value which is on the stack, in 2 successsive DWords
6460 // eg 2 DWords at [ESP+0x10]
6464 regNumber vls2BaseReg;
6465 NATIVE_OFFSET vls2Offset;
6468 // VLT_FPSTK -- enregisterd TYP_DOUBLE (on the FP stack)
6469 // eg. ST(3). Actually it is ST("FPstkHeight - vpFpStk")
6476 // VLT_FIXED_VA -- fixed argument of a varargs function.
6477 // The argument location depends on the size of the variable
6478 // arguments (...). Inspecting the VARARGS_HANDLE indicates the
6479 // location of the first arg. This argument can then be accessed
6480 // relative to the position of the first arg
6484 unsigned vlfvOffset;
6491 void* rpValue; // pointer to the in-process
6492 // location of the value.
6498 bool vlIsInReg(regNumber reg);
6499 bool vlIsOnStk(regNumber reg, signed offset);
6502 /*************************************************************************/
6507 void eeGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6508 CORINFO_RESOLVED_TOKEN* pConstrainedToken,
6509 CORINFO_CALLINFO_FLAGS flags,
6510 CORINFO_CALL_INFO* pResult);
6511 inline CORINFO_CALLINFO_FLAGS addVerifyFlag(CORINFO_CALLINFO_FLAGS flags);
6513 void eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6514 CORINFO_ACCESS_FLAGS flags,
6515 CORINFO_FIELD_INFO* pResult);
6519 BOOL eeIsValueClass(CORINFO_CLASS_HANDLE clsHnd);
6521 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(TRACK_LSRA_STATS)
6523 bool IsSuperPMIException(unsigned code)
6525 // Copied from NDP\clr\src\ToolBox\SuperPMI\SuperPMI-Shared\ErrorHandling.h
6527 const unsigned EXCEPTIONCODE_DebugBreakorAV = 0xe0421000;
6528 const unsigned EXCEPTIONCODE_MC = 0xe0422000;
6529 const unsigned EXCEPTIONCODE_LWM = 0xe0423000;
6530 const unsigned EXCEPTIONCODE_SASM = 0xe0424000;
6531 const unsigned EXCEPTIONCODE_SSYM = 0xe0425000;
6532 const unsigned EXCEPTIONCODE_CALLUTILS = 0xe0426000;
6533 const unsigned EXCEPTIONCODE_TYPEUTILS = 0xe0427000;
6534 const unsigned EXCEPTIONCODE_ASSERT = 0xe0440000;
6538 case EXCEPTIONCODE_DebugBreakorAV:
6539 case EXCEPTIONCODE_MC:
6540 case EXCEPTIONCODE_LWM:
6541 case EXCEPTIONCODE_SASM:
6542 case EXCEPTIONCODE_SSYM:
6543 case EXCEPTIONCODE_CALLUTILS:
6544 case EXCEPTIONCODE_TYPEUTILS:
6545 case EXCEPTIONCODE_ASSERT:
6552 const char* eeGetMethodName(CORINFO_METHOD_HANDLE hnd, const char** className);
6553 const char* eeGetMethodFullName(CORINFO_METHOD_HANDLE hnd);
6555 bool eeIsNativeMethod(CORINFO_METHOD_HANDLE method);
6556 CORINFO_METHOD_HANDLE eeGetMethodHandleForNative(CORINFO_METHOD_HANDLE method);
6559 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6560 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig, bool* isPinned);
6561 unsigned eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6563 // VOM info, method sigs
6565 void eeGetSig(unsigned sigTok,
6566 CORINFO_MODULE_HANDLE scope,
6567 CORINFO_CONTEXT_HANDLE context,
6568 CORINFO_SIG_INFO* retSig);
6570 void eeGetCallSiteSig(unsigned sigTok,
6571 CORINFO_MODULE_HANDLE scope,
6572 CORINFO_CONTEXT_HANDLE context,
6573 CORINFO_SIG_INFO* retSig);
6575 void eeGetMethodSig(CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* retSig, CORINFO_CLASS_HANDLE owner = nullptr);
6577 // Method entry-points, instrs
6579 void* eeGetFieldAddress(CORINFO_FIELD_HANDLE handle, void*** ppIndir);
6581 CORINFO_METHOD_HANDLE eeMarkNativeTarget(CORINFO_METHOD_HANDLE method);
6583 CORINFO_EE_INFO eeInfo;
6584 bool eeInfoInitialized;
6586 CORINFO_EE_INFO* eeGetEEInfo();
6588 // Gets the offset of a SDArray's first element
6589 unsigned eeGetArrayDataOffset(var_types type);
6590 // Gets the offset of a MDArray's first element
6591 unsigned eeGetMDArrayDataOffset(var_types type, unsigned rank);
6593 GenTreePtr eeGetPInvokeCookie(CORINFO_SIG_INFO* szMetaSig);
6595 // Returns the page size for the target machine as reported by the EE.
6596 inline size_t eeGetPageSize()
6598 return eeGetEEInfo()->osPageSize;
6601 // Returns the frame size at which we will generate a loop to probe the stack.
6602 inline size_t getVeryLargeFrameSize()
6605 // The looping probe code is 40 bytes, whereas the straight-line probing for
6606 // the (0x2000..0x3000) case is 44, so use looping for anything 0x2000 bytes
6607 // or greater, to generate smaller code.
6608 return 2 * eeGetPageSize();
6610 return 3 * eeGetPageSize();
6614 inline bool IsTargetAbi(CORINFO_RUNTIME_ABI abi)
6616 return eeGetEEInfo()->targetAbi == abi;
6619 inline bool generateCFIUnwindCodes()
6621 #ifdef UNIX_AMD64_ABI
6622 return IsTargetAbi(CORINFO_CORERT_ABI);
6630 unsigned eeGetEHcount(CORINFO_METHOD_HANDLE handle);
6632 // Debugging support - Line number info
6634 void eeGetStmtOffsets();
6636 unsigned eeBoundariesCount;
6638 struct boundariesDsc
6640 UNATIVE_OFFSET nativeIP;
6642 unsigned sourceReason;
6643 } * eeBoundaries; // Boundaries to report to EE
6644 void eeSetLIcount(unsigned count);
6645 void eeSetLIinfo(unsigned which, UNATIVE_OFFSET offs, unsigned srcIP, bool stkEmpty, bool callInstruction);
6649 static void eeDispILOffs(IL_OFFSET offs);
6650 static void eeDispLineInfo(const boundariesDsc* line);
6651 void eeDispLineInfos();
6654 // Debugging support - Local var info
6658 unsigned eeVarsCount;
6660 struct VarResultInfo
6662 UNATIVE_OFFSET startOffset;
6663 UNATIVE_OFFSET endOffset;
6667 void eeSetLVcount(unsigned count);
6668 void eeSetLVinfo(unsigned which,
6669 UNATIVE_OFFSET startOffs,
6670 UNATIVE_OFFSET length,
6675 const siVarLoc& loc);
6679 void eeDispVar(ICorDebugInfo::NativeVarInfo* var);
6680 void eeDispVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars);
6683 // ICorJitInfo wrappers
6685 void eeReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize);
6687 void eeAllocUnwindInfo(BYTE* pHotCode,
6693 CorJitFuncKind funcKind);
6695 void eeSetEHcount(unsigned cEH);
6697 void eeSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause);
6699 WORD eeGetRelocTypeHint(void* target);
6701 // ICorStaticInfo wrapper functions
6703 bool eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken);
6705 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
6707 static void dumpSystemVClassificationType(SystemVClassificationType ct);
6710 void eeGetSystemVAmd64PassStructInRegisterDescriptor(
6711 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
6712 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr);
6713 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
6715 template <typename ParamType>
6716 bool eeRunWithErrorTrap(void (*function)(ParamType*), ParamType* param)
6718 return eeRunWithErrorTrapImp(reinterpret_cast<void (*)(void*)>(function), reinterpret_cast<void*>(param));
6721 bool eeRunWithErrorTrapImp(void (*function)(void*), void* param);
6723 // Utility functions
6725 const char* eeGetFieldName(CORINFO_FIELD_HANDLE fieldHnd, const char** classNamePtr = nullptr);
6728 const wchar_t* eeGetCPString(size_t stringHandle);
6731 const char* eeGetClassName(CORINFO_CLASS_HANDLE clsHnd);
6733 static CORINFO_METHOD_HANDLE eeFindHelper(unsigned helper);
6734 static CorInfoHelpFunc eeGetHelperNum(CORINFO_METHOD_HANDLE method);
6736 static fgWalkPreFn CountSharedStaticHelper;
6737 static bool IsSharedStaticHelper(GenTreePtr tree);
6738 static bool IsTreeAlwaysHoistable(GenTreePtr tree);
6740 static CORINFO_FIELD_HANDLE eeFindJitDataOffs(unsigned jitDataOffs);
6741 // returns true/false if 'field' is a Jit Data offset
6742 static bool eeIsJitDataOffs(CORINFO_FIELD_HANDLE field);
6743 // returns a number < 0 if 'field' is not a Jit Data offset, otherwise the data offset (limited to 2GB)
6744 static int eeGetJitDataOffs(CORINFO_FIELD_HANDLE field);
6746 /*****************************************************************************/
6751 enum TEMP_USAGE_TYPE
6757 static var_types tmpNormalizeType(var_types type);
6758 TempDsc* tmpGetTemp(var_types type); // get temp for the given type
6759 void tmpRlsTemp(TempDsc* temp);
6760 TempDsc* tmpFindNum(int temp, TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const;
6763 TempDsc* tmpListBeg(TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const;
6764 TempDsc* tmpListNxt(TempDsc* curTemp, TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const;
6768 bool tmpAllFree() const;
6771 #ifndef LEGACY_BACKEND
6772 void tmpPreAllocateTemps(var_types type, unsigned count);
6773 #endif // !LEGACY_BACKEND
6776 #ifdef LEGACY_BACKEND
6777 unsigned tmpIntSpillMax; // number of int-sized spill temps
6778 unsigned tmpDoubleSpillMax; // number of double-sized spill temps
6779 #endif // LEGACY_BACKEND
6781 unsigned tmpCount; // Number of temps
6782 unsigned tmpSize; // Size of all the temps
6785 // Used by RegSet::rsSpillChk()
6786 unsigned tmpGetCount; // Temps which haven't been released yet
6789 static unsigned tmpSlot(unsigned size); // which slot in tmpFree[] or tmpUsed[] to use
6791 TempDsc* tmpFree[TEMP_MAX_SIZE / sizeof(int)];
6792 TempDsc* tmpUsed[TEMP_MAX_SIZE / sizeof(int)];
6795 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6796 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6800 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6801 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6805 CodeGenInterface* codeGen;
6807 // The following holds information about instr offsets in terms of generated code.
6811 IPmappingDsc* ipmdNext; // next line# record
6812 IL_OFFSETX ipmdILoffsx; // the instr offset
6813 emitLocation ipmdNativeLoc; // the emitter location of the native code corresponding to the IL offset
6814 bool ipmdIsLabel; // Can this code be a branch label?
6817 // Record the instr offset mapping to the generated code
6819 IPmappingDsc* genIPmappingList;
6820 IPmappingDsc* genIPmappingLast;
6822 // Managed RetVal - A side hash table meant to record the mapping from a
6823 // GT_CALL node to its IL offset. This info is used to emit sequence points
6824 // that can be used by debugger to determine the native offset at which the
6825 // managed RetVal will be available.
6827 // In fact we can store IL offset in a GT_CALL node. This was ruled out in
6828 // favor of a side table for two reasons: 1) We need IL offset for only those
6829 // GT_CALL nodes (created during importation) that correspond to an IL call and
6830 // whose return type is other than TYP_VOID. 2) GT_CALL node is a frequently used
6831 // structure and IL offset is needed only when generating debuggable code. Therefore
6832 // it is desirable to avoid memory size penalty in retail scenarios.
6833 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, IL_OFFSETX, JitSimplerHashBehavior>
6834 CallSiteILOffsetTable;
6835 CallSiteILOffsetTable* genCallSite2ILOffsetMap;
6837 unsigned genReturnLocal; // Local number for the return value when applicable.
6838 BasicBlock* genReturnBB; // jumped to when not optimizing for speed.
6840 // The following properties are part of CodeGenContext. Getters are provided here for
6841 // convenience and backward compatibility, but the properties can only be set by invoking
6842 // the setter on CodeGenContext directly.
6844 __declspec(property(get = getEmitter)) emitter* genEmitter;
6845 emitter* getEmitter()
6847 return codeGen->getEmitter();
6850 const bool isFramePointerUsed()
6852 return codeGen->isFramePointerUsed();
6855 __declspec(property(get = getInterruptible, put = setInterruptible)) bool genInterruptible;
6856 bool getInterruptible()
6858 return codeGen->genInterruptible;
6860 void setInterruptible(bool value)
6862 codeGen->setInterruptible(value);
6866 const bool genDoubleAlign()
6868 return codeGen->doDoubleAlign();
6870 DWORD getCanDoubleAlign();
6871 bool shouldDoubleAlign(unsigned refCntStk,
6873 unsigned refCntWtdReg,
6874 unsigned refCntStkParam,
6875 unsigned refCntWtdStkDbl);
6876 #endif // DOUBLE_ALIGN
6878 __declspec(property(get = getFullPtrRegMap, put = setFullPtrRegMap)) bool genFullPtrRegMap;
6879 bool getFullPtrRegMap()
6881 return codeGen->genFullPtrRegMap;
6883 void setFullPtrRegMap(bool value)
6885 codeGen->setFullPtrRegMap(value);
6888 // Things that MAY belong either in CodeGen or CodeGenContext
6890 #if FEATURE_EH_FUNCLETS
6891 FuncInfoDsc* compFuncInfos;
6892 unsigned short compCurrFuncIdx;
6893 unsigned short compFuncInfoCount;
6895 unsigned short compFuncCount()
6897 assert(fgFuncletsCreated);
6898 return compFuncInfoCount;
6901 #else // !FEATURE_EH_FUNCLETS
6903 // This is a no-op when there are no funclets!
6904 void genUpdateCurrentFunclet(BasicBlock* block)
6909 FuncInfoDsc compFuncInfoRoot;
6911 static const unsigned compCurrFuncIdx = 0;
6913 unsigned short compFuncCount()
6918 #endif // !FEATURE_EH_FUNCLETS
6920 FuncInfoDsc* funCurrentFunc();
6921 void funSetCurrentFunc(unsigned funcIdx);
6922 FuncInfoDsc* funGetFunc(unsigned funcIdx);
6923 unsigned int funGetFuncIdx(BasicBlock* block);
6927 VARSET_TP compCurLife; // current live variables
6928 GenTreePtr compCurLifeTree; // node after which compCurLife has been computed
6930 template <bool ForCodeGen>
6931 void compChangeLife(VARSET_VALARG_TP newLife DEBUGARG(GenTreePtr tree));
6933 void genChangeLife(VARSET_VALARG_TP newLife DEBUGARG(GenTreePtr tree))
6935 compChangeLife</*ForCodeGen*/ true>(newLife DEBUGARG(tree));
6938 template <bool ForCodeGen>
6939 void compUpdateLife(GenTreePtr tree);
6941 // Updates "compCurLife" to its state after evaluate of "true". If "pLastUseVars" is
6942 // non-null, sets "*pLastUseVars" to the set of tracked variables for which "tree" was a last
6943 // use. (Can be more than one var in the case of dependently promoted struct vars.)
6944 template <bool ForCodeGen>
6945 void compUpdateLifeVar(GenTreePtr tree, VARSET_TP* pLastUseVars = nullptr);
6947 template <bool ForCodeGen>
6948 inline void compUpdateLife(VARSET_VALARG_TP newLife);
6950 // Gets a register mask that represent the kill set for a helper call since
6951 // not all JIT Helper calls follow the standard ABI on the target architecture.
6952 regMaskTP compHelperCallKillSet(CorInfoHelpFunc helper);
6954 // Gets a register mask that represent the kill set for a NoGC helper call.
6955 regMaskTP compNoGCHelperCallKillSet(CorInfoHelpFunc helper);
6958 // Requires that "varDsc" be a promoted struct local variable being passed as an argument, beginning at
6959 // "firstArgRegNum", which is assumed to have already been aligned to the register alignment restriction of the
6960 // struct type. Adds bits to "*pArgSkippedRegMask" for any argument registers *not* used in passing "varDsc" --
6961 // i.e., internal "holes" caused by internal alignment constraints. For example, if the struct contained an int and
6962 // a double, and we at R0 (on ARM), then R1 would be skipped, and the bit for R1 would be added to the mask.
6963 void fgAddSkippedRegsInPromotedStructArg(LclVarDsc* varDsc, unsigned firstArgRegNum, regMaskTP* pArgSkippedRegMask);
6964 #endif // _TARGET_ARM_
6966 // 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
6968 static GenTreePtr fgIsIndirOfAddrOfLocal(GenTreePtr tree);
6970 // This is indexed by GT_OBJ nodes that are address of promoted struct variables, which
6971 // have been annotated with the GTF_VAR_DEATH flag. If such a node is *not* mapped in this
6972 // table, one may assume that all the (tracked) field vars die at this point. Otherwise,
6973 // the node maps to a pointer to a VARSET_TP, containing set bits for each of the tracked field
6974 // vars of the promoted struct local that go dead at the given node (the set bits are the bits
6975 // for the tracked var indices of the field vars, as in a live var set).
6976 NodeToVarsetPtrMap* m_promotedStructDeathVars;
6978 NodeToVarsetPtrMap* GetPromotedStructDeathVars()
6980 if (m_promotedStructDeathVars == nullptr)
6982 m_promotedStructDeathVars = new (getAllocator()) NodeToVarsetPtrMap(getAllocator());
6984 return m_promotedStructDeathVars;
6988 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6989 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6993 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6994 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6997 #if !defined(__GNUC__)
6998 #pragma region Unwind information
7003 // Infrastructure functions: start/stop/reserve/emit.
7006 void unwindBegProlog();
7007 void unwindEndProlog();
7008 void unwindBegEpilog();
7009 void unwindEndEpilog();
7010 void unwindReserve();
7011 void unwindEmit(void* pHotCode, void* pColdCode);
7014 // Specific unwind information functions: called by code generation to indicate a particular
7015 // prolog or epilog unwindable instruction has been generated.
7018 void unwindPush(regNumber reg);
7019 void unwindAllocStack(unsigned size);
7020 void unwindSetFrameReg(regNumber reg, unsigned offset);
7021 void unwindSaveReg(regNumber reg, unsigned offset);
7023 #if defined(_TARGET_ARM_)
7024 void unwindPushMaskInt(regMaskTP mask);
7025 void unwindPushMaskFloat(regMaskTP mask);
7026 void unwindPopMaskInt(regMaskTP mask);
7027 void unwindPopMaskFloat(regMaskTP mask);
7028 void unwindBranch16(); // The epilog terminates with a 16-bit branch (e.g., "bx lr")
7029 void unwindNop(unsigned codeSizeInBytes); // Generate unwind NOP code. 'codeSizeInBytes' is 2 or 4 bytes. Only
7030 // called via unwindPadding().
7031 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7032 // instruction and the current location.
7033 #endif // _TARGET_ARM_
7035 #if defined(_TARGET_ARM64_)
7037 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7038 // instruction and the current location.
7039 void unwindSaveReg(regNumber reg, int offset); // str reg, [sp, #offset]
7040 void unwindSaveRegPreindexed(regNumber reg, int offset); // str reg, [sp, #offset]!
7041 void unwindSaveRegPair(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]
7042 void unwindSaveRegPairPreindexed(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]!
7043 void unwindSaveNext(); // unwind code: save_next
7044 void unwindReturn(regNumber reg); // ret lr
7045 #endif // defined(_TARGET_ARM64_)
7048 // Private "helper" functions for the unwind implementation.
7052 #if FEATURE_EH_FUNCLETS
7053 void unwindGetFuncLocations(FuncInfoDsc* func,
7054 bool getHotSectionData,
7055 /* OUT */ emitLocation** ppStartLoc,
7056 /* OUT */ emitLocation** ppEndLoc);
7057 #endif // FEATURE_EH_FUNCLETS
7059 void unwindReserveFunc(FuncInfoDsc* func);
7060 void unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
7062 #if defined(_TARGET_AMD64_) || (defined(_TARGET_X86_) && FEATURE_EH_FUNCLETS)
7064 void unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode);
7065 void unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode);
7067 #endif // _TARGET_AMD64_ || (_TARGET_X86_ && FEATURE_EH_FUNCLETS)
7069 #if defined(_TARGET_AMD64_)
7071 UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func);
7073 void unwindBegPrologWindows();
7074 void unwindPushWindows(regNumber reg);
7075 void unwindAllocStackWindows(unsigned size);
7076 void unwindSetFrameRegWindows(regNumber reg, unsigned offset);
7077 void unwindSaveRegWindows(regNumber reg, unsigned offset);
7079 #ifdef UNIX_AMD64_ABI
7080 void unwindBegPrologCFI();
7081 void unwindPushCFI(regNumber reg);
7082 void unwindAllocStackCFI(unsigned size);
7083 void unwindSetFrameRegCFI(regNumber reg, unsigned offset);
7084 void unwindSaveRegCFI(regNumber reg, unsigned offset);
7085 int mapRegNumToDwarfReg(regNumber reg);
7086 void createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR opcode, USHORT dwarfReg, INT offset = 0);
7087 #endif // UNIX_AMD64_ABI
7088 #elif defined(_TARGET_ARM_)
7090 void unwindPushPopMaskInt(regMaskTP mask, bool useOpsize16);
7091 void unwindPushPopMaskFloat(regMaskTP mask);
7092 void unwindSplit(FuncInfoDsc* func);
7094 #endif // _TARGET_ARM_
7096 #if !defined(__GNUC__)
7097 #pragma endregion // Note: region is NOT under !defined(__GNUC__)
7101 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7102 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7106 XX Info about SIMD types, methods and the SIMD assembly (i.e. the assembly XX
7107 XX that contains the distinguished, well-known SIMD type definitions). XX
7109 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7110 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7113 // Get highest available instruction set for floating point codegen
7114 InstructionSet getFloatingPointInstructionSet()
7116 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7119 return InstructionSet_AVX;
7124 return InstructionSet_SSE3_4;
7128 assert(canUseSSE2());
7129 return InstructionSet_SSE2;
7131 assert(!"getFPInstructionSet() is not implemented for target arch");
7133 return InstructionSet_NONE;
7137 // Get highest available instruction set for SIMD codegen
7138 InstructionSet getSIMDInstructionSet()
7140 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7141 return getFloatingPointInstructionSet();
7143 assert(!"Available instruction set(s) for SIMD codegen is not defined for target arch");
7145 return InstructionSet_NONE;
7151 // Should we support SIMD intrinsics?
7154 // Have we identified any SIMD types?
7155 // This is currently used by struct promotion to avoid getting type information for a struct
7156 // field to see if it is a SIMD type, if we haven't seen any SIMD types or operations in
7158 bool _usesSIMDTypes;
7159 bool usesSIMDTypes()
7161 return _usesSIMDTypes;
7163 void setUsesSIMDTypes(bool value)
7165 _usesSIMDTypes = value;
7168 // This is a temp lclVar allocated on the stack as TYP_SIMD. It is used to implement intrinsics
7169 // that require indexed access to the individual fields of the vector, which is not well supported
7170 // by the hardware. It is allocated when/if such situations are encountered during Lowering.
7171 unsigned lvaSIMDInitTempVarNum;
7174 CORINFO_CLASS_HANDLE SIMDFloatHandle;
7175 CORINFO_CLASS_HANDLE SIMDDoubleHandle;
7176 CORINFO_CLASS_HANDLE SIMDIntHandle;
7177 CORINFO_CLASS_HANDLE SIMDUShortHandle;
7178 CORINFO_CLASS_HANDLE SIMDUByteHandle;
7179 CORINFO_CLASS_HANDLE SIMDShortHandle;
7180 CORINFO_CLASS_HANDLE SIMDByteHandle;
7181 CORINFO_CLASS_HANDLE SIMDLongHandle;
7182 CORINFO_CLASS_HANDLE SIMDUIntHandle;
7183 CORINFO_CLASS_HANDLE SIMDULongHandle;
7184 CORINFO_CLASS_HANDLE SIMDVector2Handle;
7185 CORINFO_CLASS_HANDLE SIMDVector3Handle;
7186 CORINFO_CLASS_HANDLE SIMDVector4Handle;
7187 CORINFO_CLASS_HANDLE SIMDVectorHandle;
7189 // Get the handle for a SIMD type.
7190 CORINFO_CLASS_HANDLE gtGetStructHandleForSIMD(var_types simdType, var_types simdBaseType)
7192 if (simdBaseType == TYP_FLOAT)
7197 return SIMDVector2Handle;
7199 return SIMDVector3Handle;
7201 if ((getSIMDVectorType() == TYP_SIMD32) || (SIMDVector4Handle != NO_CLASS_HANDLE))
7203 return SIMDVector4Handle;
7212 assert(simdType == getSIMDVectorType());
7213 switch (simdBaseType)
7216 return SIMDFloatHandle;
7218 return SIMDDoubleHandle;
7220 return SIMDIntHandle;
7222 return SIMDUShortHandle;
7224 return SIMDUShortHandle;
7226 return SIMDUByteHandle;
7228 return SIMDShortHandle;
7230 return SIMDByteHandle;
7232 return SIMDLongHandle;
7234 return SIMDUIntHandle;
7236 return SIMDULongHandle;
7238 assert(!"Didn't find a class handle for simdType");
7240 return NO_CLASS_HANDLE;
7244 CORINFO_METHOD_HANDLE SIMDVectorFloat_set_Item;
7245 CORINFO_METHOD_HANDLE SIMDVectorFloat_get_Length;
7246 CORINFO_METHOD_HANDLE SIMDVectorFloat_op_Addition;
7248 // Returns true if the tree corresponds to a TYP_SIMD lcl var.
7249 // Note that both SIMD vector args and locals are mared as lvSIMDType = true, but
7250 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD or TYP_STRUCT.
7251 bool isSIMDTypeLocal(GenTree* tree)
7253 return tree->OperIsLocal() && lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7256 // Returns true if the type of the tree is a byref of TYP_SIMD
7257 bool isAddrOfSIMDType(GenTree* tree)
7259 if (tree->TypeGet() == TYP_BYREF || tree->TypeGet() == TYP_I_IMPL)
7261 switch (tree->OperGet())
7264 return varTypeIsSIMD(tree->gtGetOp1());
7266 case GT_LCL_VAR_ADDR:
7267 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7270 return isSIMDTypeLocal(tree);
7277 static bool isRelOpSIMDIntrinsic(SIMDIntrinsicID intrinsicId)
7279 return (intrinsicId == SIMDIntrinsicEqual || intrinsicId == SIMDIntrinsicLessThan ||
7280 intrinsicId == SIMDIntrinsicLessThanOrEqual || intrinsicId == SIMDIntrinsicGreaterThan ||
7281 intrinsicId == SIMDIntrinsicGreaterThanOrEqual);
7284 // Returns base type of a TYP_SIMD local.
7285 // Returns TYP_UNKNOWN if the local is not TYP_SIMD.
7286 var_types getBaseTypeOfSIMDLocal(GenTree* tree)
7288 if (isSIMDTypeLocal(tree))
7290 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvBaseType;
7296 bool isSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7298 return info.compCompHnd->isInSIMDModule(clsHnd);
7301 bool isSIMDClass(typeInfo* pTypeInfo)
7303 return pTypeInfo->IsStruct() && isSIMDClass(pTypeInfo->GetClassHandleForValueClass());
7306 // Get the base (element) type and size in bytes for a SIMD type. Returns TYP_UNKNOWN
7307 // if it is not a SIMD type or is an unsupported base type.
7308 var_types getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes = nullptr);
7310 var_types getBaseTypeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7312 return getBaseTypeAndSizeOfSIMDType(typeHnd, nullptr);
7315 // Get SIMD Intrinsic info given the method handle.
7316 // Also sets typeHnd, argCount, baseType and sizeBytes out params.
7317 const SIMDIntrinsicInfo* getSIMDIntrinsicInfo(CORINFO_CLASS_HANDLE* typeHnd,
7318 CORINFO_METHOD_HANDLE methodHnd,
7319 CORINFO_SIG_INFO* sig,
7322 var_types* baseType,
7323 unsigned* sizeBytes);
7325 // Pops and returns GenTree node from importers type stack.
7326 // Normalizes TYP_STRUCT value in case of GT_CALL, GT_RET_EXPR and arg nodes.
7327 GenTreePtr impSIMDPopStack(var_types type, bool expectAddr = false);
7329 // Create a GT_SIMD tree for a Get property of SIMD vector with a fixed index.
7330 GenTreeSIMD* impSIMDGetFixed(var_types simdType, var_types baseType, unsigned simdSize, int index);
7332 // Creates a GT_SIMD tree for Select operation
7333 GenTreePtr impSIMDSelect(CORINFO_CLASS_HANDLE typeHnd,
7335 unsigned simdVectorSize,
7340 // Creates a GT_SIMD tree for Min/Max operation
7341 GenTreePtr impSIMDMinMax(SIMDIntrinsicID intrinsicId,
7342 CORINFO_CLASS_HANDLE typeHnd,
7344 unsigned simdVectorSize,
7348 // Transforms operands and returns the SIMD intrinsic to be applied on
7349 // transformed operands to obtain given relop result.
7350 SIMDIntrinsicID impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId,
7351 CORINFO_CLASS_HANDLE typeHnd,
7352 unsigned simdVectorSize,
7353 var_types* baseType,
7357 // Creates a GT_SIMD tree for Abs intrinsic.
7358 GenTreePtr impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType, unsigned simdVectorSize, GenTree* op1);
7360 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7361 // Transforms operands and returns the SIMD intrinsic to be applied on
7362 // transformed operands to obtain == comparison result.
7363 SIMDIntrinsicID impSIMDLongRelOpEqual(CORINFO_CLASS_HANDLE typeHnd,
7364 unsigned simdVectorSize,
7368 // Transforms operands and returns the SIMD intrinsic to be applied on
7369 // transformed operands to obtain > comparison result.
7370 SIMDIntrinsicID impSIMDLongRelOpGreaterThan(CORINFO_CLASS_HANDLE typeHnd,
7371 unsigned simdVectorSize,
7375 // Transforms operands and returns the SIMD intrinsic to be applied on
7376 // transformed operands to obtain >= comparison result.
7377 SIMDIntrinsicID impSIMDLongRelOpGreaterThanOrEqual(CORINFO_CLASS_HANDLE typeHnd,
7378 unsigned simdVectorSize,
7382 // Transforms operands and returns the SIMD intrinsic to be applied on
7383 // transformed operands to obtain >= comparison result in case of int32
7384 // and small int base type vectors.
7385 SIMDIntrinsicID impSIMDIntegralRelOpGreaterThanOrEqual(
7386 CORINFO_CLASS_HANDLE typeHnd, unsigned simdVectorSize, var_types baseType, GenTree** op1, GenTree** op2);
7387 #endif // defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7389 void setLclRelatedToSIMDIntrinsic(GenTreePtr tree);
7390 bool areFieldsContiguous(GenTreePtr op1, GenTreePtr op2);
7391 bool areArrayElementsContiguous(GenTreePtr op1, GenTreePtr op2);
7392 bool areArgumentsContiguous(GenTreePtr op1, GenTreePtr op2);
7393 GenTreePtr createAddressNodeForSIMDInit(GenTreePtr tree, unsigned simdSize);
7395 // check methodHnd to see if it is a SIMD method that is expanded as an intrinsic in the JIT.
7396 GenTreePtr impSIMDIntrinsic(OPCODE opcode,
7397 GenTreePtr newobjThis,
7398 CORINFO_CLASS_HANDLE clsHnd,
7399 CORINFO_METHOD_HANDLE method,
7400 CORINFO_SIG_INFO* sig,
7403 GenTreePtr getOp1ForConstructor(OPCODE opcode, GenTreePtr newobjThis, CORINFO_CLASS_HANDLE clsHnd);
7405 // Whether SIMD vector occupies part of SIMD register.
7406 // SSE2: vector2f/3f are considered sub register SIMD types.
7407 // AVX: vector2f, 3f and 4f are all considered sub register SIMD types.
7408 bool isSubRegisterSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7410 unsigned sizeBytes = 0;
7411 var_types baseType = getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7412 return (baseType == TYP_FLOAT) && (sizeBytes < getSIMDVectorRegisterByteLength());
7415 bool isSubRegisterSIMDType(GenTreeSIMD* simdNode)
7417 return (simdNode->gtSIMDSize < getSIMDVectorRegisterByteLength());
7420 // Get the type for the hardware SIMD vector.
7421 // This is the maximum SIMD type supported for this target.
7422 var_types getSIMDVectorType()
7424 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7431 assert(canUseSSE2());
7435 assert(!"getSIMDVectorType() unimplemented on target arch");
7440 // Get the size of the SIMD type in bytes
7441 int getSIMDTypeSizeInBytes(CORINFO_CLASS_HANDLE typeHnd)
7443 unsigned sizeBytes = 0;
7444 (void)getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7448 // Get the the number of elements of basetype of SIMD vector given by its size and baseType
7449 static int getSIMDVectorLength(unsigned simdSize, var_types baseType);
7451 // Get the the number of elements of basetype of SIMD vector given by its type handle
7452 int getSIMDVectorLength(CORINFO_CLASS_HANDLE typeHnd);
7454 // Get preferred alignment of SIMD type.
7455 int getSIMDTypeAlignment(var_types simdType);
7457 // Get the number of bytes in a SIMD Vector for the current compilation.
7458 unsigned getSIMDVectorRegisterByteLength()
7460 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7463 return YMM_REGSIZE_BYTES;
7467 assert(canUseSSE2());
7468 return XMM_REGSIZE_BYTES;
7471 assert(!"getSIMDVectorRegisterByteLength() unimplemented on target arch");
7476 // The minimum and maximum possible number of bytes in a SIMD vector.
7477 unsigned int maxSIMDStructBytes()
7479 return getSIMDVectorRegisterByteLength();
7481 unsigned int minSIMDStructBytes()
7483 return emitTypeSize(TYP_SIMD8);
7486 #ifdef FEATURE_AVX_SUPPORT
7487 // (maxPossibleSIMDStructBytes is for use in a context that requires a compile-time constant.)
7488 static const unsigned maxPossibleSIMDStructBytes = 32;
7489 #else // !FEATURE_AVX_SUPPORT
7490 static const unsigned maxPossibleSIMDStructBytes = 16;
7491 #endif // !FEATURE_AVX_SUPPORT
7493 // Returns the codegen type for a given SIMD size.
7494 var_types getSIMDTypeForSize(unsigned size)
7496 var_types simdType = TYP_UNDEF;
7499 simdType = TYP_SIMD8;
7501 else if (size == 12)
7503 simdType = TYP_SIMD12;
7505 else if (size == 16)
7507 simdType = TYP_SIMD16;
7509 #ifdef FEATURE_AVX_SUPPORT
7510 else if (size == 32)
7512 simdType = TYP_SIMD32;
7514 #endif // FEATURE_AVX_SUPPORT
7517 noway_assert(!"Unexpected size for SIMD type");
7522 unsigned getSIMDInitTempVarNum()
7524 if (lvaSIMDInitTempVarNum == BAD_VAR_NUM)
7526 lvaSIMDInitTempVarNum = lvaGrabTempWithImplicitUse(false DEBUGARG("SIMDInitTempVar"));
7527 lvaTable[lvaSIMDInitTempVarNum].lvType = getSIMDVectorType();
7529 return lvaSIMDInitTempVarNum;
7532 #endif // FEATURE_SIMD
7535 //------------------------------------------------------------------------
7536 // largestEnregisterableStruct: The size in bytes of the largest struct that can be enregistered.
7538 // Notes: It is not guaranteed that the struct of this size or smaller WILL be a
7539 // candidate for enregistration.
7541 unsigned largestEnregisterableStructSize()
7544 unsigned vectorRegSize = getSIMDVectorRegisterByteLength();
7545 if (vectorRegSize > TARGET_POINTER_SIZE)
7547 return vectorRegSize;
7550 #endif // FEATURE_SIMD
7552 return TARGET_POINTER_SIZE;
7557 // These routines need not be enclosed under FEATURE_SIMD since lvIsSIMDType()
7558 // is defined for both FEATURE_SIMD and !FEATURE_SIMD apropriately. The use
7559 // of this routines also avoids the need of #ifdef FEATURE_SIMD specific code.
7561 // Is this var is of type simd struct?
7562 bool lclVarIsSIMDType(unsigned varNum)
7564 LclVarDsc* varDsc = lvaTable + varNum;
7565 return varDsc->lvIsSIMDType();
7568 // Is this Local node a SIMD local?
7569 bool lclVarIsSIMDType(GenTreeLclVarCommon* lclVarTree)
7571 return lclVarIsSIMDType(lclVarTree->gtLclNum);
7574 // Returns true if the TYP_SIMD locals on stack are aligned at their
7575 // preferred byte boundary specified by getSIMDTypeAlignment().
7577 // As per the Intel manual, the preferred alignment for AVX vectors is 32-bytes. On Amd64,
7578 // RSP/EBP is aligned at 16-bytes, therefore to align SIMD types at 32-bytes we need even
7579 // RSP/EBP to be 32-byte aligned. It is not clear whether additional stack space used in
7580 // aligning stack is worth the benefit and for now will use 16-byte alignment for AVX
7581 // 256-bit vectors with unaligned load/stores to/from memory. On x86, the stack frame
7582 // is aligned to 4 bytes. We need to extend existing support for double (8-byte) alignment
7583 // to 16 or 32 byte alignment for frames with local SIMD vars, if that is determined to be
7586 bool isSIMDTypeLocalAligned(unsigned varNum)
7588 #if defined(FEATURE_SIMD) && ALIGN_SIMD_TYPES
7589 if (lclVarIsSIMDType(varNum) && lvaTable[varNum].lvType != TYP_BYREF)
7592 int off = lvaFrameAddress(varNum, &ebpBased);
7593 // TODO-Cleanup: Can't this use the lvExactSize on the varDsc?
7594 int alignment = getSIMDTypeAlignment(lvaTable[varNum].lvType);
7595 bool isAligned = (alignment <= STACK_ALIGN) && ((off % alignment) == 0);
7598 #endif // FEATURE_SIMD
7603 // Whether SSE2 is available
7604 bool canUseSSE2() const
7606 #ifdef _TARGET_XARCH_
7607 return opts.compCanUseSSE2;
7613 // Whether SSE3, SSE3, SSE4.1 and SSE4.2 is available
7614 bool CanUseSSE3_4() const
7616 #ifdef _TARGET_XARCH_
7617 return opts.compCanUseSSE3_4;
7623 bool canUseAVX() const
7625 #ifdef FEATURE_AVX_SUPPORT
7626 return opts.compCanUseAVX;
7633 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7634 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7638 XX Generic info about the compilation and the method being compiled. XX
7639 XX It is responsible for driving the other phases. XX
7640 XX It is also responsible for all the memory management. XX
7642 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7643 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7647 Compiler* InlineeCompiler; // The Compiler instance for the inlinee
7649 InlineResult* compInlineResult; // The result of importing the inlinee method.
7651 bool compDoAggressiveInlining; // If true, mark every method as CORINFO_FLG_FORCEINLINE
7652 bool compJmpOpUsed; // Does the method do a JMP
7653 bool compLongUsed; // Does the method use TYP_LONG
7654 bool compFloatingPointUsed; // Does the method use TYP_FLOAT or TYP_DOUBLE
7655 bool compTailCallUsed; // Does the method do a tailcall
7656 bool compLocallocUsed; // Does the method use localloc.
7657 bool compQmarkUsed; // Does the method use GT_QMARK/GT_COLON
7658 bool compQmarkRationalized; // Is it allowed to use a GT_QMARK/GT_COLON node.
7659 bool compUnsafeCastUsed; // Does the method use LDIND/STIND to cast between scalar/refernce types
7661 // NOTE: These values are only reliable after
7662 // the importing is completely finished.
7664 ExpandArrayStack<GenTreePtr>* compQMarks; // The set of QMark nodes created in the current compilation, so
7665 // we can iterate over these efficiently.
7667 #if CPU_USES_BLOCK_MOVE
7668 bool compBlkOpUsed; // Does the method do a COPYBLK or INITBLK
7672 // State information - which phases have completed?
7673 // These are kept together for easy discoverability
7675 bool bRangeAllowStress;
7676 bool compCodeGenDone;
7677 int64_t compNumStatementLinksTraversed; // # of links traversed while doing debug checks
7678 bool fgNormalizeEHDone; // Has the flowgraph EH normalization phase been done?
7679 size_t compSizeEstimate; // The estimated size of the method as per `gtSetEvalOrder`.
7680 size_t compCycleEstimate; // The estimated cycle count of the method as per `gtSetEvalOrder`
7683 bool fgLocalVarLivenessDone; // Note that this one is used outside of debug.
7684 bool fgLocalVarLivenessChanged;
7686 bool compStackProbePrologDone;
7688 #ifndef LEGACY_BACKEND
7690 #endif // !LEGACY_BACKEND
7691 bool compRationalIRForm;
7693 bool compUsesThrowHelper; // There is a call to a THOROW_HELPER for the compiled method.
7695 bool compGeneratingProlog;
7696 bool compGeneratingEpilog;
7697 bool compNeedsGSSecurityCookie; // There is an unsafe buffer (or localloc) on the stack.
7698 // Insert cookie on frame and code to check the cookie, like VC++ -GS.
7699 bool compGSReorderStackLayout; // There is an unsafe buffer on the stack, reorder locals and make local
7700 // copies of susceptible parameters to avoid buffer overrun attacks through locals/params
7701 bool getNeedsGSSecurityCookie() const
7703 return compNeedsGSSecurityCookie;
7705 void setNeedsGSSecurityCookie()
7707 compNeedsGSSecurityCookie = true;
7710 FrameLayoutState lvaDoneFrameLayout; // The highest frame layout state that we've completed. During
7711 // frame layout calculations, this is the level we are currently
7714 //---------------------------- JITing options -----------------------------
7727 JitFlags* jitFlags; // all flags passed from the EE
7728 unsigned compFlags; // method attributes
7730 codeOptimize compCodeOpt; // what type of code optimizations
7734 #ifdef _TARGET_XARCH_
7735 bool compCanUseSSE2; // Allow CodeGen to use "movq XMM" instructions
7736 bool compCanUseSSE3_4; // Allow CodeGen to use SSE3, SSSE3, SSE4.1 and SSE4.2 instructions
7738 #ifdef FEATURE_AVX_SUPPORT
7739 bool compCanUseAVX; // Allow CodeGen to use AVX 256-bit vectors for SIMD operations
7740 #endif // FEATURE_AVX_SUPPORT
7741 #endif // _TARGET_XARCH_
7743 // optimize maximally and/or favor speed over size?
7745 #define DEFAULT_MIN_OPTS_CODE_SIZE 60000
7746 #define DEFAULT_MIN_OPTS_INSTR_COUNT 20000
7747 #define DEFAULT_MIN_OPTS_BB_COUNT 2000
7748 #define DEFAULT_MIN_OPTS_LV_NUM_COUNT 2000
7749 #define DEFAULT_MIN_OPTS_LV_REF_COUNT 8000
7751 // Maximun number of locals before turning off the inlining
7752 #define MAX_LV_NUM_COUNT_FOR_INLINING 512
7755 unsigned instrCount;
7756 unsigned lvRefCount;
7757 bool compMinOptsIsSet;
7759 bool compMinOptsIsUsed;
7761 inline bool MinOpts()
7763 assert(compMinOptsIsSet);
7764 compMinOptsIsUsed = true;
7767 inline bool IsMinOptsSet()
7769 return compMinOptsIsSet;
7772 inline bool MinOpts()
7776 inline bool IsMinOptsSet()
7778 return compMinOptsIsSet;
7781 inline void SetMinOpts(bool val)
7783 assert(!compMinOptsIsUsed);
7784 assert(!compMinOptsIsSet || (compMinOpts == val));
7786 compMinOptsIsSet = true;
7789 // true if the CLFLG_* for an optimization is set.
7790 inline bool OptEnabled(unsigned optFlag)
7792 return !!(compFlags & optFlag);
7795 #ifdef FEATURE_READYTORUN_COMPILER
7796 inline bool IsReadyToRun()
7798 return jitFlags->IsSet(JitFlags::JIT_FLAG_READYTORUN);
7801 inline bool IsReadyToRun()
7807 // true if we should use the PINVOKE_{BEGIN,END} helpers instead of generating
7808 // PInvoke transitions inline (e.g. when targeting CoreRT).
7809 inline bool ShouldUsePInvokeHelpers()
7811 return jitFlags->IsSet(JitFlags::JIT_FLAG_USE_PINVOKE_HELPERS);
7814 // true if we should use insert the REVERSE_PINVOKE_{ENTER,EXIT} helpers in the method
7816 inline bool IsReversePInvoke()
7818 return jitFlags->IsSet(JitFlags::JIT_FLAG_REVERSE_PINVOKE);
7821 // true if we must generate code compatible with JIT32 quirks
7822 inline bool IsJit32Compat()
7824 #if defined(_TARGET_X86_)
7825 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
7831 // true if we must generate code compatible with Jit64 quirks
7832 inline bool IsJit64Compat()
7834 #if defined(_TARGET_AMD64_)
7835 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
7836 #elif !defined(FEATURE_CORECLR)
7843 bool compScopeInfo; // Generate the LocalVar info ?
7844 bool compDbgCode; // Generate debugger-friendly code?
7845 bool compDbgInfo; // Gather debugging info?
7848 #ifdef PROFILING_SUPPORTED
7849 bool compNoPInvokeInlineCB;
7851 static const bool compNoPInvokeInlineCB;
7855 bool compGcChecks; // Check arguments and return values to ensure they are sane
7856 bool compStackCheckOnRet; // Check ESP on return to ensure it is correct
7857 bool compStackCheckOnCall; // Check ESP after every call to ensure it is correct
7861 bool compNeedSecurityCheck; // This flag really means where or not a security object needs
7862 // to be allocated on the stack.
7863 // It will be set to true in the following cases:
7864 // 1. When the method being compiled has a declarative security
7865 // (i.e. when CORINFO_FLG_NOSECURITYWRAP is reset for the current method).
7866 // This is also the case when we inject a prolog and epilog in the method.
7868 // 2. When the method being compiled has imperative security (i.e. the method
7869 // calls into another method that has CORINFO_FLG_SECURITYCHECK flag set).
7871 // 3. When opts.compDbgEnC is true. (See also Compiler::compCompile).
7873 // When this flag is set, jit will allocate a gc-reference local variable (lvaSecurityObject),
7874 // which gets reported as a GC root to stackwalker.
7875 // (See also ICodeManager::GetAddrOfSecurityObject.)
7880 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7881 bool compEnablePCRelAddr; // Whether absolute addr be encoded as PC-rel offset by RyuJIT where possible
7885 #ifdef UNIX_AMD64_ABI
7886 // This flag is indicating if there is a need to align the frame.
7887 // On AMD64-Windows, if there are calls, 4 slots for the outgoing ars are allocated, except for
7888 // FastTailCall. This slots makes the frame size non-zero, so alignment logic will be called.
7889 // On AMD64-Unix, there are no such slots. There is a possibility to have calls in the method with frame size of
7890 // 0. The frame alignment logic won't kick in. This flags takes care of the AMD64-Unix case by remembering that
7891 // there are calls and making sure the frame alignment logic is executed.
7892 bool compNeedToAlignFrame;
7893 #endif // UNIX_AMD64_ABI
7895 bool compProcedureSplitting; // Separate cold code from hot code
7897 bool genFPorder; // Preserve FP order (operations are non-commutative)
7898 bool genFPopt; // Can we do frame-pointer-omission optimization?
7899 bool altJit; // True if we are an altjit and are compiling this method
7902 bool optRepeat; // Repeat optimizer phases k times
7906 bool compProcedureSplittingEH; // Separate cold code from hot code for functions with EH
7907 bool dspCode; // Display native code generated
7908 bool dspEHTable; // Display the EH table reported to the VM
7909 bool dspInstrs; // Display the IL instructions intermixed with the native code output
7910 bool dspEmit; // Display emitter output
7911 bool dspLines; // Display source-code lines intermixed with native code output
7912 bool dmpHex; // Display raw bytes in hex of native code output
7913 bool varNames; // Display variables names in native code output
7914 bool disAsm; // Display native code as it is generated
7915 bool disAsmSpilled; // Display native code when any register spilling occurs
7916 bool disDiffable; // Makes the Disassembly code 'diff-able'
7917 bool disAsm2; // Display native code after it is generated using external disassembler
7918 bool dspOrder; // Display names of each of the methods that we ngen/jit
7919 bool dspUnwind; // Display the unwind info output
7920 bool dspDiffable; // Makes the Jit Dump 'diff-able' (currently uses same COMPlus_* flag as disDiffable)
7921 bool compLongAddress; // Force using large pseudo instructions for long address
7922 // (IF_LARGEJMP/IF_LARGEADR/IF_LARGLDC)
7923 bool dspGCtbls; // Display the GC tables
7927 bool doLateDisasm; // Run the late disassembler
7928 #endif // LATE_DISASM
7930 #if DUMP_GC_TABLES && !defined(DEBUG) && defined(JIT32_GCENCODER)
7931 // Only the JIT32_GCENCODER implements GC dumping in non-DEBUG code.
7932 #pragma message("NOTE: this non-debug build has GC ptr table dumping always enabled!")
7933 static const bool dspGCtbls = true;
7936 // We need stack probes to guarantee that we won't trigger a stack overflow
7937 // when calling unmanaged code until they get a chance to set up a frame, because
7938 // the EE will have no idea where it is.
7940 // We will only be doing this currently for hosted environments. Unfortunately
7941 // we need to take care of stubs, so potentially, we will have to do the probes
7942 // for any call. We have a plan for not needing for stubs though
7943 bool compNeedStackProbes;
7945 #ifdef PROFILING_SUPPORTED
7946 // Whether to emit Enter/Leave/TailCall hooks using a dummy stub (DummyProfilerELTStub()).
7947 // This option helps make the JIT behave as if it is running under a profiler.
7948 bool compJitELTHookEnabled;
7949 #endif // PROFILING_SUPPORTED
7951 #if FEATURE_TAILCALL_OPT
7952 // Whether opportunistic or implicit tail call optimization is enabled.
7953 bool compTailCallOpt;
7954 // Whether optimization of transforming a recursive tail call into a loop is enabled.
7955 bool compTailCallLoopOpt;
7959 static const bool compUseSoftFP = true;
7960 #else // !ARM_SOFTFP
7961 static const bool compUseSoftFP = false;
7964 GCPollType compGCPollType;
7968 static bool s_pAltJitExcludeAssembliesListInitialized;
7969 static AssemblyNamesList2* s_pAltJitExcludeAssembliesList;
7974 template <typename T>
7977 return (p == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : p);
7980 template <typename T>
7983 return (o == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : o);
7986 static int dspTreeID(GenTree* tree)
7988 return tree->gtTreeID;
7990 static void printTreeID(GenTree* tree)
7992 if (tree == nullptr)
7998 printf("[%06d]", dspTreeID(tree));
8005 #define STRESS_MODES \
8009 /* "Variations" stress areas which we try to mix up with each other. */ \
8010 /* These should not be exhaustively used as they might */ \
8011 /* hide/trivialize other areas */ \
8014 STRESS_MODE(DBL_ALN) \
8015 STRESS_MODE(LCL_FLDS) \
8016 STRESS_MODE(UNROLL_LOOPS) \
8017 STRESS_MODE(MAKE_CSE) \
8018 STRESS_MODE(LEGACY_INLINE) \
8019 STRESS_MODE(CLONE_EXPR) \
8020 STRESS_MODE(USE_FCOMI) \
8021 STRESS_MODE(USE_CMOV) \
8023 STRESS_MODE(BB_PROFILE) \
8024 STRESS_MODE(OPT_BOOLS_GC) \
8025 STRESS_MODE(REMORPH_TREES) \
8026 STRESS_MODE(64RSLT_MUL) \
8027 STRESS_MODE(DO_WHILE_LOOPS) \
8028 STRESS_MODE(MIN_OPTS) \
8029 STRESS_MODE(REVERSE_FLAG) /* Will set GTF_REVERSE_OPS whenever we can */ \
8030 STRESS_MODE(REVERSE_COMMA) /* Will reverse commas created with gtNewCommaNode */ \
8031 STRESS_MODE(TAILCALL) /* Will make the call as a tailcall whenever legal */ \
8032 STRESS_MODE(CATCH_ARG) /* Will spill catch arg */ \
8033 STRESS_MODE(UNSAFE_BUFFER_CHECKS) \
8034 STRESS_MODE(NULL_OBJECT_CHECK) \
8035 STRESS_MODE(PINVOKE_RESTORE_ESP) \
8036 STRESS_MODE(RANDOM_INLINE) \
8037 STRESS_MODE(SWITCH_CMP_BR_EXPANSION) \
8038 STRESS_MODE(GENERIC_VARN) \
8040 /* After COUNT_VARN, stress level 2 does all of these all the time */ \
8042 STRESS_MODE(COUNT_VARN) \
8044 /* "Check" stress areas that can be exhaustively used if we */ \
8045 /* dont care about performance at all */ \
8047 STRESS_MODE(FORCE_INLINE) /* Treat every method as AggressiveInlining */ \
8048 STRESS_MODE(CHK_FLOW_UPDATE) \
8049 STRESS_MODE(EMITTER) \
8050 STRESS_MODE(CHK_REIMPORT) \
8051 STRESS_MODE(FLATFP) \
8052 STRESS_MODE(GENERIC_CHECK) \
8057 #define STRESS_MODE(mode) STRESS_##mode,
8064 static const LPCWSTR s_compStressModeNames[STRESS_COUNT + 1];
8065 BYTE compActiveStressModes[STRESS_COUNT];
8068 #define MAX_STRESS_WEIGHT 100
8070 bool compStressCompile(compStressArea stressArea, unsigned weightPercentage);
8074 bool compInlineStress()
8076 return compStressCompile(STRESS_LEGACY_INLINE, 50);
8079 bool compRandomInlineStress()
8081 return compStressCompile(STRESS_RANDOM_INLINE, 50);
8086 bool compTailCallStress()
8089 return (JitConfig.TailcallStress() != 0 || compStressCompile(STRESS_TAILCALL, 5));
8095 codeOptimize compCodeOpt()
8098 // Switching between size & speed has measurable throughput impact
8099 // (3.5% on NGen mscorlib when measured). It used to be enabled for
8100 // DEBUG, but should generate identical code between CHK & RET builds,
8101 // so that's not acceptable.
8102 // TODO-Throughput: Figure out what to do about size vs. speed & throughput.
8103 // Investigate the cause of the throughput regression.
8105 return opts.compCodeOpt;
8107 return BLENDED_CODE;
8111 //--------------------- Info about the procedure --------------------------
8115 COMP_HANDLE compCompHnd;
8116 CORINFO_MODULE_HANDLE compScopeHnd;
8117 CORINFO_CLASS_HANDLE compClassHnd;
8118 CORINFO_METHOD_HANDLE compMethodHnd;
8119 CORINFO_METHOD_INFO* compMethodInfo;
8121 BOOL hasCircularClassConstraints;
8122 BOOL hasCircularMethodConstraints;
8124 #if defined(DEBUG) || defined(LATE_DISASM)
8125 const char* compMethodName;
8126 const char* compClassName;
8127 const char* compFullName;
8128 #endif // defined(DEBUG) || defined(LATE_DISASM)
8130 #if defined(DEBUG) || defined(INLINE_DATA)
8131 // Method hash is logcally const, but computed
8133 mutable unsigned compMethodHashPrivate;
8134 unsigned compMethodHash() const;
8135 #endif // defined(DEBUG) || defined(INLINE_DATA)
8137 #ifdef PSEUDORANDOM_NOP_INSERTION
8138 // things for pseudorandom nop insertion
8139 unsigned compChecksum;
8143 // The following holds the FLG_xxxx flags for the method we're compiling.
8146 // The following holds the class attributes for the method we're compiling.
8147 unsigned compClassAttr;
8149 const BYTE* compCode;
8150 IL_OFFSET compILCodeSize; // The IL code size
8151 UNATIVE_OFFSET compNativeCodeSize; // The native code size, after instructions are issued. This
8152 // is less than (compTotalHotCodeSize + compTotalColdCodeSize) only if:
8153 // (1) the code is not hot/cold split, and we issued less code than we expected, or
8154 // (2) the code is hot/cold split, and we issued less code than we expected
8155 // in the cold section (the hot section will always be padded out to compTotalHotCodeSize).
8157 bool compIsStatic : 1; // Is the method static (no 'this' pointer)?
8158 bool compIsVarArgs : 1; // Does the method have varargs parameters?
8159 bool compIsContextful : 1; // contextful method
8160 bool compInitMem : 1; // Is the CORINFO_OPT_INIT_LOCALS bit set in the method info options?
8161 bool compUnwrapContextful : 1; // JIT should unwrap proxies when possible
8162 bool compProfilerCallback : 1; // JIT inserted a profiler Enter callback
8163 bool compPublishStubParam : 1; // EAX captured in prolog will be available through an instrinsic
8164 bool compRetBuffDefStack : 1; // The ret buff argument definitely points into the stack.
8166 var_types compRetType; // Return type of the method as declared in IL
8167 var_types compRetNativeType; // Normalized return type as per target arch ABI
8168 unsigned compILargsCount; // Number of arguments (incl. implicit but not hidden)
8169 unsigned compArgsCount; // Number of arguments (incl. implicit and hidden)
8170 unsigned compRetBuffArg; // position of hidden return param var (0, 1) (BAD_VAR_NUM means not present);
8171 int compTypeCtxtArg; // position of hidden param for type context for generic code (CORINFO_CALLCONV_PARAMTYPE)
8172 unsigned compThisArg; // position of implicit this pointer param (not to be confused with lvaArg0Var)
8173 unsigned compILlocalsCount; // Number of vars : args + locals (incl. implicit but not hidden)
8174 unsigned compLocalsCount; // Number of vars : args + locals (incl. implicit and hidden)
8175 unsigned compMaxStack;
8176 UNATIVE_OFFSET compTotalHotCodeSize; // Total number of bytes of Hot Code in the method
8177 UNATIVE_OFFSET compTotalColdCodeSize; // Total number of bytes of Cold Code in the method
8179 unsigned compCallUnmanaged; // count of unmanaged calls
8180 unsigned compLvFrameListRoot; // lclNum for the Frame root
8181 unsigned compXcptnsCount; // Number of exception-handling clauses read in the method's IL.
8182 // You should generally use compHndBBtabCount instead: it is the
8183 // current number of EH clauses (after additions like synchronized
8184 // methods and funclets, and removals like unreachable code deletion).
8186 bool compMatchedVM; // true if the VM is "matched": either the JIT is a cross-compiler
8187 // and the VM expects that, or the JIT is a "self-host" compiler
8188 // (e.g., x86 hosted targeting x86) and the VM expects that.
8190 /* The following holds IL scope information about local variables.
8193 unsigned compVarScopesCount;
8194 VarScopeDsc* compVarScopes;
8196 /* The following holds information about instr offsets for
8197 * which we need to report IP-mappings
8200 IL_OFFSET* compStmtOffsets; // sorted
8201 unsigned compStmtOffsetsCount;
8202 ICorDebugInfo::BoundaryTypes compStmtOffsetsImplicit;
8204 #define CPU_X86 0x0100 // The generic X86 CPU
8205 #define CPU_X86_PENTIUM_4 0x0110
8207 #define CPU_X64 0x0200 // The generic x64 CPU
8208 #define CPU_AMD_X64 0x0210 // AMD x64 CPU
8209 #define CPU_INTEL_X64 0x0240 // Intel x64 CPU
8211 #define CPU_ARM 0x0300 // The generic ARM CPU
8213 unsigned genCPU; // What CPU are we running on
8216 // Returns true if the method being compiled returns a non-void and non-struct value.
8217 // Note that lvaInitTypeRef() normalizes compRetNativeType for struct returns in a
8218 // single register as per target arch ABI (e.g on Amd64 Windows structs of size 1, 2,
8219 // 4 or 8 gets normalized to TYP_BYTE/TYP_SHORT/TYP_INT/TYP_LONG; On Arm HFA structs).
8220 // Methods returning such structs are considered to return non-struct return value and
8221 // this method returns true in that case.
8222 bool compMethodReturnsNativeScalarType()
8224 return (info.compRetType != TYP_VOID) && !varTypeIsStruct(info.compRetNativeType);
8227 // Returns true if the method being compiled returns RetBuf addr as its return value
8228 bool compMethodReturnsRetBufAddr()
8230 // There are cases where implicit RetBuf argument should be explicitly returned in a register.
8231 // In such cases the return type is changed to TYP_BYREF and appropriate IR is generated.
8233 // 1. Profiler Leave calllback expects the address of retbuf as return value for
8234 // methods with hidden RetBuf argument. impReturnInstruction() when profiler
8235 // callbacks are needed creates GT_RETURN(TYP_BYREF, op1 = Addr of RetBuf) for
8236 // methods with hidden RetBufArg.
8238 // 2. As per the System V ABI, the address of RetBuf needs to be returned by
8239 // methods with hidden RetBufArg in RAX. In such case GT_RETURN is of TYP_BYREF,
8240 // returning the address of RetBuf.
8242 // 3. Windows 64-bit native calling convention also requires the address of RetBuff
8243 // to be returned in RAX.
8244 CLANG_FORMAT_COMMENT_ANCHOR;
8246 #ifdef _TARGET_AMD64_
8247 return (info.compRetBuffArg != BAD_VAR_NUM);
8248 #else // !_TARGET_AMD64_
8249 return (compIsProfilerHookNeeded()) && (info.compRetBuffArg != BAD_VAR_NUM);
8250 #endif // !_TARGET_AMD64_
8253 // Returns true if the method returns a value in more than one return register
8254 // TODO-ARM-Bug: Deal with multi-register genReturnLocaled structs?
8255 // TODO-ARM64: Does this apply for ARM64 too?
8256 bool compMethodReturnsMultiRegRetType()
8258 #if FEATURE_MULTIREG_RET
8259 #if defined(_TARGET_X86_)
8260 // On x86 only 64-bit longs are returned in multiple registers
8261 return varTypeIsLong(info.compRetNativeType);
8262 #else // targets: X64-UNIX, ARM64 or ARM32
8263 // On all other targets that support multireg return values:
8264 // Methods returning a struct in multiple registers have a return value of TYP_STRUCT.
8265 // Such method's compRetNativeType is TYP_STRUCT without a hidden RetBufArg
8266 return varTypeIsStruct(info.compRetNativeType) && (info.compRetBuffArg == BAD_VAR_NUM);
8267 #endif // TARGET_XXX
8269 #else // not FEATURE_MULTIREG_RET
8271 // For this architecture there are no multireg returns
8274 #endif // FEATURE_MULTIREG_RET
8277 #if FEATURE_MULTIREG_ARGS
8278 // Given a GenTree node of TYP_STRUCT that represents a pass by value argument
8279 // return the gcPtr layout for the pointers sized fields
8280 void getStructGcPtrsFromOp(GenTreePtr op, BYTE* gcPtrsOut);
8281 #endif // FEATURE_MULTIREG_ARGS
8283 // Returns true if the method being compiled returns a value
8284 bool compMethodHasRetVal()
8286 return compMethodReturnsNativeScalarType() || compMethodReturnsRetBufAddr() ||
8287 compMethodReturnsMultiRegRetType();
8292 void compDispLocalVars();
8296 //-------------------------- Global Compiler Data ------------------------------------
8299 static unsigned s_compMethodsCount; // to produce unique label names
8300 unsigned compGenTreeID;
8303 BasicBlock* compCurBB; // the current basic block in process
8304 GenTreePtr compCurStmt; // the current statement in process
8306 unsigned compCurStmtNum; // to give all statements an increasing StmtNum when printing dumps
8309 // The following is used to create the 'method JIT info' block.
8310 size_t compInfoBlkSize;
8311 BYTE* compInfoBlkAddr;
8313 EHblkDsc* compHndBBtab; // array of EH data
8314 unsigned compHndBBtabCount; // element count of used elements in EH data array
8315 unsigned compHndBBtabAllocCount; // element count of allocated elements in EH data array
8317 #if defined(_TARGET_X86_)
8319 //-------------------------------------------------------------------------
8320 // Tracking of region covered by the monitor in synchronized methods
8321 void* syncStartEmitCookie; // the emitter cookie for first instruction after the call to MON_ENTER
8322 void* syncEndEmitCookie; // the emitter cookie for first instruction after the call to MON_EXIT
8324 #endif // !_TARGET_X86_
8326 Phases previousCompletedPhase; // the most recently completed phase
8328 //-------------------------------------------------------------------------
8329 // The following keeps track of how many bytes of local frame space we've
8330 // grabbed so far in the current function, and how many argument bytes we
8331 // need to pop when we return.
8334 unsigned compLclFrameSize; // secObject+lclBlk+locals+temps
8336 // Count of callee-saved regs we pushed in the prolog.
8337 // Does not include EBP for isFramePointerUsed() and double-aligned frames.
8338 // In case of Amd64 this doesn't include float regs saved on stack.
8339 unsigned compCalleeRegsPushed;
8341 #if defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87
8342 // Mask of callee saved float regs on stack.
8343 regMaskTP compCalleeFPRegsSavedMask;
8345 #ifdef _TARGET_AMD64_
8346 // Quirk for VS debug-launch scenario to work:
8347 // Bytes of padding between save-reg area and locals.
8348 #define VSQUIRK_STACK_PAD (2 * REGSIZE_BYTES)
8349 unsigned compVSQuirkStackPaddingNeeded;
8350 bool compQuirkForPPPflag;
8353 unsigned compArgSize; // total size of arguments in bytes (including register args (lvIsRegArg))
8355 unsigned compMapILargNum(unsigned ILargNum); // map accounting for hidden args
8356 unsigned compMapILvarNum(unsigned ILvarNum); // map accounting for hidden args
8357 unsigned compMap2ILvarNum(unsigned varNum); // map accounting for hidden args
8359 //-------------------------------------------------------------------------
8361 static void compStartup(); // One-time initialization
8362 static void compShutdown(); // One-time finalization
8364 void compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo);
8367 static void compDisplayStaticSizes(FILE* fout);
8369 //------------ Some utility functions --------------
8371 void* compGetHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
8372 void** ppIndirection); /* OUT */
8374 // Several JIT/EE interface functions return a CorInfoType, and also return a
8375 // class handle as an out parameter if the type is a value class. Returns the
8376 // size of the type these describe.
8377 unsigned compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd);
8380 // Components used by the compiler may write unit test suites, and
8381 // have them run within this method. They will be run only once per process, and only
8382 // in debug. (Perhaps should be under the control of a COMPlus_ flag.)
8383 // These should fail by asserting.
8384 void compDoComponentUnitTestsOnce();
8387 int compCompile(CORINFO_METHOD_HANDLE methodHnd,
8388 CORINFO_MODULE_HANDLE classPtr,
8389 COMP_HANDLE compHnd,
8390 CORINFO_METHOD_INFO* methodInfo,
8391 void** methodCodePtr,
8392 ULONG* methodCodeSize,
8393 JitFlags* compileFlags);
8394 void compCompileFinish();
8395 int compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
8396 COMP_HANDLE compHnd,
8397 CORINFO_METHOD_INFO* methodInfo,
8398 void** methodCodePtr,
8399 ULONG* methodCodeSize,
8400 JitFlags* compileFlags,
8401 CorInfoInstantiationVerification instVerInfo);
8403 ArenaAllocator* compGetAllocator();
8405 #if MEASURE_MEM_ALLOC
8407 static bool s_dspMemStats; // Display per-phase memory statistics for every function
8411 unsigned allocCnt; // # of allocs
8412 UINT64 allocSz; // total size of those alloc.
8413 UINT64 allocSzMax; // Maximum single allocation.
8414 UINT64 allocSzByKind[CMK_Count]; // Classified by "kind".
8415 UINT64 nraTotalSizeAlloc;
8416 UINT64 nraTotalSizeUsed;
8418 static const char* s_CompMemKindNames[]; // Names of the kinds.
8420 MemStats() : allocCnt(0), allocSz(0), allocSzMax(0), nraTotalSizeAlloc(0), nraTotalSizeUsed(0)
8422 for (int i = 0; i < CMK_Count; i++)
8424 allocSzByKind[i] = 0;
8427 MemStats(const MemStats& ms)
8428 : allocCnt(ms.allocCnt)
8429 , allocSz(ms.allocSz)
8430 , allocSzMax(ms.allocSzMax)
8431 , nraTotalSizeAlloc(ms.nraTotalSizeAlloc)
8432 , nraTotalSizeUsed(ms.nraTotalSizeUsed)
8434 for (int i = 0; i < CMK_Count; i++)
8436 allocSzByKind[i] = ms.allocSzByKind[i];
8440 // Until we have ubiquitous constructors.
8443 this->MemStats::MemStats();
8446 void AddAlloc(size_t sz, CompMemKind cmk)
8450 if (sz > allocSzMax)
8454 allocSzByKind[cmk] += sz;
8457 void Print(FILE* f); // Print these stats to f.
8458 void PrintByKind(FILE* f); // Do just the by-kind histogram part.
8460 MemStats genMemStats;
8462 struct AggregateMemStats : public MemStats
8466 AggregateMemStats() : MemStats(), nMethods(0)
8470 void Add(const MemStats& ms)
8473 allocCnt += ms.allocCnt;
8474 allocSz += ms.allocSz;
8475 allocSzMax = max(allocSzMax, ms.allocSzMax);
8476 for (int i = 0; i < CMK_Count; i++)
8478 allocSzByKind[i] += ms.allocSzByKind[i];
8480 nraTotalSizeAlloc += ms.nraTotalSizeAlloc;
8481 nraTotalSizeUsed += ms.nraTotalSizeUsed;
8484 void Print(FILE* f); // Print these stats to jitstdout.
8487 static CritSecObject s_memStatsLock; // This lock protects the data structures below.
8488 static MemStats s_maxCompMemStats; // Stats for the compilation with the largest amount allocated.
8489 static AggregateMemStats s_aggMemStats; // Aggregates statistics for all compilations.
8491 #endif // MEASURE_MEM_ALLOC
8493 #if LOOP_HOIST_STATS
8494 unsigned m_loopsConsidered;
8495 bool m_curLoopHasHoistedExpression;
8496 unsigned m_loopsWithHoistedExpressions;
8497 unsigned m_totalHoistedExpressions;
8499 void AddLoopHoistStats();
8500 void PrintPerMethodLoopHoistStats();
8502 static CritSecObject s_loopHoistStatsLock; // This lock protects the data structures below.
8503 static unsigned s_loopsConsidered;
8504 static unsigned s_loopsWithHoistedExpressions;
8505 static unsigned s_totalHoistedExpressions;
8507 static void PrintAggregateLoopHoistStats(FILE* f);
8508 #endif // LOOP_HOIST_STATS
8510 void* compGetMemArray(size_t numElem, size_t elemSize, CompMemKind cmk = CMK_Unknown);
8511 void* compGetMemArrayA(size_t numElem, size_t elemSize, CompMemKind cmk = CMK_Unknown);
8512 void* compGetMem(size_t sz, CompMemKind cmk = CMK_Unknown);
8513 void* compGetMemA(size_t sz, CompMemKind cmk = CMK_Unknown);
8514 static void* compGetMemCallback(void*, size_t, CompMemKind cmk = CMK_Unknown);
8515 void compFreeMem(void*);
8517 bool compIsForImportOnly();
8518 bool compIsForInlining();
8519 bool compDonotInline();
8522 const char* compLocalVarName(unsigned varNum, unsigned offs);
8523 VarName compVarName(regNumber reg, bool isFloatReg = false);
8524 const char* compRegVarName(regNumber reg, bool displayVar = false, bool isFloatReg = false);
8525 const char* compRegPairName(regPairNo regPair);
8526 const char* compRegNameForSize(regNumber reg, size_t size);
8527 const char* compFPregVarName(unsigned fpReg, bool displayVar = false);
8528 void compDspSrcLinesByNativeIP(UNATIVE_OFFSET curIP);
8529 void compDspSrcLinesByLineNum(unsigned line, bool seek = false);
8532 //-------------------------------------------------------------------------
8534 typedef ListNode<VarScopeDsc*> VarScopeListNode;
8536 struct VarScopeMapInfo
8538 VarScopeListNode* head;
8539 VarScopeListNode* tail;
8540 static VarScopeMapInfo* Create(VarScopeListNode* node, IAllocator* alloc)
8542 VarScopeMapInfo* info = new (alloc) VarScopeMapInfo;
8549 // Max value of scope count for which we would use linear search; for larger values we would use hashtable lookup.
8550 static const unsigned MAX_LINEAR_FIND_LCL_SCOPELIST = 32;
8552 typedef SimplerHashTable<unsigned, SmallPrimitiveKeyFuncs<unsigned>, VarScopeMapInfo*, JitSimplerHashBehavior>
8553 VarNumToScopeDscMap;
8555 // Map to keep variables' scope indexed by varNum containing it's scope dscs at the index.
8556 VarNumToScopeDscMap* compVarScopeMap;
8558 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned lifeBeg, unsigned lifeEnd);
8560 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned offs);
8562 VarScopeDsc* compFindLocalVarLinear(unsigned varNum, unsigned offs);
8564 void compInitVarScopeMap();
8566 VarScopeDsc** compEnterScopeList; // List has the offsets where variables
8567 // enter scope, sorted by instr offset
8568 unsigned compNextEnterScope;
8570 VarScopeDsc** compExitScopeList; // List has the offsets where variables
8571 // go out of scope, sorted by instr offset
8572 unsigned compNextExitScope;
8574 void compInitScopeLists();
8576 void compResetScopeLists();
8578 VarScopeDsc* compGetNextEnterScope(unsigned offs, bool scan = false);
8580 VarScopeDsc* compGetNextExitScope(unsigned offs, bool scan = false);
8582 void compProcessScopesUntil(unsigned offset,
8584 void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*),
8585 void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*));
8588 void compDispScopeLists();
8591 bool compIsProfilerHookNeeded();
8593 //-------------------------------------------------------------------------
8594 /* Statistical Data Gathering */
8596 void compJitStats(); // call this function and enable
8597 // various ifdef's below for statistical data
8600 void compCallArgStats();
8601 static void compDispCallArgStats(FILE* fout);
8604 //-------------------------------------------------------------------------
8611 ArenaAllocator* compAllocator;
8614 // This one presents an implementation of the "IAllocator" abstract class that uses "compAllocator",
8615 // suitable for use by utilcode collection types.
8616 IAllocator* compAsIAllocator;
8618 #if MEASURE_MEM_ALLOC
8619 IAllocator* compAsIAllocatorBitset; // An allocator that uses the CMK_bitset tracker.
8620 IAllocator* compAsIAllocatorGC; // An allocator that uses the CMK_GC tracker.
8621 IAllocator* compAsIAllocatorLoopHoist; // An allocator that uses the CMK_LoopHoist tracker.
8623 IAllocator* compAsIAllocatorDebugOnly; // An allocator that uses the CMK_DebugOnly tracker.
8625 #endif // MEASURE_MEM_ALLOC
8627 void compFunctionTraceStart();
8628 void compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, bool isNYI);
8631 size_t compMaxUncheckedOffsetForNullObject;
8633 void compInitOptions(JitFlags* compileFlags);
8635 void compSetProcessor();
8636 void compInitDebuggingInfo();
8637 void compSetOptimizationLevel();
8638 #ifdef _TARGET_ARMARCH_
8639 bool compRsvdRegCheck(FrameLayoutState curState);
8641 void compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags);
8643 // Clear annotations produced during optimizations; to be used between iterations when repeating opts.
8644 void ResetOptAnnotations();
8646 // Regenerate loop descriptors; to be used between iterations when repeating opts.
8647 void RecomputeLoopInfo();
8649 #ifdef PROFILING_SUPPORTED
8650 // Data required for generating profiler Enter/Leave/TailCall hooks
8652 bool compProfilerHookNeeded; // Whether profiler Enter/Leave/TailCall hook needs to be generated for the method
8653 void* compProfilerMethHnd; // Profiler handle of the method being compiled. Passed as param to ELT callbacks
8654 bool compProfilerMethHndIndirected; // Whether compProfilerHandle is pointer to the handle or is an actual handle
8657 #ifdef _TARGET_AMD64_
8658 bool compQuirkForPPP(); // Check if this method should be Quirked for the PPP issue
8661 // Assumes called as part of process shutdown; does any compiler-specific work associated with that.
8662 static void ProcessShutdownWork(ICorStaticInfo* statInfo);
8664 IAllocator* getAllocator()
8666 return compAsIAllocator;
8669 #if MEASURE_MEM_ALLOC
8670 IAllocator* getAllocatorBitset()
8672 return compAsIAllocatorBitset;
8674 IAllocator* getAllocatorGC()
8676 return compAsIAllocatorGC;
8678 IAllocator* getAllocatorLoopHoist()
8680 return compAsIAllocatorLoopHoist;
8682 #else // !MEASURE_MEM_ALLOC
8683 IAllocator* getAllocatorBitset()
8685 return compAsIAllocator;
8687 IAllocator* getAllocatorGC()
8689 return compAsIAllocator;
8691 IAllocator* getAllocatorLoopHoist()
8693 return compAsIAllocator;
8695 #endif // !MEASURE_MEM_ALLOC
8698 IAllocator* getAllocatorDebugOnly()
8700 #if MEASURE_MEM_ALLOC
8701 return compAsIAllocatorDebugOnly;
8702 #else // !MEASURE_MEM_ALLOC
8703 return compAsIAllocator;
8704 #endif // !MEASURE_MEM_ALLOC
8709 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8710 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8714 XX Checks for type compatibility and merges types XX
8716 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8717 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8721 // Set to TRUE if verification cannot be skipped for this method
8722 // If we detect unverifiable code, we will lazily check
8723 // canSkipMethodVerification() to see if verification is REALLY needed.
8724 BOOL tiVerificationNeeded;
8726 // It it initially TRUE, and it gets set to FALSE if we run into unverifiable code
8727 // Note that this is valid only if tiVerificationNeeded was ever TRUE.
8728 BOOL tiIsVerifiableCode;
8730 // Set to TRUE if runtime callout is needed for this method
8731 BOOL tiRuntimeCalloutNeeded;
8733 // Set to TRUE if security prolog/epilog callout is needed for this method
8734 // Note: This flag is different than compNeedSecurityCheck.
8735 // compNeedSecurityCheck means whether or not a security object needs
8736 // to be allocated on the stack, which is currently true for EnC as well.
8737 // tiSecurityCalloutNeeded means whether or not security callouts need
8738 // to be inserted in the jitted code.
8739 BOOL tiSecurityCalloutNeeded;
8741 // Returns TRUE if child is equal to or a subtype of parent for merge purposes
8742 // This support is necessary to suport attributes that are not described in
8743 // for example, signatures. For example, the permanent home byref (byref that
8744 // points to the gc heap), isn't a property of method signatures, therefore,
8745 // it is safe to have mismatches here (that tiCompatibleWith will not flag),
8746 // but when deciding if we need to reimport a block, we need to take these
8748 BOOL tiMergeCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
8750 // Returns TRUE if child is equal to or a subtype of parent.
8751 // normalisedForStack indicates that both types are normalised for the stack
8752 BOOL tiCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
8754 // Merges pDest and pSrc. Returns FALSE if merge is undefined.
8755 // *pDest is modified to represent the merged type. Sets "*changed" to true
8756 // if this changes "*pDest".
8757 BOOL tiMergeToCommonParent(typeInfo* pDest, const typeInfo* pSrc, bool* changed) const;
8759 // Set pDest from the primitive value type.
8760 // Eg. System.Int32 -> ELEMENT_TYPE_I4
8762 BOOL tiFromPrimitiveValueClass(typeInfo* pDest, const typeInfo* pVC) const;
8765 // <BUGNUM> VSW 471305
8766 // IJW allows assigning REF to BYREF. The following allows us to temporarily
8767 // bypass the assert check in gcMarkRegSetGCref and gcMarkRegSetByref
8768 // We use a "short" as we need to push/pop this scope.
8770 short compRegSetCheckLevel;
8774 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8775 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8777 XX IL verification stuff XX
8780 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8781 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8785 // The following is used to track liveness of local variables, initialization
8786 // of valueclass constructors, and type safe use of IL instructions.
8788 // dynamic state info needed for verification
8789 EntryState verCurrentState;
8791 // this ptr of object type .ctors are considered intited only after
8792 // the base class ctor is called, or an alternate ctor is called.
8793 // An uninited this ptr can be used to access fields, but cannot
8794 // be used to call a member function.
8795 BOOL verTrackObjCtorInitState;
8797 void verInitBBEntryState(BasicBlock* block, EntryState* currentState);
8799 // Requires that "tis" is not TIS_Bottom -- it's a definite init/uninit state.
8800 void verSetThisInit(BasicBlock* block, ThisInitState tis);
8801 void verInitCurrentState();
8802 void verResetCurrentState(BasicBlock* block, EntryState* currentState);
8804 // Merges the current verification state into the entry state of "block", return FALSE if that merge fails,
8805 // TRUE if it succeeds. Further sets "*changed" to true if this changes the entry state of "block".
8806 BOOL verMergeEntryStates(BasicBlock* block, bool* changed);
8808 void verConvertBBToThrowVerificationException(BasicBlock* block DEBUGARG(bool logMsg));
8809 void verHandleVerificationFailure(BasicBlock* block DEBUGARG(bool logMsg));
8810 typeInfo verMakeTypeInfo(CORINFO_CLASS_HANDLE clsHnd,
8811 bool bashStructToRef = false); // converts from jit type representation to typeInfo
8812 typeInfo verMakeTypeInfo(CorInfoType ciType,
8813 CORINFO_CLASS_HANDLE clsHnd); // converts from jit type representation to typeInfo
8814 BOOL verIsSDArray(typeInfo ti);
8815 typeInfo verGetArrayElemType(typeInfo ti);
8817 typeInfo verParseArgSigToTypeInfo(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args);
8818 BOOL verNeedsVerification();
8819 BOOL verIsByRefLike(const typeInfo& ti);
8820 BOOL verIsSafeToReturnByRef(const typeInfo& ti);
8822 // generic type variables range over types that satisfy IsBoxable
8823 BOOL verIsBoxable(const typeInfo& ti);
8825 void DECLSPEC_NORETURN verRaiseVerifyException(INDEBUG(const char* reason) DEBUGARG(const char* file)
8826 DEBUGARG(unsigned line));
8827 void verRaiseVerifyExceptionIfNeeded(INDEBUG(const char* reason) DEBUGARG(const char* file)
8828 DEBUGARG(unsigned line));
8829 bool verCheckTailCallConstraint(OPCODE opcode,
8830 CORINFO_RESOLVED_TOKEN* pResolvedToken,
8831 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call
8832 // on a type parameter?
8833 bool speculative // If true, won't throw if verificatoin fails. Instead it will
8834 // return false to the caller.
8835 // If false, it will throw.
8837 bool verIsBoxedValueType(typeInfo ti);
8839 void verVerifyCall(OPCODE opcode,
8840 CORINFO_RESOLVED_TOKEN* pResolvedToken,
8841 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
8843 bool readonlyCall, // is this a "readonly." call?
8844 const BYTE* delegateCreateStart,
8845 const BYTE* codeAddr,
8846 CORINFO_CALL_INFO* callInfo DEBUGARG(const char* methodName));
8848 BOOL verCheckDelegateCreation(const BYTE* delegateCreateStart, const BYTE* codeAddr, mdMemberRef& targetMemberRef);
8850 typeInfo verVerifySTIND(const typeInfo& ptr, const typeInfo& value, const typeInfo& instrType);
8851 typeInfo verVerifyLDIND(const typeInfo& ptr, const typeInfo& instrType);
8852 void verVerifyField(CORINFO_RESOLVED_TOKEN* pResolvedToken,
8853 const CORINFO_FIELD_INFO& fieldInfo,
8854 const typeInfo* tiThis,
8856 BOOL allowPlainStructAsThis = FALSE);
8857 void verVerifyCond(const typeInfo& tiOp1, const typeInfo& tiOp2, unsigned opcode);
8858 void verVerifyThisPtrInitialised();
8859 BOOL verIsCallToInitThisPtr(CORINFO_CLASS_HANDLE context, CORINFO_CLASS_HANDLE target);
8861 // Register allocator
8862 void raInitStackFP();
8863 void raEnregisterVarsPrePassStackFP();
8864 void raSetRegLclBirthDeath(GenTreePtr tree, VARSET_VALARG_TP lastlife, bool fromLDOBJ);
8865 void raEnregisterVarsPostPassStackFP();
8866 void raGenerateFPRefCounts();
8867 void raEnregisterVarsStackFP();
8868 void raUpdateHeightsForVarsStackFP(VARSET_VALARG_TP mask);
8870 regNumber raRegForVarStackFP(unsigned varTrackedIndex);
8871 void raAddPayloadStackFP(VARSET_VALARG_TP mask, unsigned weight);
8873 // returns true if enregistering v1 would save more mem accesses than v2
8874 bool raVarIsGreaterValueStackFP(LclVarDsc* lv1, LclVarDsc* lv2);
8877 void raDumpHeightsStackFP();
8878 void raDumpVariableRegIntfFloat();
8881 #if FEATURE_STACK_FP_X87
8883 // Currently, we use FP transition blocks in only 2 situations:
8885 // -conditional jump on longs where FP stack differs with target: it's not strictly
8886 // necessary, but its low frequency and the code would get complicated if we try to
8887 // inline the FP stack adjustment, as we have a lot of special casing going on to try
8888 // minimize the way we generate the jump code.
8889 // -case statements of switch where the FP stack differs with the one of evaluating the switch () statement
8890 // We do this as we want to codegen switch as a jumptable. Again, this is low frequency.
8892 // However, transition blocks have 2 problems
8894 // - Procedure splitting: current implementation of procedure splitting requires all basic blocks to
8895 // be known at codegen time, as it generates all hot blocks first and cold blocks later. This ties
8896 // us up in codegen and is a solvable problem (we could make procedure splitting generate blocks
8897 // in the right place without preordering them), this causes us to have to generate the transition
8898 // blocks in the cold area if we want procedure splitting.
8901 // - Thread abort exceptions and transition blocks. Transition blocks were designed under the assumption
8902 // that no exceptions can happen inside them. Unfortunately Thread.Abort can happen in any instruction,
8903 // and if we have handlers we will have to try to call them. Fixing this the right way would imply
8904 // having multiple try native code regions for a single try il region. This is doable and shouldnt be
8905 // a big change in the exception.
8907 // Given the low frequency of the cases where we have transition blocks, I've decided to dumb down
8908 // optimizations. For these 2 cases:
8910 // - When there is a chance that we will have FP transition blocks, we won't do procedure splitting.
8911 // - When a method has a handler, it won't enregister any FP variables that go thru a conditional long or
8912 // a switch statement.
8914 // If at any point we find we need to optimize this, we should throw work at unblocking the restrictions our
8915 // current procedure splitting and exception code have.
8916 bool compMayHaveTransitionBlocks;
8918 VARSET_TP raMaskDontEnregFloat; // mask for additional restrictions
8920 VARSET_TP raLclRegIntfFloat[REG_FPCOUNT];
8922 unsigned raCntStkStackFP;
8923 unsigned raCntWtdStkDblStackFP;
8924 unsigned raCntStkParamDblStackFP;
8926 // Payload in mem accesses for enregistering a variable (we dont want to mix with refcounts)
8927 // TODO: Do we want to put this in LclVarDsc?
8928 unsigned raPayloadStackFP[lclMAX_TRACKED];
8929 unsigned raHeightsStackFP[lclMAX_TRACKED][FP_VIRTUALREGISTERS + 1];
8931 // Useful for debugging
8932 unsigned raHeightsNonWeightedStackFP[lclMAX_TRACKED][FP_VIRTUALREGISTERS + 1];
8934 #endif // FEATURE_STACK_FP_X87
8937 // One line log function. Default level is 0. Increasing it gives you
8938 // more log information
8940 // levels are currently unused: #define JITDUMP(level,...) ();
8941 void JitLogEE(unsigned level, const char* fmt, ...);
8943 bool compDebugBreak;
8945 bool compJitHaltMethod();
8950 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8951 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8953 XX GS Security checks for unsafe buffers XX
8955 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8956 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8959 struct ShadowParamVarInfo
8961 FixedBitVect* assignGroup; // the closure set of variables whose values depend on each other
8962 unsigned shadowCopy; // Lcl var num, valid only if not set to NO_SHADOW_COPY
8964 static bool mayNeedShadowCopy(LclVarDsc* varDsc)
8966 #if defined(_TARGET_AMD64_) && !defined(LEGACY_BACKEND)
8967 // GS cookie logic to create shadow slots, create trees to copy reg args to shadow
8968 // slots and update all trees to refer to shadow slots is done immediately after
8969 // fgMorph(). Lsra could potentially mark a param as DoNotEnregister after JIT determines
8970 // not to shadow a parameter. Also, LSRA could potentially spill a param which is passed
8971 // in register. Therefore, conservatively all params may need a shadow copy. Note that
8972 // GS cookie logic further checks whether the param is a ptr or an unsafe buffer before
8973 // creating a shadow slot even though this routine returns true.
8975 // TODO-AMD64-CQ: Revisit this conservative approach as it could create more shadow slots than
8976 // required. There are two cases under which a reg arg could potentially be used from its
8978 // a) LSRA marks it as DoNotEnregister (see LinearScan::identifyCandidates())
8979 // b) LSRA spills it
8981 // Possible solution to address case (a)
8982 // - The conditions under which LSRA marks a varDsc as DoNotEnregister could be checked
8983 // in this routine. Note that live out of exception handler is something we may not be
8984 // able to do it here since GS cookie logic is invoked ahead of liveness computation.
8985 // Therefore, for methods with exception handling and need GS cookie check we might have
8986 // to take conservative approach.
8988 // Possible solution to address case (b)
8989 // - Whenver a parameter passed in an argument register needs to be spilled by LSRA, we
8990 // create a new spill temp if the method needs GS cookie check.
8991 return varDsc->lvIsParam;
8992 #else // !(defined(_TARGET_AMD64_) && defined(LEGACY_BACKEND))
8993 return varDsc->lvIsParam && !varDsc->lvIsRegArg;
9000 printf("assignGroup [%p]; shadowCopy: [%d];\n", assignGroup, shadowCopy);
9005 GSCookie* gsGlobalSecurityCookieAddr; // Address of global cookie for unsafe buffer checks
9006 GSCookie gsGlobalSecurityCookieVal; // Value of global cookie if addr is NULL
9007 ShadowParamVarInfo* gsShadowVarInfo; // Table used by shadow param analysis code
9009 void gsGSChecksInitCookie(); // Grabs cookie variable
9010 void gsCopyShadowParams(); // Identify vulnerable params and create dhadow copies
9011 bool gsFindVulnerableParams(); // Shadow param analysis code
9012 void gsParamsToShadows(); // Insert copy code and replave param uses by shadow
9014 static fgWalkPreFn gsMarkPtrsAndAssignGroups; // Shadow param analysis tree-walk
9015 static fgWalkPreFn gsReplaceShadowParams; // Shadow param replacement tree-walk
9017 #define DEFAULT_MAX_INLINE_SIZE 100 // Methods with > DEFAULT_MAX_INLINE_SIZE IL bytes will never be inlined.
9018 // This can be overwritten by setting complus_JITInlineSize env variable.
9020 #define DEFAULT_MAX_INLINE_DEPTH 20 // Methods at more than this level deep will not be inlined
9023 #ifdef FEATURE_JIT_METHOD_PERF
9024 JitTimer* pCompJitTimer; // Timer data structure (by phases) for current compilation.
9025 static CompTimeSummaryInfo s_compJitTimerSummary; // Summary of the Timer information for the whole run.
9027 static LPCWSTR JitTimeLogCsv(); // Retrieve the file name for CSV from ConfigDWORD.
9028 static LPCWSTR compJitTimeLogFilename; // If a log file for JIT time is desired, filename to write it to.
9030 inline void EndPhase(Phases phase); // Indicate the end of the given phase.
9032 #if MEASURE_CLRAPI_CALLS
9033 // Thin wrappers that call into JitTimer (if present).
9034 inline void CLRApiCallEnter(unsigned apix);
9035 inline void CLRApiCallLeave(unsigned apix);
9038 inline void CLR_API_Enter(API_ICorJitInfo_Names ename);
9039 inline void CLR_API_Leave(API_ICorJitInfo_Names ename);
9044 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9045 // These variables are associated with maintaining SQM data about compile time.
9046 unsigned __int64 m_compCyclesAtEndOfInlining; // The thread-virtualized cycle count at the end of the inlining phase
9047 // in the current compilation.
9048 unsigned __int64 m_compCycles; // Net cycle count for current compilation
9049 DWORD m_compTickCountAtEndOfInlining; // The result of GetTickCount() (# ms since some epoch marker) at the end of
9050 // the inlining phase in the current compilation.
9051 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9053 // Records the SQM-relevant (cycles and tick count). Should be called after inlining is complete.
9054 // (We do this after inlining because this marks the last point at which the JIT is likely to cause
9055 // type-loading and class initialization).
9056 void RecordStateAtEndOfInlining();
9057 // Assumes being called at the end of compilation. Update the SQM state.
9058 void RecordStateAtEndOfCompilation();
9060 #ifdef FEATURE_CLRSQM
9061 // Does anything SQM related necessary at process shutdown time.
9062 static void ProcessShutdownSQMWork(ICorStaticInfo* statInfo);
9063 #endif // FEATURE_CLRSQM
9066 #if FUNC_INFO_LOGGING
9067 static LPCWSTR compJitFuncInfoFilename; // If a log file for per-function information is required, this is the
9068 // filename to write it to.
9069 static FILE* compJitFuncInfoFile; // And this is the actual FILE* to write to.
9070 #endif // FUNC_INFO_LOGGING
9072 Compiler* prevCompiler; // Previous compiler on stack for TLS Compiler* linked list for reentrant compilers.
9074 // Is the compilation in a full trust context?
9075 bool compIsFullTrust();
9077 #ifndef FEATURE_TRACELOGGING
9078 // Should we actually fire the noway assert body and the exception handler?
9079 bool compShouldThrowOnNoway();
9080 #else // FEATURE_TRACELOGGING
9081 // Should we actually fire the noway assert body and the exception handler?
9082 bool compShouldThrowOnNoway(const char* filename, unsigned line);
9084 // Telemetry instance to use per method compilation.
9085 JitTelemetry compJitTelemetry;
9087 // Get common parameters that have to be logged with most telemetry data.
9088 void compGetTelemetryDefaults(const char** assemblyName,
9089 const char** scopeName,
9090 const char** methodName,
9091 unsigned* methodHash);
9092 #endif // !FEATURE_TRACELOGGING
9096 NodeToTestDataMap* m_nodeTestData;
9098 static const unsigned FIRST_LOOP_HOIST_CSE_CLASS = 1000;
9099 unsigned m_loopHoistCSEClass; // LoopHoist test annotations turn into CSE requirements; we
9100 // label them with CSE Class #'s starting at FIRST_LOOP_HOIST_CSE_CLASS.
9101 // Current kept in this.
9103 NodeToTestDataMap* GetNodeTestData()
9105 Compiler* compRoot = impInlineRoot();
9106 if (compRoot->m_nodeTestData == nullptr)
9108 compRoot->m_nodeTestData = new (getAllocatorDebugOnly()) NodeToTestDataMap(getAllocatorDebugOnly());
9110 return compRoot->m_nodeTestData;
9113 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, int, JitSimplerHashBehavior> NodeToIntMap;
9115 // Returns the set (i.e., the domain of the result map) of nodes that are keys in m_nodeTestData, and
9116 // currently occur in the AST graph.
9117 NodeToIntMap* FindReachableNodesInNodeTestData();
9119 // Node "from" is being eliminated, and being replaced by node "to". If "from" had any associated
9120 // test data, associate that data with "to".
9121 void TransferTestDataToNode(GenTreePtr from, GenTreePtr to);
9123 // Requires that "to" is a clone of "from". If any nodes in the "from" tree
9124 // have annotations, attach similar annotations to the corresponding nodes in "to".
9125 void CopyTestDataToCloneTree(GenTreePtr from, GenTreePtr to);
9127 // These are the methods that test that the various conditions implied by the
9128 // test attributes are satisfied.
9129 void JitTestCheckSSA(); // SSA builder tests.
9130 void JitTestCheckVN(); // Value numbering tests.
9133 // The "FieldSeqStore", for canonicalizing field sequences. See the definition of FieldSeqStore for
9135 FieldSeqStore* m_fieldSeqStore;
9137 FieldSeqStore* GetFieldSeqStore()
9139 Compiler* compRoot = impInlineRoot();
9140 if (compRoot->m_fieldSeqStore == nullptr)
9142 // Create a CompAllocator that labels sub-structure with CMK_FieldSeqStore, and use that for allocation.
9143 IAllocator* ialloc = new (this, CMK_FieldSeqStore) CompAllocator(this, CMK_FieldSeqStore);
9144 compRoot->m_fieldSeqStore = new (ialloc) FieldSeqStore(ialloc);
9146 return compRoot->m_fieldSeqStore;
9149 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, FieldSeqNode*, JitSimplerHashBehavior> NodeToFieldSeqMap;
9151 // Some nodes of "TYP_BYREF" or "TYP_I_IMPL" actually represent the address of a field within a struct, but since
9152 // the offset of the field is zero, there's no "GT_ADD" node. We normally attach a field sequence to the constant
9153 // that is added, but what do we do when that constant is zero, and is thus not present? We use this mechanism to
9154 // attach the field sequence directly to the address node.
9155 NodeToFieldSeqMap* m_zeroOffsetFieldMap;
9157 NodeToFieldSeqMap* GetZeroOffsetFieldMap()
9159 // Don't need to worry about inlining here
9160 if (m_zeroOffsetFieldMap == nullptr)
9162 // Create a CompAllocator that labels sub-structure with CMK_ZeroOffsetFieldMap, and use that for
9164 IAllocator* ialloc = new (this, CMK_ZeroOffsetFieldMap) CompAllocator(this, CMK_ZeroOffsetFieldMap);
9165 m_zeroOffsetFieldMap = new (ialloc) NodeToFieldSeqMap(ialloc);
9167 return m_zeroOffsetFieldMap;
9170 // Requires that "op1" is a node of type "TYP_BYREF" or "TYP_I_IMPL". We are dereferencing this with the fields in
9171 // "fieldSeq", whose offsets are required all to be zero. Ensures that any field sequence annotation currently on
9172 // "op1" or its components is augmented by appending "fieldSeq". In practice, if "op1" is a GT_LCL_FLD, it has
9173 // a field sequence as a member; otherwise, it may be the addition of an a byref and a constant, where the const
9174 // has a field sequence -- in this case "fieldSeq" is appended to that of the constant; otherwise, we
9175 // record the the field sequence using the ZeroOffsetFieldMap described above.
9177 // One exception above is that "op1" is a node of type "TYP_REF" where "op1" is a GT_LCL_VAR.
9178 // This happens when System.Object vtable pointer is a regular field at offset 0 in System.Private.CoreLib in
9179 // CoreRT. Such case is handled same as the default case.
9180 void fgAddFieldSeqForZeroOffset(GenTreePtr op1, FieldSeqNode* fieldSeq);
9182 typedef SimplerHashTable<const GenTree*, PtrKeyFuncs<GenTree>, ArrayInfo, JitSimplerHashBehavior>
9184 NodeToArrayInfoMap* m_arrayInfoMap;
9186 NodeToArrayInfoMap* GetArrayInfoMap()
9188 Compiler* compRoot = impInlineRoot();
9189 if (compRoot->m_arrayInfoMap == nullptr)
9191 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9192 IAllocator* ialloc = new (this, CMK_ArrayInfoMap) CompAllocator(this, CMK_ArrayInfoMap);
9193 compRoot->m_arrayInfoMap = new (ialloc) NodeToArrayInfoMap(ialloc);
9195 return compRoot->m_arrayInfoMap;
9198 NodeToUnsignedMap* m_memorySsaMap[MemoryKindCount];
9200 // In some cases, we want to assign intermediate SSA #'s to memory states, and know what nodes create those memory
9201 // states. (We do this for try blocks, where, if the try block doesn't do a call that loses track of the memory
9202 // state, all the possible memory states are possible initial states of the corresponding catch block(s).)
9203 NodeToUnsignedMap* GetMemorySsaMap(MemoryKind memoryKind)
9205 if (memoryKind == GcHeap && byrefStatesMatchGcHeapStates)
9207 // Use the same map for GCHeap and ByrefExposed when their states match.
9208 memoryKind = ByrefExposed;
9211 assert(memoryKind < MemoryKindCount);
9212 Compiler* compRoot = impInlineRoot();
9213 if (compRoot->m_memorySsaMap[memoryKind] == nullptr)
9215 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9216 IAllocator* ialloc = new (this, CMK_ArrayInfoMap) CompAllocator(this, CMK_ArrayInfoMap);
9217 compRoot->m_memorySsaMap[memoryKind] = new (ialloc) NodeToUnsignedMap(ialloc);
9219 return compRoot->m_memorySsaMap[memoryKind];
9222 // The Refany type is the only struct type whose structure is implicitly assumed by IL. We need its fields.
9223 CORINFO_CLASS_HANDLE m_refAnyClass;
9224 CORINFO_FIELD_HANDLE GetRefanyDataField()
9226 if (m_refAnyClass == nullptr)
9228 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9230 return info.compCompHnd->getFieldInClass(m_refAnyClass, 0);
9232 CORINFO_FIELD_HANDLE GetRefanyTypeField()
9234 if (m_refAnyClass == nullptr)
9236 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9238 return info.compCompHnd->getFieldInClass(m_refAnyClass, 1);
9242 static BitSetSupport::BitSetOpCounter m_varsetOpCounter;
9244 #if ALLVARSET_COUNTOPS
9245 static BitSetSupport::BitSetOpCounter m_allvarsetOpCounter;
9248 static HelperCallProperties s_helperCallProperties;
9250 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
9251 static var_types GetTypeFromClassificationAndSizes(SystemVClassificationType classType, int size);
9252 static var_types GetEightByteType(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9254 static void GetStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9257 unsigned __int8* offset0,
9258 unsigned __int8* offset1);
9259 void fgMorphSystemVStructArgs(GenTreeCall* call, bool hasStructArgument);
9260 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
9262 void fgMorphMultiregStructArgs(GenTreeCall* call);
9263 GenTreePtr fgMorphMultiregStructArg(GenTreePtr arg, fgArgTabEntryPtr fgEntryPtr);
9265 }; // end of class Compiler
9267 // Inline methods of CompAllocator.
9268 void* CompAllocator::Alloc(size_t sz)
9270 #if MEASURE_MEM_ALLOC
9271 return m_comp->compGetMem(sz, m_cmk);
9273 return m_comp->compGetMem(sz);
9277 void* CompAllocator::ArrayAlloc(size_t elems, size_t elemSize)
9279 #if MEASURE_MEM_ALLOC
9280 return m_comp->compGetMemArray(elems, elemSize, m_cmk);
9282 return m_comp->compGetMemArray(elems, elemSize);
9286 // LclVarDsc constructor. Uses Compiler, so must come after Compiler definition.
9287 inline LclVarDsc::LclVarDsc(Compiler* comp)
9288 : // Initialize the ArgRegs to REG_STK.
9289 // The morph will do the right thing to change
9290 // to the right register if passed in register.
9293 #if FEATURE_MULTIREG_ARGS
9294 _lvOtherArgReg(REG_STK)
9296 #endif // FEATURE_MULTIREG_ARGS
9298 lvRefBlks(BlockSetOps::UninitVal())
9300 #endif // ASSERTION_PROP
9301 lvPerSsaData(comp->getAllocator())
9306 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9307 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9309 XX Miscellaneous Compiler stuff XX
9311 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9312 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9315 // Values used to mark the types a stack slot is used for
9317 const unsigned TYPE_REF_INT = 0x01; // slot used as a 32-bit int
9318 const unsigned TYPE_REF_LNG = 0x02; // slot used as a 64-bit long
9319 const unsigned TYPE_REF_FLT = 0x04; // slot used as a 32-bit float
9320 const unsigned TYPE_REF_DBL = 0x08; // slot used as a 64-bit float
9321 const unsigned TYPE_REF_PTR = 0x10; // slot used as a 32-bit pointer
9322 const unsigned TYPE_REF_BYR = 0x20; // slot used as a byref pointer
9323 const unsigned TYPE_REF_STC = 0x40; // slot used as a struct
9324 const unsigned TYPE_REF_TYPEMASK = 0x7F; // bits that represent the type
9326 // const unsigned TYPE_REF_ADDR_TAKEN = 0x80; // slots address was taken
9328 /*****************************************************************************
9330 * Variables to keep track of total code amounts.
9335 extern size_t grossVMsize;
9336 extern size_t grossNCsize;
9337 extern size_t totalNCsize;
9339 extern unsigned genMethodICnt;
9340 extern unsigned genMethodNCnt;
9341 extern size_t gcHeaderISize;
9342 extern size_t gcPtrMapISize;
9343 extern size_t gcHeaderNSize;
9344 extern size_t gcPtrMapNSize;
9346 #endif // DISPLAY_SIZES
9348 /*****************************************************************************
9350 * Variables to keep track of basic block counts (more data on 1 BB methods)
9353 #if COUNT_BASIC_BLOCKS
9354 extern Histogram bbCntTable;
9355 extern Histogram bbOneBBSizeTable;
9358 /*****************************************************************************
9360 * Used by optFindNaturalLoops to gather statistical information such as
9361 * - total number of natural loops
9362 * - number of loops with 1, 2, ... exit conditions
9363 * - number of loops that have an iterator (for like)
9364 * - number of loops that have a constant iterator
9369 extern unsigned totalLoopMethods; // counts the total number of methods that have natural loops
9370 extern unsigned maxLoopsPerMethod; // counts the maximum number of loops a method has
9371 extern unsigned totalLoopOverflows; // # of methods that identified more loops than we can represent
9372 extern unsigned totalLoopCount; // counts the total number of natural loops
9373 extern unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
9374 extern unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
9375 extern unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
9376 extern unsigned simpleTestLoopCount; // counts the # of loops with an iterator and a simple loop condition (iter <
9378 extern unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
9379 extern bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
9380 extern unsigned loopsThisMethod; // counts the number of loops in the current method
9381 extern bool loopOverflowThisMethod; // True if we exceeded the max # of loops in the method.
9382 extern Histogram loopCountTable; // Histogram of loop counts
9383 extern Histogram loopExitCountTable; // Histogram of loop exit counts
9385 #endif // COUNT_LOOPS
9387 /*****************************************************************************
9388 * variables to keep track of how many iterations we go in a dataflow pass
9393 extern unsigned CSEiterCount; // counts the # of iteration for the CSE dataflow
9394 extern unsigned CFiterCount; // counts the # of iteration for the Const Folding dataflow
9396 #endif // DATAFLOW_ITER
9398 #if MEASURE_BLOCK_SIZE
9399 extern size_t genFlowNodeSize;
9400 extern size_t genFlowNodeCnt;
9401 #endif // MEASURE_BLOCK_SIZE
9403 #if MEASURE_NODE_SIZE
9404 struct NodeSizeStats
9409 genTreeNodeSize = 0;
9410 genTreeNodeActualSize = 0;
9413 size_t genTreeNodeCnt;
9414 size_t genTreeNodeSize; // The size we allocate
9415 size_t genTreeNodeActualSize; // The actual size of the node. Note that the actual size will likely be smaller
9416 // than the allocated size, but we sometimes use SetOper()/ChangeOper() to change
9417 // a smaller node to a larger one. TODO-Cleanup: add stats on
9418 // SetOper()/ChangeOper() usage to quanitfy this.
9420 extern NodeSizeStats genNodeSizeStats; // Total node size stats
9421 extern NodeSizeStats genNodeSizeStatsPerFunc; // Per-function node size stats
9422 extern Histogram genTreeNcntHist;
9423 extern Histogram genTreeNsizHist;
9424 #endif // MEASURE_NODE_SIZE
9426 /*****************************************************************************
9427 * Count fatal errors (including noway_asserts).
9431 extern unsigned fatal_badCode;
9432 extern unsigned fatal_noWay;
9433 extern unsigned fatal_NOMEM;
9434 extern unsigned fatal_noWayAssertBody;
9436 extern unsigned fatal_noWayAssertBodyArgs;
9438 extern unsigned fatal_NYI;
9439 #endif // MEASURE_FATAL
9441 /*****************************************************************************
9445 #ifdef _TARGET_XARCH_
9447 const instruction INS_SHIFT_LEFT_LOGICAL = INS_shl;
9448 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_shr;
9449 const instruction INS_SHIFT_RIGHT_ARITHM = INS_sar;
9451 const instruction INS_AND = INS_and;
9452 const instruction INS_OR = INS_or;
9453 const instruction INS_XOR = INS_xor;
9454 const instruction INS_NEG = INS_neg;
9455 const instruction INS_TEST = INS_test;
9456 const instruction INS_MUL = INS_imul;
9457 const instruction INS_SIGNED_DIVIDE = INS_idiv;
9458 const instruction INS_UNSIGNED_DIVIDE = INS_div;
9459 const instruction INS_BREAKPOINT = INS_int3;
9460 const instruction INS_ADDC = INS_adc;
9461 const instruction INS_SUBC = INS_sbb;
9462 const instruction INS_NOT = INS_not;
9468 const instruction INS_SHIFT_LEFT_LOGICAL = INS_lsl;
9469 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_lsr;
9470 const instruction INS_SHIFT_RIGHT_ARITHM = INS_asr;
9472 const instruction INS_AND = INS_and;
9473 const instruction INS_OR = INS_orr;
9474 const instruction INS_XOR = INS_eor;
9475 const instruction INS_NEG = INS_rsb;
9476 const instruction INS_TEST = INS_tst;
9477 const instruction INS_MUL = INS_mul;
9478 const instruction INS_SIGNED_DIVIDE = INS_sdiv;
9479 const instruction INS_UNSIGNED_DIVIDE = INS_udiv;
9480 const instruction INS_BREAKPOINT = INS_bkpt;
9481 const instruction INS_ADDC = INS_adc;
9482 const instruction INS_SUBC = INS_sbc;
9483 const instruction INS_NOT = INS_mvn;
9485 const instruction INS_ABS = INS_vabs;
9486 const instruction INS_ROUND = INS_invalid;
9487 const instruction INS_SQRT = INS_vsqrt;
9491 #ifdef _TARGET_ARM64_
9493 const instruction INS_SHIFT_LEFT_LOGICAL = INS_lsl;
9494 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_lsr;
9495 const instruction INS_SHIFT_RIGHT_ARITHM = INS_asr;
9497 const instruction INS_AND = INS_and;
9498 const instruction INS_OR = INS_orr;
9499 const instruction INS_XOR = INS_eor;
9500 const instruction INS_NEG = INS_neg;
9501 const instruction INS_TEST = INS_tst;
9502 const instruction INS_MUL = INS_mul;
9503 const instruction INS_SIGNED_DIVIDE = INS_sdiv;
9504 const instruction INS_UNSIGNED_DIVIDE = INS_udiv;
9505 const instruction INS_BREAKPOINT = INS_bkpt;
9506 const instruction INS_ADDC = INS_adc;
9507 const instruction INS_SUBC = INS_sbc;
9508 const instruction INS_NOT = INS_mvn;
9510 const instruction INS_ABS = INS_fabs;
9511 const instruction INS_ROUND = INS_frintn;
9512 const instruction INS_SQRT = INS_fsqrt;
9516 /*****************************************************************************/
9518 extern const BYTE genTypeSizes[];
9519 extern const BYTE genTypeAlignments[];
9520 extern const BYTE genTypeStSzs[];
9521 extern const BYTE genActualTypes[];
9523 /*****************************************************************************/
9525 // VERY_LARGE_FRAME_SIZE_REG_MASK is the set of registers we need to use for
9526 // the probing loop generated for very large stack frames (see `getVeryLargeFrameSize`).
9529 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R4 | RBM_R5 | RBM_R6)
9530 #elif defined(_TARGET_ARM64_)
9531 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R9 | RBM_R10 | RBM_R11)
9534 /*****************************************************************************/
9536 #define REG_CORRUPT regNumber(REG_NA + 1)
9537 #define RBM_CORRUPT (RBM_ILLEGAL | regMaskTP(1))
9538 #define REG_PAIR_CORRUPT regPairNo(REG_PAIR_NONE + 1)
9540 /*****************************************************************************/
9542 extern BasicBlock dummyBB;
9544 /*****************************************************************************/
9545 /*****************************************************************************/
9547 // foreach_treenode_execution_order: An iterator that iterates through all the tree
9548 // nodes of a statement in execution order.
9549 // __stmt: a GT_STMT type GenTree*
9550 // __node: a GenTree*, already declared, that gets updated with each node in the statement, in execution order
9552 #define foreach_treenode_execution_order(__node, __stmt) \
9553 for ((__node) = (__stmt)->gtStmt.gtStmtList; (__node); (__node) = (__node)->gtNext)
9555 // foreach_block: An iterator over all blocks in the function.
9556 // __compiler: the Compiler* object
9557 // __block : a BasicBlock*, already declared, that gets updated each iteration.
9559 #define foreach_block(__compiler, __block) \
9560 for ((__block) = (__compiler)->fgFirstBB; (__block); (__block) = (__block)->bbNext)
9562 /*****************************************************************************/
9563 /*****************************************************************************/
9567 void dumpConvertedVarSet(Compiler* comp, VARSET_VALARG_TP vars);
9569 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9570 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9572 XX Debugging helpers XX
9574 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9575 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9578 /*****************************************************************************/
9579 /* The following functions are intended to be called from the debugger, to dump
9580 * various data structures. The can be used in the debugger Watch or Quick Watch
9581 * windows. They are designed to be short to type and take as few arguments as
9582 * possible. The 'c' versions take a Compiler*, whereas the 'd' versions use the TlsCompiler.
9583 * See the function definition comment for more details.
9586 void cBlock(Compiler* comp, BasicBlock* block);
9587 void cBlocks(Compiler* comp);
9588 void cBlocksV(Compiler* comp);
9589 void cTree(Compiler* comp, GenTree* tree);
9590 void cTrees(Compiler* comp);
9591 void cEH(Compiler* comp);
9592 void cVar(Compiler* comp, unsigned lclNum);
9593 void cVarDsc(Compiler* comp, LclVarDsc* varDsc);
9594 void cVars(Compiler* comp);
9595 void cVarsFinal(Compiler* comp);
9596 void cBlockPreds(Compiler* comp, BasicBlock* block);
9597 void cReach(Compiler* comp);
9598 void cDoms(Compiler* comp);
9599 void cLiveness(Compiler* comp);
9600 void cCVarSet(Compiler* comp, VARSET_VALARG_TP vars);
9602 void cFuncIR(Compiler* comp);
9603 void cBlockIR(Compiler* comp, BasicBlock* block);
9604 void cLoopIR(Compiler* comp, Compiler::LoopDsc* loop);
9605 void cTreeIR(Compiler* comp, GenTree* tree);
9606 int cTreeTypeIR(Compiler* comp, GenTree* tree);
9607 int cTreeKindsIR(Compiler* comp, GenTree* tree);
9608 int cTreeFlagsIR(Compiler* comp, GenTree* tree);
9609 int cOperandIR(Compiler* comp, GenTree* operand);
9610 int cLeafIR(Compiler* comp, GenTree* tree);
9611 int cIndirIR(Compiler* comp, GenTree* tree);
9612 int cListIR(Compiler* comp, GenTree* list);
9613 int cSsaNumIR(Compiler* comp, GenTree* tree);
9614 int cValNumIR(Compiler* comp, GenTree* tree);
9615 int cDependsIR(Compiler* comp, GenTree* comma, bool* first);
9617 void dBlock(BasicBlock* block);
9620 void dTree(GenTree* tree);
9623 void dVar(unsigned lclNum);
9624 void dVarDsc(LclVarDsc* varDsc);
9627 void dBlockPreds(BasicBlock* block);
9631 void dCVarSet(VARSET_VALARG_TP vars);
9633 void dVarSet(VARSET_VALARG_TP vars);
9634 void dRegMask(regMaskTP mask);
9637 void dBlockIR(BasicBlock* block);
9638 void dTreeIR(GenTree* tree);
9639 void dLoopIR(Compiler::LoopDsc* loop);
9640 void dLoopNumIR(unsigned loopNum);
9641 int dTabStopIR(int curr, int tabstop);
9642 int dTreeTypeIR(GenTree* tree);
9643 int dTreeKindsIR(GenTree* tree);
9644 int dTreeFlagsIR(GenTree* tree);
9645 int dOperandIR(GenTree* operand);
9646 int dLeafIR(GenTree* tree);
9647 int dIndirIR(GenTree* tree);
9648 int dListIR(GenTree* list);
9649 int dSsaNumIR(GenTree* tree);
9650 int dValNumIR(GenTree* tree);
9651 int dDependsIR(GenTree* comma);
9654 GenTree* dFindTree(GenTree* tree, unsigned id);
9655 GenTree* dFindTree(unsigned id);
9656 GenTreeStmt* dFindStmt(unsigned id);
9657 BasicBlock* dFindBlock(unsigned bbNum);
9661 #include "compiler.hpp" // All the shared inline functions
9663 /*****************************************************************************/
9664 #endif //_COMPILER_H_
9665 /*****************************************************************************/