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 lvArgWrite : 1; // variable is a parameter and STARG was used on it
256 unsigned char lvIsTemp : 1; // Short-lifetime compiler temp
258 unsigned char lvIsBoolean : 1; // set if variable is boolean
260 unsigned char lvRngOptDone : 1; // considered for range check opt?
261 unsigned char lvLoopInc : 1; // incremented in the loop?
262 unsigned char lvLoopAsg : 1; // reassigned in the loop (other than a monotonic inc/dec for the index var)?
263 unsigned char lvArrIndx : 1; // used as an array index?
264 unsigned char lvArrIndxOff : 1; // used as an array index with an offset?
265 unsigned char lvArrIndxDom : 1; // index dominates loop exit
267 unsigned char lvSingleDef : 1; // variable has a single def
268 unsigned char lvDisqualify : 1; // variable is no longer OK for add copy optimization
269 unsigned char lvVolatileHint : 1; // hint for AssertionProp
272 unsigned char lvSpilled : 1; // enregistered variable was spilled
273 #ifndef _TARGET_64BIT_
274 unsigned char lvStructDoubleAlign : 1; // Must we double align this struct?
275 #endif // !_TARGET_64BIT_
276 #ifdef _TARGET_64BIT_
277 unsigned char lvQuirkToLong : 1; // Quirk to allocate this LclVar as a 64-bit long
280 unsigned char lvKeepType : 1; // Don't change the type of this variable
281 unsigned char lvNoLclFldStress : 1; // Can't apply local field stress on this one
283 unsigned char lvIsPtr : 1; // Might this be used in an address computation? (used by buffer overflow security
285 unsigned char lvIsUnsafeBuffer : 1; // Does this contain an unsafe buffer requiring buffer overflow security checks?
286 unsigned char lvPromoted : 1; // True when this local is a promoted struct, a normed struct, or a "split" long on a
288 unsigned char lvIsStructField : 1; // Is this local var a field of a promoted struct local?
289 unsigned char lvContainsFloatingFields : 1; // Does this struct contains floating point fields?
290 unsigned char lvOverlappingFields : 1; // True when we have a struct with possibly overlapping fields
291 unsigned char lvContainsHoles : 1; // True when we have a promoted struct that contains holes
292 unsigned char lvCustomLayout : 1; // True when this struct has "CustomLayout"
294 unsigned char lvIsMultiRegArg : 1; // true if this is a multireg LclVar struct used in an argument context
295 unsigned char lvIsMultiRegRet : 1; // true if this is a multireg LclVar struct assigned from a multireg call
298 unsigned char _lvIsHfa : 1; // Is this a struct variable who's class handle is an HFA type
299 unsigned char _lvIsHfaRegArg : 1; // Is this a HFA argument variable? // TODO-CLEANUP: Remove this and replace
300 // with (lvIsRegArg && lvIsHfa())
301 unsigned char _lvHfaTypeIsFloat : 1; // Is the HFA type float or double?
302 #endif // FEATURE_HFA
305 // TODO-Cleanup: See the note on lvSize() - this flag is only in use by asserts that are checking for struct
306 // types, and is needed because of cases where TYP_STRUCT is bashed to an integral type.
307 // Consider cleaning this up so this workaround is not required.
308 unsigned char lvUnusedStruct : 1; // All references to this promoted struct are through its field locals.
309 // I.e. there is no longer any reference to the struct directly.
310 // In this case we can simply remove this struct local.
312 #ifndef LEGACY_BACKEND
313 unsigned char lvLRACandidate : 1; // Tracked for linear scan register allocation purposes
314 #endif // !LEGACY_BACKEND
317 // Note that both SIMD vector args and locals are marked as lvSIMDType = true, but the
318 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD*.
319 unsigned char lvSIMDType : 1; // This is a SIMD struct
320 unsigned char lvUsedInSIMDIntrinsic : 1; // This tells lclvar is used for simd intrinsic
321 var_types lvBaseType : 5; // Note: this only packs because var_types is a typedef of unsigned char
322 #endif // FEATURE_SIMD
323 unsigned char lvRegStruct : 1; // This is a reg-sized non-field-addressed struct.
326 unsigned lvFieldLclStart; // The index of the local var representing the first field in the promoted struct
328 unsigned lvParentLcl; // The index of the local var representing the parent (i.e. the promoted struct local).
329 // Valid on promoted struct local fields.
332 unsigned char lvFieldCnt; // Number of fields in the promoted VarDsc.
333 unsigned char lvFldOffset;
334 unsigned char lvFldOrdinal;
336 #if FEATURE_MULTIREG_ARGS
337 regNumber lvRegNumForSlot(unsigned slotNum)
343 else if (slotNum == 1)
345 return lvOtherArgReg;
349 assert(false && "Invalid slotNum!");
354 #endif // FEATURE_MULTIREG_ARGS
372 bool lvIsHfaRegArg() const
375 return _lvIsHfaRegArg;
381 void lvSetIsHfaRegArg()
384 _lvIsHfaRegArg = true;
388 bool lvHfaTypeIsFloat() const
391 return _lvHfaTypeIsFloat;
397 void lvSetHfaTypeIsFloat(bool value)
400 _lvHfaTypeIsFloat = value;
404 // on Arm64 - Returns 1-4 indicating the number of register slots used by the HFA
405 // on Arm32 - Returns the total number of single FP register slots used by the HFA, max is 8
407 unsigned lvHfaSlots() const
410 assert(lvType == TYP_STRUCT);
412 return lvExactSize / sizeof(float);
413 #else // _TARGET_ARM64_
414 if (lvHfaTypeIsFloat())
416 return lvExactSize / sizeof(float);
420 return lvExactSize / sizeof(double);
422 #endif // _TARGET_ARM64_
425 // lvIsMultiRegArgOrRet()
426 // returns true if this is a multireg LclVar struct used in an argument context
427 // or if this is a multireg LclVar struct assigned from a multireg call
428 bool lvIsMultiRegArgOrRet()
430 return lvIsMultiRegArg || lvIsMultiRegRet;
434 regNumberSmall _lvRegNum; // Used to store the register this variable is in (or, the low register of a
435 // register pair). For LEGACY_BACKEND, this is only set if lvRegister is
436 // non-zero. For non-LEGACY_BACKEND, it is set during codegen any time the
437 // variable is enregistered (in non-LEGACY_BACKEND, lvRegister is only set
438 // to non-zero if the variable gets the same register assignment for its entire
440 #if !defined(_TARGET_64BIT_)
441 regNumberSmall _lvOtherReg; // Used for "upper half" of long var.
442 #endif // !defined(_TARGET_64BIT_)
444 regNumberSmall _lvArgReg; // The register in which this argument is passed.
446 #if FEATURE_MULTIREG_ARGS
447 regNumberSmall _lvOtherArgReg; // Used for the second part of the struct passed in a register.
448 // Note this is defined but not used by ARM32
449 #endif // FEATURE_MULTIREG_ARGS
451 #ifndef LEGACY_BACKEND
453 regNumberSmall _lvArgInitReg; // the register into which the argument is moved at entry
454 regPairNoSmall _lvArgInitRegPair; // the register pair into which the argument is moved at entry
456 #endif // !LEGACY_BACKEND
459 // The register number is stored in a small format (8 bits), but the getters return and the setters take
460 // a full-size (unsigned) format, to localize the casts here.
462 /////////////////////
464 __declspec(property(get = GetRegNum, put = SetRegNum)) regNumber lvRegNum;
466 regNumber GetRegNum() const
468 return (regNumber)_lvRegNum;
471 void SetRegNum(regNumber reg)
473 _lvRegNum = (regNumberSmall)reg;
474 assert(_lvRegNum == reg);
477 /////////////////////
479 #if defined(_TARGET_64BIT_)
480 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
482 regNumber GetOtherReg() const
484 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
485 // "unreachable code" warnings
489 void SetOtherReg(regNumber reg)
491 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
492 // "unreachable code" warnings
494 #else // !_TARGET_64BIT_
495 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
497 regNumber GetOtherReg() const
499 return (regNumber)_lvOtherReg;
502 void SetOtherReg(regNumber reg)
504 _lvOtherReg = (regNumberSmall)reg;
505 assert(_lvOtherReg == reg);
507 #endif // !_TARGET_64BIT_
509 /////////////////////
511 __declspec(property(get = GetArgReg, put = SetArgReg)) regNumber lvArgReg;
513 regNumber GetArgReg() const
515 return (regNumber)_lvArgReg;
518 void SetArgReg(regNumber reg)
520 _lvArgReg = (regNumberSmall)reg;
521 assert(_lvArgReg == reg);
524 #if FEATURE_MULTIREG_ARGS
525 __declspec(property(get = GetOtherArgReg, put = SetOtherArgReg)) regNumber lvOtherArgReg;
527 regNumber GetOtherArgReg() const
529 return (regNumber)_lvOtherArgReg;
532 void SetOtherArgReg(regNumber reg)
534 _lvOtherArgReg = (regNumberSmall)reg;
535 assert(_lvOtherArgReg == reg);
537 #endif // FEATURE_MULTIREG_ARGS
540 // Is this is a SIMD struct?
541 bool lvIsSIMDType() const
546 // Is this is a SIMD struct which is used for SIMD intrinsic?
547 bool lvIsUsedInSIMDIntrinsic() const
549 return lvUsedInSIMDIntrinsic;
552 // If feature_simd not enabled, return false
553 bool lvIsSIMDType() const
557 bool lvIsUsedInSIMDIntrinsic() const
563 /////////////////////
565 #ifndef LEGACY_BACKEND
566 __declspec(property(get = GetArgInitReg, put = SetArgInitReg)) regNumber lvArgInitReg;
568 regNumber GetArgInitReg() const
570 return (regNumber)_lvArgInitReg;
573 void SetArgInitReg(regNumber reg)
575 _lvArgInitReg = (regNumberSmall)reg;
576 assert(_lvArgInitReg == reg);
579 /////////////////////
581 __declspec(property(get = GetArgInitRegPair, put = SetArgInitRegPair)) regPairNo lvArgInitRegPair;
583 regPairNo GetArgInitRegPair() const
585 regPairNo regPair = (regPairNo)_lvArgInitRegPair;
586 assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
590 void SetArgInitRegPair(regPairNo regPair)
592 assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
593 _lvArgInitRegPair = (regPairNoSmall)regPair;
594 assert(_lvArgInitRegPair == regPair);
597 /////////////////////
599 bool lvIsRegCandidate() const
601 return lvLRACandidate != 0;
604 bool lvIsInReg() const
606 return lvIsRegCandidate() && (lvRegNum != REG_STK);
609 #else // LEGACY_BACKEND
611 bool lvIsRegCandidate() const
613 return lvTracked != 0;
616 bool lvIsInReg() const
618 return lvRegister != 0;
621 #endif // LEGACY_BACKEND
623 regMaskTP lvRegMask() const
625 regMaskTP regMask = RBM_NONE;
626 if (varTypeIsFloating(TypeGet()))
628 if (lvRegNum != REG_STK)
630 regMask = genRegMaskFloat(lvRegNum, TypeGet());
635 if (lvRegNum != REG_STK)
637 regMask = genRegMask(lvRegNum);
640 // For longs we may have two regs
641 if (isRegPairType(lvType) && lvOtherReg != REG_STK)
643 regMask |= genRegMask(lvOtherReg);
649 regMaskSmall lvPrefReg; // set of regs it prefers to live in
651 unsigned short lvVarIndex; // variable tracking index
652 unsigned short lvRefCnt; // unweighted (real) reference count
653 unsigned lvRefCntWtd; // weighted reference count
654 int lvStkOffs; // stack offset of home
655 unsigned lvExactSize; // (exact) size of the type in bytes
657 // Is this a promoted struct?
658 // This method returns true only for structs (including SIMD structs), not for
659 // locals that are split on a 32-bit target.
660 // It is only necessary to use this:
661 // 1) if only structs are wanted, and
662 // 2) if Lowering has already been done.
663 // Otherwise lvPromoted is valid.
664 bool lvPromotedStruct()
666 #if !defined(_TARGET_64BIT_)
667 return (lvPromoted && !varTypeIsLong(lvType));
668 #else // defined(_TARGET_64BIT_)
670 #endif // defined(_TARGET_64BIT_)
673 unsigned lvSize() const // Size needed for storage representation. Only used for structs or TYP_BLK.
675 // TODO-Review: Sometimes we get called on ARM with HFA struct variables that have been promoted,
676 // where the struct itself is no longer used because all access is via its member fields.
677 // When that happens, the struct is marked as unused and its type has been changed to
678 // TYP_INT (to keep the GC tracking code from looking at it).
679 // See Compiler::raAssignVars() for details. For example:
680 // N002 ( 4, 3) [00EA067C] ------------- return struct $346
681 // N001 ( 3, 2) [00EA0628] ------------- lclVar struct(U) V03 loc2
682 // float V03.f1 (offs=0x00) -> V12 tmp7
683 // f8 (last use) (last use) $345
684 // Here, the "struct(U)" shows that the "V03 loc2" variable is unused. Not shown is that V03
685 // is now TYP_INT in the local variable table. It's not really unused, because it's in the tree.
687 assert(varTypeIsStruct(lvType) || (lvType == TYP_BLK) || (lvPromoted && lvUnusedStruct));
689 #if defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
690 // For 32-bit architectures, we make local variable SIMD12 types 16 bytes instead of just 12. We can't do
691 // this for arguments, which must be passed according the defined ABI. We don't want to do this for
692 // dependently promoted struct fields, but we don't know that here. See lvaMapSimd12ToSimd16().
693 if ((lvType == TYP_SIMD12) && !lvIsParam)
695 assert(lvExactSize == 12);
698 #endif // defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
700 return (unsigned)(roundUp(lvExactSize, TARGET_POINTER_SIZE));
703 unsigned lvSlotNum; // original slot # (if remapped)
705 typeInfo lvVerTypeInfo; // type info needed for verification
707 BYTE* lvGcLayout; // GC layout info for structs
710 BlockSet lvRefBlks; // Set of blocks that contain refs
711 GenTreePtr lvDefStmt; // Pointer to the statement with the single definition
712 void lvaDisqualifyVar(); // Call to disqualify a local variable from use in optAddCopies
714 var_types TypeGet() const
716 return (var_types)lvType;
718 bool lvStackAligned() const
720 assert(lvIsStructField);
721 return ((lvFldOffset % sizeof(void*)) == 0);
723 bool lvNormalizeOnLoad() const
725 return varTypeIsSmall(TypeGet()) &&
726 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
727 (lvIsParam || lvAddrExposed || lvIsStructField);
730 bool lvNormalizeOnStore()
732 return varTypeIsSmall(TypeGet()) &&
733 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
734 !(lvIsParam || lvAddrExposed || lvIsStructField);
737 void lvaResetSortAgainFlag(Compiler* pComp);
738 void decRefCnts(BasicBlock::weight_t weight, Compiler* pComp, bool propagate = true);
739 void incRefCnts(BasicBlock::weight_t weight, Compiler* pComp, bool propagate = true);
740 void setPrefReg(regNumber regNum, Compiler* pComp);
741 void addPrefReg(regMaskTP regMask, Compiler* pComp);
742 bool IsFloatRegType() const
744 return isFloatRegType(lvType) || lvIsHfaRegArg();
746 var_types GetHfaType() const
748 return lvIsHfa() ? (lvHfaTypeIsFloat() ? TYP_FLOAT : TYP_DOUBLE) : TYP_UNDEF;
750 void SetHfaType(var_types type)
752 assert(varTypeIsFloating(type));
753 lvSetHfaTypeIsFloat(type == TYP_FLOAT);
756 #ifndef LEGACY_BACKEND
757 var_types lvaArgType();
760 PerSsaArray lvPerSsaData;
763 // Keep track of the # of SsaNames, for a bounds check.
764 unsigned lvNumSsaNames;
767 // Returns the address of the per-Ssa data for the given ssaNum (which is required
768 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
769 // not an SSA variable).
770 LclSsaVarDsc* GetPerSsaData(unsigned ssaNum)
772 assert(ssaNum != SsaConfig::RESERVED_SSA_NUM);
773 assert(SsaConfig::RESERVED_SSA_NUM == 0);
774 unsigned zeroBased = ssaNum - SsaConfig::UNINIT_SSA_NUM;
775 assert(zeroBased < lvNumSsaNames);
776 return &lvPerSsaData.GetRef(zeroBased);
781 void PrintVarReg() const
783 if (isRegPairType(TypeGet()))
785 printf("%s:%s", getRegName(lvOtherReg), // hi32
786 getRegName(lvRegNum)); // lo32
790 printf("%s", getRegName(lvRegNum));
795 }; // class LclVarDsc
798 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
799 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
803 XX The temporary lclVars allocated by the compiler for code generation XX
805 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
806 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
809 /*****************************************************************************
811 * The following keeps track of temporaries allocated in the stack frame
812 * during code-generation (after register allocation). These spill-temps are
813 * only used if we run out of registers while evaluating a tree.
815 * These are different from the more common temps allocated by lvaGrabTemp().
826 static const int BAD_TEMP_OFFSET = 0xDDDDDDDD; // used as a sentinel "bad value" for tdOffs in DEBUG
834 TempDsc(int _tdNum, unsigned _tdSize, var_types _tdType) : tdNum(_tdNum), tdSize((BYTE)_tdSize), tdType(_tdType)
838 0); // temps must have a negative number (so they have a different number from all local variables)
839 tdOffs = BAD_TEMP_OFFSET;
843 IMPL_LIMITATION("too many spill temps");
848 bool tdLegalOffset() const
850 return tdOffs != BAD_TEMP_OFFSET;
854 int tdTempOffs() const
856 assert(tdLegalOffset());
859 void tdSetTempOffs(int offs)
862 assert(tdLegalOffset());
864 void tdAdjustTempOffs(int offs)
867 assert(tdLegalOffset());
870 int tdTempNum() const
875 unsigned tdTempSize() const
879 var_types tdTempType() const
885 // interface to hide linearscan implementation from rest of compiler
886 class LinearScanInterface
889 virtual void doLinearScan() = 0;
890 virtual void recordVarLocationsAtStartOfBB(BasicBlock* bb) = 0;
893 LinearScanInterface* getLinearScanAllocator(Compiler* comp);
895 // Information about arrays: their element type and size, and the offset of the first element.
896 // We label GT_IND's that are array indices with GTF_IND_ARR_INDEX, and, for such nodes,
897 // associate an array info via the map retrieved by GetArrayInfoMap(). This information is used,
898 // for example, in value numbering of array index expressions.
901 var_types m_elemType;
902 CORINFO_CLASS_HANDLE m_elemStructType;
904 unsigned m_elemOffset;
906 ArrayInfo() : m_elemType(TYP_UNDEF), m_elemStructType(nullptr), m_elemSize(0), m_elemOffset(0)
910 ArrayInfo(var_types elemType, unsigned elemSize, unsigned elemOffset, CORINFO_CLASS_HANDLE elemStructType)
911 : m_elemType(elemType), m_elemStructType(elemStructType), m_elemSize(elemSize), m_elemOffset(elemOffset)
916 // This enumeration names the phases into which we divide compilation. The phases should completely
917 // partition a compilation.
920 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) enum_nm,
921 #include "compphases.h"
925 extern const char* PhaseNames[];
926 extern const char* PhaseEnums[];
927 extern const LPCWSTR PhaseShortNames[];
929 // The following enum provides a simple 1:1 mapping to CLR API's
930 enum API_ICorJitInfo_Names
932 #define DEF_CLR_API(name) API_##name,
933 #include "ICorJitInfo_API_names.h"
937 //---------------------------------------------------------------
941 // A "CompTimeInfo" is a structure for tracking the compilation time of one or more methods.
942 // We divide a compilation into a sequence of contiguous phases, and track the total (per-thread) cycles
943 // of the compilation, as well as the cycles for each phase. We also track the number of bytecodes.
944 // If there is a failure in reading a timer at any point, the "CompTimeInfo" becomes invalid, as indicated
945 // by "m_timerFailure" being true.
946 // If FEATURE_JIT_METHOD_PERF is not set, we define a minimal form of this, enough to let other code compile.
949 #ifdef FEATURE_JIT_METHOD_PERF
950 // The string names of the phases.
951 static const char* PhaseNames[];
953 static bool PhaseHasChildren[];
954 static int PhaseParent[];
955 static bool PhaseReportsIRSize[];
957 unsigned m_byteCodeBytes;
958 unsigned __int64 m_totalCycles;
959 unsigned __int64 m_invokesByPhase[PHASE_NUMBER_OF];
960 unsigned __int64 m_cyclesByPhase[PHASE_NUMBER_OF];
961 #if MEASURE_CLRAPI_CALLS
962 unsigned __int64 m_CLRinvokesByPhase[PHASE_NUMBER_OF];
963 unsigned __int64 m_CLRcyclesByPhase[PHASE_NUMBER_OF];
966 unsigned m_nodeCountAfterPhase[PHASE_NUMBER_OF];
968 // For better documentation, we call EndPhase on
969 // non-leaf phases. We should also call EndPhase on the
970 // last leaf subphase; obviously, the elapsed cycles between the EndPhase
971 // for the last leaf subphase and the EndPhase for an ancestor should be very small.
972 // We add all such "redundant end phase" intervals to this variable below; we print
973 // it out in a report, so we can verify that it is, indeed, very small. If it ever
974 // isn't, this means that we're doing something significant between the end of the last
975 // declared subphase and the end of its parent.
976 unsigned __int64 m_parentPhaseEndSlop;
979 #if MEASURE_CLRAPI_CALLS
980 // The following measures the time spent inside each individual CLR API call.
981 unsigned m_allClrAPIcalls;
982 unsigned m_perClrAPIcalls[API_ICorJitInfo_Names::API_COUNT];
983 unsigned __int64 m_allClrAPIcycles;
984 unsigned __int64 m_perClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
985 unsigned __int32 m_maxClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
986 #endif // MEASURE_CLRAPI_CALLS
988 CompTimeInfo(unsigned byteCodeBytes);
992 #ifdef FEATURE_JIT_METHOD_PERF
994 #if MEASURE_CLRAPI_CALLS
995 struct WrapICorJitInfo;
998 // This class summarizes the JIT time information over the course of a run: the number of methods compiled,
999 // and the total and maximum timings. (These are instances of the "CompTimeInfo" type described above).
1000 // The operation of adding a single method's timing to the summary may be performed concurrently by several
1001 // threads, so it is protected by a lock.
1002 // This class is intended to be used as a singleton type, with only a single instance.
1003 class CompTimeSummaryInfo
1005 // This lock protects the fields of all CompTimeSummaryInfo(s) (of which we expect there to be one).
1006 static CritSecObject s_compTimeSummaryLock;
1010 CompTimeInfo m_total;
1011 CompTimeInfo m_maximum;
1013 int m_numFilteredMethods;
1014 CompTimeInfo m_filtered;
1016 // This method computes the number of cycles/sec for the current machine. The cycles are those counted
1017 // by GetThreadCycleTime; we assume that these are of equal duration, though that is not necessarily true.
1018 // If any OS interaction fails, returns 0.0.
1019 double CyclesPerSecond();
1021 // This can use what ever data you want to determine if the value to be added
1022 // belongs in the filtered section (it's always included in the unfiltered section)
1023 bool IncludedInFilteredData(CompTimeInfo& info);
1026 // This is the unique CompTimeSummaryInfo object for this instance of the runtime.
1027 static CompTimeSummaryInfo s_compTimeSummary;
1029 CompTimeSummaryInfo()
1030 : m_numMethods(0), m_totMethods(0), m_total(0), m_maximum(0), m_numFilteredMethods(0), m_filtered(0)
1034 // Assumes that "info" is a completed CompTimeInfo for a compilation; adds it to the summary.
1035 // This is thread safe.
1036 void AddInfo(CompTimeInfo& info, bool includePhases);
1038 // Print the summary information to "f".
1039 // This is not thread-safe; assumed to be called by only one thread.
1040 void Print(FILE* f);
1043 // A JitTimer encapsulates a CompTimeInfo for a single compilation. It also tracks the start of compilation,
1044 // and when the current phase started. This is intended to be part of a Compilation object. This is
1045 // disabled (FEATURE_JIT_METHOD_PERF not defined) when FEATURE_CORECLR is set, or on non-windows platforms.
1049 unsigned __int64 m_start; // Start of the compilation.
1050 unsigned __int64 m_curPhaseStart; // Start of the current phase.
1051 #if MEASURE_CLRAPI_CALLS
1052 unsigned __int64 m_CLRcallStart; // Start of the current CLR API call (if any).
1053 unsigned __int64 m_CLRcallInvokes; // CLR API invokes under current outer so far
1054 unsigned __int64 m_CLRcallCycles; // CLR API cycles under current outer so far.
1055 int m_CLRcallAPInum; // The enum/index of the current CLR API call (or -1).
1056 static double s_cyclesPerSec; // Cached for speedier measurements
1059 Phases m_lastPhase; // The last phase that was completed (or (Phases)-1 to start).
1061 CompTimeInfo m_info; // The CompTimeInfo for this compilation.
1063 static CritSecObject s_csvLock; // Lock to protect the time log file.
1064 void PrintCsvMethodStats(Compiler* comp);
1067 void* operator new(size_t);
1068 void* operator new[](size_t);
1069 void operator delete(void*);
1070 void operator delete[](void*);
1073 // Initialized the timer instance
1074 JitTimer(unsigned byteCodeSize);
1076 static JitTimer* Create(Compiler* comp, unsigned byteCodeSize)
1078 return ::new (comp, CMK_Unknown) JitTimer(byteCodeSize);
1081 static void PrintCsvHeader();
1083 // Ends the current phase (argument is for a redundant check).
1084 void EndPhase(Compiler* compiler, Phases phase);
1086 #if MEASURE_CLRAPI_CALLS
1087 // Start and end a timed CLR API call.
1088 void CLRApiCallEnter(unsigned apix);
1089 void CLRApiCallLeave(unsigned apix);
1090 #endif // MEASURE_CLRAPI_CALLS
1092 // Completes the timing of the current method, which is assumed to have "byteCodeBytes" bytes of bytecode,
1093 // and adds it to "sum".
1094 void Terminate(Compiler* comp, CompTimeSummaryInfo& sum, bool includePhases);
1096 // Attempts to query the cycle counter of the current thread. If successful, returns "true" and sets
1097 // *cycles to the cycle counter value. Otherwise, returns false and sets the "m_timerFailure" flag of
1098 // "m_info" to true.
1099 bool GetThreadCycles(unsigned __int64* cycles)
1101 bool res = CycleTimer::GetThreadCyclesS(cycles);
1104 m_info.m_timerFailure = true;
1109 #endif // FEATURE_JIT_METHOD_PERF
1111 //------------------- Function/Funclet info -------------------------------
1112 DECLARE_TYPED_ENUM(FuncKind, BYTE)
1114 FUNC_ROOT, // The main/root function (always id==0)
1115 FUNC_HANDLER, // a funclet associated with an EH handler (finally, fault, catch, filter handler)
1116 FUNC_FILTER, // a funclet associated with an EH filter
1119 END_DECLARE_TYPED_ENUM(FuncKind, BYTE)
1126 BYTE funFlags; // Currently unused, just here for padding
1127 unsigned short funEHIndex; // index, into the ebd table, of innermost EH clause corresponding to this
1128 // funclet. It is only valid if funKind field indicates this is a
1129 // EH-related funclet: FUNC_HANDLER or FUNC_FILTER
1131 #if defined(_TARGET_AMD64_)
1133 // TODO-AMD64-Throughput: make the AMD64 info more like the ARM info to avoid having this large static array.
1134 emitLocation* startLoc;
1135 emitLocation* endLoc;
1136 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1137 emitLocation* coldEndLoc;
1138 UNWIND_INFO unwindHeader;
1139 // Maximum of 255 UNWIND_CODE 'nodes' and then the unwind header. If there are an odd
1140 // number of codes, the VM or Zapper will 4-byte align the whole thing.
1141 BYTE unwindCodes[offsetof(UNWIND_INFO, UnwindCode) + (0xFF * sizeof(UNWIND_CODE))];
1142 unsigned unwindCodeSlot;
1144 #ifdef UNIX_AMD64_ABI
1145 jitstd::vector<CFI_CODE>* cfiCodes;
1146 #endif // UNIX_AMD64_ABI
1148 #elif defined(_TARGET_ARMARCH_)
1150 UnwindInfo uwi; // Unwind information for this function/funclet's hot section
1151 UnwindInfo* uwiCold; // Unwind information for this function/funclet's cold section
1152 // Note: we only have a pointer here instead of the actual object,
1153 // to save memory in the JIT case (compared to the NGEN case),
1154 // where we don't have any cold section.
1155 // Note 2: we currently don't support hot/cold splitting in functions
1156 // with EH, so uwiCold will be NULL for all funclets.
1158 #endif // _TARGET_ARMARCH_
1160 // Eventually we may want to move rsModifiedRegsMask, lvaOutgoingArgSize, and anything else
1161 // that isn't shared between the main function body and funclets.
1164 struct fgArgTabEntry
1167 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1170 otherRegNum = REG_NA;
1171 isStruct = false; // is this a struct arg
1173 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1175 GenTreePtr node; // Initially points at the Op1 field of 'parent', but if the argument is replaced with an GT_ASG or
1177 // it will point at the actual argument in the gtCallLateArgs list.
1178 GenTreePtr parent; // Points at the GT_LIST node in the gtCallArgs for this argument
1180 unsigned argNum; // The original argument number, also specifies the required argument evaluation order from the IL
1182 regNumber regNum; // The (first) register to use when passing this argument, set to REG_STK for arguments passed on
1184 unsigned numRegs; // Count of number of registers that this argument uses
1186 // A slot is a pointer sized region in the OutArg area.
1187 unsigned slotNum; // When an argument is passed in the OutArg area this is the slot number in the OutArg area
1188 unsigned numSlots; // Count of number of slots that this argument uses
1190 unsigned alignment; // 1 or 2 (slots/registers)
1191 unsigned lateArgInx; // index into gtCallLateArgs list
1192 unsigned tmpNum; // the LclVar number if we had to force evaluation of this arg
1193 #if defined(UNIX_X86_ABI)
1194 unsigned padStkAlign; // Count of number of padding slots for stack alignment. For each Call, only the first
1195 // argument may have a value to emit "sub esp, n" to adjust the stack before pushing
1199 bool isSplit : 1; // True when this argument is split between the registers and OutArg area
1200 bool needTmp : 1; // True when we force this argument's evaluation into a temp LclVar
1201 bool needPlace : 1; // True when we must replace this argument with a placeholder node
1202 bool isTmp : 1; // True when we setup a temp LclVar for this argument due to size issues with the struct
1203 bool processed : 1; // True when we have decided the evaluation order for this argument in the gtCallLateArgs
1204 bool isHfaRegArg : 1; // True when the argument is passed as a HFA in FP registers.
1205 bool isBackFilled : 1; // True when the argument fills a register slot skipped due to alignment requirements of
1206 // previous arguments.
1207 bool isNonStandard : 1; // True if it is an arg that is passed in a reg other than a standard arg reg, or is forced
1208 // to be on the stack despite its arg list position.
1210 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1211 bool isStruct : 1; // True if this is a struct arg
1213 regNumber otherRegNum; // The (second) register to use when passing this argument.
1215 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
1216 #elif defined(_TARGET_X86_)
1217 __declspec(property(get = getIsStruct)) bool isStruct;
1220 return varTypeIsStruct(node);
1222 #endif // _TARGET_X86_
1225 void SetIsHfaRegArg(bool hfaRegArg)
1227 isHfaRegArg = hfaRegArg;
1230 void SetIsBackFilled(bool backFilled)
1232 isBackFilled = backFilled;
1235 bool IsBackFilled() const
1237 return isBackFilled;
1239 #else // !_TARGET_ARM_
1240 // To make the callers easier, we allow these calls (and the isHfaRegArg and isBackFilled data members) for all
1242 void SetIsHfaRegArg(bool hfaRegArg)
1246 void SetIsBackFilled(bool backFilled)
1250 bool IsBackFilled() const
1254 #endif // !_TARGET_ARM_
1260 typedef struct fgArgTabEntry* fgArgTabEntryPtr;
1262 //-------------------------------------------------------------------------
1264 // The class fgArgInfo is used to handle the arguments
1265 // when morphing a GT_CALL node.
1270 Compiler* compiler; // Back pointer to the compiler instance so that we can allocate memory
1271 GenTreePtr callTree; // Back pointer to the GT_CALL node for this fgArgInfo
1272 unsigned argCount; // Updatable arg count value
1273 unsigned nextSlotNum; // Updatable slot count value
1274 unsigned stkLevel; // Stack depth when we make this call (for x86)
1275 #if defined(UNIX_X86_ABI)
1276 unsigned padStkAlign; // Count of number of padding slots for stack alignment. This value is used to turn back
1277 // stack pointer before it was adjusted after each Call
1280 unsigned argTableSize; // size of argTable array (equal to the argCount when done with fgMorphArgs)
1281 bool hasRegArgs; // true if we have one or more register arguments
1282 bool hasStackArgs; // true if we have one or more stack arguments
1283 bool argsComplete; // marker for state
1284 bool argsSorted; // marker for state
1285 fgArgTabEntryPtr* argTable; // variable sized array of per argument descrption: (i.e. argTable[argTableSize])
1288 void AddArg(fgArgTabEntryPtr curArgTabEntry);
1291 fgArgInfo(Compiler* comp, GenTreePtr call, unsigned argCount);
1292 fgArgInfo(GenTreePtr newCall, GenTreePtr oldCall);
1294 fgArgTabEntryPtr AddRegArg(
1295 unsigned argNum, GenTreePtr node, GenTreePtr parent, regNumber regNum, unsigned numRegs, unsigned alignment);
1297 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
1298 fgArgTabEntryPtr AddRegArg(
1305 const bool isStruct,
1306 const regNumber otherRegNum = REG_NA,
1307 const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* const structDescPtr = nullptr);
1308 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
1310 fgArgTabEntryPtr AddStkArg(unsigned argNum,
1314 unsigned alignment FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(const bool isStruct));
1316 void RemorphReset();
1317 fgArgTabEntryPtr RemorphRegArg(
1318 unsigned argNum, GenTreePtr node, GenTreePtr parent, regNumber regNum, unsigned numRegs, unsigned alignment);
1320 void RemorphStkArg(unsigned argNum, GenTreePtr node, GenTreePtr parent, unsigned numSlots, unsigned alignment);
1322 void SplitArg(unsigned argNum, unsigned numRegs, unsigned numSlots);
1324 void EvalToTmp(unsigned argNum, unsigned tmpNum, GenTreePtr newNode);
1326 void ArgsComplete();
1328 #if defined(UNIX_X86_ABI)
1329 void ArgsAlignPadding();
1334 void EvalArgsToTemps();
1336 void RecordStkLevel(unsigned stkLvl);
1337 unsigned RetrieveStkLevel();
1343 fgArgTabEntryPtr* ArgTable()
1347 unsigned GetNextSlotNum()
1351 #if defined(UNIX_X86_ABI)
1352 unsigned GetPadStackAlign()
1363 return hasStackArgs;
1365 bool AreArgsComplete() const
1367 return argsComplete;
1370 // Get the late arg for arg at position argIndex. Caller must ensure this position has a late arg.
1371 GenTreePtr GetLateArg(unsigned argIndex);
1375 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1376 // We have the ability to mark source expressions with "Test Labels."
1377 // These drive assertions within the JIT, or internal JIT testing. For example, we could label expressions
1378 // that should be CSE defs, and other expressions that should uses of those defs, with a shared label.
1380 enum TestLabel // This must be kept identical to System.Runtime.CompilerServices.JitTestLabel.TestLabel.
1383 TL_VN, // Defines a "VN equivalence class". (For full VN, including exceptions thrown).
1384 TL_VNNorm, // Like above, but uses the non-exceptional value of the expression.
1385 TL_CSE_Def, // This must be identified in the JIT as a CSE def
1386 TL_CSE_Use, // This must be identified in the JIT as a CSE use
1387 TL_LoopHoist, // Expression must (or must not) be hoisted out of the loop.
1390 struct TestLabelAndNum
1395 TestLabelAndNum() : m_tl(TestLabel(0)), m_num(0)
1400 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, TestLabelAndNum, JitSimplerHashBehavior> NodeToTestDataMap;
1402 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1405 // This class implements the "IAllocator" interface, so that we can use
1406 // utilcode collection classes in the JIT, and have them use the JIT's allocator.
1408 class CompAllocator : public IAllocator
1411 #if MEASURE_MEM_ALLOC
1415 CompAllocator(Compiler* comp, CompMemKind cmk)
1417 #if MEASURE_MEM_ALLOC
1423 inline void* Alloc(size_t sz);
1425 inline void* ArrayAlloc(size_t elems, size_t elemSize);
1427 // For the compiler's no-release allocator, free operations are no-ops.
1434 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1435 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1437 XX The big guy. The sections are currently organized as : XX
1439 XX o GenTree and BasicBlock XX
1451 XX o PrologScopeInfo XX
1452 XX o CodeGenerator XX
1457 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1458 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1463 friend class emitter;
1464 friend class UnwindInfo;
1465 friend class UnwindFragmentInfo;
1466 friend class UnwindEpilogInfo;
1467 friend class JitTimer;
1468 friend class LinearScan;
1469 friend class fgArgInfo;
1470 friend class Rationalizer;
1472 friend class Lowering;
1473 friend class CSE_DataFlow;
1474 friend class CSE_Heuristic;
1475 friend class CodeGenInterface;
1476 friend class CodeGen;
1477 friend class LclVarDsc;
1478 friend class TempDsc;
1480 friend class ObjectAllocator;
1482 #ifndef _TARGET_64BIT_
1483 friend class DecomposeLongs;
1484 #endif // !_TARGET_64BIT_
1487 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1488 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1490 XX Misc structs definitions XX
1492 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1493 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1497 hashBvGlobalData hbvGlobalData; // Used by the hashBv bitvector package.
1516 bool dumpIRDataflow;
1517 bool dumpIRBlockHeaders;
1519 LPCWSTR dumpIRPhase;
1520 LPCWSTR dumpIRFormat;
1522 bool shouldUseVerboseTrees();
1523 bool asciiTrees; // If true, dump trees using only ASCII characters
1524 bool shouldDumpASCIITrees();
1525 bool verboseSsa; // If true, produce especially verbose dump output in SSA construction.
1526 bool shouldUseVerboseSsa();
1527 bool treesBeforeAfterMorph; // If true, print trees before/after morphing (paired by an intra-compilation id:
1528 int morphNum; // This counts the the trees that have been morphed, allowing us to label each uniquely.
1530 const char* VarNameToStr(VarName name)
1535 DWORD expensiveDebugCheckLevel;
1538 #if FEATURE_MULTIREG_RET
1539 GenTreePtr impAssignMultiRegTypeToVar(GenTreePtr op, CORINFO_CLASS_HANDLE hClass);
1540 #endif // FEATURE_MULTIREG_RET
1543 bool isSingleFloat32Struct(CORINFO_CLASS_HANDLE hClass);
1544 #endif // ARM_SOFTFP
1546 //-------------------------------------------------------------------------
1547 // Functions to handle homogeneous floating-point aggregates (HFAs) in ARM.
1548 // HFAs are one to four element structs where each element is the same
1549 // type, either all float or all double. They are treated specially
1550 // in the ARM Procedure Call Standard, specifically, they are passed in
1551 // floating-point registers instead of the general purpose registers.
1554 bool IsHfa(CORINFO_CLASS_HANDLE hClass);
1555 bool IsHfa(GenTreePtr tree);
1557 var_types GetHfaType(GenTreePtr tree);
1558 unsigned GetHfaCount(GenTreePtr tree);
1560 var_types GetHfaType(CORINFO_CLASS_HANDLE hClass);
1561 unsigned GetHfaCount(CORINFO_CLASS_HANDLE hClass);
1563 bool IsMultiRegPassedType(CORINFO_CLASS_HANDLE hClass);
1564 bool IsMultiRegReturnedType(CORINFO_CLASS_HANDLE hClass);
1566 //-------------------------------------------------------------------------
1567 // The following is used for validating format of EH table
1571 typedef struct EHNodeDsc* pEHNodeDsc;
1573 EHNodeDsc* ehnTree; // root of the tree comprising the EHnodes.
1574 EHNodeDsc* ehnNext; // root of the tree comprising the EHnodes.
1587 EHBlockType ehnBlockType; // kind of EH block
1588 IL_OFFSET ehnStartOffset; // IL offset of start of the EH block
1589 IL_OFFSET ehnEndOffset; // IL offset past end of the EH block. (TODO: looks like verInsertEhNode() sets this to
1590 // the last IL offset, not "one past the last one", i.e., the range Start to End is
1592 pEHNodeDsc ehnNext; // next (non-nested) block in sequential order
1593 pEHNodeDsc ehnChild; // leftmost nested block
1595 pEHNodeDsc ehnTryNode; // for filters and handlers, the corresponding try node
1596 pEHNodeDsc ehnHandlerNode; // for a try node, the corresponding handler node
1598 pEHNodeDsc ehnFilterNode; // if this is a try node and has a filter, otherwise 0
1599 pEHNodeDsc ehnEquivalent; // if blockType=tryNode, start offset and end offset is same,
1601 inline void ehnSetTryNodeType()
1603 ehnBlockType = TryNode;
1605 inline void ehnSetFilterNodeType()
1607 ehnBlockType = FilterNode;
1609 inline void ehnSetHandlerNodeType()
1611 ehnBlockType = HandlerNode;
1613 inline void ehnSetFinallyNodeType()
1615 ehnBlockType = FinallyNode;
1617 inline void ehnSetFaultNodeType()
1619 ehnBlockType = FaultNode;
1622 inline BOOL ehnIsTryBlock()
1624 return ehnBlockType == TryNode;
1626 inline BOOL ehnIsFilterBlock()
1628 return ehnBlockType == FilterNode;
1630 inline BOOL ehnIsHandlerBlock()
1632 return ehnBlockType == HandlerNode;
1634 inline BOOL ehnIsFinallyBlock()
1636 return ehnBlockType == FinallyNode;
1638 inline BOOL ehnIsFaultBlock()
1640 return ehnBlockType == FaultNode;
1643 // returns true if there is any overlap between the two nodes
1644 static inline BOOL ehnIsOverlap(pEHNodeDsc node1, pEHNodeDsc node2)
1646 if (node1->ehnStartOffset < node2->ehnStartOffset)
1648 return (node1->ehnEndOffset >= node2->ehnStartOffset);
1652 return (node1->ehnStartOffset <= node2->ehnEndOffset);
1656 // fails with BADCODE if inner is not completely nested inside outer
1657 static inline BOOL ehnIsNested(pEHNodeDsc inner, pEHNodeDsc outer)
1659 return ((inner->ehnStartOffset >= outer->ehnStartOffset) && (inner->ehnEndOffset <= outer->ehnEndOffset));
1663 //-------------------------------------------------------------------------
1664 // Exception handling functions
1667 #if !FEATURE_EH_FUNCLETS
1669 bool ehNeedsShadowSPslots()
1671 return (info.compXcptnsCount || opts.compDbgEnC);
1674 // 0 for methods with no EH
1675 // 1 for methods with non-nested EH, or where only the try blocks are nested
1676 // 2 for a method with a catch within a catch
1678 unsigned ehMaxHndNestingCount;
1680 #endif // !FEATURE_EH_FUNCLETS
1682 static bool jitIsBetween(unsigned value, unsigned start, unsigned end);
1683 static bool jitIsBetweenInclusive(unsigned value, unsigned start, unsigned end);
1685 bool bbInCatchHandlerILRange(BasicBlock* blk);
1686 bool bbInFilterILRange(BasicBlock* blk);
1687 bool bbInTryRegions(unsigned regionIndex, BasicBlock* blk);
1688 bool bbInExnFlowRegions(unsigned regionIndex, BasicBlock* blk);
1689 bool bbInHandlerRegions(unsigned regionIndex, BasicBlock* blk);
1690 bool bbInCatchHandlerRegions(BasicBlock* tryBlk, BasicBlock* hndBlk);
1691 unsigned short bbFindInnermostCommonTryRegion(BasicBlock* bbOne, BasicBlock* bbTwo);
1693 unsigned short bbFindInnermostTryRegionContainingHandlerRegion(unsigned handlerIndex);
1694 unsigned short bbFindInnermostHandlerRegionContainingTryRegion(unsigned tryIndex);
1696 // Returns true if "block" is the start of a try region.
1697 bool bbIsTryBeg(BasicBlock* block);
1699 // Returns true if "block" is the start of a handler or filter region.
1700 bool bbIsHandlerBeg(BasicBlock* block);
1702 // Returns true iff "block" is where control flows if an exception is raised in the
1703 // try region, and sets "*regionIndex" to the index of the try for the handler.
1704 // Differs from "IsHandlerBeg" in the case of filters, where this is true for the first
1705 // block of the filter, but not for the filter's handler.
1706 bool bbIsExFlowBlock(BasicBlock* block, unsigned* regionIndex);
1708 bool ehHasCallableHandlers();
1710 // Return the EH descriptor for the given region index.
1711 EHblkDsc* ehGetDsc(unsigned regionIndex);
1713 // Return the EH index given a region descriptor.
1714 unsigned ehGetIndex(EHblkDsc* ehDsc);
1716 // Return the EH descriptor index of the enclosing try, for the given region index.
1717 unsigned ehGetEnclosingTryIndex(unsigned regionIndex);
1719 // Return the EH descriptor index of the enclosing handler, for the given region index.
1720 unsigned ehGetEnclosingHndIndex(unsigned regionIndex);
1722 // Return the EH descriptor for the most nested 'try' region this BasicBlock is a member of (or nullptr if this
1723 // block is not in a 'try' region).
1724 EHblkDsc* ehGetBlockTryDsc(BasicBlock* block);
1726 // Return the EH descriptor for the most nested filter or handler region this BasicBlock is a member of (or nullptr
1727 // if this block is not in a filter or handler region).
1728 EHblkDsc* ehGetBlockHndDsc(BasicBlock* block);
1730 // Return the EH descriptor for the most nested region that may handle exceptions raised in this BasicBlock (or
1731 // nullptr if this block's exceptions propagate to caller).
1732 EHblkDsc* ehGetBlockExnFlowDsc(BasicBlock* block);
1734 EHblkDsc* ehIsBlockTryLast(BasicBlock* block);
1735 EHblkDsc* ehIsBlockHndLast(BasicBlock* block);
1736 bool ehIsBlockEHLast(BasicBlock* block);
1738 bool ehBlockHasExnFlowDsc(BasicBlock* block);
1740 // Return the region index of the most nested EH region this block is in.
1741 unsigned ehGetMostNestedRegionIndex(BasicBlock* block, bool* inTryRegion);
1743 // Find the true enclosing try index, ignoring 'mutual protect' try. Uses IL ranges to check.
1744 unsigned ehTrueEnclosingTryIndexIL(unsigned regionIndex);
1746 // Return the index of the most nested enclosing region for a particular EH region. Returns NO_ENCLOSING_INDEX
1747 // if there is no enclosing region. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion'
1748 // is set to 'true' if the enclosing region is a 'try', or 'false' if the enclosing region is a handler.
1749 // (It can never be a filter.)
1750 unsigned ehGetEnclosingRegionIndex(unsigned regionIndex, bool* inTryRegion);
1752 // A block has been deleted. Update the EH table appropriately.
1753 void ehUpdateForDeletedBlock(BasicBlock* block);
1755 // Determine whether a block can be deleted while preserving the EH normalization rules.
1756 bool ehCanDeleteEmptyBlock(BasicBlock* block);
1758 // Update the 'last' pointers in the EH table to reflect new or deleted blocks in an EH region.
1759 void ehUpdateLastBlocks(BasicBlock* oldLast, BasicBlock* newLast);
1761 // For a finally handler, find the region index that the BBJ_CALLFINALLY lives in that calls the handler,
1762 // or NO_ENCLOSING_INDEX if the BBJ_CALLFINALLY lives in the main function body. Normally, the index
1763 // is the same index as the handler (and the BBJ_CALLFINALLY lives in the 'try' region), but for AMD64 the
1764 // BBJ_CALLFINALLY lives in the enclosing try or handler region, whichever is more nested, or the main function
1765 // body. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion' is set to 'true' if the
1766 // BBJ_CALLFINALLY lives in the returned index's 'try' region, or 'false' if lives in the handler region. (It never
1767 // lives in a filter.)
1768 unsigned ehGetCallFinallyRegionIndex(unsigned finallyIndex, bool* inTryRegion);
1770 // Find the range of basic blocks in which all BBJ_CALLFINALLY will be found that target the 'finallyIndex' region's
1771 // handler. Set begBlk to the first block, and endBlk to the block after the last block of the range
1772 // (nullptr if the last block is the last block in the program).
1773 // Precondition: 'finallyIndex' is the EH region of a try/finally clause.
1774 void ehGetCallFinallyBlockRange(unsigned finallyIndex, BasicBlock** begBlk, BasicBlock** endBlk);
1777 // Given a BBJ_CALLFINALLY block and the EH region index of the finally it is calling, return
1778 // 'true' if the BBJ_CALLFINALLY is in the correct EH region.
1779 bool ehCallFinallyInCorrectRegion(BasicBlock* blockCallFinally, unsigned finallyIndex);
1782 #if FEATURE_EH_FUNCLETS
1783 // Do we need a PSPSym in the main function? For codegen purposes, we only need one
1784 // if there is a filter that protects a region with a nested EH clause (such as a
1785 // try/catch nested in the 'try' body of a try/filter/filter-handler). See
1786 // genFuncletProlog() for more details. However, the VM seems to use it for more
1787 // purposes, maybe including debugging. Until we are sure otherwise, always create
1788 // a PSPSym for functions with any EH.
1789 bool ehNeedsPSPSym() const
1793 #else // _TARGET_X86_
1794 return compHndBBtabCount > 0;
1795 #endif // _TARGET_X86_
1798 bool ehAnyFunclets(); // Are there any funclets in this function?
1799 unsigned ehFuncletCount(); // Return the count of funclets in the function
1801 unsigned bbThrowIndex(BasicBlock* blk); // Get the index to use as the cache key for sharing throw blocks
1802 #else // !FEATURE_EH_FUNCLETS
1803 bool ehAnyFunclets()
1807 unsigned ehFuncletCount()
1812 unsigned bbThrowIndex(BasicBlock* blk)
1814 return blk->bbTryIndex;
1815 } // Get the index to use as the cache key for sharing throw blocks
1816 #endif // !FEATURE_EH_FUNCLETS
1818 // Returns a flowList representing the "EH predecessors" of "blk". These are the normal predecessors of
1819 // "blk", plus one special case: if "blk" is the first block of a handler, considers the predecessor(s) of the first
1820 // first block of the corresponding try region to be "EH predecessors". (If there is a single such predecessor,
1821 // for example, we want to consider that the immediate dominator of the catch clause start block, so it's
1822 // convenient to also consider it a predecessor.)
1823 flowList* BlockPredsWithEH(BasicBlock* blk);
1825 // This table is useful for memoization of the method above.
1826 typedef SimplerHashTable<BasicBlock*, PtrKeyFuncs<BasicBlock>, flowList*, JitSimplerHashBehavior>
1828 BlockToFlowListMap* m_blockToEHPreds;
1829 BlockToFlowListMap* GetBlockToEHPreds()
1831 if (m_blockToEHPreds == nullptr)
1833 m_blockToEHPreds = new (getAllocator()) BlockToFlowListMap(getAllocator());
1835 return m_blockToEHPreds;
1838 void* ehEmitCookie(BasicBlock* block);
1839 UNATIVE_OFFSET ehCodeOffset(BasicBlock* block);
1841 EHblkDsc* ehInitHndRange(BasicBlock* src, IL_OFFSET* hndBeg, IL_OFFSET* hndEnd, bool* inFilter);
1843 EHblkDsc* ehInitTryRange(BasicBlock* src, IL_OFFSET* tryBeg, IL_OFFSET* tryEnd);
1845 EHblkDsc* ehInitHndBlockRange(BasicBlock* blk, BasicBlock** hndBeg, BasicBlock** hndLast, bool* inFilter);
1847 EHblkDsc* ehInitTryBlockRange(BasicBlock* blk, BasicBlock** tryBeg, BasicBlock** tryLast);
1849 void fgSetTryEnd(EHblkDsc* handlerTab, BasicBlock* newTryLast);
1851 void fgSetHndEnd(EHblkDsc* handlerTab, BasicBlock* newHndLast);
1853 void fgSkipRmvdBlocks(EHblkDsc* handlerTab);
1855 void fgAllocEHTable();
1857 void fgRemoveEHTableEntry(unsigned XTnum);
1859 #if FEATURE_EH_FUNCLETS
1861 EHblkDsc* fgAddEHTableEntry(unsigned XTnum);
1863 #endif // FEATURE_EH_FUNCLETS
1867 #endif // !FEATURE_EH
1869 void fgSortEHTable();
1871 // Causes the EH table to obey some well-formedness conditions, by inserting
1872 // empty BB's when necessary:
1873 // * No block is both the first block of a handler and the first block of a try.
1874 // * No block is the first block of multiple 'try' regions.
1875 // * No block is the last block of multiple EH regions.
1876 void fgNormalizeEH();
1877 bool fgNormalizeEHCase1();
1878 bool fgNormalizeEHCase2();
1879 bool fgNormalizeEHCase3();
1882 void dispIncomingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
1883 void dispOutgoingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
1884 void fgVerifyHandlerTab();
1885 void fgDispHandlerTab();
1888 bool fgNeedToSortEHTable;
1890 void verInitEHTree(unsigned numEHClauses);
1891 void verInsertEhNode(CORINFO_EH_CLAUSE* clause, EHblkDsc* handlerTab);
1892 void verInsertEhNodeInTree(EHNodeDsc** ppRoot, EHNodeDsc* node);
1893 void verInsertEhNodeParent(EHNodeDsc** ppRoot, EHNodeDsc* node);
1894 void verCheckNestingLevel(EHNodeDsc* initRoot);
1897 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1898 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1900 XX GenTree and BasicBlock XX
1902 XX Functions to allocate and display the GenTrees and BasicBlocks XX
1904 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1905 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1908 // Functions to create nodes
1909 GenTreeStmt* gtNewStmt(GenTreePtr expr = nullptr, IL_OFFSETX offset = BAD_IL_OFFSET);
1912 GenTreePtr gtNewOperNode(genTreeOps oper, var_types type, GenTreePtr op1, bool doSimplifications = TRUE);
1914 // For binary opers.
1915 GenTreePtr gtNewOperNode(genTreeOps oper, var_types type, GenTreePtr op1, GenTreePtr op2);
1917 GenTreePtr gtNewQmarkNode(var_types type, GenTreePtr cond, GenTreePtr colon);
1919 GenTreePtr gtNewLargeOperNode(genTreeOps oper,
1920 var_types type = TYP_I_IMPL,
1921 GenTreePtr op1 = nullptr,
1922 GenTreePtr op2 = nullptr);
1924 GenTreeIntCon* gtNewIconNode(ssize_t value, var_types type = TYP_INT);
1926 GenTree* gtNewPhysRegNode(regNumber reg, var_types type);
1928 GenTree* gtNewPhysRegNode(regNumber reg, GenTree* src);
1930 GenTreePtr gtNewJmpTableNode();
1931 GenTreePtr gtNewIconHandleNode(
1932 size_t value, unsigned flags, FieldSeqNode* fields = nullptr, unsigned handle1 = 0, void* handle2 = nullptr);
1934 unsigned gtTokenToIconFlags(unsigned token);
1936 GenTreePtr gtNewIconEmbHndNode(void* value,
1939 unsigned handle1 = 0,
1940 void* handle2 = nullptr,
1941 void* compileTimeHandle = nullptr);
1943 GenTreePtr gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
1944 GenTreePtr gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
1945 GenTreePtr gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
1946 GenTreePtr gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
1948 GenTreePtr gtNewStringLiteralNode(InfoAccessType iat, void* pValue);
1950 GenTreePtr gtNewLconNode(__int64 value);
1952 GenTreePtr gtNewDconNode(double value);
1954 GenTreePtr gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle);
1956 GenTreePtr gtNewZeroConNode(var_types type);
1958 GenTreePtr gtNewOneConNode(var_types type);
1961 GenTreePtr gtNewSIMDVectorZero(var_types simdType, var_types baseType, unsigned size);
1962 GenTreePtr gtNewSIMDVectorOne(var_types simdType, var_types baseType, unsigned size);
1965 GenTreeBlk* gtNewBlkOpNode(
1966 genTreeOps oper, GenTreePtr dst, GenTreePtr srcOrFillVal, GenTreePtr sizeOrClsTok, bool isVolatile);
1968 GenTree* gtNewBlkOpNode(GenTreePtr dst, GenTreePtr srcOrFillVal, unsigned size, bool isVolatile, bool isCopyBlock);
1971 void gtBlockOpInit(GenTreePtr result, GenTreePtr dst, GenTreePtr srcOrFillVal, bool isVolatile);
1974 GenTree* gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTreePtr addr);
1975 void gtSetObjGcInfo(GenTreeObj* objNode);
1976 GenTree* gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTreePtr addr);
1977 GenTree* gtNewBlockVal(GenTreePtr addr, unsigned size);
1979 GenTree* gtNewCpObjNode(GenTreePtr dst, GenTreePtr src, CORINFO_CLASS_HANDLE structHnd, bool isVolatile);
1981 GenTreeArgList* gtNewListNode(GenTreePtr op1, GenTreeArgList* op2);
1983 GenTreeCall* gtNewCallNode(gtCallTypes callType,
1984 CORINFO_METHOD_HANDLE handle,
1986 GenTreeArgList* args,
1987 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
1989 GenTreeCall* gtNewIndCallNode(GenTreePtr addr,
1991 GenTreeArgList* args,
1992 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
1994 GenTreeCall* gtNewHelperCallNode(unsigned helper,
1997 GenTreeArgList* args = nullptr);
1999 GenTreePtr gtNewLclvNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs = BAD_IL_OFFSET);
2002 GenTreeSIMD* gtNewSIMDNode(
2003 var_types type, GenTreePtr op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
2004 GenTreeSIMD* gtNewSIMDNode(var_types type,
2007 SIMDIntrinsicID simdIntrinsicID,
2010 void SetOpLclRelatedToSIMDIntrinsic(GenTreePtr op);
2013 GenTreePtr gtNewLclLNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs = BAD_IL_OFFSET);
2014 GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset);
2015 GenTreePtr gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate, var_types type);
2017 GenTreePtr gtNewCodeRef(BasicBlock* block);
2019 GenTreePtr gtNewFieldRef(
2020 var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTreePtr obj = nullptr, DWORD offset = 0, bool nullcheck = false);
2022 GenTreePtr gtNewIndexRef(var_types typ, GenTreePtr arrayOp, GenTreePtr indexOp);
2024 GenTreeArgList* gtNewArgList(GenTreePtr op);
2025 GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2);
2026 GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2, GenTreePtr op3);
2028 static fgArgTabEntryPtr gtArgEntryByArgNum(GenTreePtr call, unsigned argNum);
2029 static fgArgTabEntryPtr gtArgEntryByNode(GenTreePtr call, GenTreePtr node);
2030 fgArgTabEntryPtr gtArgEntryByLateArgIndex(GenTreePtr call, unsigned lateArgInx);
2031 bool gtArgIsThisPtr(fgArgTabEntryPtr argEntry);
2033 GenTreePtr gtNewAssignNode(GenTreePtr dst, GenTreePtr src);
2035 GenTreePtr gtNewTempAssign(unsigned tmp, GenTreePtr val);
2037 GenTreePtr gtNewRefCOMfield(GenTreePtr objPtr,
2038 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2039 CORINFO_ACCESS_FLAGS access,
2040 CORINFO_FIELD_INFO* pFieldInfo,
2042 CORINFO_CLASS_HANDLE structType,
2045 GenTreePtr gtNewNothingNode();
2047 GenTreePtr gtNewArgPlaceHolderNode(var_types type, CORINFO_CLASS_HANDLE clsHnd);
2049 GenTreePtr gtUnusedValNode(GenTreePtr expr);
2051 GenTreePtr gtNewCastNode(var_types typ, GenTreePtr op1, var_types castType);
2053 GenTreePtr gtNewCastNodeL(var_types typ, GenTreePtr op1, var_types castType);
2055 GenTreePtr gtNewAllocObjNode(unsigned int helper, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTreePtr op1);
2057 //------------------------------------------------------------------------
2058 // Other GenTree functions
2060 GenTreePtr gtClone(GenTree* tree, bool complexOK = false);
2062 // If `tree` is a lclVar with lclNum `varNum`, return an IntCns with value `varVal`; otherwise,
2063 // create a copy of `tree`, adding specified flags, replacing uses of lclVar `deepVarNum` with
2064 // IntCnses with value `deepVarVal`.
2065 GenTreePtr gtCloneExpr(
2066 GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal);
2068 // Create a copy of `tree`, optionally adding specifed flags, and optionally mapping uses of local
2069 // `varNum` to int constants with value `varVal`.
2070 GenTreePtr gtCloneExpr(GenTree* tree, unsigned addFlags = 0, unsigned varNum = (unsigned)-1, int varVal = 0)
2072 return gtCloneExpr(tree, addFlags, varNum, varVal, varNum, varVal);
2075 GenTreePtr gtReplaceTree(GenTreePtr stmt, GenTreePtr tree, GenTreePtr replacementTree);
2077 void gtUpdateSideEffects(GenTreePtr tree, unsigned oldGtFlags, unsigned newGtFlags);
2079 // Returns "true" iff the complexity (not formally defined, but first interpretation
2080 // is #of nodes in subtree) of "tree" is greater than "limit".
2081 // (This is somewhat redundant with the "gtCostEx/gtCostSz" fields, but can be used
2082 // before they have been set.)
2083 bool gtComplexityExceeds(GenTreePtr* tree, unsigned limit);
2085 bool gtCompareTree(GenTree* op1, GenTree* op2);
2087 GenTreePtr gtReverseCond(GenTree* tree);
2089 bool gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly);
2091 bool gtHasLocalsWithAddrOp(GenTreePtr tree);
2093 unsigned gtSetListOrder(GenTree* list, bool regs, bool isListCallArgs);
2095 void gtWalkOp(GenTree** op1, GenTree** op2, GenTree* adr, bool constOnly);
2098 unsigned gtHashValue(GenTree* tree);
2100 GenTreePtr gtWalkOpEffectiveVal(GenTreePtr op);
2103 void gtPrepareCost(GenTree* tree);
2104 bool gtIsLikelyRegVar(GenTree* tree);
2106 unsigned gtSetEvalOrderAndRestoreFPstkLevel(GenTree* tree);
2108 // Returns true iff the secondNode can be swapped with firstNode.
2109 bool gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode);
2111 unsigned gtSetEvalOrder(GenTree* tree);
2113 #if FEATURE_STACK_FP_X87
2115 void gtComputeFPlvls(GenTreePtr tree);
2116 #endif // FEATURE_STACK_FP_X87
2118 void gtSetStmtInfo(GenTree* stmt);
2120 // Returns "true" iff "node" has any of the side effects in "flags".
2121 bool gtNodeHasSideEffects(GenTreePtr node, unsigned flags);
2123 // Returns "true" iff "tree" or its (transitive) children have any of the side effects in "flags".
2124 bool gtTreeHasSideEffects(GenTreePtr tree, unsigned flags);
2126 // Appends 'expr' in front of 'list'
2127 // 'list' will typically start off as 'nullptr'
2128 // when 'list' is non-null a GT_COMMA node is used to insert 'expr'
2129 GenTreePtr gtBuildCommaList(GenTreePtr list, GenTreePtr expr);
2131 void gtExtractSideEffList(GenTreePtr expr,
2133 unsigned flags = GTF_SIDE_EFFECT,
2134 bool ignoreRoot = false);
2136 GenTreePtr gtGetThisArg(GenTreePtr call);
2138 // Static fields of struct types (and sometimes the types that those are reduced to) are represented by having the
2139 // static field contain an object pointer to the boxed struct. This simplifies the GC implementation...but
2140 // complicates the JIT somewhat. This predicate returns "true" iff a node with type "fieldNodeType", representing
2141 // the given "fldHnd", is such an object pointer.
2142 bool gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd);
2144 // Return true if call is a recursive call; return false otherwise.
2145 bool gtIsRecursiveCall(GenTreeCall* call)
2147 return (call->gtCallMethHnd == info.compMethodHnd);
2150 //-------------------------------------------------------------------------
2152 GenTreePtr gtFoldExpr(GenTreePtr tree);
2155 // TODO-Amd64-Unix: Remove this when the clang optimizer is fixed and/or the method implementation is
2156 // refactored in a simpler code. This is a workaround for a bug in the clang-3.5 optimizer. The issue is that in
2157 // release build the optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner case
2158 // of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div operation instead of 64 bit) - see
2159 // the implementation of the method in gentree.cpp. For the case of lval1 and lval2 equal to MIN_LONG
2160 // (0x8000000000000000) this results in raising a SIGFPE. The method implementation is rather complex. Disable
2161 // optimizations for now.
2162 __attribute__((optnone))
2164 gtFoldExprConst(GenTreePtr tree);
2165 GenTreePtr gtFoldExprSpecial(GenTreePtr tree);
2166 GenTreePtr gtFoldExprCompare(GenTreePtr tree);
2168 //-------------------------------------------------------------------------
2169 // Get the handle, if any.
2170 CORINFO_CLASS_HANDLE gtGetStructHandleIfPresent(GenTreePtr tree);
2171 // Get the handle, and assert if not found.
2172 CORINFO_CLASS_HANDLE gtGetStructHandle(GenTreePtr tree);
2174 //-------------------------------------------------------------------------
2175 // Functions to display the trees
2178 void gtDispNode(GenTreePtr tree, IndentStack* indentStack, __in_z const char* msg, bool isLIR);
2180 void gtDispVN(GenTreePtr tree);
2181 void gtDispConst(GenTreePtr tree);
2182 void gtDispLeaf(GenTreePtr tree, IndentStack* indentStack);
2183 void gtDispNodeName(GenTreePtr tree);
2184 void gtDispRegVal(GenTreePtr tree);
2196 void gtDispChild(GenTreePtr child,
2197 IndentStack* indentStack,
2199 __in_opt const char* msg = nullptr,
2200 bool topOnly = false);
2201 void gtDispTree(GenTreePtr tree,
2202 IndentStack* indentStack = nullptr,
2203 __in_opt const char* msg = nullptr,
2204 bool topOnly = false,
2205 bool isLIR = false);
2206 void gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut);
2207 int gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining);
2208 char* gtGetLclVarName(unsigned lclNum);
2209 void gtDispLclVar(unsigned varNum, bool padForBiggestDisp = true);
2210 void gtDispTreeList(GenTreePtr tree, IndentStack* indentStack = nullptr);
2211 void gtGetArgMsg(GenTreePtr call, GenTreePtr arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength);
2212 void gtGetLateArgMsg(GenTreePtr call, GenTreePtr arg, int argNum, int listCount, char* bufp, unsigned bufLength);
2213 void gtDispArgList(GenTreePtr tree, IndentStack* indentStack);
2214 void gtDispFieldSeq(FieldSeqNode* pfsn);
2216 void gtDispRange(LIR::ReadOnlyRange const& range);
2218 void gtDispTreeRange(LIR::Range& containingRange, GenTree* tree);
2220 void gtDispLIRNode(GenTree* node);
2232 typedef fgWalkResult(fgWalkPreFn)(GenTreePtr* pTree, fgWalkData* data);
2233 typedef fgWalkResult(fgWalkPostFn)(GenTreePtr* pTree, fgWalkData* data);
2236 static fgWalkPreFn gtAssertColonCond;
2238 static fgWalkPreFn gtMarkColonCond;
2239 static fgWalkPreFn gtClearColonCond;
2241 GenTreePtr* gtFindLink(GenTreePtr stmt, GenTreePtr node);
2242 bool gtHasCatchArg(GenTreePtr tree);
2243 bool gtHasUnmanagedCall(GenTreePtr tree);
2245 typedef ArrayStack<GenTree*> GenTreeStack;
2247 static bool gtHasCallOnStack(GenTreeStack* parentStack);
2248 void gtCheckQuirkAddrExposedLclVar(GenTreePtr argTree, GenTreeStack* parentStack);
2250 //=========================================================================
2251 // BasicBlock functions
2253 // This is a debug flag we will use to assert when creating block during codegen
2254 // as this interferes with procedure splitting. If you know what you're doing, set
2255 // it to true before creating the block. (DEBUG only)
2256 bool fgSafeBasicBlockCreation;
2259 BasicBlock* bbNewBasicBlock(BBjumpKinds jumpKind);
2262 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2263 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2267 XX The variables to be used by the code generator. XX
2269 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2270 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2274 // For both PROMOTION_TYPE_NONE and PROMOTION_TYPE_DEPENDENT the struct will
2275 // be placed in the stack frame and it's fields must be laid out sequentially.
2277 // For PROMOTION_TYPE_INDEPENDENT each of the struct's fields is replaced by
2278 // a local variable that can be enregistered or placed in the stack frame.
2279 // The fields do not need to be laid out sequentially
2281 enum lvaPromotionType
2283 PROMOTION_TYPE_NONE, // The struct local is not promoted
2284 PROMOTION_TYPE_INDEPENDENT, // The struct local is promoted,
2285 // and its field locals are independent of its parent struct local.
2286 PROMOTION_TYPE_DEPENDENT // The struct local is promoted,
2287 // but its field locals depend on its parent struct local.
2290 static int __cdecl RefCntCmp(const void* op1, const void* op2);
2291 static int __cdecl WtdRefCntCmp(const void* op1, const void* op2);
2293 /*****************************************************************************/
2295 enum FrameLayoutState
2298 INITIAL_FRAME_LAYOUT,
2299 PRE_REGALLOC_FRAME_LAYOUT,
2300 REGALLOC_FRAME_LAYOUT,
2301 TENTATIVE_FRAME_LAYOUT,
2306 bool lvaRefCountingStarted; // Set to true when we have started counting the local vars
2307 bool lvaLocalVarRefCounted; // Set to true after we have called lvaMarkLocalVars()
2308 bool lvaSortAgain; // true: We need to sort the lvaTable
2309 bool lvaTrackedFixed; // true: We cannot add new 'tracked' variable
2310 unsigned lvaCount; // total number of locals
2312 unsigned lvaRefCount; // total number of references to locals
2313 LclVarDsc* lvaTable; // variable descriptor table
2314 unsigned lvaTableCnt; // lvaTable size (>= lvaCount)
2316 LclVarDsc** lvaRefSorted; // table sorted by refcount
2318 unsigned short lvaTrackedCount; // actual # of locals being tracked
2319 unsigned lvaTrackedCountInSizeTUnits; // min # of size_t's sufficient to hold a bit for all the locals being tracked
2321 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
2322 // Only for AMD64 System V cache the first caller stack homed argument.
2323 unsigned lvaFirstStackIncomingArgNum; // First argument with stack slot in the caller.
2324 #endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
2327 VARSET_TP lvaTrackedVars; // set of tracked variables
2329 #ifndef _TARGET_64BIT_
2330 VARSET_TP lvaLongVars; // set of long (64-bit) variables
2332 VARSET_TP lvaFloatVars; // set of floating-point (32-bit and 64-bit) variables
2334 unsigned lvaCurEpoch; // VarSets are relative to a specific set of tracked var indices.
2335 // It that changes, this changes. VarSets from different epochs
2336 // cannot be meaningfully combined.
2338 unsigned GetCurLVEpoch()
2343 // reverse map of tracked number to var number
2344 unsigned lvaTrackedToVarNum[lclMAX_TRACKED];
2346 #ifdef LEGACY_BACKEND
2347 // variable interference graph
2348 VARSET_TP lvaVarIntf[lclMAX_TRACKED];
2351 // variable preference graph
2352 VARSET_TP lvaVarPref[lclMAX_TRACKED];
2356 // # of procs compiled a with double-aligned stack
2357 static unsigned s_lvaDoubleAlignedProcsCount;
2361 // Getters and setters for address-exposed and do-not-enregister local var properties.
2362 bool lvaVarAddrExposed(unsigned varNum);
2363 void lvaSetVarAddrExposed(unsigned varNum);
2364 bool lvaVarDoNotEnregister(unsigned varNum);
2366 // Reasons why we can't enregister. Some of these correspond to debug properties of local vars.
2367 enum DoNotEnregisterReason
2372 DNER_VMNeedsStackAddr,
2373 DNER_LiveInOutOfHandler,
2374 DNER_LiveAcrossUnmanagedCall,
2375 DNER_BlockOp, // Is read or written via a block operation that explicitly takes the address.
2376 DNER_IsStructArg, // Is a struct passed as an argument in a way that requires a stack location.
2377 #ifdef JIT32_GCENCODER
2382 void lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregisterReason reason));
2384 unsigned lvaVarargsHandleArg;
2386 unsigned lvaVarargsBaseOfStkArgs; // Pointer (computed based on incoming varargs handle) to the start of the stack
2388 #endif // _TARGET_X86_
2390 unsigned lvaInlinedPInvokeFrameVar; // variable representing the InlinedCallFrame
2391 unsigned lvaReversePInvokeFrameVar; // variable representing the reverse PInvoke frame
2392 #if FEATURE_FIXED_OUT_ARGS
2393 unsigned lvaPInvokeFrameRegSaveVar; // variable representing the RegSave for PInvoke inlining.
2395 unsigned lvaMonAcquired; // boolean variable introduced into in synchronized methods
2396 // that tracks whether the lock has been taken
2398 unsigned lvaArg0Var; // The lclNum of arg0. Normally this will be info.compThisArg.
2399 // However, if there is a "ldarga 0" or "starg 0" in the IL,
2400 // we will redirect all "ldarg(a) 0" and "starg 0" to this temp.
2402 unsigned lvaInlineeReturnSpillTemp; // The temp to spill the non-VOID return expression
2403 // in case there are multiple BBJ_RETURN blocks in the inlinee.
2405 #if FEATURE_FIXED_OUT_ARGS
2406 unsigned lvaOutgoingArgSpaceVar; // dummy TYP_LCLBLK var for fixed outgoing argument space
2407 unsigned lvaOutgoingArgSpaceSize; // size of fixed outgoing argument space
2408 #endif // FEATURE_FIXED_OUT_ARGS
2411 // On architectures whose ABIs allow structs to be passed in registers, struct promotion will sometimes
2412 // require us to "rematerialize" a struct from it's separate constituent field variables. Packing several sub-word
2413 // field variables into an argument register is a hard problem. It's easier to reserve a word of memory into which
2414 // such field can be copied, after which the assembled memory word can be read into the register. We will allocate
2415 // this variable to be this scratch word whenever struct promotion occurs.
2416 unsigned lvaPromotedStructAssemblyScratchVar;
2417 #endif // _TARGET_ARM_
2420 unsigned lvaReturnEspCheck; // confirms ESP not corrupted on return
2421 unsigned lvaCallEspCheck; // confirms ESP not corrupted after a call
2424 bool lvaGenericsContextUsed;
2426 bool lvaKeepAliveAndReportThis(); // Synchronized instance method of a reference type, or
2427 // CORINFO_GENERICS_CTXT_FROM_THIS?
2428 bool lvaReportParamTypeArg(); // Exceptions and CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG?
2430 //-------------------------------------------------------------------------
2431 // All these frame offsets are inter-related and must be kept in sync
2433 #if !FEATURE_EH_FUNCLETS
2434 // This is used for the callable handlers
2435 unsigned lvaShadowSPslotsVar; // TYP_BLK variable for all the shadow SP slots
2436 #endif // FEATURE_EH_FUNCLETS
2438 unsigned lvaCachedGenericContextArgOffs;
2439 unsigned lvaCachedGenericContextArgOffset(); // For CORINFO_CALLCONV_PARAMTYPE and if generic context is passed as
2442 unsigned lvaLocAllocSPvar; // variable which has the result of the last alloca/localloc
2444 unsigned lvaNewObjArrayArgs; // variable with arguments for new MD array helper
2446 // TODO-Review: Prior to reg predict we reserve 24 bytes for Spill temps.
2447 // after the reg predict we will use a computed maxTmpSize
2448 // which is based upon the number of spill temps predicted by reg predict
2449 // All this is necessary because if we under-estimate the size of the spill
2450 // temps we could fail when encoding instructions that reference stack offsets for ARM.
2452 // Pre codegen max spill temp size.
2453 static const unsigned MAX_SPILL_TEMP_SIZE = 24;
2455 //-------------------------------------------------------------------------
2457 unsigned lvaGetMaxSpillTempSize();
2459 bool lvaIsPreSpilled(unsigned lclNum, regMaskTP preSpillMask);
2460 #endif // _TARGET_ARM_
2461 void lvaAssignFrameOffsets(FrameLayoutState curState);
2462 void lvaFixVirtualFrameOffsets();
2464 #ifndef LEGACY_BACKEND
2465 void lvaUpdateArgsWithInitialReg();
2466 #endif // !LEGACY_BACKEND
2468 void lvaAssignVirtualFrameOffsetsToArgs();
2469 #ifdef UNIX_AMD64_ABI
2470 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs, int* callerArgOffset);
2471 #else // !UNIX_AMD64_ABI
2472 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs);
2473 #endif // !UNIX_AMD64_ABI
2474 void lvaAssignVirtualFrameOffsetsToLocals();
2475 int lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, int stkOffs);
2476 #ifdef _TARGET_AMD64_
2477 // Returns true if compCalleeRegsPushed (including RBP if used as frame pointer) is even.
2478 bool lvaIsCalleeSavedIntRegCountEven();
2480 void lvaAlignFrame();
2481 void lvaAssignFrameOffsetsToPromotedStructs();
2482 int lvaAllocateTemps(int stkOffs, bool mustDoubleAlign);
2485 void lvaDumpRegLocation(unsigned lclNum);
2486 void lvaDumpFrameLocation(unsigned lclNum);
2487 void lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t refCntWtdWidth = 6);
2488 void lvaTableDump(FrameLayoutState curState = NO_FRAME_LAYOUT); // NO_FRAME_LAYOUT means use the current frame
2489 // layout state defined by lvaDoneFrameLayout
2492 // Limit frames size to 1GB. The maximum is 2GB in theory - make it intentionally smaller
2493 // to avoid bugs from borderline cases.
2494 #define MAX_FrameSize 0x3FFFFFFF
2495 void lvaIncrementFrameSize(unsigned size);
2497 unsigned lvaFrameSize(FrameLayoutState curState);
2499 // Returns the caller-SP-relative offset for the SP/FP relative offset determined by FP based.
2500 int lvaToCallerSPRelativeOffset(int offs, bool isFpBased);
2502 // Returns the caller-SP-relative offset for the local variable "varNum."
2503 int lvaGetCallerSPRelativeOffset(unsigned varNum);
2505 // Returns the SP-relative offset for the local variable "varNum". Illegal to ask this for functions with localloc.
2506 int lvaGetSPRelativeOffset(unsigned varNum);
2508 int lvaToInitialSPRelativeOffset(unsigned offset, bool isFpBased);
2509 int lvaGetInitialSPRelativeOffset(unsigned varNum);
2511 //------------------------ For splitting types ----------------------------
2513 void lvaInitTypeRef();
2515 void lvaInitArgs(InitVarDscInfo* varDscInfo);
2516 void lvaInitThisPtr(InitVarDscInfo* varDscInfo);
2517 void lvaInitRetBuffArg(InitVarDscInfo* varDscInfo);
2518 void lvaInitUserArgs(InitVarDscInfo* varDscInfo);
2519 void lvaInitGenericsCtxt(InitVarDscInfo* varDscInfo);
2520 void lvaInitVarArgsHandle(InitVarDscInfo* varDscInfo);
2522 void lvaInitVarDsc(LclVarDsc* varDsc,
2524 CorInfoType corInfoType,
2525 CORINFO_CLASS_HANDLE typeHnd,
2526 CORINFO_ARG_LIST_HANDLE varList,
2527 CORINFO_SIG_INFO* varSig);
2529 static unsigned lvaTypeRefMask(var_types type);
2531 var_types lvaGetActualType(unsigned lclNum);
2532 var_types lvaGetRealType(unsigned lclNum);
2534 //-------------------------------------------------------------------------
2538 unsigned lvaLclSize(unsigned varNum);
2539 unsigned lvaLclExactSize(unsigned varNum);
2541 bool lvaLclVarRefs(GenTreePtr tree, GenTreePtr* findPtr, varRefKinds* refsPtr, void* result);
2543 // Call lvaLclVarRefs on "true"; accumulate "*result" into whichever of
2544 // "allVars" and "trkdVars" is indiated by the nullness of "findPtr"; return
2545 // the return result.
2546 bool lvaLclVarRefsAccum(
2547 GenTreePtr tree, GenTreePtr* findPtr, varRefKinds* refsPtr, ALLVARSET_TP* allVars, VARSET_TP* trkdVars);
2549 // If "findPtr" is non-NULL, assumes "result" is an "ALLVARSET_TP*", and
2550 // (destructively) unions "allVars" into "*result". Otherwise, assumes "result" is a "VARSET_TP*",
2551 // and (destructively) unions "trkedVars" into "*result".
2552 void lvaLclVarRefsAccumIntoRes(GenTreePtr* findPtr,
2554 ALLVARSET_VALARG_TP allVars,
2555 VARSET_VALARG_TP trkdVars);
2557 bool lvaHaveManyLocals() const;
2559 unsigned lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason));
2560 unsigned lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason));
2561 unsigned lvaGrabTempWithImplicitUse(bool shortLifetime DEBUGARG(const char* reason));
2564 void lvaSortByRefCount();
2565 void lvaDumpRefCounts();
2567 void lvaMarkLocalVars(BasicBlock* block);
2569 void lvaMarkLocalVars(); // Local variable ref-counting
2571 void lvaAllocOutgoingArgSpace(); // 'Commit' lvaOutgoingArgSpaceSize and lvaOutgoingArgSpaceVar
2573 VARSET_VALRET_TP lvaStmtLclMask(GenTreePtr stmt);
2575 static fgWalkPreFn lvaIncRefCntsCB;
2576 void lvaIncRefCnts(GenTreePtr tree);
2578 static fgWalkPreFn lvaDecRefCntsCB;
2579 void lvaDecRefCnts(GenTreePtr tree);
2580 void lvaDecRefCnts(BasicBlock* basicBlock, GenTreePtr tree);
2581 void lvaRecursiveDecRefCounts(GenTreePtr tree);
2582 void lvaRecursiveIncRefCounts(GenTreePtr tree);
2585 struct lvaStressLclFldArgs
2587 Compiler* m_pCompiler;
2591 static fgWalkPreFn lvaStressLclFldCB;
2592 void lvaStressLclFld();
2594 void lvaDispVarSet(VARSET_VALARG_TP set, VARSET_VALARG_TP allVars);
2595 void lvaDispVarSet(VARSET_VALARG_TP set);
2600 int lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset);
2602 int lvaFrameAddress(int varNum, bool* pFPbased);
2605 bool lvaIsParameter(unsigned varNum);
2606 bool lvaIsRegArgument(unsigned varNum);
2607 BOOL lvaIsOriginalThisArg(unsigned varNum); // Is this varNum the original this argument?
2608 BOOL lvaIsOriginalThisReadOnly(); // return TRUE if there is no place in the code
2609 // that writes to arg0
2611 // Struct parameters that are passed by reference are marked as both lvIsParam and lvIsTemp
2612 // (this is an overload of lvIsTemp because there are no temp parameters).
2613 // For x64 this is 3, 5, 6, 7, >8 byte structs that are passed by reference.
2614 // For ARM64, this is structs larger than 16 bytes that are passed by reference.
2615 bool lvaIsImplicitByRefLocal(unsigned varNum)
2617 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
2618 LclVarDsc* varDsc = &(lvaTable[varNum]);
2619 if (varDsc->lvIsParam && varDsc->lvIsTemp)
2621 assert((varDsc->lvType == TYP_STRUCT) || (varDsc->lvType == TYP_BYREF));
2624 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
2628 // Returns true if this local var is a multireg struct
2629 bool lvaIsMultiregStruct(LclVarDsc* varDsc);
2631 // If the class is a TYP_STRUCT, get/set a class handle describing it
2633 CORINFO_CLASS_HANDLE lvaGetStruct(unsigned varNum);
2634 void lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool unsafeValueClsCheck, bool setTypeInfo = true);
2636 #define MAX_NumOfFieldsInPromotableStruct 4 // Maximum number of fields in promotable struct
2638 // Info about struct fields
2639 struct lvaStructFieldInfo
2641 CORINFO_FIELD_HANDLE fldHnd;
2642 unsigned char fldOffset;
2643 unsigned char fldOrdinal;
2646 CORINFO_CLASS_HANDLE fldTypeHnd;
2649 // Info about struct to be promoted.
2650 struct lvaStructPromotionInfo
2652 CORINFO_CLASS_HANDLE typeHnd;
2654 bool requiresScratchVar;
2657 unsigned char fieldCnt;
2658 lvaStructFieldInfo fields[MAX_NumOfFieldsInPromotableStruct];
2660 lvaStructPromotionInfo()
2661 : typeHnd(nullptr), canPromote(false), requiresScratchVar(false), containsHoles(false), customLayout(false)
2666 static int __cdecl lvaFieldOffsetCmp(const void* field1, const void* field2);
2667 void lvaCanPromoteStructType(CORINFO_CLASS_HANDLE typeHnd,
2668 lvaStructPromotionInfo* StructPromotionInfo,
2670 void lvaCanPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo);
2671 void lvaPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo);
2672 #if !defined(_TARGET_64BIT_)
2673 void lvaPromoteLongVars();
2674 #endif // !defined(_TARGET_64BIT_)
2675 unsigned lvaGetFieldLocal(LclVarDsc* varDsc, unsigned int fldOffset);
2676 lvaPromotionType lvaGetPromotionType(const LclVarDsc* varDsc);
2677 lvaPromotionType lvaGetPromotionType(unsigned varNum);
2678 lvaPromotionType lvaGetParentPromotionType(const LclVarDsc* varDsc);
2679 lvaPromotionType lvaGetParentPromotionType(unsigned varNum);
2680 bool lvaIsFieldOfDependentlyPromotedStruct(const LclVarDsc* varDsc);
2681 bool lvaIsGCTracked(const LclVarDsc* varDsc);
2683 #if defined(FEATURE_SIMD)
2684 bool lvaMapSimd12ToSimd16(const LclVarDsc* varDsc)
2686 assert(varDsc->lvType == TYP_SIMD12);
2687 assert(varDsc->lvExactSize == 12);
2689 #if defined(_TARGET_64BIT_)
2690 assert(varDsc->lvSize() == 16);
2692 #else // !defined(_TARGET_64BIT_)
2694 // For 32-bit architectures, we make local variable SIMD12 types 16 bytes instead of just 12. lvSize()
2695 // already does this calculation. However, we also need to prevent mapping types if the var is a
2696 // depenendently promoted struct field, which must remain its exact size within its parent struct.
2697 // However, we don't know this until late, so we may have already pretended the field is bigger
2699 if ((varDsc->lvSize() == 16) && !lvaIsFieldOfDependentlyPromotedStruct(varDsc))
2708 #endif // !defined(_TARGET_64BIT_)
2710 #endif // defined(FEATURE_SIMD)
2712 BYTE* lvaGetGcLayout(unsigned varNum);
2713 bool lvaTypeIsGC(unsigned varNum);
2714 unsigned lvaGSSecurityCookie; // LclVar number
2715 bool lvaTempsHaveLargerOffsetThanVars();
2717 unsigned lvaSecurityObject; // variable representing the security object on the stack
2718 unsigned lvaStubArgumentVar; // variable representing the secret stub argument coming in EAX
2720 #if FEATURE_EH_FUNCLETS
2721 unsigned lvaPSPSym; // variable representing the PSPSym
2724 InlineInfo* impInlineInfo;
2725 InlineStrategy* m_inlineStrategy;
2727 // The Compiler* that is the root of the inlining tree of which "this" is a member.
2728 Compiler* impInlineRoot();
2730 #if defined(DEBUG) || defined(INLINE_DATA)
2731 unsigned __int64 getInlineCycleCount()
2733 return m_compCycles;
2735 #endif // defined(DEBUG) || defined(INLINE_DATA)
2737 bool fgNoStructPromotion; // Set to TRUE to turn off struct promotion for this method.
2738 bool fgNoStructParamPromotion; // Set to TRUE to turn off struct promotion for parameters this method.
2740 //=========================================================================
2742 //=========================================================================
2745 //---------------- Local variable ref-counting ----------------------------
2748 BasicBlock* lvaMarkRefsCurBlock;
2749 GenTreePtr lvaMarkRefsCurStmt;
2751 BasicBlock::weight_t lvaMarkRefsWeight;
2753 static fgWalkPreFn lvaMarkLclRefsCallback;
2754 void lvaMarkLclRefs(GenTreePtr tree);
2756 // Keeps the mapping from SSA #'s to VN's for the implicit memory variables.
2757 PerSsaArray lvMemoryPerSsaData;
2758 unsigned lvMemoryNumSsaNames;
2761 // Returns the address of the per-Ssa data for memory at the given ssaNum (which is required
2762 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
2763 // not an SSA variable).
2764 LclSsaVarDsc* GetMemoryPerSsaData(unsigned ssaNum)
2766 assert(ssaNum != SsaConfig::RESERVED_SSA_NUM);
2767 assert(SsaConfig::RESERVED_SSA_NUM == 0);
2769 assert(ssaNum < lvMemoryNumSsaNames);
2770 return &lvMemoryPerSsaData.GetRef(ssaNum);
2774 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2775 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2779 XX Imports the given method and converts it to semantic trees XX
2781 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2782 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2788 void impImport(BasicBlock* method);
2790 CORINFO_CLASS_HANDLE impGetRefAnyClass();
2791 CORINFO_CLASS_HANDLE impGetRuntimeArgumentHandle();
2792 CORINFO_CLASS_HANDLE impGetTypeHandleClass();
2793 CORINFO_CLASS_HANDLE impGetStringClass();
2794 CORINFO_CLASS_HANDLE impGetObjectClass();
2796 //=========================================================================
2798 //=========================================================================
2801 //-------------------- Stack manipulation ---------------------------------
2803 unsigned impStkSize; // Size of the full stack
2805 #define SMALL_STACK_SIZE 16 // number of elements in impSmallStack
2807 StackEntry impSmallStack[SMALL_STACK_SIZE]; // Use this array if possible
2809 struct SavedStack // used to save/restore stack contents.
2811 unsigned ssDepth; // number of values on stack
2812 StackEntry* ssTrees; // saved tree values
2815 bool impIsPrimitive(CorInfoType type);
2816 bool impILConsumesAddr(const BYTE* codeAddr, CORINFO_METHOD_HANDLE fncHandle, CORINFO_MODULE_HANDLE scpHandle);
2818 void impResolveToken(const BYTE* addr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CorInfoTokenKind kind);
2819 void impPushOnStackNoType(GenTreePtr tree);
2821 void impPushOnStack(GenTreePtr tree, typeInfo ti);
2822 void impPushNullObjRefOnStack();
2823 StackEntry impPopStack();
2824 StackEntry impPopStack(CORINFO_CLASS_HANDLE& structTypeRet);
2825 GenTreePtr impPopStack(typeInfo& ti);
2826 StackEntry& impStackTop(unsigned n = 0);
2828 void impSaveStackState(SavedStack* savePtr, bool copy);
2829 void impRestoreStackState(SavedStack* savePtr);
2831 GenTreePtr impImportLdvirtftn(GenTreePtr thisPtr,
2832 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2833 CORINFO_CALL_INFO* pCallInfo);
2835 void impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken);
2837 void impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
2839 bool impCanPInvokeInline();
2840 bool impCanPInvokeInlineCallSite(BasicBlock* block);
2841 void impCheckForPInvokeCall(
2842 GenTreePtr call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block);
2843 GenTreePtr impImportIndirectCall(CORINFO_SIG_INFO* sig, IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2844 void impPopArgsForUnmanagedCall(GenTreePtr call, CORINFO_SIG_INFO* sig);
2846 void impInsertHelperCall(CORINFO_HELPER_DESC* helperCall);
2847 void impHandleAccessAllowed(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
2848 void impHandleAccessAllowedInternal(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
2850 void impInsertCalloutForDelegate(CORINFO_METHOD_HANDLE callerMethodHnd,
2851 CORINFO_METHOD_HANDLE calleeMethodHnd,
2852 CORINFO_CLASS_HANDLE delegateTypeHnd);
2854 var_types impImportCall(OPCODE opcode,
2855 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2856 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call on a
2858 GenTreePtr newobjThis,
2860 CORINFO_CALL_INFO* callInfo,
2861 IL_OFFSET rawILOffset);
2863 bool impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo);
2865 GenTreePtr impFixupCallStructReturn(GenTreePtr call, CORINFO_CLASS_HANDLE retClsHnd);
2867 GenTreePtr impFixupStructReturnType(GenTreePtr op, CORINFO_CLASS_HANDLE retClsHnd);
2870 var_types impImportJitTestLabelMark(int numArgs);
2873 GenTreePtr impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken);
2875 GenTreePtr impImportStaticReadOnlyField(void* fldAddr, var_types lclTyp);
2877 GenTreePtr impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken,
2878 CORINFO_ACCESS_FLAGS access,
2879 CORINFO_FIELD_INFO* pFieldInfo,
2882 static void impBashVarAddrsToI(GenTreePtr tree1, GenTreePtr tree2 = nullptr);
2884 GenTreePtr impImplicitIorI4Cast(GenTreePtr tree, var_types dstTyp);
2886 GenTreePtr impImplicitR4orR8Cast(GenTreePtr tree, var_types dstTyp);
2888 void impImportLeave(BasicBlock* block);
2889 void impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr);
2890 GenTreePtr impIntrinsic(GenTreePtr newobjThis,
2891 CORINFO_CLASS_HANDLE clsHnd,
2892 CORINFO_METHOD_HANDLE method,
2893 CORINFO_SIG_INFO* sig,
2897 CorInfoIntrinsics* pIntrinsicID);
2898 GenTreePtr impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
2899 CORINFO_SIG_INFO* sig,
2902 CorInfoIntrinsics intrinsicID);
2903 GenTreePtr impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig);
2905 GenTreePtr impMethodPointer(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
2907 GenTreePtr impTransformThis(GenTreePtr thisPtr,
2908 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
2909 CORINFO_THIS_TRANSFORM transform);
2911 //----------------- Manipulating the trees and stmts ----------------------
2913 GenTreePtr impTreeList; // Trees for the BB being imported
2914 GenTreePtr impTreeLast; // The last tree for the current BB
2918 CHECK_SPILL_ALL = -1,
2919 CHECK_SPILL_NONE = -2
2923 void impBeginTreeList();
2924 void impEndTreeList(BasicBlock* block, GenTreePtr firstStmt, GenTreePtr lastStmt);
2925 void impEndTreeList(BasicBlock* block);
2926 void impAppendStmtCheck(GenTreePtr stmt, unsigned chkLevel);
2927 void impAppendStmt(GenTreePtr stmt, unsigned chkLevel);
2928 void impInsertStmtBefore(GenTreePtr stmt, GenTreePtr stmtBefore);
2929 GenTreePtr impAppendTree(GenTreePtr tree, unsigned chkLevel, IL_OFFSETX offset);
2930 void impInsertTreeBefore(GenTreePtr tree, IL_OFFSETX offset, GenTreePtr stmtBefore);
2931 void impAssignTempGen(unsigned tmp,
2934 GenTreePtr* pAfterStmt = nullptr,
2935 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
2936 BasicBlock* block = nullptr);
2937 void impAssignTempGen(unsigned tmpNum,
2939 CORINFO_CLASS_HANDLE structHnd,
2941 GenTreePtr* pAfterStmt = nullptr,
2942 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
2943 BasicBlock* block = nullptr);
2944 GenTreePtr impCloneExpr(GenTreePtr tree,
2946 CORINFO_CLASS_HANDLE structHnd,
2948 GenTreePtr* pAfterStmt DEBUGARG(const char* reason));
2949 GenTreePtr impAssignStruct(GenTreePtr dest,
2951 CORINFO_CLASS_HANDLE structHnd,
2953 GenTreePtr* pAfterStmt = nullptr,
2954 BasicBlock* block = nullptr);
2955 GenTreePtr impAssignStructPtr(GenTreePtr dest,
2957 CORINFO_CLASS_HANDLE structHnd,
2959 GenTreePtr* pAfterStmt = nullptr,
2960 BasicBlock* block = nullptr);
2962 GenTreePtr impGetStructAddr(GenTreePtr structVal,
2963 CORINFO_CLASS_HANDLE structHnd,
2967 var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd,
2968 BYTE* gcLayout = nullptr,
2969 unsigned* numGCVars = nullptr,
2970 var_types* simdBaseType = nullptr);
2972 GenTreePtr impNormStructVal(GenTreePtr structVal,
2973 CORINFO_CLASS_HANDLE structHnd,
2975 bool forceNormalization = false);
2977 GenTreePtr impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
2978 BOOL* pRuntimeLookup = nullptr,
2979 BOOL mustRestoreHandle = FALSE,
2980 BOOL importParent = FALSE);
2982 GenTreePtr impParentClassTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
2983 BOOL* pRuntimeLookup = nullptr,
2984 BOOL mustRestoreHandle = FALSE)
2986 return impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, TRUE);
2989 GenTreePtr impLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
2990 CORINFO_LOOKUP* pLookup,
2992 void* compileTimeHandle);
2994 GenTreePtr getRuntimeContextTree(CORINFO_RUNTIME_LOOKUP_KIND kind);
2996 GenTreePtr impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
2997 CORINFO_LOOKUP* pLookup,
2998 void* compileTimeHandle);
3000 GenTreePtr impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP* pLookup, unsigned flags, void* compileTimeHandle);
3002 GenTreePtr impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3003 CorInfoHelpFunc helper,
3005 GenTreeArgList* arg = nullptr,
3006 CORINFO_LOOKUP_KIND* pGenericLookupKind = nullptr);
3008 GenTreePtr impCastClassOrIsInstToTree(GenTreePtr op1,
3010 CORINFO_RESOLVED_TOKEN* pResolvedToken,
3013 bool VarTypeIsMultiByteAndCanEnreg(var_types type,
3014 CORINFO_CLASS_HANDLE typeClass,
3018 static bool IsIntrinsicImplementedByUserCall(CorInfoIntrinsics intrinsicId);
3019 static bool IsTargetIntrinsic(CorInfoIntrinsics intrinsicId);
3020 static bool IsMathIntrinsic(CorInfoIntrinsics intrinsicId);
3021 static bool IsMathIntrinsic(GenTreePtr tree);
3024 //----------------- Importing the method ----------------------------------
3026 CORINFO_CONTEXT_HANDLE impTokenLookupContextHandle; // The context used for looking up tokens.
3029 unsigned impCurOpcOffs;
3030 const char* impCurOpcName;
3031 bool impNestedStackSpill;
3033 // For displaying instrs with generated native code (-n:B)
3034 GenTreePtr impLastILoffsStmt; // oldest stmt added for which we did not gtStmtLastILoffs
3035 void impNoteLastILoffs();
3038 /* IL offset of the stmt currently being imported. It gets set to
3039 BAD_IL_OFFSET after it has been set in the appended trees. Then it gets
3040 updated at IL offsets for which we have to report mapping info.
3041 It also includes flag bits, so use jitGetILoffs()
3042 to get the actual IL offset value.
3045 IL_OFFSETX impCurStmtOffs;
3046 void impCurStmtOffsSet(IL_OFFSET offs);
3048 void impNoteBranchOffs();
3050 unsigned impInitBlockLineInfo();
3052 GenTreePtr impCheckForNullPointer(GenTreePtr obj);
3053 bool impIsThis(GenTreePtr obj);
3054 bool impIsLDFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3055 bool impIsDUP_LDVIRTFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3056 bool impIsAnySTLOC(OPCODE opcode)
3058 return ((opcode == CEE_STLOC) || (opcode == CEE_STLOC_S) ||
3059 ((opcode >= CEE_STLOC_0) && (opcode <= CEE_STLOC_3)));
3062 GenTreeArgList* impPopList(unsigned count,
3064 CORINFO_SIG_INFO* sig,
3065 GenTreeArgList* prefixTree = nullptr);
3067 GenTreeArgList* impPopRevList(unsigned count,
3069 CORINFO_SIG_INFO* sig,
3070 unsigned skipReverseCount = 0);
3073 * Get current IL offset with stack-empty info incoporated
3075 IL_OFFSETX impCurILOffset(IL_OFFSET offs, bool callInstruction = false);
3077 //---------------- Spilling the importer stack ----------------------------
3083 SavedStack pdSavedStack;
3084 ThisInitState pdThisPtrInit;
3087 PendingDsc* impPendingList; // list of BBs currently waiting to be imported.
3088 PendingDsc* impPendingFree; // Freed up dscs that can be reused
3090 // We keep a byte-per-block map (dynamically extended) in the top-level Compiler object of a compilation.
3091 ExpandArray<BYTE> impPendingBlockMembers;
3093 // Return the byte for "b" (allocating/extending impPendingBlockMembers if necessary.)
3094 // Operates on the map in the top-level ancestor.
3095 BYTE impGetPendingBlockMember(BasicBlock* blk)
3097 return impInlineRoot()->impPendingBlockMembers.Get(blk->bbInd());
3100 // Set the byte for "b" to "val" (allocating/extending impPendingBlockMembers if necessary.)
3101 // Operates on the map in the top-level ancestor.
3102 void impSetPendingBlockMember(BasicBlock* blk, BYTE val)
3104 impInlineRoot()->impPendingBlockMembers.Set(blk->bbInd(), val);
3107 bool impCanReimport;
3109 bool impSpillStackEntry(unsigned level,
3113 bool bAssertOnRecursion,
3118 void impSpillStackEnsure(bool spillLeaves = false);
3119 void impEvalSideEffects();
3120 void impSpillSpecialSideEff();
3121 void impSpillSideEffects(bool spillGlobEffects, unsigned chkLevel DEBUGARG(const char* reason));
3122 void impSpillValueClasses();
3123 void impSpillEvalStack();
3124 static fgWalkPreFn impFindValueClasses;
3125 void impSpillLclRefs(ssize_t lclNum);
3127 BasicBlock* impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_HANDLE clsHnd);
3129 void impImportBlockCode(BasicBlock* block);
3131 void impReimportMarkBlock(BasicBlock* block);
3132 void impReimportMarkSuccessors(BasicBlock* block);
3134 void impVerifyEHBlock(BasicBlock* block, bool isTryStart);
3136 void impImportBlockPending(BasicBlock* block);
3138 // Similar to impImportBlockPending, but assumes that block has already been imported once and is being
3139 // reimported for some reason. It specifically does *not* look at verCurrentState to set the EntryState
3140 // for the block, but instead, just re-uses the block's existing EntryState.
3141 void impReimportBlockPending(BasicBlock* block);
3143 var_types impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTreePtr* pOp1, GenTreePtr* pOp2);
3145 void impImportBlock(BasicBlock* block);
3147 // Assumes that "block" is a basic block that completes with a non-empty stack. We will assign the values
3148 // on the stack to local variables (the "spill temp" variables). The successor blocks will assume that
3149 // its incoming stack contents are in those locals. This requires "block" and its successors to agree on
3150 // the variables that will be used -- and for all the predecessors of those successors, and the
3151 // successors of those predecessors, etc. Call such a set of blocks closed under alternating
3152 // successor/predecessor edges a "spill clique." A block is a "predecessor" or "successor" member of the
3153 // clique (or, conceivably, both). Each block has a specified sequence of incoming and outgoing spill
3154 // temps. If "block" already has its outgoing spill temps assigned (they are always a contiguous series
3155 // of local variable numbers, so we represent them with the base local variable number), returns that.
3156 // Otherwise, picks a set of spill temps, and propagates this choice to all blocks in the spill clique of
3157 // which "block" is a member (asserting, in debug mode, that no block in this clique had its spill temps
3158 // chosen already. More precisely, that the incoming or outgoing spill temps are not chosen, depending
3159 // on which kind of member of the clique the block is).
3160 unsigned impGetSpillTmpBase(BasicBlock* block);
3162 // Assumes that "block" is a basic block that completes with a non-empty stack. We have previously
3163 // assigned the values on the stack to local variables (the "spill temp" variables). The successor blocks
3164 // will assume that its incoming stack contents are in those locals. This requires "block" and its
3165 // successors to agree on the variables and their types that will be used. The CLI spec allows implicit
3166 // conversions between 'int' and 'native int' or 'float' and 'double' stack types. So one predecessor can
3167 // push an int and another can push a native int. For 64-bit we have chosen to implement this by typing
3168 // the "spill temp" as native int, and then importing (or re-importing as needed) so that all the
3169 // predecessors in the "spill clique" push a native int (sign-extending if needed), and all the
3170 // successors receive a native int. Similarly float and double are unified to double.
3171 // This routine is called after a type-mismatch is detected, and it will walk the spill clique to mark
3172 // blocks for re-importation as appropriate (both successors, so they get the right incoming type, and
3173 // predecessors, so they insert an upcast if needed).
3174 void impReimportSpillClique(BasicBlock* block);
3176 // When we compute a "spill clique" (see above) these byte-maps are allocated to have a byte per basic
3177 // block, and represent the predecessor and successor members of the clique currently being computed.
3178 // *** Access to these will need to be locked in a parallel compiler.
3179 ExpandArray<BYTE> impSpillCliquePredMembers;
3180 ExpandArray<BYTE> impSpillCliqueSuccMembers;
3188 // Abstract class for receiving a callback while walking a spill clique
3189 class SpillCliqueWalker
3192 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk) = 0;
3195 // This class is used for setting the bbStkTempsIn and bbStkTempsOut on the blocks within a spill clique
3196 class SetSpillTempsBase : public SpillCliqueWalker
3201 SetSpillTempsBase(unsigned baseTmp) : m_baseTmp(baseTmp)
3204 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3207 // This class is used for implementing impReimportSpillClique part on each block within the spill clique
3208 class ReimportSpillClique : public SpillCliqueWalker
3213 ReimportSpillClique(Compiler* pComp) : m_pComp(pComp)
3216 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3219 // This is the heart of the algorithm for walking spill cliques. It invokes callback->Visit for each
3220 // predecessor or successor within the spill clique
3221 void impWalkSpillCliqueFromPred(BasicBlock* pred, SpillCliqueWalker* callback);
3223 // For a BasicBlock that has already been imported, the EntryState has an array of GenTrees for the
3224 // incoming locals. This walks that list an resets the types of the GenTrees to match the types of
3225 // the VarDscs. They get out of sync when we have int/native int issues (see impReimportSpillClique).
3226 void impRetypeEntryStateTemps(BasicBlock* blk);
3228 BYTE impSpillCliqueGetMember(SpillCliqueDir predOrSucc, BasicBlock* blk);
3229 void impSpillCliqueSetMember(SpillCliqueDir predOrSucc, BasicBlock* blk, BYTE val);
3231 void impPushVar(GenTree* op, typeInfo tiRetVal);
3232 void impLoadVar(unsigned lclNum, IL_OFFSET offset, typeInfo tiRetVal);
3233 void impLoadVar(unsigned lclNum, IL_OFFSET offset)
3235 impLoadVar(lclNum, offset, lvaTable[lclNum].lvVerTypeInfo);
3237 void impLoadArg(unsigned ilArgNum, IL_OFFSET offset);
3238 void impLoadLoc(unsigned ilLclNum, IL_OFFSET offset);
3239 bool impReturnInstruction(BasicBlock* block, int prefixFlags, OPCODE& opcode);
3242 void impMarkLclDstNotPromotable(unsigned tmpNum, GenTreePtr op, CORINFO_CLASS_HANDLE hClass);
3245 // A free list of linked list nodes used to represent to-do stacks of basic blocks.
3246 struct BlockListNode
3249 BlockListNode* m_next;
3250 BlockListNode(BasicBlock* blk, BlockListNode* next = nullptr) : m_blk(blk), m_next(next)
3253 void* operator new(size_t sz, Compiler* comp);
3255 BlockListNode* impBlockListNodeFreeList;
3257 BlockListNode* AllocBlockListNode();
3258 void FreeBlockListNode(BlockListNode* node);
3260 bool impIsValueType(typeInfo* pTypeInfo);
3261 var_types mangleVarArgsType(var_types type);
3264 regNumber getCallArgIntRegister(regNumber floatReg);
3265 regNumber getCallArgFloatRegister(regNumber intReg);
3266 #endif // FEATURE_VARARG
3269 static unsigned jitTotalMethodCompiled;
3273 static LONG jitNestingLevel;
3276 static BOOL impIsAddressInLocal(GenTreePtr tree, GenTreePtr* lclVarTreeOut);
3278 void impMakeDiscretionaryInlineObservations(InlineInfo* pInlineInfo, InlineResult* inlineResult);
3280 // STATIC inlining decision based on the IL code.
3281 void impCanInlineIL(CORINFO_METHOD_HANDLE fncHandle,
3282 CORINFO_METHOD_INFO* methInfo,
3284 InlineResult* inlineResult);
3286 void impCheckCanInline(GenTreePtr call,
3287 CORINFO_METHOD_HANDLE fncHandle,
3289 CORINFO_CONTEXT_HANDLE exactContextHnd,
3290 InlineCandidateInfo** ppInlineCandidateInfo,
3291 InlineResult* inlineResult);
3293 void impInlineRecordArgInfo(InlineInfo* pInlineInfo,
3294 GenTreePtr curArgVal,
3296 InlineResult* inlineResult);
3298 void impInlineInitVars(InlineInfo* pInlineInfo);
3300 unsigned impInlineFetchLocal(unsigned lclNum DEBUGARG(const char* reason));
3302 GenTreePtr impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, InlLclVarInfo* lclTypeInfo);
3304 BOOL impInlineIsThis(GenTreePtr tree, InlArgInfo* inlArgInfo);
3306 BOOL impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTreePtr additionalTreesToBeEvaluatedBefore,
3307 GenTreePtr variableBeingDereferenced,
3308 InlArgInfo* inlArgInfo);
3310 void impMarkInlineCandidate(GenTreePtr call, CORINFO_CONTEXT_HANDLE exactContextHnd, CORINFO_CALL_INFO* callInfo);
3312 bool impTailCallRetTypeCompatible(var_types callerRetType,
3313 CORINFO_CLASS_HANDLE callerRetTypeClass,
3314 var_types calleeRetType,
3315 CORINFO_CLASS_HANDLE calleeRetTypeClass);
3317 bool impIsTailCallILPattern(bool tailPrefixed,
3319 const BYTE* codeAddrOfNextOpcode,
3320 const BYTE* codeEnd,
3322 bool* IsCallPopRet = nullptr);
3324 bool impIsImplicitTailCallCandidate(
3325 OPCODE curOpcode, const BYTE* codeAddrOfNextOpcode, const BYTE* codeEnd, int prefixFlags, bool isRecursive);
3328 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3329 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3333 XX Info about the basic-blocks, their contents and the flow analysis XX
3335 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3336 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3340 BasicBlock* fgFirstBB; // Beginning of the basic block list
3341 BasicBlock* fgLastBB; // End of the basic block list
3342 BasicBlock* fgFirstColdBlock; // First block to be placed in the cold section
3343 #if FEATURE_EH_FUNCLETS
3344 BasicBlock* fgFirstFuncletBB; // First block of outlined funclets (to allow block insertion before the funclets)
3346 BasicBlock* fgFirstBBScratch; // Block inserted for initialization stuff. Is nullptr if no such block has been
3348 BasicBlockList* fgReturnBlocks; // list of BBJ_RETURN blocks
3349 unsigned fgEdgeCount; // # of control flow edges between the BBs
3350 unsigned fgBBcount; // # of BBs in the method
3352 unsigned fgBBcountAtCodegen; // # of BBs in the method at the start of codegen
3354 unsigned fgBBNumMax; // The max bbNum that has been assigned to basic blocks
3355 unsigned fgDomBBcount; // # of BBs for which we have dominator and reachability information
3356 BasicBlock** fgBBInvPostOrder; // The flow graph stored in an array sorted in topological order, needed to compute
3357 // dominance. Indexed by block number. Size: fgBBNumMax + 1.
3359 // After the dominance tree is computed, we cache a DFS preorder number and DFS postorder number to compute
3360 // dominance queries in O(1). fgDomTreePreOrder and fgDomTreePostOrder are arrays giving the block's preorder and
3361 // postorder number, respectively. The arrays are indexed by basic block number. (Note that blocks are numbered
3362 // starting from one. Thus, we always waste element zero. This makes debugging easier and makes the code less likely
3363 // to suffer from bugs stemming from forgetting to add or subtract one from the block number to form an array
3364 // index). The arrays are of size fgBBNumMax + 1.
3365 unsigned* fgDomTreePreOrder;
3366 unsigned* fgDomTreePostOrder;
3368 bool fgBBVarSetsInited;
3370 // Allocate array like T* a = new T[fgBBNumMax + 1];
3371 // Using helper so we don't keep forgetting +1.
3372 template <typename T>
3373 T* fgAllocateTypeForEachBlk(CompMemKind cmk = CMK_Unknown)
3375 return (T*)compGetMem((fgBBNumMax + 1) * sizeof(T), cmk);
3378 // BlockSets are relative to a specific set of BasicBlock numbers. If that changes
3379 // (if the blocks are renumbered), this changes. BlockSets from different epochs
3380 // cannot be meaningfully combined. Note that new blocks can be created with higher
3381 // block numbers without changing the basic block epoch. These blocks *cannot*
3382 // participate in a block set until the blocks are all renumbered, causing the epoch
3383 // to change. This is useful if continuing to use previous block sets is valuable.
3384 // If the epoch is zero, then it is uninitialized, and block sets can't be used.
3385 unsigned fgCurBBEpoch;
3387 unsigned GetCurBasicBlockEpoch()
3389 return fgCurBBEpoch;
3392 // The number of basic blocks in the current epoch. When the blocks are renumbered,
3393 // this is fgBBcount. As blocks are added, fgBBcount increases, fgCurBBEpochSize remains
3394 // the same, until a new BasicBlock epoch is created, such as when the blocks are all renumbered.
3395 unsigned fgCurBBEpochSize;
3397 // The number of "size_t" elements required to hold a bitset large enough for fgCurBBEpochSize
3398 // bits. This is precomputed to avoid doing math every time BasicBlockBitSetTraits::GetArrSize() is called.
3399 unsigned fgBBSetCountInSizeTUnits;
3401 void NewBasicBlockEpoch()
3403 INDEBUG(unsigned oldEpochArrSize = fgBBSetCountInSizeTUnits);
3405 // We have a new epoch. Compute and cache the size needed for new BlockSets.
3407 fgCurBBEpochSize = fgBBNumMax + 1;
3408 fgBBSetCountInSizeTUnits =
3409 unsigned(roundUp(fgCurBBEpochSize, sizeof(size_t) * 8)) / unsigned(sizeof(size_t) * 8);
3412 // All BlockSet objects are now invalid!
3413 fgReachabilitySetsValid = false; // the bbReach sets are now invalid!
3414 fgEnterBlksSetValid = false; // the fgEnterBlks set is now invalid!
3418 unsigned epochArrSize = BasicBlockBitSetTraits::GetArrSize(this, sizeof(size_t));
3419 printf("\nNew BlockSet epoch %d, # of blocks (including unused BB00): %u, bitset array size: %u (%s)",
3420 fgCurBBEpoch, fgCurBBEpochSize, epochArrSize, (epochArrSize <= 1) ? "short" : "long");
3421 if ((fgCurBBEpoch != 1) && ((oldEpochArrSize <= 1) != (epochArrSize <= 1)))
3423 // If we're not just establishing the first epoch, and the epoch array size has changed such that we're
3424 // going to change our bitset representation from short (just a size_t bitset) to long (a pointer to an
3425 // array of size_t bitsets), then print that out.
3426 printf("; NOTE: BlockSet size was previously %s!", (oldEpochArrSize <= 1) ? "short" : "long");
3433 void EnsureBasicBlockEpoch()
3435 if (fgCurBBEpochSize != fgBBNumMax + 1)
3437 NewBasicBlockEpoch();
3441 BasicBlock* fgNewBasicBlock(BBjumpKinds jumpKind);
3442 void fgEnsureFirstBBisScratch();
3443 bool fgFirstBBisScratch();
3444 bool fgBBisScratch(BasicBlock* block);
3446 void fgExtendEHRegionBefore(BasicBlock* block);
3447 void fgExtendEHRegionAfter(BasicBlock* block);
3449 BasicBlock* fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
3451 BasicBlock* fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
3453 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
3456 BasicBlock* nearBlk,
3457 bool putInFilter = false,
3458 bool runRarely = false,
3459 bool insertAtEnd = false);
3461 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
3463 bool runRarely = false,
3464 bool insertAtEnd = false);
3466 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind);
3468 BasicBlock* fgNewBBinRegionWorker(BBjumpKinds jumpKind,
3469 BasicBlock* afterBlk,
3470 unsigned xcptnIndex,
3471 bool putInTryRegion);
3473 void fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk);
3474 void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk);
3475 void fgUnlinkBlock(BasicBlock* block);
3477 unsigned fgMeasureIR();
3479 #if OPT_BOOL_OPS // Used to detect multiple logical "not" assignments.
3480 bool fgMultipleNots;
3483 bool fgModified; // True if the flow graph has been modified recently
3484 bool fgComputePredsDone; // Have we computed the bbPreds list
3485 bool fgCheapPredsValid; // Is the bbCheapPreds list valid?
3486 bool fgDomsComputed; // Have we computed the dominator sets?
3487 bool fgOptimizedFinally; // Did we optimize any try-finallys?
3489 bool fgHasSwitch; // any BBJ_SWITCH jumps?
3490 bool fgHasPostfix; // any postfix ++/-- found?
3491 unsigned fgIncrCount; // number of increment nodes found
3493 BlockSet fgEnterBlks; // Set of blocks which have a special transfer of control; the "entry" blocks plus EH handler
3497 bool fgReachabilitySetsValid; // Are the bbReach sets valid?
3498 bool fgEnterBlksSetValid; // Is the fgEnterBlks set valid?
3501 bool fgRemoveRestOfBlock; // true if we know that we will throw
3502 bool fgStmtRemoved; // true if we remove statements -> need new DFA
3504 // There are two modes for ordering of the trees.
3505 // - In FGOrderTree, the dominant ordering is the tree order, and the nodes contained in
3506 // each tree and sub-tree are contiguous, and can be traversed (in gtNext/gtPrev order)
3507 // by traversing the tree according to the order of the operands.
3508 // - In FGOrderLinear, the dominant ordering is the linear order.
3515 FlowGraphOrder fgOrder;
3517 // The following are boolean flags that keep track of the state of internal data structures
3519 bool fgStmtListThreaded;
3520 bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
3521 bool fgEdgeWeightsComputed; // true after we have called fgComputeEdgeWeights
3522 bool fgHaveValidEdgeWeights; // true if we were successful in computing all of the edge weights
3523 bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
3524 bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
3525 bool fgNeedsUpdateFlowGraph; // true if we need to run fgUpdateFlowGraph
3526 BasicBlock::weight_t fgCalledWeight; // count of the number of times this method was called
3527 // This is derived from the profile data
3528 // or is BB_UNITY_WEIGHT when we don't have profile data
3530 #if FEATURE_EH_FUNCLETS
3531 bool fgFuncletsCreated; // true if the funclet creation phase has been run
3532 #endif // FEATURE_EH_FUNCLETS
3534 bool fgGlobalMorph; // indicates if we are during the global morphing phase
3535 // since fgMorphTree can be called from several places
3536 bool fgExpandInline; // indicates that we are creating tree for the inliner
3538 bool impBoxTempInUse; // the temp below is valid and available
3539 unsigned impBoxTemp; // a temporary that is used for boxing
3542 bool jitFallbackCompile; // Are we doing a fallback compile? That is, have we executed a NO_WAY assert,
3543 // and we are trying to compile again in a "safer", minopts mode?
3547 unsigned impInlinedCodeSize;
3550 //-------------------------------------------------------------------------
3556 void fgTransformFatCalli();
3560 void fgRemoveEmptyTry();
3562 void fgRemoveEmptyFinally();
3564 void fgCloneFinally();
3566 void fgCleanupContinuation(BasicBlock* continuation);
3568 void fgUpdateFinallyTargetFlags();
3570 GenTreePtr fgGetCritSectOfStaticMethod();
3572 #if !defined(_TARGET_X86_)
3574 void fgAddSyncMethodEnterExit();
3576 GenTree* fgCreateMonitorTree(unsigned lvaMonitorBool, unsigned lvaThisVar, BasicBlock* block, bool enter);
3578 void fgConvertSyncReturnToLeave(BasicBlock* block);
3580 #endif // !_TARGET_X86_
3582 void fgAddReversePInvokeEnterExit();
3584 bool fgMoreThanOneReturnBlock();
3586 // The number of separate return points in the method.
3587 unsigned fgReturnCount;
3589 void fgAddInternal();
3591 bool fgFoldConditional(BasicBlock* block);
3593 void fgMorphStmts(BasicBlock* block, bool* mult, bool* lnot, bool* loadw);
3594 void fgMorphBlocks();
3596 bool fgMorphBlockStmt(BasicBlock* block, GenTreeStmt* stmt DEBUGARG(const char* msg));
3598 void fgCheckArgCnt();
3599 void fgSetOptions();
3602 static fgWalkPreFn fgAssertNoQmark;
3603 void fgPreExpandQmarkChecks(GenTreePtr expr);
3604 void fgPostExpandQmarkChecks();
3605 static void fgCheckQmarkAllowedForm(GenTreePtr tree);
3608 IL_OFFSET fgFindBlockILOffset(BasicBlock* block);
3610 BasicBlock* fgSplitBlockAtBeginning(BasicBlock* curr);
3611 BasicBlock* fgSplitBlockAtEnd(BasicBlock* curr);
3612 BasicBlock* fgSplitBlockAfterStatement(BasicBlock* curr, GenTree* stmt);
3613 BasicBlock* fgSplitBlockAfterNode(BasicBlock* curr, GenTree* node); // for LIR
3614 BasicBlock* fgSplitEdge(BasicBlock* curr, BasicBlock* succ);
3616 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree, BasicBlock* block, IL_OFFSETX offs);
3617 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree);
3618 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree, BasicBlock* block);
3619 GenTreeStmt* fgNewStmtFromTree(GenTreePtr tree, IL_OFFSETX offs);
3621 GenTreePtr fgGetTopLevelQmark(GenTreePtr expr, GenTreePtr* ppDst = nullptr);
3622 void fgExpandQmarkForCastInstOf(BasicBlock* block, GenTreePtr stmt);
3623 void fgExpandQmarkStmt(BasicBlock* block, GenTreePtr expr);
3624 void fgExpandQmarkNodes();
3628 // Do "simple lowering." This functionality is (conceptually) part of "general"
3629 // lowering that is distributed between fgMorph and the lowering phase of LSRA.
3630 void fgSimpleLowering();
3632 bool fgShouldCreateAssignOp(GenTreePtr tree, bool* bReverse);
3634 GenTreePtr fgInitThisClass();
3636 GenTreePtr fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper);
3638 GenTreePtr fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls);
3640 void fgLocalVarLiveness();
3642 void fgLocalVarLivenessInit();
3644 #ifdef LEGACY_BACKEND
3645 GenTreePtr fgLegacyPerStatementLocalVarLiveness(GenTreePtr startNode, GenTreePtr relopNode);
3647 void fgPerNodeLocalVarLiveness(GenTree* node);
3649 void fgPerBlockLocalVarLiveness();
3651 VARSET_VALRET_TP fgGetHandlerLiveVars(BasicBlock* block);
3653 void fgLiveVarAnalysis(bool updateInternalOnly = false);
3655 // This is used in the liveness computation, as a temporary. When we use the
3656 // arbitrary-length VarSet representation, it is better not to allocate a new one
3658 VARSET_TP fgMarkIntfUnionVS;
3660 bool fgMarkIntf(VARSET_VALARG_TP varSet);
3662 bool fgMarkIntf(VARSET_VALARG_TP varSet1, VARSET_VALARG_TP varSet2);
3664 void fgUpdateRefCntForClone(BasicBlock* addedToBlock, GenTreePtr clonedTree);
3666 void fgUpdateRefCntForExtract(GenTreePtr wholeTree, GenTreePtr keptTree);
3668 void fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call);
3670 bool fgComputeLifeLocal(VARSET_TP& life, VARSET_TP& keepAliveVars, GenTree* lclVarNode, GenTree* node);
3672 VARSET_VALRET_TP fgComputeLife(VARSET_VALARG_TP life,
3673 GenTreePtr startNode,
3675 VARSET_VALARG_TP volatileVars,
3676 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
3678 VARSET_VALRET_TP fgComputeLifeLIR(VARSET_VALARG_TP life, BasicBlock* block, VARSET_VALARG_TP volatileVars);
3680 bool fgRemoveDeadStore(GenTree** pTree,
3684 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
3686 bool fgTryRemoveDeadLIRStore(LIR::Range& blockRange, GenTree* node, GenTree** next);
3688 // For updating liveset during traversal AFTER fgComputeLife has completed
3689 VARSET_VALRET_TP fgGetVarBits(GenTreePtr tree);
3690 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTreePtr tree);
3692 // Returns the set of live variables after endTree,
3693 // assuming that liveSet is the set of live variables BEFORE tree.
3694 // Requires that fgComputeLife has completed, and that tree is in the same
3695 // statement as endTree, and that it comes before endTree in execution order
3697 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTreePtr tree, GenTreePtr endTree)
3699 VARSET_TP VARSET_INIT(this, newLiveSet, liveSet);
3700 while (tree != nullptr && tree != endTree->gtNext)
3702 VarSetOps::AssignNoCopy(this, newLiveSet, fgUpdateLiveSet(newLiveSet, tree));
3703 tree = tree->gtNext;
3705 assert(tree == endTree->gtNext);
3709 void fgInterBlockLocalVarLiveness();
3711 // The presence of "x op= y" operations presents some difficulties for SSA: this is both a use of some SSA name of
3712 // "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
3713 // whether to treat that as the use or def. It chooses the "use", and thus the old SSA name. This map allows us
3714 // to record/recover the "def" SSA number, given the lcl var node for "x" in such a tree.
3715 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, unsigned, JitSimplerHashBehavior> NodeToUnsignedMap;
3716 NodeToUnsignedMap* m_opAsgnVarDefSsaNums;
3717 NodeToUnsignedMap* GetOpAsgnVarDefSsaNums()
3719 if (m_opAsgnVarDefSsaNums == nullptr)
3721 m_opAsgnVarDefSsaNums = new (getAllocator()) NodeToUnsignedMap(getAllocator());
3723 return m_opAsgnVarDefSsaNums;
3726 // Requires value numbering phase to have completed. Returns the value number ("gtVN") of the
3727 // "tree," EXCEPT in the case of GTF_VAR_USEASG, because the tree node's gtVN member is the
3728 // "use" VN. Performs a lookup into the map of (use asg tree -> def VN.) to return the "def's"
3730 inline ValueNum GetUseAsgDefVNOrTreeVN(GenTreePtr tree);
3732 // Requires that "lcl" has the GTF_VAR_DEF flag set. Returns the SSA number of "lcl".
3733 // Except: assumes that lcl is a def, and if it is
3734 // a def appearing in "lcl op= rhs" (GTF_VAR_USEASG), looks up and returns the SSA number for the "def",
3735 // rather than the "use" SSA number recorded in the tree "lcl".
3736 inline unsigned GetSsaNumForLocalVarDef(GenTreePtr lcl);
3738 // Some assignments assign to a local "indirectly": they are part of a comma expression that takes the address
3739 // of the local (or a field thereof), assigns this address to a temp, and uses an indirection of this temp as
3740 // the LHS of the assignment. This actually arises in exactly one situation. At the source level we assign one
3741 // struct local to another: "s1 = s2". This becomes a copyblk. If "s2" is promoted into field variables "s2f0",
3742 // ..."s2fn", then the copyblk will morph to a comma expression that takes the address of "s1" and does field-wise
3744 // (byref addrS1 = &s1,
3745 // *(addrS1 * offsetof(f0)) = s2f0,
3747 // *(addrS1 * offsetof(fn)) = s2fn)
3749 // It would be a shame, given the simple form at the source level, to be unable to track the values in the
3750 // fields of "s1" after this. But "s1" does not appear in the assignments that modify it. How, then, to
3751 // give it SSA names and value numbers?
3753 // The solution is to use the side table described below to annotate each of the field-wise assignments at the
3754 // end with an instance of the structure below, whose fields are described in the declaration.
3755 struct IndirectAssignmentAnnotation
3757 unsigned m_lclNum; // The local num that is being indirectly assigned.
3758 FieldSeqNode* m_fieldSeq; // If the LHS of the struct assignment is itself a struct field dereference,
3759 // as in "s0.g = s2", then "m_lclNum" would be "s0", and "m_fieldSeq" would
3760 // be the singleton field sequence "g". The individual assignments would
3761 // further append the fields of "s.g" to that.
3762 bool m_isEntire; // True iff this assignment writes all of m_lclNum. (This can occur if the
3763 // structure has a single field).
3764 unsigned m_defSsaNum; // The new SSA number of "m_lclNum" after the assignment.
3765 unsigned m_useSsaNum; // Only valid if "m_isEntire" is false; if so, the SSA number of "m_lclNum" before the
3768 IndirectAssignmentAnnotation(unsigned lclNum,
3769 FieldSeqNode* fldSeq,
3771 unsigned defSsaNum = SsaConfig::RESERVED_SSA_NUM,
3772 unsigned useSsaNum = SsaConfig::RESERVED_SSA_NUM)
3773 : m_lclNum(lclNum), m_fieldSeq(fldSeq), m_isEntire(isEntire), m_defSsaNum(defSsaNum), m_useSsaNum(useSsaNum)
3777 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, IndirectAssignmentAnnotation*, JitSimplerHashBehavior>
3778 NodeToIndirAssignMap;
3779 NodeToIndirAssignMap* m_indirAssignMap;
3780 NodeToIndirAssignMap* GetIndirAssignMap()
3782 if (m_indirAssignMap == nullptr)
3784 // Create a CompAllocator that labels sub-structure with CMK_IndirAssignMap, and use that for allocation.
3785 IAllocator* ialloc = new (this, CMK_IndirAssignMap) CompAllocator(this, CMK_IndirAssignMap);
3786 m_indirAssignMap = new (ialloc) NodeToIndirAssignMap(ialloc);
3788 return m_indirAssignMap;
3791 // Performs SSA conversion.
3794 // Reset any data structures to the state expected by "fgSsaBuild", so it can be run again.
3795 void fgResetForSsa();
3797 unsigned fgSsaPassesCompleted; // Number of times fgSsaBuild has been run.
3799 // Returns "true" iff lcl "lclNum" should be excluded from SSA.
3800 inline bool fgExcludeFromSsa(unsigned lclNum);
3802 // The value numbers for this compilation.
3803 ValueNumStore* vnStore;
3806 ValueNumStore* GetValueNumStore()
3811 // Do value numbering (assign a value number to each
3813 void fgValueNumber();
3815 // Computes new GcHeap VN via the assignment H[elemTypeEq][arrVN][inx][fldSeq] = rhsVN.
3816 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
3817 // The 'indType' is the indirection type of the lhs of the assignment and will typically
3818 // match the element type of the array or fldSeq. When this type doesn't match
3819 // or if the fldSeq is 'NotAField' we invalidate the array contents H[elemTypeEq][arrVN]
3821 ValueNum fgValueNumberArrIndexAssign(CORINFO_CLASS_HANDLE elemTypeEq,
3824 FieldSeqNode* fldSeq,
3828 // Requires that "tree" is a GT_IND marked as an array index, and that its address argument
3829 // has been parsed to yield the other input arguments. If evaluation of the address
3830 // can raise exceptions, those should be captured in the exception set "excVN."
3831 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
3832 // Marks "tree" with the VN for H[elemTypeEq][arrVN][inx][fldSeq] (for the liberal VN; a new unique
3833 // VN for the conservative VN.) Also marks the tree's argument as the address of an array element.
3834 // The type tree->TypeGet() will typically match the element type of the array or fldSeq.
3835 // When this type doesn't match or if the fldSeq is 'NotAField' we return a new unique VN
3837 ValueNum fgValueNumberArrIndexVal(GenTreePtr tree,
3838 CORINFO_CLASS_HANDLE elemTypeEq,
3842 FieldSeqNode* fldSeq);
3844 // Requires "funcApp" to be a VNF_PtrToArrElem, and "addrXvn" to represent the exception set thrown
3845 // by evaluating the array index expression "tree". Returns the value number resulting from
3846 // dereferencing the array in the current GcHeap state. If "tree" is non-null, it must be the
3847 // "GT_IND" that does the dereference, and it is given the returned value number.
3848 ValueNum fgValueNumberArrIndexVal(GenTreePtr tree, struct VNFuncApp* funcApp, ValueNum addrXvn);
3850 // Compute the value number for a byref-exposed load of the given type via the given pointerVN.
3851 ValueNum fgValueNumberByrefExposedLoad(var_types type, ValueNum pointerVN);
3853 unsigned fgVNPassesCompleted; // Number of times fgValueNumber has been run.
3855 // Utility functions for fgValueNumber.
3857 // Perform value-numbering for the trees in "blk".
3858 void fgValueNumberBlock(BasicBlock* blk);
3860 // Requires that "entryBlock" is the entry block of loop "loopNum", and that "loopNum" is the
3861 // innermost loop of which "entryBlock" is the entry. Returns the value number that should be
3862 // assumed for the memoryKind at the start "entryBlk".
3863 ValueNum fgMemoryVNForLoopSideEffects(MemoryKind memoryKind, BasicBlock* entryBlock, unsigned loopNum);
3865 // Called when an operation (performed by "tree", described by "msg") may cause the GcHeap to be mutated.
3866 // As GcHeap is a subset of ByrefExposed, this will also annotate the ByrefExposed mutation.
3867 void fgMutateGcHeap(GenTreePtr tree DEBUGARG(const char* msg));
3869 // Called when an operation (performed by "tree", described by "msg") may cause an address-exposed local to be
3871 void fgMutateAddressExposedLocal(GenTreePtr tree DEBUGARG(const char* msg));
3873 // For a GC heap store at curTree, record the new curMemoryVN's and update curTree's MemorySsaMap.
3874 // As GcHeap is a subset of ByrefExposed, this will also record the ByrefExposed store.
3875 void recordGcHeapStore(GenTreePtr curTree, ValueNum gcHeapVN DEBUGARG(const char* msg));
3877 // For a store to an address-exposed local at curTree, record the new curMemoryVN and update curTree's MemorySsaMap.
3878 void recordAddressExposedLocalStore(GenTreePtr curTree, ValueNum memoryVN DEBUGARG(const char* msg));
3880 // Tree caused an update in the current memory VN. If "tree" has an associated heap SSA #, record that
3881 // value in that SSA #.
3882 void fgValueNumberRecordMemorySsa(MemoryKind memoryKind, GenTreePtr tree);
3884 // The input 'tree' is a leaf node that is a constant
3885 // Assign the proper value number to the tree
3886 void fgValueNumberTreeConst(GenTreePtr tree);
3888 // Assumes that all inputs to "tree" have had value numbers assigned; assigns a VN to tree.
3889 // (With some exceptions: the VN of the lhs of an assignment is assigned as part of the
3891 // If "evalAsgLhsInd" is true, evaluate a GT_IND node, even if it's labeled as the LHS of
3893 void fgValueNumberTree(GenTreePtr tree, bool evalAsgLhsInd = false);
3895 // Does value-numbering for a block assignment.
3896 void fgValueNumberBlockAssignment(GenTreePtr tree, bool evalAsgLhsInd);
3898 // Does value-numbering for a cast tree.
3899 void fgValueNumberCastTree(GenTreePtr tree);
3901 // Does value-numbering for an intrinsic tree.
3902 void fgValueNumberIntrinsic(GenTreePtr tree);
3904 // Does value-numbering for a call. We interpret some helper calls.
3905 void fgValueNumberCall(GenTreeCall* call);
3907 // The VN of some nodes in "args" may have changed -- reassign VNs to the arg list nodes.
3908 void fgUpdateArgListVNs(GenTreeArgList* args);
3910 // Does value-numbering for a helper "call" that has a VN function symbol "vnf".
3911 void fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc);
3913 // Requires "helpCall" to be a helper call. Assigns it a value number;
3914 // we understand the semantics of some of the calls. Returns "true" if
3915 // the call may modify the heap (we assume arbitrary memory side effects if so).
3916 bool fgValueNumberHelperCall(GenTreeCall* helpCall);
3918 // Requires "helpFunc" to be pure. Returns the corresponding VNFunc.
3919 VNFunc fgValueNumberHelperMethVNFunc(CorInfoHelpFunc helpFunc);
3921 // These are the current value number for the memory implicit variables while
3922 // doing value numbering. These are the value numbers under the "liberal" interpretation
3923 // of memory values; the "conservative" interpretation needs no VN, since every access of
3924 // memory yields an unknown value.
3925 ValueNum fgCurMemoryVN[MemoryKindCount];
3927 // Return a "pseudo"-class handle for an array element type. If "elemType" is TYP_STRUCT,
3928 // requires "elemStructType" to be non-null (and to have a low-order zero). Otherwise, low order bit
3929 // is 1, and the rest is an encoding of "elemTyp".
3930 static CORINFO_CLASS_HANDLE EncodeElemType(var_types elemTyp, CORINFO_CLASS_HANDLE elemStructType)
3932 if (elemStructType != nullptr)
3934 assert(varTypeIsStruct(elemTyp) || elemTyp == TYP_REF || elemTyp == TYP_BYREF ||
3935 varTypeIsIntegral(elemTyp));
3936 assert((size_t(elemStructType) & 0x1) == 0x0); // Make sure the encoding below is valid.
3937 return elemStructType;
3941 elemTyp = varTypeUnsignedToSigned(elemTyp);
3942 return CORINFO_CLASS_HANDLE(size_t(elemTyp) << 1 | 0x1);
3945 // If "clsHnd" is the result of an "EncodePrim" call, returns true and sets "*pPrimType" to the
3946 // var_types it represents. Otherwise, returns TYP_STRUCT (on the assumption that "clsHnd" is
3947 // the struct type of the element).
3948 static var_types DecodeElemType(CORINFO_CLASS_HANDLE clsHnd)
3950 size_t clsHndVal = size_t(clsHnd);
3951 if (clsHndVal & 0x1)
3953 return var_types(clsHndVal >> 1);
3961 // Convert a BYTE which represents the VM's CorInfoGCtype to the JIT's var_types
3962 var_types getJitGCType(BYTE gcType);
3964 enum structPassingKind
3966 SPK_Unknown, // Invalid value, never returned
3967 SPK_PrimitiveType, // The struct is passed/returned using a primitive type.
3968 SPK_ByValue, // The struct is passed/returned by value (using the ABI rules)
3969 // for ARM64 and UNIX_X64 in multiple registers. (when all of the
3970 // parameters registers are used, then the stack will be used)
3971 // for X86 passed on the stack, for ARM32 passed in registers
3972 // or the stack or split between registers and the stack.
3973 SPK_ByValueAsHfa, // The struct is passed/returned as an HFA in multiple registers.
3975 }; // The struct is passed/returned by reference to a copy/buffer.
3977 // Get the "primitive" type that is is used when we are given a struct of size 'structSize'.
3978 // For pointer sized structs the 'clsHnd' is used to determine if the struct contains GC ref.
3979 // A "primitive" type is one of the scalar types: byte, short, int, long, ref, float, double
3980 // If we can't or shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
3982 var_types getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS_HANDLE clsHnd);
3984 // Get the type that is used to pass values of the given struct type.
3985 // If you have already retrieved the struct size then pass it as the optional third argument
3987 var_types getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
3988 structPassingKind* wbPassStruct,
3989 unsigned structSize = 0);
3991 // Get the type that is used to return values of the given struct type.
3992 // If you have already retrieved the struct size then pass it as the optional third argument
3994 var_types getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
3995 structPassingKind* wbPassStruct = nullptr,
3996 unsigned structSize = 0);
3999 // Print a representation of "vnp" or "vn" on standard output.
4000 // If "level" is non-zero, we also print out a partial expansion of the value.
4001 void vnpPrint(ValueNumPair vnp, unsigned level);
4002 void vnPrint(ValueNum vn, unsigned level);
4005 // Dominator computation member functions
4006 // Not exposed outside Compiler
4008 bool fgDominate(BasicBlock* b1, BasicBlock* b2); // Return true if b1 dominates b2
4010 bool fgReachable(BasicBlock* b1, BasicBlock* b2); // Returns true if block b1 can reach block b2
4012 void fgComputeDoms(); // Computes the immediate dominators for each basic block in the
4013 // flow graph. We first assume the fields bbIDom on each
4014 // basic block are invalid. This computation is needed later
4015 // by fgBuildDomTree to build the dominance tree structure.
4016 // Based on: A Simple, Fast Dominance Algorithm
4017 // by Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
4019 BlockSet_ValRet_T fgGetDominatorSet(BasicBlock* block); // Returns a set of blocks that dominate the given block.
4020 // Note: this is relatively slow compared to calling fgDominate(),
4021 // especially if dealing with a single block versus block check.
4023 void fgComputeReachabilitySets(); // Compute bbReach sets. (Also sets BBF_GC_SAFE_POINT flag on blocks.)
4025 void fgComputeEnterBlocksSet(); // Compute the set of entry blocks, 'fgEnterBlks'.
4027 bool fgRemoveUnreachableBlocks(); // Remove blocks determined to be unreachable by the bbReach sets.
4029 void fgComputeReachability(); // Perform flow graph node reachability analysis.
4031 BasicBlock* fgIntersectDom(BasicBlock* a, BasicBlock* b); // Intersect two immediate dominator sets.
4033 void fgDfsInvPostOrder(); // In order to compute dominance using fgIntersectDom, the flow graph nodes must be
4034 // processed in topological sort, this function takes care of that.
4036 void fgDfsInvPostOrderHelper(BasicBlock* block, BlockSet& visited, unsigned* count);
4038 BlockSet_ValRet_T fgDomFindStartNodes(); // Computes which basic blocks don't have incoming edges in the flow graph.
4039 // Returns this as a set.
4041 BlockSet_ValRet_T fgDomTreeEntryNodes(BasicBlockList** domTree); // Computes which nodes in the dominance forest are
4042 // root nodes. Returns this as a set.
4045 void fgDispDomTree(BasicBlockList** domTree); // Helper that prints out the Dominator Tree in debug builds.
4048 void fgBuildDomTree(); // Once we compute all the immediate dominator sets for each node in the flow graph
4049 // (performed by fgComputeDoms), this procedure builds the dominance tree represented
4052 // In order to speed up the queries of the form 'Does A dominates B', we can perform a DFS preorder and postorder
4053 // traversal of the dominance tree and the dominance query will become A dominates B iif preOrder(A) <= preOrder(B)
4054 // && postOrder(A) >= postOrder(B) making the computation O(1).
4055 void fgTraverseDomTree(unsigned bbNum, BasicBlockList** domTree, unsigned* preNum, unsigned* postNum);
4057 // When the flow graph changes, we need to update the block numbers, predecessor lists, reachability sets, and
4059 void fgUpdateChangedFlowGraph();
4062 // Compute the predecessors of the blocks in the control flow graph.
4063 void fgComputePreds();
4065 // Remove all predecessor information.
4066 void fgRemovePreds();
4068 // Compute the cheap flow graph predecessors lists. This is used in some early phases
4069 // before the full predecessors lists are computed.
4070 void fgComputeCheapPreds();
4073 void fgAddCheapPred(BasicBlock* block, BasicBlock* blockPred);
4075 void fgRemoveCheapPred(BasicBlock* block, BasicBlock* blockPred);
4085 // Initialize the per-block variable sets (used for liveness analysis).
4086 void fgInitBlockVarSets();
4088 // true if we've gone through and created GC Poll calls.
4089 bool fgGCPollsCreated;
4090 void fgMarkGCPollBlocks();
4091 void fgCreateGCPolls();
4092 bool fgCreateGCPoll(GCPollType pollType, BasicBlock* block);
4094 // Requires that "block" is a block that returns from
4095 // a finally. Returns the number of successors (jump targets of
4096 // of blocks in the covered "try" that did a "LEAVE".)
4097 unsigned fgNSuccsOfFinallyRet(BasicBlock* block);
4099 // Requires that "block" is a block that returns (in the sense of BBJ_EHFINALLYRET) from
4100 // a finally. Returns its "i"th successor (jump targets of
4101 // of blocks in the covered "try" that did a "LEAVE".)
4102 // Requires that "i" < fgNSuccsOfFinallyRet(block).
4103 BasicBlock* fgSuccOfFinallyRet(BasicBlock* block, unsigned i);
4106 // Factor out common portions of the impls of the methods above.
4107 void fgSuccOfFinallyRetWork(BasicBlock* block, unsigned i, BasicBlock** bres, unsigned* nres);
4110 // For many purposes, it is desirable to be able to enumerate the *distinct* targets of a switch statement,
4111 // skipping duplicate targets. (E.g., in flow analyses that are only interested in the set of possible targets.)
4112 // SwitchUniqueSuccSet contains the non-duplicated switch targets.
4113 // (Code that modifies the jump table of a switch has an obligation to call Compiler::UpdateSwitchTableTarget,
4114 // which in turn will call the "UpdateTarget" method of this type if a SwitchUniqueSuccSet has already
4115 // been computed for the switch block. If a switch block is deleted or is transformed into a non-switch,
4116 // we leave the entry associated with the block, but it will no longer be accessed.)
4117 struct SwitchUniqueSuccSet
4119 unsigned numDistinctSuccs; // Number of distinct targets of the switch.
4120 BasicBlock** nonDuplicates; // Array of "numDistinctSuccs", containing all the distinct switch target
4123 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4124 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4125 // remove it from "this", and ensure that "to" is a member. Use "alloc" to do any required allocation.
4126 void UpdateTarget(IAllocator* alloc, BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4129 typedef SimplerHashTable<BasicBlock*, PtrKeyFuncs<BasicBlock>, SwitchUniqueSuccSet, JitSimplerHashBehavior>
4130 BlockToSwitchDescMap;
4133 // Maps BasicBlock*'s that end in switch statements to SwitchUniqueSuccSets that allow
4134 // iteration over only the distinct successors.
4135 BlockToSwitchDescMap* m_switchDescMap;
4138 BlockToSwitchDescMap* GetSwitchDescMap()
4140 if (m_switchDescMap == nullptr)
4142 m_switchDescMap = new (getAllocator()) BlockToSwitchDescMap(getAllocator());
4144 return m_switchDescMap;
4147 // Invalidate the map of unique switch block successors. For example, since the hash key of the map
4148 // depends on block numbers, we must invalidate the map when the blocks are renumbered, to ensure that
4149 // we don't accidentally look up and return the wrong switch data.
4150 void InvalidateUniqueSwitchSuccMap()
4152 m_switchDescMap = nullptr;
4155 // Requires "switchBlock" to be a block that ends in a switch. Returns
4156 // the corresponding SwitchUniqueSuccSet.
4157 SwitchUniqueSuccSet GetDescriptorForSwitch(BasicBlock* switchBlk);
4159 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4160 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4161 // remove it from "this", and ensure that "to" is a member.
4162 void UpdateSwitchTableTarget(BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4164 // Remove the "SwitchUniqueSuccSet" of "switchBlk" in the BlockToSwitchDescMap.
4165 void fgInvalidateSwitchDescMapEntry(BasicBlock* switchBlk);
4167 BasicBlock* fgFirstBlockOfHandler(BasicBlock* block);
4169 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred);
4171 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred, flowList*** ptrToPred);
4173 flowList* fgSpliceOutPred(BasicBlock* block, BasicBlock* blockPred);
4175 flowList* fgRemoveRefPred(BasicBlock* block, BasicBlock* blockPred);
4177 flowList* fgRemoveAllRefPreds(BasicBlock* block, BasicBlock* blockPred);
4179 flowList* fgRemoveAllRefPreds(BasicBlock* block, flowList** ptrToPred);
4181 void fgRemoveBlockAsPred(BasicBlock* block);
4183 void fgChangeSwitchBlock(BasicBlock* oldSwitchBlock, BasicBlock* newSwitchBlock);
4185 void fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* newTarget, BasicBlock* oldTarget);
4187 void fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, BasicBlock* oldTarget);
4189 void fgReplacePred(BasicBlock* block, BasicBlock* oldPred, BasicBlock* newPred);
4191 flowList* fgAddRefPred(BasicBlock* block,
4192 BasicBlock* blockPred,
4193 flowList* oldEdge = nullptr,
4194 bool initializingPreds = false); // Only set to 'true' when we are computing preds in
4197 void fgFindBasicBlocks();
4199 bool fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt);
4201 bool fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionIndex, bool putInTryRegion);
4203 BasicBlock* fgFindInsertPoint(unsigned regionIndex,
4204 bool putInTryRegion,
4205 BasicBlock* startBlk,
4207 BasicBlock* nearBlk,
4208 BasicBlock* jumpBlk,
4211 unsigned fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNesting = nullptr);
4213 void fgRemoveEmptyBlocks();
4215 void fgRemoveStmt(BasicBlock* block, GenTreePtr stmt, bool updateRefCnt = true);
4217 bool fgCheckRemoveStmt(BasicBlock* block, GenTreePtr stmt);
4219 void fgCreateLoopPreHeader(unsigned lnum);
4221 void fgUnreachableBlock(BasicBlock* block);
4223 void fgRemoveConditionalJump(BasicBlock* block);
4225 BasicBlock* fgLastBBInMainFunction();
4227 BasicBlock* fgEndBBAfterMainFunction();
4229 void fgUnlinkRange(BasicBlock* bBeg, BasicBlock* bEnd);
4231 void fgRemoveBlock(BasicBlock* block, bool unreachable);
4233 bool fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4235 void fgCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4237 void fgUpdateLoopsAfterCompacting(BasicBlock* block, BasicBlock* bNext);
4239 BasicBlock* fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst);
4241 bool fgRenumberBlocks();
4243 bool fgExpandRarelyRunBlocks();
4245 bool fgEhAllowsMoveBlock(BasicBlock* bBefore, BasicBlock* bAfter);
4247 void fgMoveBlocksAfter(BasicBlock* bStart, BasicBlock* bEnd, BasicBlock* insertAfterBlk);
4249 enum FG_RELOCATE_TYPE
4251 FG_RELOCATE_TRY, // relocate the 'try' region
4252 FG_RELOCATE_HANDLER // relocate the handler region (including the filter if necessary)
4254 BasicBlock* fgRelocateEHRange(unsigned regionIndex, FG_RELOCATE_TYPE relocateType);
4256 #if FEATURE_EH_FUNCLETS
4257 #if defined(_TARGET_ARM_)
4258 void fgClearFinallyTargetBit(BasicBlock* block);
4259 #endif // defined(_TARGET_ARM_)
4260 bool fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block);
4261 bool fgAnyIntraHandlerPreds(BasicBlock* block);
4262 void fgInsertFuncletPrologBlock(BasicBlock* block);
4263 void fgCreateFuncletPrologBlocks();
4264 void fgCreateFunclets();
4265 #else // !FEATURE_EH_FUNCLETS
4266 bool fgRelocateEHRegions();
4267 #endif // !FEATURE_EH_FUNCLETS
4269 bool fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* target);
4271 bool fgBlockEndFavorsTailDuplication(BasicBlock* block);
4273 bool fgBlockIsGoodTailDuplicationCandidate(BasicBlock* block);
4275 bool fgOptimizeFallthroughTailDup(BasicBlock* block, BasicBlock* target);
4277 bool fgOptimizeEmptyBlock(BasicBlock* block);
4279 bool fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBlock* bDest);
4281 bool fgOptimizeBranch(BasicBlock* bJump);
4283 bool fgOptimizeSwitchBranches(BasicBlock* block);
4285 bool fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev);
4287 bool fgOptimizeSwitchJumps();
4289 void fgPrintEdgeWeights();
4291 void fgComputeEdgeWeights();
4293 void fgReorderBlocks();
4295 void fgDetermineFirstColdBlock();
4297 bool fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc = nullptr);
4299 bool fgUpdateFlowGraph(bool doTailDup = false);
4301 void fgFindOperOrder();
4303 // method that returns if you should split here
4304 typedef bool(fgSplitPredicate)(GenTree* tree, GenTree* parent, fgWalkData* data);
4306 void fgSetBlockOrder();
4308 void fgRemoveReturnBlock(BasicBlock* block);
4310 /* Helper code that has been factored out */
4311 inline void fgConvertBBToThrowBB(BasicBlock* block);
4313 bool fgCastNeeded(GenTreePtr tree, var_types toType);
4314 GenTreePtr fgDoNormalizeOnStore(GenTreePtr tree);
4315 GenTreePtr fgMakeTmpArgNode(
4316 unsigned tmpVarNum FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(const bool passedInRegisters));
4318 // The following check for loops that don't execute calls
4319 bool fgLoopCallMarked;
4321 void fgLoopCallTest(BasicBlock* srcBB, BasicBlock* dstBB);
4322 void fgLoopCallMark();
4324 void fgMarkLoopHead(BasicBlock* block);
4326 unsigned fgGetCodeEstimate(BasicBlock* block);
4329 const char* fgProcessEscapes(const char* nameIn, escapeMapping_t* map);
4330 FILE* fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, LPCWSTR type);
4331 bool fgDumpFlowGraph(Phases phase);
4333 #endif // DUMP_FLOWGRAPHS
4338 void fgDispBBLiveness(BasicBlock* block);
4339 void fgDispBBLiveness();
4340 void fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth = 0);
4341 void fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, bool dumpTrees);
4342 void fgDispBasicBlocks(bool dumpTrees = false);
4343 void fgDumpStmtTree(GenTreePtr stmt, unsigned blkNum);
4344 void fgDumpBlock(BasicBlock* block);
4345 void fgDumpTrees(BasicBlock* firstBlock, BasicBlock* lastBlock);
4347 static fgWalkPreFn fgStress64RsltMulCB;
4348 void fgStress64RsltMul();
4349 void fgDebugCheckUpdate();
4350 void fgDebugCheckBBlist(bool checkBBNum = false, bool checkBBRefs = true);
4351 void fgDebugCheckBlockLinks();
4352 void fgDebugCheckLinks(bool morphTrees = false);
4353 void fgDebugCheckNodeLinks(BasicBlock* block, GenTreePtr stmt);
4354 void fgDebugCheckFlags(GenTreePtr tree);
4355 void fgDebugCheckFlagsHelper(GenTreePtr tree, unsigned treeFlags, unsigned chkFlags);
4356 void fgDebugCheckTryFinallyExits();
4359 #ifdef LEGACY_BACKEND
4360 static void fgOrderBlockOps(GenTreePtr tree,
4364 GenTreePtr* opsPtr, // OUT
4365 regMaskTP* regsPtr); // OUT
4366 #endif // LEGACY_BACKEND
4368 static GenTreePtr fgGetFirstNode(GenTreePtr tree);
4369 static bool fgTreeIsInStmt(GenTree* tree, GenTreeStmt* stmt);
4371 inline bool fgIsInlining()
4373 return fgExpandInline;
4376 void fgTraverseRPO();
4378 //--------------------- Walking the trees in the IR -----------------------
4383 fgWalkPreFn* wtprVisitorFn;
4384 fgWalkPostFn* wtpoVisitorFn;
4385 void* pCallbackData; // user-provided data
4386 bool wtprLclsOnly; // whether to only visit lclvar nodes
4387 GenTreePtr parent; // parent of current node, provided to callback
4388 GenTreeStack* parentStack; // stack of parent nodes, if asked for
4390 bool printModified; // callback can use this
4394 template <bool computeStack>
4395 static fgWalkResult fgWalkTreePreRec(GenTreePtr* pTree, fgWalkData* fgWalkPre);
4397 // general purpose tree-walker that is capable of doing pre- and post- order
4398 // callbacks at the same time
4399 template <bool doPreOrder, bool doPostOrder>
4400 static fgWalkResult fgWalkTreeRec(GenTreePtr* pTree, fgWalkData* fgWalkPre);
4402 fgWalkResult fgWalkTreePre(GenTreePtr* pTree,
4403 fgWalkPreFn* visitor,
4404 void* pCallBackData = nullptr,
4405 bool lclVarsOnly = false,
4406 bool computeStack = false);
4408 fgWalkResult fgWalkTree(GenTreePtr* pTree,
4409 fgWalkPreFn* preVisitor,
4410 fgWalkPostFn* postVisitor,
4411 void* pCallBackData = nullptr);
4413 void fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData);
4417 template <bool computeStack>
4418 static fgWalkResult fgWalkTreePostRec(GenTreePtr* pTree, fgWalkData* fgWalkPre);
4420 fgWalkResult fgWalkTreePost(GenTreePtr* pTree,
4421 fgWalkPostFn* visitor,
4422 void* pCallBackData = nullptr,
4423 bool computeStack = false);
4425 // An fgWalkPreFn that looks for expressions that have inline throws in
4426 // minopts mode. Basically it looks for tress with gtOverflowEx() or
4427 // GTF_IND_RNGCHK. It returns WALK_ABORT if one is found. It
4428 // returns WALK_SKIP_SUBTREES if GTF_EXCEPT is not set (assumes flags
4429 // properly propagated to parent trees). It returns WALK_CONTINUE
4431 static fgWalkResult fgChkThrowCB(GenTreePtr* pTree, Compiler::fgWalkData* data);
4432 static fgWalkResult fgChkLocAllocCB(GenTreePtr* pTree, Compiler::fgWalkData* data);
4433 static fgWalkResult fgChkQmarkCB(GenTreePtr* pTree, Compiler::fgWalkData* data);
4435 /**************************************************************************
4437 *************************************************************************/
4440 friend class SsaBuilder;
4441 friend struct ValueNumberState;
4443 //--------------------- Detect the basic blocks ---------------------------
4445 BasicBlock** fgBBs; // Table of pointers to the BBs
4447 void fgInitBBLookup();
4448 BasicBlock* fgLookupBB(unsigned addr);
4450 void fgMarkJumpTarget(BYTE* jumpTarget, IL_OFFSET offs);
4452 void fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget);
4454 void fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock);
4456 void fgLinkBasicBlocks();
4458 unsigned fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE* jumpTarget);
4460 void fgCheckBasicBlockControlFlow();
4462 void fgControlFlowPermitted(BasicBlock* blkSrc,
4463 BasicBlock* blkDest,
4464 BOOL IsLeave = false /* is the src a leave block */);
4466 bool fgFlowToFirstBlockOfInnerTry(BasicBlock* blkSrc, BasicBlock* blkDest, bool sibling);
4468 void fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, bool isInlining);
4470 void fgAdjustForAddressExposedOrWrittenThis();
4472 bool fgProfileData_ILSizeMismatch;
4473 ICorJitInfo::ProfileBuffer* fgProfileBuffer;
4474 ULONG fgProfileBufferCount;
4475 ULONG fgNumProfileRuns;
4477 unsigned fgStressBBProf()
4480 unsigned result = JitConfig.JitStressBBProf();
4483 if (compStressCompile(STRESS_BB_PROFILE, 15))
4494 bool fgHaveProfileData();
4495 bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weight);
4497 bool fgIsUsingProfileWeights()
4499 return (fgHaveProfileData() || fgStressBBProf());
4501 void fgInstrumentMethod();
4503 //-------- Insert a statement at the start or end of a basic block --------
4507 static bool fgBlockContainsStatementBounded(BasicBlock* block, GenTree* stmt, bool answerOnBoundExceeded = true);
4511 GenTreeStmt* fgInsertStmtAtEnd(BasicBlock* block, GenTreePtr node);
4513 public: // Used by linear scan register allocation
4514 GenTreeStmt* fgInsertStmtNearEnd(BasicBlock* block, GenTreePtr node);
4517 GenTreePtr fgInsertStmtAtBeg(BasicBlock* block, GenTreePtr stmt);
4518 GenTreePtr fgInsertStmtAfter(BasicBlock* block, GenTreePtr insertionPoint, GenTreePtr stmt);
4520 public: // Used by linear scan register allocation
4521 GenTreePtr fgInsertStmtBefore(BasicBlock* block, GenTreePtr insertionPoint, GenTreePtr stmt);
4524 GenTreePtr fgInsertStmtListAfter(BasicBlock* block, GenTreePtr stmtAfter, GenTreePtr stmtList);
4526 GenTreePtr fgMorphSplitTree(GenTree** splitPoint, GenTree* stmt, BasicBlock* blk);
4528 // Create a new temporary variable to hold the result of *ppTree,
4529 // and transform the graph accordingly.
4530 GenTree* fgInsertCommaFormTemp(GenTree** ppTree, CORINFO_CLASS_HANDLE structType = nullptr);
4531 GenTree* fgMakeMultiUse(GenTree** ppTree);
4534 // Recognize a bitwise rotation pattern and convert into a GT_ROL or a GT_ROR node.
4535 GenTreePtr fgRecognizeAndMorphBitwiseRotation(GenTreePtr tree);
4536 bool fgOperIsBitwiseRotationRoot(genTreeOps oper);
4538 //-------- Determine the order in which the trees will be evaluated -------
4540 unsigned fgTreeSeqNum;
4541 GenTree* fgTreeSeqLst;
4542 GenTree* fgTreeSeqBeg;
4544 GenTree* fgSetTreeSeq(GenTree* tree, GenTree* prev = nullptr, bool isLIR = false);
4545 void fgSetTreeSeqHelper(GenTree* tree, bool isLIR);
4546 void fgSetTreeSeqFinish(GenTreePtr tree, bool isLIR);
4547 void fgSetStmtSeq(GenTree* tree);
4548 void fgSetBlockOrder(BasicBlock* block);
4550 //------------------------- Morphing --------------------------------------
4552 unsigned fgPtrArgCntCur;
4553 unsigned fgPtrArgCntMax;
4554 hashBv* fgOutgoingArgTemps;
4555 hashBv* fgCurrentlyInUseArgTemps;
4557 bool compCanEncodePtrArgCntMax();
4559 void fgSetRngChkTarget(GenTreePtr tree, bool delay = true);
4562 void fgMoveOpsLeft(GenTreePtr tree);
4565 bool fgIsCommaThrow(GenTreePtr tree, bool forFolding = false);
4567 bool fgIsThrow(GenTreePtr tree);
4569 bool fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2);
4570 bool fgIsBlockCold(BasicBlock* block);
4572 GenTreePtr fgMorphCastIntoHelper(GenTreePtr tree, int helper, GenTreePtr oper);
4574 GenTreePtr fgMorphIntoHelperCall(GenTreePtr tree, int helper, GenTreeArgList* args);
4576 GenTreePtr fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType, unsigned lclOffs);
4578 bool fgMorphRelopToQmark(GenTreePtr tree);
4580 // A "MorphAddrContext" carries information from the surrounding context. If we are evaluating a byref address,
4581 // it is useful to know whether the address will be immediately dereferenced, or whether the address value will
4582 // be used, perhaps by passing it as an argument to a called method. This affects how null checking is done:
4583 // for sufficiently small offsets, we can rely on OS page protection to implicitly null-check addresses that we
4584 // know will be dereferenced. To know that reliance on implicit null checking is sound, we must further know that
4585 // all offsets between the top-level indirection and the bottom are constant, and that their sum is sufficiently
4586 // small; hence the other fields of MorphAddrContext.
4587 enum MorphAddrContextKind
4592 struct MorphAddrContext
4594 MorphAddrContextKind m_kind;
4595 bool m_allConstantOffsets; // Valid only for "m_kind == MACK_Ind". True iff all offsets between
4596 // top-level indirection and here have been constants.
4597 size_t m_totalOffset; // Valid only for "m_kind == MACK_Ind", and if "m_allConstantOffsets" is true.
4598 // In that case, is the sum of those constant offsets.
4600 MorphAddrContext(MorphAddrContextKind kind) : m_kind(kind), m_allConstantOffsets(true), m_totalOffset(0)
4605 // A MACK_CopyBlock context is immutable, so we can just make one of these and share it.
4606 static MorphAddrContext s_CopyBlockMAC;
4609 GenTreePtr getSIMDStructFromField(GenTreePtr tree,
4610 var_types* baseTypeOut,
4612 unsigned* simdSizeOut,
4613 bool ignoreUsedInSIMDIntrinsic = false);
4614 GenTreePtr fgMorphFieldAssignToSIMDIntrinsicSet(GenTreePtr tree);
4615 GenTreePtr fgMorphFieldToSIMDIntrinsicGet(GenTreePtr tree);
4616 bool fgMorphCombineSIMDFieldAssignments(BasicBlock* block, GenTreePtr stmt);
4617 void impMarkContiguousSIMDFieldAssignments(GenTreePtr stmt);
4619 // fgPreviousCandidateSIMDFieldAsgStmt is only used for tracking previous simd field assignment
4620 // in function: Complier::impMarkContiguousSIMDFieldAssignments.
4621 GenTreePtr fgPreviousCandidateSIMDFieldAsgStmt;
4623 #endif // FEATURE_SIMD
4624 GenTreePtr fgMorphArrayIndex(GenTreePtr tree);
4625 GenTreePtr fgMorphCast(GenTreePtr tree);
4626 GenTreePtr fgUnwrapProxy(GenTreePtr objRef);
4627 GenTreeCall* fgMorphArgs(GenTreeCall* call);
4629 void fgMakeOutgoingStructArgCopy(GenTreeCall* call,
4632 CORINFO_CLASS_HANDLE copyBlkClass FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(
4633 const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structDescPtr));
4635 void fgFixupStructReturn(GenTreePtr call);
4636 GenTreePtr fgMorphLocalVar(GenTreePtr tree);
4637 bool fgAddrCouldBeNull(GenTreePtr addr);
4638 GenTreePtr fgMorphField(GenTreePtr tree, MorphAddrContext* mac);
4639 bool fgCanFastTailCall(GenTreeCall* call);
4640 void fgMorphTailCall(GenTreeCall* call);
4641 void fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCall* recursiveTailCall);
4642 GenTreePtr fgAssignRecursiveCallArgToCallerParam(GenTreePtr arg,
4643 fgArgTabEntryPtr argTabEntry,
4645 IL_OFFSETX callILOffset,
4646 GenTreePtr tmpAssignmentInsertionPoint,
4647 GenTreePtr paramAssignmentInsertionPoint);
4648 static int fgEstimateCallStackSize(GenTreeCall* call);
4649 GenTreePtr fgMorphCall(GenTreeCall* call);
4650 void fgMorphCallInline(GenTreeCall* call, InlineResult* result);
4651 void fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result);
4653 void fgNoteNonInlineCandidate(GenTreeStmt* stmt, GenTreeCall* call);
4654 static fgWalkPreFn fgFindNonInlineCandidate;
4656 GenTreePtr fgOptimizeDelegateConstructor(GenTreePtr call, CORINFO_CONTEXT_HANDLE* ExactContextHnd);
4657 GenTreePtr fgMorphLeaf(GenTreePtr tree);
4658 void fgAssignSetVarDef(GenTreePtr tree);
4659 GenTreePtr fgMorphOneAsgBlockOp(GenTreePtr tree);
4660 GenTreePtr fgMorphInitBlock(GenTreePtr tree);
4661 GenTreePtr fgMorphBlkToInd(GenTreeBlk* tree, var_types type);
4662 GenTreePtr fgMorphGetStructAddr(GenTreePtr* pTree, CORINFO_CLASS_HANDLE clsHnd, bool isRValue = false);
4663 GenTreePtr fgMorphBlkNode(GenTreePtr tree, bool isDest);
4664 GenTreePtr fgMorphBlockOperand(GenTreePtr tree, var_types asgType, unsigned blockWidth, bool isDest);
4665 void fgMorphUnsafeBlk(GenTreeObj* obj);
4666 GenTreePtr fgMorphCopyBlock(GenTreePtr tree);
4667 GenTreePtr fgMorphForRegisterFP(GenTreePtr tree);
4668 GenTreePtr fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac = nullptr);
4669 GenTreePtr fgMorphSmpOpPre(GenTreePtr tree);
4670 GenTreePtr fgMorphModToSubMulDiv(GenTreeOp* tree);
4671 GenTreePtr fgMorphSmpOpOptional(GenTreeOp* tree);
4672 GenTreePtr fgMorphRecognizeBoxNullable(GenTree* compare);
4674 GenTreePtr fgMorphToEmulatedFP(GenTreePtr tree);
4675 GenTreePtr fgMorphConst(GenTreePtr tree);
4678 GenTreePtr fgMorphTree(GenTreePtr tree, MorphAddrContext* mac = nullptr);
4681 #if LOCAL_ASSERTION_PROP
4682 void fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTreePtr tree));
4683 void fgKillDependentAssertions(unsigned lclNum DEBUGARG(GenTreePtr tree));
4685 void fgMorphTreeDone(GenTreePtr tree, GenTreePtr oldTree = nullptr DEBUGARG(int morphNum = 0));
4687 GenTreeStmt* fgMorphStmt;
4689 unsigned fgGetBigOffsetMorphingTemp(var_types type); // We cache one temp per type to be
4690 // used when morphing big offset.
4692 //----------------------- Liveness analysis -------------------------------
4694 VARSET_TP fgCurUseSet; // vars used by block (before an assignment)
4695 VARSET_TP fgCurDefSet; // vars assigned by block (before a use)
4697 MemoryKindSet fgCurMemoryUse; // True iff the current basic block uses memory.
4698 MemoryKindSet fgCurMemoryDef; // True iff the current basic block modifies memory.
4699 MemoryKindSet fgCurMemoryHavoc; // True if the current basic block is known to set memory to a "havoc" value.
4701 bool byrefStatesMatchGcHeapStates; // True iff GcHeap and ByrefExposed memory have all the same def points.
4703 void fgMarkUseDef(GenTreeLclVarCommon* tree);
4705 void fgBeginScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
4706 void fgEndScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
4708 void fgMarkInScope(BasicBlock* block, VARSET_VALARG_TP inScope);
4709 void fgUnmarkInScope(BasicBlock* block, VARSET_VALARG_TP unmarkScope);
4711 void fgExtendDbgScopes();
4712 void fgExtendDbgLifetimes();
4715 void fgDispDebugScopes();
4718 //-------------------------------------------------------------------------
4720 // The following keeps track of any code we've added for things like array
4721 // range checking or explicit calls to enable GC, and so on.
4726 AddCodeDsc* acdNext;
4727 BasicBlock* acdDstBlk; // block to which we jump
4729 SpecialCodeKind acdKind; // what kind of a special block is this?
4730 unsigned short acdStkLvl;
4734 static unsigned acdHelper(SpecialCodeKind codeKind);
4736 AddCodeDsc* fgAddCodeList;
4738 bool fgRngChkThrowAdded;
4739 AddCodeDsc* fgExcptnTargetCache[SCK_COUNT];
4741 BasicBlock* fgRngChkTarget(BasicBlock* block, unsigned stkDepth, SpecialCodeKind kind);
4743 BasicBlock* fgAddCodeRef(BasicBlock* srcBlk, unsigned refData, SpecialCodeKind kind, unsigned stkDepth = 0);
4746 AddCodeDsc* fgFindExcptnTarget(SpecialCodeKind kind, unsigned refData);
4749 bool fgIsCodeAdded();
4751 bool fgIsThrowHlpBlk(BasicBlock* block);
4752 unsigned fgThrowHlpBlkStkLevel(BasicBlock* block);
4754 unsigned fgBigOffsetMorphingTemps[TYP_COUNT];
4756 unsigned fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo);
4757 void fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* result);
4758 void fgInsertInlineeBlocks(InlineInfo* pInlineInfo);
4759 GenTreePtr fgInlinePrependStatements(InlineInfo* inlineInfo);
4760 void fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, GenTreePtr stmt);
4762 #if FEATURE_MULTIREG_RET
4763 GenTreePtr fgGetStructAsStructPtr(GenTreePtr tree);
4764 GenTreePtr fgAssignStructInlineeToVar(GenTreePtr child, CORINFO_CLASS_HANDLE retClsHnd);
4765 void fgAttachStructInlineeToAsg(GenTreePtr tree, GenTreePtr child, CORINFO_CLASS_HANDLE retClsHnd);
4766 #endif // FEATURE_MULTIREG_RET
4768 static fgWalkPreFn fgUpdateInlineReturnExpressionPlaceHolder;
4771 static fgWalkPreFn fgDebugCheckInlineCandidates;
4773 void CheckNoFatPointerCandidatesLeft();
4774 static fgWalkPreFn fgDebugCheckFatPointerCandidates;
4777 void fgPromoteStructs();
4778 fgWalkResult fgMorphStructField(GenTreePtr tree, fgWalkData* fgWalkPre);
4779 fgWalkResult fgMorphLocalField(GenTreePtr tree, fgWalkData* fgWalkPre);
4780 void fgMarkImplicitByRefArgs();
4781 bool fgMorphImplicitByRefArgs(GenTree** pTree, fgWalkData* fgWalkPre);
4782 static fgWalkPreFn fgMarkAddrTakenLocalsPreCB;
4783 static fgWalkPostFn fgMarkAddrTakenLocalsPostCB;
4784 void fgMarkAddressExposedLocals();
4785 bool fgNodesMayInterfere(GenTree* store, GenTree* load);
4787 // Returns true if the type of tree is of size at least "width", or if "tree" is not a
4789 bool fgFitsInOrNotLoc(GenTreePtr tree, unsigned width);
4791 // The given local variable, required to be a struct variable, is being assigned via
4792 // a "lclField", to make it masquerade as an integral type in the ABI. Make sure that
4793 // the variable is not enregistered, and is therefore not promoted independently.
4794 void fgLclFldAssign(unsigned lclNum);
4796 static fgWalkPreFn gtHasLocalsWithAddrOpCB;
4797 bool gtCanOptimizeTypeEquality(GenTreePtr tree);
4798 bool gtIsTypeHandleToRuntimeTypeHelper(GenTreePtr tree);
4799 bool gtIsActiveCSE_Candidate(GenTreePtr tree);
4802 bool fgPrintInlinedMethods;
4805 bool fgIsBigOffset(size_t offset);
4807 // The following are used when morphing special cases of integer div/mod operations and also by codegen
4808 bool fgIsSignedDivOptimizable(GenTreePtr divisor);
4809 bool fgIsUnsignedDivOptimizable(GenTreePtr divisor);
4810 bool fgIsSignedModOptimizable(GenTreePtr divisor);
4811 bool fgIsUnsignedModOptimizable(GenTreePtr divisor);
4814 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4815 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4819 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4820 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4827 LclVarDsc* optIsTrackedLocal(GenTreePtr tree);
4830 void optRemoveRangeCheck(
4831 GenTreePtr tree, GenTreePtr stmt, bool updateCSEcounts, unsigned sideEffFlags = 0, bool forceRemove = false);
4832 bool optIsRangeCheckRemovable(GenTreePtr tree);
4835 static fgWalkPreFn optValidRangeCheckIndex;
4836 static fgWalkPreFn optRemoveTreeVisitor; // Helper passed to Compiler::fgWalkAllTreesPre() to decrement the LclVar
4839 void optRemoveTree(GenTreePtr deadTree, GenTreePtr keepList);
4841 /**************************************************************************
4843 *************************************************************************/
4846 // Do hoisting for all loops.
4847 void optHoistLoopCode();
4849 // To represent sets of VN's that have already been hoisted in outer loops.
4850 typedef SimplerHashTable<ValueNum, SmallPrimitiveKeyFuncs<ValueNum>, bool, JitSimplerHashBehavior> VNToBoolMap;
4851 typedef VNToBoolMap VNSet;
4853 struct LoopHoistContext
4856 // The set of variables hoisted in the current loop (or nullptr if there are none).
4857 VNSet* m_pHoistedInCurLoop;
4860 // Value numbers of expressions that have been hoisted in parent loops in the loop nest.
4861 VNSet m_hoistedInParentLoops;
4862 // Value numbers of expressions that have been hoisted in the current (or most recent) loop in the nest.
4863 // Previous decisions on loop-invariance of value numbers in the current loop.
4864 VNToBoolMap m_curLoopVnInvariantCache;
4866 VNSet* GetHoistedInCurLoop(Compiler* comp)
4868 if (m_pHoistedInCurLoop == nullptr)
4870 m_pHoistedInCurLoop = new (comp->getAllocatorLoopHoist()) VNSet(comp->getAllocatorLoopHoist());
4872 return m_pHoistedInCurLoop;
4875 VNSet* ExtractHoistedInCurLoop()
4877 VNSet* res = m_pHoistedInCurLoop;
4878 m_pHoistedInCurLoop = nullptr;
4882 LoopHoistContext(Compiler* comp)
4883 : m_pHoistedInCurLoop(nullptr)
4884 , m_hoistedInParentLoops(comp->getAllocatorLoopHoist())
4885 , m_curLoopVnInvariantCache(comp->getAllocatorLoopHoist())
4890 // Do hoisting for loop "lnum" (an index into the optLoopTable), and all loops nested within it.
4891 // Tracks the expressions that have been hoisted by containing loops by temporary recording their
4892 // value numbers in "m_hoistedInParentLoops". This set is not modified by the call.
4893 void optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);
4895 // Do hoisting for a particular loop ("lnum" is an index into the optLoopTable.)
4896 // Assumes that expressions have been hoisted in containing loops if their value numbers are in
4897 // "m_hoistedInParentLoops".
4899 void optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt);
4901 // Hoist all expressions in "blk" that are invariant in loop "lnum" (an index into the optLoopTable)
4902 // outside of that loop. Exempt expressions whose value number is in "m_hoistedInParentLoops"; add VN's of hoisted
4903 // expressions to "hoistInLoop".
4904 void optHoistLoopExprsForBlock(BasicBlock* blk, unsigned lnum, LoopHoistContext* hoistCtxt);
4906 // Return true if the tree looks profitable to hoist out of loop 'lnum'.
4907 bool optIsProfitableToHoistableTree(GenTreePtr tree, unsigned lnum);
4909 // Hoist all proper sub-expressions of "tree" (which occurs in "stmt", which occurs in "blk")
4910 // that are invariant in loop "lnum" (an index into the optLoopTable)
4911 // outside of that loop. Exempt expressions whose value number is in "hoistedInParents"; add VN's of hoisted
4912 // expressions to "hoistInLoop".
4913 // Returns "true" iff "tree" is loop-invariant (wrt "lnum").
4914 // Assumes that the value of "*firstBlockAndBeforeSideEffect" indicates that we're in the first block, and before
4915 // any possible globally visible side effects. Assume is called in evaluation order, and updates this.
4916 bool optHoistLoopExprsForTree(GenTreePtr tree,
4918 LoopHoistContext* hoistCtxt,
4919 bool* firstBlockAndBeforeSideEffect,
4922 // Performs the hoisting 'tree' into the PreHeader for loop 'lnum'
4923 void optHoistCandidate(GenTreePtr tree, unsigned lnum, LoopHoistContext* hoistCtxt);
4925 // Returns true iff the ValueNum "vn" represents a value that is loop-invariant in "lnum".
4926 // Constants and init values are always loop invariant.
4927 // VNPhi's connect VN's to the SSA definition, so we can know if the SSA def occurs in the loop.
4928 bool optVNIsLoopInvariant(ValueNum vn, unsigned lnum, VNToBoolMap* recordedVNs);
4930 // Returns "true" iff "tree" is valid at the head of loop "lnum", in the context of the hoist substitution
4931 // "subst". If "tree" is a local SSA var, it is valid if its SSA definition occurs outside of the loop, or
4932 // if it is in the domain of "subst" (meaning that it's definition has been previously hoisted, with a "standin"
4933 // local.) If tree is a constant, it is valid. Otherwise, if it is an operator, it is valid iff its children are.
4934 bool optTreeIsValidAtLoopHead(GenTreePtr tree, unsigned lnum);
4936 // If "blk" is the entry block of a natural loop, returns true and sets "*pLnum" to the index of the loop
4937 // in the loop table.
4938 bool optBlockIsLoopEntry(BasicBlock* blk, unsigned* pLnum);
4940 // Records the set of "side effects" of all loops: fields (object instance and static)
4941 // written to, and SZ-array element type equivalence classes updated.
4942 void optComputeLoopSideEffects();
4945 // Requires "lnum" to be the index of an outermost loop in the loop table. Traverses the body of that loop,
4946 // including all nested loops, and records the set of "side effects" of the loop: fields (object instance and
4947 // static) written to, and SZ-array element type equivalence classes updated.
4948 void optComputeLoopNestSideEffects(unsigned lnum);
4950 // Add the side effects of "blk" (which is required to be within a loop) to all loops of which it is a part.
4951 void optComputeLoopSideEffectsOfBlock(BasicBlock* blk);
4953 // Hoist the expression "expr" out of loop "lnum".
4954 void optPerformHoistExpr(GenTreePtr expr, unsigned lnum);
4957 void optOptimizeBools();
4960 GenTree* optIsBoolCond(GenTree* condBranch, GenTree** compPtr, bool* boolPtr);
4962 void optOptimizeBoolsGcStress(BasicBlock* condBlock);
4965 void optOptimizeLayout(); // Optimize the BasicBlock layout of the method
4967 void optOptimizeLoops(); // for "while-do" loops duplicates simple loop conditions and transforms
4968 // the loop into a "do-while" loop
4969 // Also finds all natural loops and records them in the loop table
4971 // Optionally clone loops in the loop table.
4972 void optCloneLoops();
4974 // Clone loop "loopInd" in the loop table.
4975 void optCloneLoop(unsigned loopInd, LoopCloneContext* context);
4977 // Ensure that loop "loopInd" has a unique head block. (If the existing entry has
4978 // non-loop predecessors other than the head entry, create a new, empty block that goes (only) to the entry,
4979 // and redirects the preds of the entry to this new block.) Sets the weight of the newly created block to
4981 void optEnsureUniqueHead(unsigned loopInd, unsigned ambientWeight);
4983 void optUnrollLoops(); // Unrolls loops (needs to have cost info)
4986 // This enumeration describes what is killed by a call.
4990 CALLINT_NONE, // no interference (most helpers)
4991 CALLINT_REF_INDIRS, // kills GC ref indirections (SETFIELD OBJ)
4992 CALLINT_SCL_INDIRS, // kills non GC ref indirections (SETFIELD non-OBJ)
4993 CALLINT_ALL_INDIRS, // kills both GC ref and non GC ref indirections (SETFIELD STRUCT)
4994 CALLINT_ALL, // kills everything (normal method call)
4998 // A "LoopDsc" describes a ("natural") loop. We (currently) require the body of a loop to be a contiguous (in
4999 // bbNext order) sequence of basic blocks. (At times, we may require the blocks in a loop to be "properly numbered"
5000 // in bbNext order; we use comparisons on the bbNum to decide order.)
5001 // The blocks that define the body are
5002 // first <= top <= entry <= bottom .
5003 // The "head" of the loop is a block outside the loop that has "entry" as a successor. We only support loops with a
5004 // single 'head' block. The meanings of these blocks are given in the definitions below. Also see the picture at
5005 // Compiler::optFindNaturalLoops().
5008 BasicBlock* lpHead; // HEAD of the loop (not part of the looping of the loop) -- has ENTRY as a successor.
5009 BasicBlock* lpFirst; // FIRST block (in bbNext order) reachable within this loop. (May be part of a nested
5010 // loop, but not the outer loop.)
5011 BasicBlock* lpTop; // loop TOP (the back edge from lpBottom reaches here) (in most cases FIRST and TOP are the
5013 BasicBlock* lpEntry; // the ENTRY in the loop (in most cases TOP or BOTTOM)
5014 BasicBlock* lpBottom; // loop BOTTOM (from here we have a back edge to the TOP)
5015 BasicBlock* lpExit; // if a single exit loop this is the EXIT (in most cases BOTTOM)
5017 callInterf lpAsgCall; // "callInterf" for calls in the loop
5018 ALLVARSET_TP lpAsgVars; // set of vars assigned within the loop (all vars, not just tracked)
5019 varRefKinds lpAsgInds : 8; // set of inds modified within the loop
5021 unsigned short lpFlags; // Mask of the LPFLG_* constants
5023 unsigned char lpExitCnt; // number of exits from the loop
5025 unsigned char lpParent; // The index of the most-nested loop that completely contains this one,
5026 // or else BasicBlock::NOT_IN_LOOP if no such loop exists.
5027 unsigned char lpChild; // The index of a nested loop, or else BasicBlock::NOT_IN_LOOP if no child exists.
5028 // (Actually, an "immediately" nested loop --
5029 // no other child of this loop is a parent of lpChild.)
5030 unsigned char lpSibling; // The index of another loop that is an immediate child of lpParent,
5031 // or else BasicBlock::NOT_IN_LOOP. One can enumerate all the children of a loop
5032 // by following "lpChild" then "lpSibling" links.
5034 #define LPFLG_DO_WHILE 0x0001 // it's a do-while loop (i.e ENTRY is at the TOP)
5035 #define LPFLG_ONE_EXIT 0x0002 // the loop has only one exit
5037 #define LPFLG_ITER 0x0004 // for (i = icon or lclVar; test_condition(); i++)
5038 #define LPFLG_HOISTABLE 0x0008 // the loop is in a form that is suitable for hoisting expressions
5039 #define LPFLG_CONST 0x0010 // for (i=icon;i<icon;i++){ ... } - constant loop
5041 #define LPFLG_VAR_INIT 0x0020 // iterator is initialized with a local var (var # found in lpVarInit)
5042 #define LPFLG_CONST_INIT 0x0040 // iterator is initialized with a constant (found in lpConstInit)
5044 #define LPFLG_VAR_LIMIT 0x0100 // iterator is compared with a local var (var # found in lpVarLimit)
5045 #define LPFLG_CONST_LIMIT 0x0200 // iterator is compared with a constant (found in lpConstLimit)
5046 #define LPFLG_ARRLEN_LIMIT 0x0400 // iterator is compared with a.len or a[i].len (found in lpArrLenLimit)
5047 #define LPFLG_SIMD_LIMIT 0x0080 // iterator is compared with Vector<T>.Count (found in lpConstLimit)
5049 #define LPFLG_HAS_PREHEAD 0x0800 // lpHead is known to be a preHead for this loop
5050 #define LPFLG_REMOVED 0x1000 // has been removed from the loop table (unrolled or optimized away)
5051 #define LPFLG_DONT_UNROLL 0x2000 // do not unroll this loop
5053 #define LPFLG_ASGVARS_YES 0x4000 // "lpAsgVars" has been computed
5054 #define LPFLG_ASGVARS_INC 0x8000 // "lpAsgVars" is incomplete -- vars beyond those representable in an AllVarSet
5055 // type are assigned to.
5057 bool lpLoopHasMemoryHavoc[MemoryKindCount]; // The loop contains an operation that we assume has arbitrary
5058 // memory side effects. If this is set, the fields below
5059 // may not be accurate (since they become irrelevant.)
5060 bool lpContainsCall; // True if executing the loop body *may* execute a call
5062 VARSET_TP lpVarInOut; // The set of variables that are IN or OUT during the execution of this loop
5063 VARSET_TP lpVarUseDef; // The set of variables that are USE or DEF during the execution of this loop
5065 int lpHoistedExprCount; // The register count for the non-FP expressions from inside this loop that have been
5067 int lpLoopVarCount; // The register count for the non-FP LclVars that are read/written inside this loop
5068 int lpVarInOutCount; // The register count for the non-FP LclVars that are alive inside or accross this loop
5070 int lpHoistedFPExprCount; // The register count for the FP expressions from inside this loop that have been
5072 int lpLoopVarFPCount; // The register count for the FP LclVars that are read/written inside this loop
5073 int lpVarInOutFPCount; // The register count for the FP LclVars that are alive inside or accross this loop
5075 typedef SimplerHashTable<CORINFO_FIELD_HANDLE,
5076 PtrKeyFuncs<struct CORINFO_FIELD_STRUCT_>,
5078 JitSimplerHashBehavior>
5080 FieldHandleSet* lpFieldsModified; // This has entries (mappings to "true") for all static field and object
5081 // instance fields modified
5084 typedef SimplerHashTable<CORINFO_CLASS_HANDLE,
5085 PtrKeyFuncs<struct CORINFO_CLASS_STRUCT_>,
5087 JitSimplerHashBehavior>
5089 ClassHandleSet* lpArrayElemTypesModified; // Bits set indicate the set of sz array element types such that
5090 // arrays of that type are modified
5093 // Adds the variable liveness information for 'blk' to 'this' LoopDsc
5094 void AddVariableLiveness(Compiler* comp, BasicBlock* blk);
5096 inline void AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd);
5097 // This doesn't *always* take a class handle -- it can also take primitive types, encoded as class handles
5098 // (shifted left, with a low-order bit set to distinguish.)
5099 // Use the {Encode/Decode}ElemType methods to construct/destruct these.
5100 inline void AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd);
5102 /* The following values are set only for iterator loops, i.e. has the flag LPFLG_ITER set */
5104 GenTreePtr lpIterTree; // The "i <op>= const" tree
5105 unsigned lpIterVar(); // iterator variable #
5106 int lpIterConst(); // the constant with which the iterator is incremented
5107 genTreeOps lpIterOper(); // the type of the operation on the iterator (ASG_ADD, ASG_SUB, etc.)
5108 void VERIFY_lpIterTree();
5110 var_types lpIterOperType(); // For overflow instructions
5113 int lpConstInit; // initial constant value of iterator : Valid if LPFLG_CONST_INIT
5114 unsigned lpVarInit; // initial local var number to which we initialize the iterator : Valid if
5118 /* The following is for LPFLG_ITER loops only (i.e. the loop condition is "i RELOP const or var" */
5120 GenTreePtr lpTestTree; // pointer to the node containing the loop test
5121 genTreeOps lpTestOper(); // the type of the comparison between the iterator and the limit (GT_LE, GT_GE, etc.)
5122 void VERIFY_lpTestTree();
5124 bool lpIsReversed(); // true if the iterator node is the second operand in the loop condition
5125 GenTreePtr lpIterator(); // the iterator node in the loop test
5126 GenTreePtr lpLimit(); // the limit node in the loop test
5128 int lpConstLimit(); // limit constant value of iterator - loop condition is "i RELOP const" : Valid if
5129 // LPFLG_CONST_LIMIT
5130 unsigned lpVarLimit(); // the lclVar # in the loop condition ( "i RELOP lclVar" ) : Valid if
5132 bool lpArrLenLimit(Compiler* comp, ArrIndex* index); // The array length in the loop condition ( "i RELOP
5133 // arr.len" or "i RELOP arr[i][j].len" ) : Valid if
5134 // LPFLG_ARRLEN_LIMIT
5136 // Returns "true" iff "*this" contains the blk.
5137 bool lpContains(BasicBlock* blk)
5139 return lpFirst->bbNum <= blk->bbNum && blk->bbNum <= lpBottom->bbNum;
5141 // Returns "true" iff "*this" (properly) contains the range [first, bottom] (allowing firsts
5142 // to be equal, but requiring bottoms to be different.)
5143 bool lpContains(BasicBlock* first, BasicBlock* bottom)
5145 return lpFirst->bbNum <= first->bbNum && bottom->bbNum < lpBottom->bbNum;
5148 // Returns "true" iff "*this" (properly) contains "lp2" (allowing firsts to be equal, but requiring
5149 // bottoms to be different.)
5150 bool lpContains(const LoopDsc& lp2)
5152 return lpContains(lp2.lpFirst, lp2.lpBottom);
5155 // Returns "true" iff "*this" is (properly) contained by the range [first, bottom]
5156 // (allowing firsts to be equal, but requiring bottoms to be different.)
5157 bool lpContainedBy(BasicBlock* first, BasicBlock* bottom)
5159 return first->bbNum <= lpFirst->bbNum && lpBottom->bbNum < bottom->bbNum;
5162 // Returns "true" iff "*this" is (properly) contained by "lp2"
5163 // (allowing firsts to be equal, but requiring bottoms to be different.)
5164 bool lpContainedBy(const LoopDsc& lp2)
5166 return lpContains(lp2.lpFirst, lp2.lpBottom);
5169 // Returns "true" iff "*this" is disjoint from the range [top, bottom].
5170 bool lpDisjoint(BasicBlock* first, BasicBlock* bottom)
5172 return bottom->bbNum < lpFirst->bbNum || lpBottom->bbNum < first->bbNum;
5174 // Returns "true" iff "*this" is disjoint from "lp2".
5175 bool lpDisjoint(const LoopDsc& lp2)
5177 return lpDisjoint(lp2.lpFirst, lp2.lpBottom);
5179 // Returns "true" iff the loop is well-formed (see code for defn).
5182 return lpFirst->bbNum <= lpTop->bbNum && lpTop->bbNum <= lpEntry->bbNum &&
5183 lpEntry->bbNum <= lpBottom->bbNum &&
5184 (lpHead->bbNum < lpTop->bbNum || lpHead->bbNum > lpBottom->bbNum);
5189 bool fgMightHaveLoop(); // returns true if there are any backedges
5190 bool fgHasLoops; // True if this method has any loops, set in fgComputeReachability
5193 LoopDsc optLoopTable[MAX_LOOP_NUM]; // loop descriptor table
5194 unsigned char optLoopCount; // number of tracked loops
5197 unsigned optCallCount; // number of calls made in the method
5198 unsigned optIndirectCallCount; // number of virtual, interface and indirect calls made in the method
5199 unsigned optNativeCallCount; // number of Pinvoke/Native calls made in the method
5200 unsigned optLoopsCloned; // number of loops cloned in the current method.
5203 unsigned optFindLoopNumberFromBeginBlock(BasicBlock* begBlk);
5204 void optPrintLoopInfo(unsigned loopNum,
5206 BasicBlock* lpFirst,
5208 BasicBlock* lpEntry,
5209 BasicBlock* lpBottom,
5210 unsigned char lpExitCnt,
5212 unsigned parentLoop = BasicBlock::NOT_IN_LOOP);
5213 void optPrintLoopInfo(unsigned lnum);
5214 void optPrintLoopRecording(unsigned lnum);
5216 void optCheckPreds();
5219 void optSetBlockWeights();
5221 void optMarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk, bool excludeEndBlk);
5223 void optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk);
5225 void optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmarkLoop = false);
5227 bool optIsLoopTestEvalIntoTemp(GenTreePtr test, GenTreePtr* newTest);
5228 unsigned optIsLoopIncrTree(GenTreePtr incr);
5229 bool optCheckIterInLoopTest(unsigned loopInd, GenTreePtr test, BasicBlock* from, BasicBlock* to, unsigned iterVar);
5230 bool optComputeIterInfo(GenTreePtr incr, BasicBlock* from, BasicBlock* to, unsigned* pIterVar);
5231 bool optPopulateInitInfo(unsigned loopInd, GenTreePtr init, unsigned iterVar);
5232 bool optExtractInitTestIncr(BasicBlock* head,
5237 GenTreePtr* ppIncr);
5239 void optRecordLoop(BasicBlock* head,
5245 unsigned char exitCnt);
5247 void optFindNaturalLoops();
5249 // Ensures that all the loops in the loop nest rooted at "loopInd" (an index into the loop table) are 'canonical' --
5250 // each loop has a unique "top." Returns "true" iff the flowgraph has been modified.
5251 bool optCanonicalizeLoopNest(unsigned char loopInd);
5253 // Ensures that the loop "loopInd" (an index into the loop table) is 'canonical' -- it has a unique "top,"
5254 // unshared with any other loop. Returns "true" iff the flowgraph has been modified
5255 bool optCanonicalizeLoop(unsigned char loopInd);
5257 // Requires "l1" to be a valid loop table index, and not "BasicBlock::NOT_IN_LOOP". Requires "l2" to be
5258 // a valid loop table index, or else "BasicBlock::NOT_IN_LOOP". Returns true
5259 // iff "l2" is not NOT_IN_LOOP, and "l1" contains "l2".
5260 bool optLoopContains(unsigned l1, unsigned l2);
5262 // Requires "loopInd" to be a valid index into the loop table.
5263 // Updates the loop table by changing loop "loopInd", whose head is required
5264 // to be "from", to be "to". Also performs this transformation for any
5265 // loop nested in "loopInd" that shares the same head as "loopInd".
5266 void optUpdateLoopHead(unsigned loopInd, BasicBlock* from, BasicBlock* to);
5268 // Updates the successors of "blk": if "blk2" is a successor of "blk", and there is a mapping for "blk2->blk3" in
5269 // "redirectMap", change "blk" so that "blk3" is this successor. Note that the predecessor lists are not updated.
5270 void optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap);
5272 // Marks the containsCall information to "lnum" and any parent loops.
5273 void AddContainsCallAllContainingLoops(unsigned lnum);
5274 // Adds the variable liveness information from 'blk' to "lnum" and any parent loops.
5275 void AddVariableLivenessAllContainingLoops(unsigned lnum, BasicBlock* blk);
5276 // Adds "fldHnd" to the set of modified fields of "lnum" and any parent loops.
5277 void AddModifiedFieldAllContainingLoops(unsigned lnum, CORINFO_FIELD_HANDLE fldHnd);
5278 // Adds "elemType" to the set of modified array element types of "lnum" and any parent loops.
5279 void AddModifiedElemTypeAllContainingLoops(unsigned lnum, CORINFO_CLASS_HANDLE elemType);
5281 // Requires that "from" and "to" have the same "bbJumpKind" (perhaps because "to" is a clone
5282 // of "from".) Copies the jump destination from "from" to "to".
5283 void optCopyBlkDest(BasicBlock* from, BasicBlock* to);
5285 // The depth of the loop described by "lnum" (an index into the loop table.) (0 == top level)
5286 unsigned optLoopDepth(unsigned lnum)
5288 unsigned par = optLoopTable[lnum].lpParent;
5289 if (par == BasicBlock::NOT_IN_LOOP)
5295 return 1 + optLoopDepth(par);
5299 void fgOptWhileLoop(BasicBlock* block);
5301 bool optComputeLoopRep(int constInit,
5304 genTreeOps iterOper,
5306 genTreeOps testOper,
5309 unsigned* iterCount);
5310 #if FEATURE_STACK_FP_X87
5313 VARSET_TP optAllFloatVars; // mask of all tracked FP variables
5314 VARSET_TP optAllFPregVars; // mask of all enregistered FP variables
5315 VARSET_TP optAllNonFPvars; // mask of all tracked non-FP variables
5316 #endif // FEATURE_STACK_FP_X87
5319 static fgWalkPreFn optIsVarAssgCB;
5322 bool optIsVarAssigned(BasicBlock* beg, BasicBlock* end, GenTreePtr skip, unsigned var);
5324 bool optIsVarAssgLoop(unsigned lnum, unsigned var);
5326 int optIsSetAssgLoop(unsigned lnum, ALLVARSET_VALARG_TP vars, varRefKinds inds = VR_NONE);
5328 bool optNarrowTree(GenTreePtr tree, var_types srct, var_types dstt, ValueNumPair vnpNarrow, bool doit);
5330 /**************************************************************************
5331 * Optimization conditions
5332 *************************************************************************/
5334 bool optFastCodeOrBlendedLoop(BasicBlock::weight_t bbWeight);
5335 bool optPentium4(void);
5336 bool optAvoidIncDec(BasicBlock::weight_t bbWeight);
5337 bool optAvoidIntMult(void);
5342 // The following is the upper limit on how many expressions we'll keep track
5343 // of for the CSE analysis.
5345 static const unsigned MAX_CSE_CNT = EXPSET_SZ;
5347 static const int MIN_CSE_COST = 2;
5349 // Keeps tracked cse indices
5350 BitVecTraits* cseTraits;
5354 /* Generic list of nodes - used by the CSE logic */
5362 typedef struct treeLst* treeLstPtr;
5366 treeStmtLst* tslNext;
5367 GenTreePtr tslTree; // tree node
5368 GenTreePtr tslStmt; // statement containing the tree
5369 BasicBlock* tslBlock; // block containing the statement
5372 typedef struct treeStmtLst* treeStmtLstPtr;
5374 // The following logic keeps track of expressions via a simple hash table.
5378 CSEdsc* csdNextInBucket; // used by the hash table
5380 unsigned csdHashValue; // the orginal hashkey
5382 unsigned csdIndex; // 1..optCSECandidateCount
5383 char csdLiveAcrossCall; // 0 or 1
5385 unsigned short csdDefCount; // definition count
5386 unsigned short csdUseCount; // use count (excluding the implicit uses at defs)
5388 unsigned csdDefWtCnt; // weighted def count
5389 unsigned csdUseWtCnt; // weighted use count (excluding the implicit uses at defs)
5391 GenTreePtr csdTree; // treenode containing the 1st occurance
5392 GenTreePtr csdStmt; // stmt containing the 1st occurance
5393 BasicBlock* csdBlock; // block containing the 1st occurance
5395 treeStmtLstPtr csdTreeList; // list of matching tree nodes: head
5396 treeStmtLstPtr csdTreeLast; // list of matching tree nodes: tail
5398 ValueNum defConservativeVN; // if all def occurrences share the same conservative value
5399 // number, this will reflect it; otherwise, NoVN.
5402 static const size_t s_optCSEhashSize;
5403 CSEdsc** optCSEhash;
5408 CSEdsc* optCSEfindDsc(unsigned index);
5409 void optUnmarkCSE(GenTreePtr tree);
5411 // user defined callback data for the tree walk function optCSE_MaskHelper()
5412 struct optCSE_MaskData
5414 EXPSET_TP CSE_defMask;
5415 EXPSET_TP CSE_useMask;
5418 // Treewalk helper for optCSE_DefMask and optCSE_UseMask
5419 static fgWalkPreFn optCSE_MaskHelper;
5421 // This function walks all the node for an given tree
5422 // and return the mask of CSE definitions and uses for the tree
5424 void optCSE_GetMaskData(GenTreePtr tree, optCSE_MaskData* pMaskData);
5426 // Given a binary tree node return true if it is safe to swap the order of evaluation for op1 and op2.
5427 bool optCSE_canSwap(GenTree* firstNode, GenTree* secondNode);
5428 bool optCSE_canSwap(GenTree* tree);
5430 static fgWalkPostFn optPropagateNonCSE;
5431 static fgWalkPreFn optHasNonCSEChild;
5433 static fgWalkPreFn optUnmarkCSEs;
5435 static int __cdecl optCSEcostCmpEx(const void* op1, const void* op2);
5436 static int __cdecl optCSEcostCmpSz(const void* op1, const void* op2);
5438 void optCleanupCSEs();
5441 void optEnsureClearCSEInfo();
5444 #endif // FEATURE_ANYCSE
5446 #if FEATURE_VALNUM_CSE
5447 /**************************************************************************
5448 * Value Number based CSEs
5449 *************************************************************************/
5452 void optOptimizeValnumCSEs();
5455 void optValnumCSE_Init();
5456 unsigned optValnumCSE_Index(GenTreePtr tree, GenTreePtr stmt);
5457 unsigned optValnumCSE_Locate();
5458 void optValnumCSE_InitDataFlow();
5459 void optValnumCSE_DataFlow();
5460 void optValnumCSE_Availablity();
5461 void optValnumCSE_Heuristic();
5462 void optValnumCSE_UnmarkCSEs(GenTreePtr deadTree, GenTreePtr keepList);
5464 #endif // FEATURE_VALNUM_CSE
5467 bool optDoCSE; // True when we have found a duplicate CSE tree
5468 bool optValnumCSE_phase; // True when we are executing the optValnumCSE_phase
5469 unsigned optCSECandidateTotal; // Grand total of CSE candidates for both Lexical and ValNum
5470 unsigned optCSECandidateCount; // Count of CSE's candidates, reset for Lexical and ValNum CSE's
5471 unsigned optCSEstart; // The first local variable number that is a CSE
5472 unsigned optCSEcount; // The total count of CSE's introduced.
5473 unsigned optCSEweight; // The weight of the current block when we are
5474 // scanning for CSE expressions
5476 bool optIsCSEcandidate(GenTreePtr tree);
5478 // lclNumIsTrueCSE returns true if the LclVar was introduced by the CSE phase of the compiler
5480 bool lclNumIsTrueCSE(unsigned lclNum) const
5482 return ((optCSEcount > 0) && (lclNum >= optCSEstart) && (lclNum < optCSEstart + optCSEcount));
5485 // lclNumIsCSE returns true if the LclVar should be treated like a CSE with regards to constant prop.
5487 bool lclNumIsCSE(unsigned lclNum) const
5489 return lvaTable[lclNum].lvIsCSE;
5493 bool optConfigDisableCSE();
5494 bool optConfigDisableCSE2();
5496 void optOptimizeCSEs();
5498 #endif // FEATURE_ANYCSE
5506 unsigned ivaVar; // Variable we are interested in, or -1
5507 ALLVARSET_TP ivaMaskVal; // Set of variables assigned to. This is a set of all vars, not tracked vars.
5508 bool ivaMaskIncomplete; // Variables not representable in ivaMaskVal were assigned to.
5509 varRefKinds ivaMaskInd; // What kind of indirect assignments are there?
5510 callInterf ivaMaskCall; // What kind of calls are there?
5513 static callInterf optCallInterf(GenTreePtr call);
5516 // VN based copy propagation.
5517 typedef ArrayStack<GenTreePtr> GenTreePtrStack;
5518 typedef SimplerHashTable<unsigned, SmallPrimitiveKeyFuncs<unsigned>, GenTreePtrStack*, JitSimplerHashBehavior>
5519 LclNumToGenTreePtrStack;
5521 // Kill set to track variables with intervening definitions.
5522 VARSET_TP optCopyPropKillSet;
5524 // Copy propagation functions.
5525 void optCopyProp(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree, LclNumToGenTreePtrStack* curSsaName);
5526 void optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
5527 void optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
5528 bool optIsSsaLocal(GenTreePtr tree);
5529 int optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2);
5530 void optVnCopyProp();
5532 /**************************************************************************
5533 * Early value propagation
5534 *************************************************************************/
5540 SSAName(unsigned lvNum, unsigned ssaNum) : m_lvNum(lvNum), m_ssaNum(ssaNum)
5544 static unsigned GetHashCode(SSAName ssaNm)
5546 return (ssaNm.m_lvNum << 16) | (ssaNm.m_ssaNum);
5549 static bool Equals(SSAName ssaNm1, SSAName ssaNm2)
5551 return (ssaNm1.m_lvNum == ssaNm2.m_lvNum) && (ssaNm1.m_ssaNum == ssaNm2.m_ssaNum);
5555 #define OMF_HAS_NEWARRAY 0x00000001 // Method contains 'new' of an array
5556 #define OMF_HAS_NEWOBJ 0x00000002 // Method contains 'new' of an object type.
5557 #define OMF_HAS_ARRAYREF 0x00000004 // Method contains array element loads or stores.
5558 #define OMF_HAS_VTABLEREF 0x00000008 // Method contains method table reference.
5559 #define OMF_HAS_NULLCHECK 0x00000010 // Method contains null check.
5560 #define OMF_HAS_FATPOINTER 0x00000020 // Method contains call, that needs fat pointer transformation.
5562 bool doesMethodHaveFatPointer()
5564 return (optMethodFlags & OMF_HAS_FATPOINTER) != 0;
5567 void setMethodHasFatPointer()
5569 optMethodFlags |= OMF_HAS_FATPOINTER;
5572 void clearMethodHasFatPointer()
5574 optMethodFlags &= ~OMF_HAS_FATPOINTER;
5577 unsigned optMethodFlags;
5579 // Recursion bound controls how far we can go backwards tracking for a SSA value.
5580 // No throughput diff was found with backward walk bound between 3-8.
5581 static const int optEarlyPropRecurBound = 5;
5583 enum class optPropKind
5591 bool gtIsVtableRef(GenTreePtr tree);
5592 GenTreePtr getArrayLengthFromAllocation(GenTreePtr tree);
5593 GenTreePtr getObjectHandleNodeFromAllocation(GenTreePtr tree);
5594 GenTreePtr optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropKind valueKind, int walkDepth);
5595 GenTreePtr optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind);
5596 bool optEarlyPropRewriteTree(GenTreePtr tree);
5597 bool optDoEarlyPropForBlock(BasicBlock* block);
5598 bool optDoEarlyPropForFunc();
5599 void optEarlyProp();
5600 void optFoldNullCheck(GenTreePtr tree);
5601 bool optCanMoveNullCheckPastTree(GenTreePtr tree, bool isInsideTry);
5604 /**************************************************************************
5605 * Value/Assertion propagation
5606 *************************************************************************/
5608 // Data structures for assertion prop
5609 BitVecTraits* apTraits;
5613 enum optAssertionKind
5628 O1K_ARRLEN_OPER_BND,
5629 O1K_ARRLEN_LOOP_BND,
5630 O1K_CONSTANT_LOOP_BND,
5651 optAssertionKind assertionKind;
5654 unsigned lclNum; // assigned to or property of this local var number
5662 struct AssertionDscOp1
5664 optOp1Kind kind; // a normal LclVar, or Exact-type or Subtype
5671 struct AssertionDscOp2
5673 optOp2Kind kind; // a const or copy assignment
5677 ssize_t iconVal; // integer
5678 unsigned iconFlags; // gtFlags
5680 struct Range // integer subrange
5694 bool IsArrLenArithBound()
5696 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_ARRLEN_OPER_BND);
5698 bool IsArrLenBound()
5700 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_ARRLEN_LOOP_BND);
5702 bool IsConstantBound()
5704 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) &&
5705 op1.kind == O1K_CONSTANT_LOOP_BND);
5707 bool IsBoundsCheckNoThrow()
5709 return ((assertionKind == OAK_NO_THROW) && (op1.kind == O1K_ARR_BND));
5712 bool IsCopyAssertion()
5714 return ((assertionKind == OAK_EQUAL) && (op1.kind == O1K_LCLVAR) && (op2.kind == O2K_LCLVAR_COPY));
5717 static bool SameKind(AssertionDsc* a1, AssertionDsc* a2)
5719 return a1->assertionKind == a2->assertionKind && a1->op1.kind == a2->op1.kind &&
5720 a1->op2.kind == a2->op2.kind;
5723 static bool ComplementaryKind(optAssertionKind kind, optAssertionKind kind2)
5725 if (kind == OAK_EQUAL)
5727 return kind2 == OAK_NOT_EQUAL;
5729 else if (kind == OAK_NOT_EQUAL)
5731 return kind2 == OAK_EQUAL;
5736 static ssize_t GetLowerBoundForIntegralType(var_types type)
5756 static ssize_t GetUpperBoundForIntegralType(var_types type)
5780 bool HasSameOp1(AssertionDsc* that, bool vnBased)
5782 return (op1.kind == that->op1.kind) &&
5783 ((vnBased && (op1.vn == that->op1.vn)) || (!vnBased && (op1.lcl.lclNum == that->op1.lcl.lclNum)));
5786 bool HasSameOp2(AssertionDsc* that, bool vnBased)
5788 if (op2.kind != that->op2.kind)
5794 case O2K_IND_CNS_INT:
5796 return ((op2.u1.iconVal == that->op2.u1.iconVal) && (op2.u1.iconFlags == that->op2.u1.iconFlags));
5798 case O2K_CONST_LONG:
5799 return (op2.lconVal == that->op2.lconVal);
5801 case O2K_CONST_DOUBLE:
5802 // exact match because of positive and negative zero.
5803 return (memcmp(&op2.dconVal, &that->op2.dconVal, sizeof(double)) == 0);
5805 case O2K_LCLVAR_COPY:
5807 return (op2.lcl.lclNum == that->op2.lcl.lclNum) &&
5808 (!vnBased || op2.lcl.ssaNum == that->op2.lcl.ssaNum);
5811 return ((op2.u2.loBound == that->op2.u2.loBound) && (op2.u2.hiBound == that->op2.u2.hiBound));
5814 // we will return false
5818 assert(!"Unexpected value for op2.kind in AssertionDsc.");
5824 bool Complementary(AssertionDsc* that, bool vnBased)
5826 return ComplementaryKind(assertionKind, that->assertionKind) && HasSameOp1(that, vnBased) &&
5827 HasSameOp2(that, vnBased);
5830 bool Equals(AssertionDsc* that, bool vnBased)
5832 return (assertionKind == that->assertionKind) && HasSameOp1(that, vnBased) && HasSameOp2(that, vnBased);
5836 typedef unsigned short AssertionIndex;
5839 static fgWalkPreFn optAddCopiesCallback;
5840 static fgWalkPreFn optVNAssertionPropCurStmtVisitor;
5841 unsigned optAddCopyLclNum;
5842 GenTreePtr optAddCopyAsgnNode;
5844 bool optLocalAssertionProp; // indicates that we are performing local assertion prop
5845 bool optAssertionPropagated; // set to true if we modified the trees
5846 bool optAssertionPropagatedCurrentStmt;
5848 GenTreePtr optAssertionPropCurrentTree;
5850 AssertionIndex* optComplementaryAssertionMap;
5851 ExpandArray<ASSERT_TP>* optAssertionDep; // table that holds dependent assertions (assertions
5852 // using the value of a local var) for each local var
5853 AssertionDsc* optAssertionTabPrivate; // table that holds info about value assignments
5854 AssertionIndex optAssertionCount; // total number of assertions in the assertion table
5855 AssertionIndex optMaxAssertionCount;
5858 void optVnNonNullPropCurStmt(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree);
5859 fgWalkResult optVNConstantPropCurStmt(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree);
5860 GenTreePtr optVNConstantPropOnRelOp(GenTreePtr tree);
5861 GenTreePtr optVNConstantPropOnJTrue(BasicBlock* block, GenTreePtr stmt, GenTreePtr test);
5862 GenTreePtr optVNConstantPropOnTree(BasicBlock* block, GenTreePtr stmt, GenTreePtr tree);
5863 GenTreePtr optPrepareTreeForReplacement(GenTreePtr extractTree, GenTreePtr replaceTree);
5865 AssertionIndex GetAssertionCount()
5867 return optAssertionCount;
5869 ASSERT_TP* bbJtrueAssertionOut;
5870 typedef SimplerHashTable<ValueNum, SmallPrimitiveKeyFuncs<ValueNum>, ASSERT_TP, JitSimplerHashBehavior>
5871 ValueNumToAssertsMap;
5872 ValueNumToAssertsMap* optValueNumToAsserts;
5874 static const AssertionIndex NO_ASSERTION_INDEX = 0;
5876 // Assertion prop helpers.
5877 ASSERT_TP& GetAssertionDep(unsigned lclNum);
5878 AssertionDsc* optGetAssertion(AssertionIndex assertIndex);
5879 void optAssertionInit(bool isLocalProp);
5880 void optAssertionTraitsInit(AssertionIndex assertionCount);
5881 #if LOCAL_ASSERTION_PROP
5882 void optAssertionReset(AssertionIndex limit);
5883 void optAssertionRemove(AssertionIndex index);
5886 // Assertion prop data flow functions.
5887 void optAssertionPropMain();
5888 GenTreePtr optVNAssertionPropCurStmt(BasicBlock* block, GenTreePtr stmt);
5889 bool optIsTreeKnownIntValue(bool vnBased, GenTreePtr tree, ssize_t* pConstant, unsigned* pIconFlags);
5890 ASSERT_TP* optInitAssertionDataflowFlags();
5891 ASSERT_TP* optComputeAssertionGen();
5893 // Assertion Gen functions.
5894 void optAssertionGen(GenTreePtr tree);
5895 AssertionIndex optAssertionGenPhiDefn(GenTreePtr tree);
5896 AssertionIndex optCreateJTrueBoundsAssertion(GenTreePtr tree);
5897 AssertionIndex optAssertionGenJtrue(GenTreePtr tree);
5898 AssertionIndex optCreateJtrueAssertions(GenTreePtr op1, GenTreePtr op2, Compiler::optAssertionKind assertionKind);
5899 AssertionIndex optFindComplementary(AssertionIndex assertionIndex);
5900 void optMapComplementary(AssertionIndex assertionIndex, AssertionIndex index);
5902 // Assertion creation functions.
5903 AssertionIndex optCreateAssertion(GenTreePtr op1, GenTreePtr op2, optAssertionKind assertionKind);
5904 AssertionIndex optCreateAssertion(GenTreePtr op1,
5906 optAssertionKind assertionKind,
5907 AssertionDsc* assertion);
5908 void optCreateComplementaryAssertion(AssertionIndex assertionIndex, GenTreePtr op1, GenTreePtr op2);
5910 bool optAssertionVnInvolvesNan(AssertionDsc* assertion);
5911 AssertionIndex optAddAssertion(AssertionDsc* assertion);
5912 void optAddVnAssertionMapping(ValueNum vn, AssertionIndex index);
5914 void optPrintVnAssertionMapping();
5916 ASSERT_TP optGetVnMappedAssertions(ValueNum vn);
5918 // Used for respective assertion propagations.
5919 AssertionIndex optAssertionIsSubrange(GenTreePtr tree, var_types toType, ASSERT_VALARG_TP assertions);
5920 AssertionIndex optAssertionIsSubtype(GenTreePtr tree, GenTreePtr methodTableArg, ASSERT_VALARG_TP assertions);
5921 AssertionIndex optAssertionIsNonNullInternal(GenTreePtr op, ASSERT_VALARG_TP assertions);
5922 bool optAssertionIsNonNull(GenTreePtr op,
5923 ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased) DEBUGARG(AssertionIndex* pIndex));
5925 // Used for Relop propagation.
5926 AssertionIndex optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP assertions, GenTreePtr op1, GenTreePtr op2);
5927 AssertionIndex optLocalAssertionIsEqualOrNotEqual(
5928 optOp1Kind op1Kind, unsigned lclNum, optOp2Kind op2Kind, ssize_t cnsVal, ASSERT_VALARG_TP assertions);
5930 // Assertion prop for lcl var functions.
5931 bool optAssertionProp_LclVarTypeCheck(GenTreePtr tree, LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc);
5932 GenTreePtr optCopyAssertionProp(AssertionDsc* curAssertion,
5934 GenTreePtr stmt DEBUGARG(AssertionIndex index));
5935 GenTreePtr optConstantAssertionProp(AssertionDsc* curAssertion,
5936 const GenTreePtr tree,
5937 const GenTreePtr stmt DEBUGARG(AssertionIndex index));
5938 GenTreePtr optVnConstantAssertionProp(const GenTreePtr tree, const GenTreePtr stmt);
5940 // Assertion propagation functions.
5941 GenTreePtr optAssertionProp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
5942 GenTreePtr optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
5943 GenTreePtr optAssertionProp_Ind(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
5944 GenTreePtr optAssertionProp_Cast(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
5945 GenTreePtr optAssertionProp_Call(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
5946 GenTreePtr optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
5947 GenTreePtr optAssertionProp_Comma(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
5948 GenTreePtr optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
5949 GenTreePtr optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
5950 GenTreePtr optAssertionPropLocal_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
5951 GenTreePtr optAssertionProp_Update(const GenTreePtr newTree, const GenTreePtr tree, const GenTreePtr stmt);
5952 GenTreePtr optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
5954 // Implied assertion functions.
5955 void optImpliedAssertions(AssertionIndex assertionIndex, ASSERT_TP& activeAssertions);
5956 void optImpliedByTypeOfAssertions(ASSERT_TP& activeAssertions);
5957 void optImpliedByCopyAssertion(AssertionDsc* copyAssertion, AssertionDsc* depAssertion, ASSERT_TP& result);
5958 void optImpliedByConstAssertion(AssertionDsc* curAssertion, ASSERT_TP& result);
5960 ASSERT_VALRET_TP optNewFullAssertSet();
5961 ASSERT_VALRET_TP optNewEmptyAssertSet();
5964 void optPrintAssertion(AssertionDsc* newAssertion, AssertionIndex assertionIndex = 0);
5965 void optDebugCheckAssertion(AssertionDsc* assertion);
5966 void optDebugCheckAssertions(AssertionIndex AssertionIndex);
5968 void optAddCopies();
5969 #endif // ASSERTION_PROP
5971 /**************************************************************************
5973 *************************************************************************/
5976 struct LoopCloneVisitorInfo
5978 LoopCloneContext* context;
5981 LoopCloneVisitorInfo(LoopCloneContext* context, unsigned loopNum, GenTreePtr stmt)
5982 : context(context), loopNum(loopNum), stmt(nullptr)
5987 bool optIsStackLocalInvariant(unsigned loopNum, unsigned lclNum);
5988 bool optExtractArrIndex(GenTreePtr tree, ArrIndex* result, unsigned lhsNum);
5989 bool optReconstructArrIndex(GenTreePtr tree, ArrIndex* result, unsigned lhsNum);
5990 bool optIdentifyLoopOptInfo(unsigned loopNum, LoopCloneContext* context);
5991 static fgWalkPreFn optCanOptimizeByLoopCloningVisitor;
5992 fgWalkResult optCanOptimizeByLoopCloning(GenTreePtr tree, LoopCloneVisitorInfo* info);
5993 void optObtainLoopCloningOpts(LoopCloneContext* context);
5994 bool optIsLoopClonable(unsigned loopInd);
5996 bool optCanCloneLoops();
5999 void optDebugLogLoopCloning(BasicBlock* block, GenTreePtr insertBefore);
6001 void optPerformStaticOptimizations(unsigned loopNum, LoopCloneContext* context DEBUGARG(bool fastPath));
6002 bool optComputeDerefConditions(unsigned loopNum, LoopCloneContext* context);
6003 bool optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext* context);
6004 BasicBlock* optInsertLoopChoiceConditions(LoopCloneContext* context,
6008 void optInsertLoopCloningStress(BasicBlock* head);
6010 #if COUNT_RANGECHECKS
6011 static unsigned optRangeChkRmv;
6012 static unsigned optRangeChkAll;
6021 #define MAX_ARRAYS 4 // a magic max number of arrays tracked for bounds check elimination
6026 RngChkDsc* rcdNextInBucket; // used by the hash table
6028 unsigned short rcdHashValue; // to make matching faster
6029 unsigned short rcdIndex; // 0..optRngChkCount-1
6031 GenTreePtr rcdTree; // the array index tree
6034 unsigned optRngChkCount;
6035 static const size_t optRngChkHashSize;
6037 ssize_t optGetArrayRefScaleAndIndex(GenTreePtr mul, GenTreePtr* pIndex DEBUGARG(bool bRngChk));
6038 GenTreePtr optFindLocalInit(BasicBlock* block, GenTreePtr local, VARSET_TP* pKilledInOut, bool* isKilledAfterInit);
6040 bool optReachWithoutCall(BasicBlock* srcBB, BasicBlock* dstBB);
6043 bool optLoopsMarked;
6046 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6047 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6051 XX Does the register allocation and puts the remaining lclVars on the stack XX
6053 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6054 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6058 #ifndef LEGACY_BACKEND
6063 #else // LEGACY_BACKEND
6068 #endif // LEGACY_BACKEND
6070 #ifdef LEGACY_BACKEND
6072 void raAssignVars(); // register allocation
6073 #endif // LEGACY_BACKEND
6075 VARSET_TP raRegVarsMask; // Set of all enregistered variables (not including FEATURE_STACK_FP_X87 enregistered
6077 regNumber raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc);
6079 void raMarkStkVars();
6082 // Some things are used by both LSRA and regpredict allocators.
6084 FrameType rpFrameType;
6085 bool rpMustCreateEBPCalled; // Set to true after we have called rpMustCreateEBPFrame once
6087 #ifdef LEGACY_BACKEND
6088 regMaskTP rpMaskPInvokeEpilogIntf; // pinvoke epilog trashes esi/edi holding stack args needed to setup tail call's
6090 #endif // LEGACY_BACKEND
6092 bool rpMustCreateEBPFrame(INDEBUG(const char** wbReason));
6094 #if FEATURE_FP_REGALLOC
6095 enum enumConfigRegisterFP
6097 CONFIG_REGISTER_FP_NONE = 0x0,
6098 CONFIG_REGISTER_FP_CALLEE_TRASH = 0x1,
6099 CONFIG_REGISTER_FP_CALLEE_SAVED = 0x2,
6100 CONFIG_REGISTER_FP_FULL = 0x3,
6102 enumConfigRegisterFP raConfigRegisterFP();
6103 #endif // FEATURE_FP_REGALLOC
6106 regMaskTP raConfigRestrictMaskFP();
6109 #ifndef LEGACY_BACKEND
6110 LinearScanInterface* m_pLinearScan; // Linear Scan allocator
6111 #else // LEGACY_BACKEND
6112 unsigned raAvoidArgRegMask; // Mask of incoming argument registers that we may need to avoid
6113 VARSET_TP raLclRegIntf[REG_COUNT]; // variable to register interference graph
6114 bool raNewBlocks; // True is we added killing blocks for FPU registers
6115 unsigned rpPasses; // Number of passes made by the register predicter
6116 unsigned rpPassesMax; // Maximum number of passes made by the register predicter
6117 unsigned rpPassesPessimize; // Number of passes non-pessimizing made by the register predicter
6118 unsigned rpStkPredict; // Weighted count of variables were predicted STK (lower means register allocation is better)
6119 unsigned rpPredictSpillCnt; // Predicted number of integer spill tmps for the current tree
6120 regMaskTP rpPredictAssignMask; // Mask of registers to consider in rpPredictAssignRegVars()
6121 VARSET_TP rpLastUseVars; // Set of last use variables in rpPredictTreeRegUse
6122 VARSET_TP rpUseInPlace; // Set of variables that we used in place
6123 int rpAsgVarNum; // VarNum for the target of GT_ASG node
6124 bool rpPredictAssignAgain; // Must rerun the rpPredictAssignRegVars()
6125 bool rpAddedVarIntf; // Set to true if we need to add a new var intf
6126 bool rpLostEnreg; // Set to true if we lost an enregister var that had lvDependReg set
6127 bool rpReverseEBPenreg; // Decided to reverse the enregistration of EBP
6129 bool rpRegAllocDone; // Set to true after we have completed register allocation
6131 regMaskTP rpPredictMap[PREDICT_COUNT]; // Holds the regMaskTP for each of the enum values
6133 void raSetupArgMasks(RegState* r);
6135 const regNumber* raGetRegVarOrder(var_types regType, unsigned* wbVarOrderSize);
6137 void raDumpVarIntf(); // Dump the variable to variable interference graph
6138 void raDumpRegIntf(); // Dump the variable to register interference graph
6140 void raAdjustVarIntf();
6142 regMaskTP rpPredictRegMask(rpPredictReg predictReg, var_types type);
6144 bool rpRecordRegIntf(regMaskTP regMask, VARSET_VALARG_TP life DEBUGARG(const char* msg));
6146 bool rpRecordVarIntf(unsigned varNum, VARSET_VALARG_TP intfVar DEBUGARG(const char* msg));
6147 regMaskTP rpPredictRegPick(var_types type, rpPredictReg predictReg, regMaskTP lockedRegs);
6149 regMaskTP rpPredictGrabReg(var_types type, rpPredictReg predictReg, regMaskTP lockedRegs);
6151 static fgWalkPreFn rpMarkRegIntf;
6153 regMaskTP rpPredictAddressMode(
6154 GenTreePtr tree, var_types type, regMaskTP lockedRegs, regMaskTP rsvdRegs, GenTreePtr lenCSE);
6156 void rpPredictRefAssign(unsigned lclNum);
6158 regMaskTP rpPredictBlkAsgRegUse(GenTreePtr tree, rpPredictReg predictReg, regMaskTP lockedRegs, regMaskTP rsvdRegs);
6160 regMaskTP rpPredictTreeRegUse(GenTreePtr tree, rpPredictReg predictReg, regMaskTP lockedRegs, regMaskTP rsvdRegs);
6162 regMaskTP rpPredictAssignRegVars(regMaskTP regAvail);
6164 void rpPredictRegUse(); // Entry point
6166 unsigned raPredictTreeRegUse(GenTreePtr tree);
6167 unsigned raPredictListRegUse(GenTreePtr list);
6169 void raSetRegVarOrder(var_types regType,
6170 regNumber* customVarOrder,
6171 unsigned* customVarOrderSize,
6173 regMaskTP avoidReg);
6175 // We use (unsigned)-1 as an uninitialized sentinel for rpStkPredict and
6176 // also as the maximum value of lvRefCntWtd. Don't allow overflow, and
6177 // saturate at UINT_MAX - 1, to avoid using the sentinel.
6178 void raAddToStkPredict(unsigned val)
6180 unsigned newStkPredict = rpStkPredict + val;
6181 if ((newStkPredict < rpStkPredict) || (newStkPredict == UINT_MAX))
6182 rpStkPredict = UINT_MAX - 1;
6184 rpStkPredict = newStkPredict;
6188 #if !FEATURE_FP_REGALLOC
6189 void raDispFPlifeInfo();
6193 regMaskTP genReturnRegForTree(GenTreePtr tree);
6194 #endif // LEGACY_BACKEND
6196 /* raIsVarargsStackArg is called by raMaskStkVars and by
6197 lvaSortByRefCount. It identifies the special case
6198 where a varargs function has a parameter passed on the
6199 stack, other than the special varargs handle. Such parameters
6200 require special treatment, because they cannot be tracked
6201 by the GC (their offsets in the stack are not known
6205 bool raIsVarargsStackArg(unsigned lclNum)
6209 LclVarDsc* varDsc = &lvaTable[lclNum];
6211 assert(varDsc->lvIsParam);
6213 return (info.compIsVarArgs && !varDsc->lvIsRegArg && (lclNum != lvaVarargsHandleArg));
6215 #else // _TARGET_X86_
6219 #endif // _TARGET_X86_
6222 #ifdef LEGACY_BACKEND
6223 // Records the current prediction, if it's better than any previous recorded prediction.
6224 void rpRecordPrediction();
6225 // Applies the best recorded prediction, if one exists and is better than the current prediction.
6226 void rpUseRecordedPredictionIfBetter();
6228 // Data members used in the methods above.
6229 unsigned rpBestRecordedStkPredict;
6230 struct VarRegPrediction
6232 bool m_isEnregistered;
6233 regNumberSmall m_regNum;
6234 regNumberSmall m_otherReg;
6236 VarRegPrediction* rpBestRecordedPrediction;
6237 #endif // LEGACY_BACKEND
6240 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6241 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6245 XX Get to the class and method info from the Execution Engine given XX
6246 XX tokens for the class and method XX
6248 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6249 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6253 /* These are the different addressing modes used to access a local var.
6254 * The JIT has to report the location of the locals back to the EE
6255 * for debugging purposes.
6261 VLT_REG_BYREF, // this type is currently only used for value types on X64
6264 VLT_STK_BYREF, // this type is currently only used for value types on X64
6278 siVarLocType vlType;
6281 // VLT_REG/VLT_REG_FP -- Any pointer-sized enregistered value (TYP_INT, TYP_REF, etc)
6283 // VLT_REG_BYREF -- the specified register contains the address of the variable
6291 // VLT_STK -- Any 32 bit value which is on the stack
6292 // eg. [ESP+0x20], or [EBP-0x28]
6293 // VLT_STK_BYREF -- the specified stack location contains the address of the variable
6294 // eg. mov EAX, [ESP+0x20]; [EAX]
6298 regNumber vlsBaseReg;
6299 NATIVE_OFFSET vlsOffset;
6302 // VLT_REG_REG -- TYP_LONG/TYP_DOUBLE with both DWords enregistered
6311 // VLT_REG_STK -- Partly enregistered TYP_LONG/TYP_DOUBLE
6312 // eg { LowerDWord=EAX UpperDWord=[ESP+0x8] }
6320 regNumber vlrssBaseReg;
6321 NATIVE_OFFSET vlrssOffset;
6325 // VLT_STK_REG -- Partly enregistered TYP_LONG/TYP_DOUBLE
6326 // eg { LowerDWord=[ESP+0x8] UpperDWord=EAX }
6332 regNumber vlsrsBaseReg;
6333 NATIVE_OFFSET vlsrsOffset;
6339 // VLT_STK2 -- Any 64 bit value which is on the stack, in 2 successsive DWords
6340 // eg 2 DWords at [ESP+0x10]
6344 regNumber vls2BaseReg;
6345 NATIVE_OFFSET vls2Offset;
6348 // VLT_FPSTK -- enregisterd TYP_DOUBLE (on the FP stack)
6349 // eg. ST(3). Actually it is ST("FPstkHeight - vpFpStk")
6356 // VLT_FIXED_VA -- fixed argument of a varargs function.
6357 // The argument location depends on the size of the variable
6358 // arguments (...). Inspecting the VARARGS_HANDLE indicates the
6359 // location of the first arg. This argument can then be accessed
6360 // relative to the position of the first arg
6364 unsigned vlfvOffset;
6371 void* rpValue; // pointer to the in-process
6372 // location of the value.
6378 bool vlIsInReg(regNumber reg);
6379 bool vlIsOnStk(regNumber reg, signed offset);
6382 /*************************************************************************/
6387 void eeGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6388 CORINFO_RESOLVED_TOKEN* pConstrainedToken,
6389 CORINFO_CALLINFO_FLAGS flags,
6390 CORINFO_CALL_INFO* pResult);
6391 inline CORINFO_CALLINFO_FLAGS addVerifyFlag(CORINFO_CALLINFO_FLAGS flags);
6393 void eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6394 CORINFO_ACCESS_FLAGS flags,
6395 CORINFO_FIELD_INFO* pResult);
6399 BOOL eeIsValueClass(CORINFO_CLASS_HANDLE clsHnd);
6401 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(TRACK_LSRA_STATS)
6403 bool IsSuperPMIException(unsigned code)
6405 // Copied from NDP\clr\src\ToolBox\SuperPMI\SuperPMI-Shared\ErrorHandling.h
6407 const unsigned EXCEPTIONCODE_DebugBreakorAV = 0xe0421000;
6408 const unsigned EXCEPTIONCODE_MC = 0xe0422000;
6409 const unsigned EXCEPTIONCODE_LWM = 0xe0423000;
6410 const unsigned EXCEPTIONCODE_SASM = 0xe0424000;
6411 const unsigned EXCEPTIONCODE_SSYM = 0xe0425000;
6412 const unsigned EXCEPTIONCODE_CALLUTILS = 0xe0426000;
6413 const unsigned EXCEPTIONCODE_TYPEUTILS = 0xe0427000;
6414 const unsigned EXCEPTIONCODE_ASSERT = 0xe0440000;
6418 case EXCEPTIONCODE_DebugBreakorAV:
6419 case EXCEPTIONCODE_MC:
6420 case EXCEPTIONCODE_LWM:
6421 case EXCEPTIONCODE_SASM:
6422 case EXCEPTIONCODE_SSYM:
6423 case EXCEPTIONCODE_CALLUTILS:
6424 case EXCEPTIONCODE_TYPEUTILS:
6425 case EXCEPTIONCODE_ASSERT:
6432 const char* eeGetMethodName(CORINFO_METHOD_HANDLE hnd, const char** className);
6433 const char* eeGetMethodFullName(CORINFO_METHOD_HANDLE hnd);
6435 bool eeIsNativeMethod(CORINFO_METHOD_HANDLE method);
6436 CORINFO_METHOD_HANDLE eeGetMethodHandleForNative(CORINFO_METHOD_HANDLE method);
6439 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6440 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig, bool* isPinned);
6441 unsigned eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6443 // VOM info, method sigs
6445 void eeGetSig(unsigned sigTok,
6446 CORINFO_MODULE_HANDLE scope,
6447 CORINFO_CONTEXT_HANDLE context,
6448 CORINFO_SIG_INFO* retSig);
6450 void eeGetCallSiteSig(unsigned sigTok,
6451 CORINFO_MODULE_HANDLE scope,
6452 CORINFO_CONTEXT_HANDLE context,
6453 CORINFO_SIG_INFO* retSig);
6455 void eeGetMethodSig(CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* retSig, CORINFO_CLASS_HANDLE owner = nullptr);
6457 // Method entry-points, instrs
6459 void* eeGetFieldAddress(CORINFO_FIELD_HANDLE handle, void*** ppIndir);
6461 CORINFO_METHOD_HANDLE eeMarkNativeTarget(CORINFO_METHOD_HANDLE method);
6463 CORINFO_EE_INFO eeInfo;
6464 bool eeInfoInitialized;
6466 CORINFO_EE_INFO* eeGetEEInfo();
6468 // Gets the offset of a SDArray's first element
6469 unsigned eeGetArrayDataOffset(var_types type);
6470 // Gets the offset of a MDArray's first element
6471 unsigned eeGetMDArrayDataOffset(var_types type, unsigned rank);
6473 GenTreePtr eeGetPInvokeCookie(CORINFO_SIG_INFO* szMetaSig);
6475 // Returns the page size for the target machine as reported by the EE.
6476 inline size_t eeGetPageSize()
6478 #if COR_JIT_EE_VERSION > 460
6479 return eeGetEEInfo()->osPageSize;
6480 #else // COR_JIT_EE_VERSION <= 460
6481 return CORINFO_PAGE_SIZE;
6482 #endif // COR_JIT_EE_VERSION > 460
6485 // Returns the frame size at which we will generate a loop to probe the stack.
6486 inline size_t getVeryLargeFrameSize()
6489 // The looping probe code is 40 bytes, whereas the straight-line probing for
6490 // the (0x2000..0x3000) case is 44, so use looping for anything 0x2000 bytes
6491 // or greater, to generate smaller code.
6492 return 2 * eeGetPageSize();
6494 return 3 * eeGetPageSize();
6498 inline bool IsTargetAbi(CORINFO_RUNTIME_ABI abi)
6500 #if COR_JIT_EE_VERSION > 460
6501 return eeGetEEInfo()->targetAbi == abi;
6503 return CORINFO_DESKTOP_ABI == abi;
6507 inline bool generateCFIUnwindCodes()
6509 #ifdef UNIX_AMD64_ABI
6510 return IsTargetAbi(CORINFO_CORERT_ABI);
6518 unsigned eeGetEHcount(CORINFO_METHOD_HANDLE handle);
6520 // Debugging support - Line number info
6522 void eeGetStmtOffsets();
6524 unsigned eeBoundariesCount;
6526 struct boundariesDsc
6528 UNATIVE_OFFSET nativeIP;
6530 unsigned sourceReason;
6531 } * eeBoundaries; // Boundaries to report to EE
6532 void eeSetLIcount(unsigned count);
6533 void eeSetLIinfo(unsigned which, UNATIVE_OFFSET offs, unsigned srcIP, bool stkEmpty, bool callInstruction);
6537 static void eeDispILOffs(IL_OFFSET offs);
6538 static void eeDispLineInfo(const boundariesDsc* line);
6539 void eeDispLineInfos();
6542 // Debugging support - Local var info
6546 unsigned eeVarsCount;
6548 struct VarResultInfo
6550 UNATIVE_OFFSET startOffset;
6551 UNATIVE_OFFSET endOffset;
6555 void eeSetLVcount(unsigned count);
6556 void eeSetLVinfo(unsigned which,
6557 UNATIVE_OFFSET startOffs,
6558 UNATIVE_OFFSET length,
6563 const siVarLoc& loc);
6567 void eeDispVar(ICorDebugInfo::NativeVarInfo* var);
6568 void eeDispVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars);
6571 // ICorJitInfo wrappers
6573 void eeReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize);
6575 void eeAllocUnwindInfo(BYTE* pHotCode,
6581 CorJitFuncKind funcKind);
6583 void eeSetEHcount(unsigned cEH);
6585 void eeSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause);
6587 WORD eeGetRelocTypeHint(void* target);
6589 // ICorStaticInfo wrapper functions
6591 bool eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken);
6593 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
6595 static void dumpSystemVClassificationType(SystemVClassificationType ct);
6598 void eeGetSystemVAmd64PassStructInRegisterDescriptor(
6599 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
6600 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr);
6601 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
6603 template <typename ParamType>
6604 bool eeRunWithErrorTrap(void (*function)(ParamType*), ParamType* param)
6606 return eeRunWithErrorTrapImp(reinterpret_cast<void (*)(void*)>(function), reinterpret_cast<void*>(param));
6609 bool eeRunWithErrorTrapImp(void (*function)(void*), void* param);
6611 // Utility functions
6613 const char* eeGetFieldName(CORINFO_FIELD_HANDLE fieldHnd, const char** classNamePtr = nullptr);
6616 const wchar_t* eeGetCPString(size_t stringHandle);
6619 const char* eeGetClassName(CORINFO_CLASS_HANDLE clsHnd);
6621 static CORINFO_METHOD_HANDLE eeFindHelper(unsigned helper);
6622 static CorInfoHelpFunc eeGetHelperNum(CORINFO_METHOD_HANDLE method);
6624 static fgWalkPreFn CountSharedStaticHelper;
6625 static bool IsSharedStaticHelper(GenTreePtr tree);
6626 static bool IsTreeAlwaysHoistable(GenTreePtr tree);
6628 static CORINFO_FIELD_HANDLE eeFindJitDataOffs(unsigned jitDataOffs);
6629 // returns true/false if 'field' is a Jit Data offset
6630 static bool eeIsJitDataOffs(CORINFO_FIELD_HANDLE field);
6631 // returns a number < 0 if 'field' is not a Jit Data offset, otherwise the data offset (limited to 2GB)
6632 static int eeGetJitDataOffs(CORINFO_FIELD_HANDLE field);
6634 /*****************************************************************************/
6639 enum TEMP_USAGE_TYPE
6645 static var_types tmpNormalizeType(var_types type);
6646 TempDsc* tmpGetTemp(var_types type); // get temp for the given type
6647 void tmpRlsTemp(TempDsc* temp);
6648 TempDsc* tmpFindNum(int temp, TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const;
6651 TempDsc* tmpListBeg(TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const;
6652 TempDsc* tmpListNxt(TempDsc* curTemp, TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const;
6656 bool tmpAllFree() const;
6659 #ifndef LEGACY_BACKEND
6660 void tmpPreAllocateTemps(var_types type, unsigned count);
6661 #endif // !LEGACY_BACKEND
6664 #ifdef LEGACY_BACKEND
6665 unsigned tmpIntSpillMax; // number of int-sized spill temps
6666 unsigned tmpDoubleSpillMax; // number of double-sized spill temps
6667 #endif // LEGACY_BACKEND
6669 unsigned tmpCount; // Number of temps
6670 unsigned tmpSize; // Size of all the temps
6673 // Used by RegSet::rsSpillChk()
6674 unsigned tmpGetCount; // Temps which haven't been released yet
6677 static unsigned tmpSlot(unsigned size); // which slot in tmpFree[] or tmpUsed[] to use
6679 TempDsc* tmpFree[TEMP_MAX_SIZE / sizeof(int)];
6680 TempDsc* tmpUsed[TEMP_MAX_SIZE / sizeof(int)];
6683 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6684 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6688 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6689 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6693 CodeGenInterface* codeGen;
6695 // The following holds information about instr offsets in terms of generated code.
6699 IPmappingDsc* ipmdNext; // next line# record
6700 IL_OFFSETX ipmdILoffsx; // the instr offset
6701 emitLocation ipmdNativeLoc; // the emitter location of the native code corresponding to the IL offset
6702 bool ipmdIsLabel; // Can this code be a branch label?
6705 // Record the instr offset mapping to the generated code
6707 IPmappingDsc* genIPmappingList;
6708 IPmappingDsc* genIPmappingLast;
6710 // Managed RetVal - A side hash table meant to record the mapping from a
6711 // GT_CALL node to its IL offset. This info is used to emit sequence points
6712 // that can be used by debugger to determine the native offset at which the
6713 // managed RetVal will be available.
6715 // In fact we can store IL offset in a GT_CALL node. This was ruled out in
6716 // favor of a side table for two reasons: 1) We need IL offset for only those
6717 // GT_CALL nodes (created during importation) that correspond to an IL call and
6718 // whose return type is other than TYP_VOID. 2) GT_CALL node is a frequently used
6719 // structure and IL offset is needed only when generating debuggable code. Therefore
6720 // it is desirable to avoid memory size penalty in retail scenarios.
6721 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, IL_OFFSETX, JitSimplerHashBehavior>
6722 CallSiteILOffsetTable;
6723 CallSiteILOffsetTable* genCallSite2ILOffsetMap;
6725 unsigned genReturnLocal; // Local number for the return value when applicable.
6726 BasicBlock* genReturnBB; // jumped to when not optimizing for speed.
6728 // The following properties are part of CodeGenContext. Getters are provided here for
6729 // convenience and backward compatibility, but the properties can only be set by invoking
6730 // the setter on CodeGenContext directly.
6732 __declspec(property(get = getEmitter)) emitter* genEmitter;
6733 emitter* getEmitter()
6735 return codeGen->getEmitter();
6738 const bool isFramePointerUsed()
6740 return codeGen->isFramePointerUsed();
6743 __declspec(property(get = getInterruptible, put = setInterruptible)) bool genInterruptible;
6744 bool getInterruptible()
6746 return codeGen->genInterruptible;
6748 void setInterruptible(bool value)
6750 codeGen->setInterruptible(value);
6754 const bool genDoubleAlign()
6756 return codeGen->doDoubleAlign();
6758 DWORD getCanDoubleAlign();
6759 bool shouldDoubleAlign(unsigned refCntStk,
6761 unsigned refCntWtdReg,
6762 unsigned refCntStkParam,
6763 unsigned refCntWtdStkDbl);
6764 #endif // DOUBLE_ALIGN
6766 __declspec(property(get = getFullPtrRegMap, put = setFullPtrRegMap)) bool genFullPtrRegMap;
6767 bool getFullPtrRegMap()
6769 return codeGen->genFullPtrRegMap;
6771 void setFullPtrRegMap(bool value)
6773 codeGen->setFullPtrRegMap(value);
6776 // Things that MAY belong either in CodeGen or CodeGenContext
6778 #if FEATURE_EH_FUNCLETS
6779 FuncInfoDsc* compFuncInfos;
6780 unsigned short compCurrFuncIdx;
6781 unsigned short compFuncInfoCount;
6783 unsigned short compFuncCount()
6785 assert(fgFuncletsCreated);
6786 return compFuncInfoCount;
6789 #else // !FEATURE_EH_FUNCLETS
6791 // This is a no-op when there are no funclets!
6792 void genUpdateCurrentFunclet(BasicBlock* block)
6797 FuncInfoDsc compFuncInfoRoot;
6799 static const unsigned compCurrFuncIdx = 0;
6801 unsigned short compFuncCount()
6806 #endif // !FEATURE_EH_FUNCLETS
6808 FuncInfoDsc* funCurrentFunc();
6809 void funSetCurrentFunc(unsigned funcIdx);
6810 FuncInfoDsc* funGetFunc(unsigned funcIdx);
6811 unsigned int funGetFuncIdx(BasicBlock* block);
6815 VARSET_TP compCurLife; // current live variables
6816 GenTreePtr compCurLifeTree; // node after which compCurLife has been computed
6818 template <bool ForCodeGen>
6819 void compChangeLife(VARSET_VALARG_TP newLife DEBUGARG(GenTreePtr tree));
6821 void genChangeLife(VARSET_VALARG_TP newLife DEBUGARG(GenTreePtr tree))
6823 compChangeLife</*ForCodeGen*/ true>(newLife DEBUGARG(tree));
6826 template <bool ForCodeGen>
6827 void compUpdateLife(GenTreePtr tree);
6829 // Updates "compCurLife" to its state after evaluate of "true". If "pLastUseVars" is
6830 // non-null, sets "*pLastUseVars" to the set of tracked variables for which "tree" was a last
6831 // use. (Can be more than one var in the case of dependently promoted struct vars.)
6832 template <bool ForCodeGen>
6833 void compUpdateLifeVar(GenTreePtr tree, VARSET_TP* pLastUseVars = nullptr);
6835 template <bool ForCodeGen>
6836 inline void compUpdateLife(VARSET_VALARG_TP newLife);
6838 // Gets a register mask that represent the kill set for a helper call since
6839 // not all JIT Helper calls follow the standard ABI on the target architecture.
6840 regMaskTP compHelperCallKillSet(CorInfoHelpFunc helper);
6842 // Gets a register mask that represent the kill set for a NoGC helper call.
6843 regMaskTP compNoGCHelperCallKillSet(CorInfoHelpFunc helper);
6846 // Requires that "varDsc" be a promoted struct local variable being passed as an argument, beginning at
6847 // "firstArgRegNum", which is assumed to have already been aligned to the register alignment restriction of the
6848 // struct type. Adds bits to "*pArgSkippedRegMask" for any argument registers *not* used in passing "varDsc" --
6849 // i.e., internal "holes" caused by internal alignment constraints. For example, if the struct contained an int and
6850 // a double, and we at R0 (on ARM), then R1 would be skipped, and the bit for R1 would be added to the mask.
6851 void fgAddSkippedRegsInPromotedStructArg(LclVarDsc* varDsc, unsigned firstArgRegNum, regMaskTP* pArgSkippedRegMask);
6852 #endif // _TARGET_ARM_
6854 // 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
6856 static GenTreePtr fgIsIndirOfAddrOfLocal(GenTreePtr tree);
6858 // This is indexed by GT_OBJ nodes that are address of promoted struct variables, which
6859 // have been annotated with the GTF_VAR_DEATH flag. If such a node is *not* mapped in this
6860 // table, one may assume that all the (tracked) field vars die at this point. Otherwise,
6861 // the node maps to a pointer to a VARSET_TP, containing set bits for each of the tracked field
6862 // vars of the promoted struct local that go dead at the given node (the set bits are the bits
6863 // for the tracked var indices of the field vars, as in a live var set).
6864 NodeToVarsetPtrMap* m_promotedStructDeathVars;
6866 NodeToVarsetPtrMap* GetPromotedStructDeathVars()
6868 if (m_promotedStructDeathVars == nullptr)
6870 m_promotedStructDeathVars = new (getAllocator()) NodeToVarsetPtrMap(getAllocator());
6872 return m_promotedStructDeathVars;
6876 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6877 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6881 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6882 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6885 #if !defined(__GNUC__)
6886 #pragma region Unwind information
6891 // Infrastructure functions: start/stop/reserve/emit.
6894 void unwindBegProlog();
6895 void unwindEndProlog();
6896 void unwindBegEpilog();
6897 void unwindEndEpilog();
6898 void unwindReserve();
6899 void unwindEmit(void* pHotCode, void* pColdCode);
6902 // Specific unwind information functions: called by code generation to indicate a particular
6903 // prolog or epilog unwindable instruction has been generated.
6906 void unwindPush(regNumber reg);
6907 void unwindAllocStack(unsigned size);
6908 void unwindSetFrameReg(regNumber reg, unsigned offset);
6909 void unwindSaveReg(regNumber reg, unsigned offset);
6911 #if defined(_TARGET_ARM_)
6912 void unwindPushMaskInt(regMaskTP mask);
6913 void unwindPushMaskFloat(regMaskTP mask);
6914 void unwindPopMaskInt(regMaskTP mask);
6915 void unwindPopMaskFloat(regMaskTP mask);
6916 void unwindBranch16(); // The epilog terminates with a 16-bit branch (e.g., "bx lr")
6917 void unwindNop(unsigned codeSizeInBytes); // Generate unwind NOP code. 'codeSizeInBytes' is 2 or 4 bytes. Only
6918 // called via unwindPadding().
6919 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
6920 // instruction and the current location.
6921 #endif // _TARGET_ARM_
6923 #if defined(_TARGET_ARM64_)
6925 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
6926 // instruction and the current location.
6927 void unwindSaveReg(regNumber reg, int offset); // str reg, [sp, #offset]
6928 void unwindSaveRegPreindexed(regNumber reg, int offset); // str reg, [sp, #offset]!
6929 void unwindSaveRegPair(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]
6930 void unwindSaveRegPairPreindexed(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]!
6931 void unwindSaveNext(); // unwind code: save_next
6932 void unwindReturn(regNumber reg); // ret lr
6933 #endif // defined(_TARGET_ARM64_)
6936 // Private "helper" functions for the unwind implementation.
6940 #if FEATURE_EH_FUNCLETS
6941 void unwindGetFuncLocations(FuncInfoDsc* func,
6942 bool getHotSectionData,
6943 /* OUT */ emitLocation** ppStartLoc,
6944 /* OUT */ emitLocation** ppEndLoc);
6945 #endif // FEATURE_EH_FUNCLETS
6947 void unwindReserveFunc(FuncInfoDsc* func);
6948 void unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
6950 #if defined(_TARGET_AMD64_) || (defined(_TARGET_X86_) && FEATURE_EH_FUNCLETS)
6952 void unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode);
6953 void unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode);
6955 #endif // _TARGET_AMD64_ || (_TARGET_X86_ && FEATURE_EH_FUNCLETS)
6957 #if defined(_TARGET_AMD64_)
6959 UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func);
6961 void unwindBegPrologWindows();
6962 void unwindPushWindows(regNumber reg);
6963 void unwindAllocStackWindows(unsigned size);
6964 void unwindSetFrameRegWindows(regNumber reg, unsigned offset);
6965 void unwindSaveRegWindows(regNumber reg, unsigned offset);
6967 #ifdef UNIX_AMD64_ABI
6968 void unwindBegPrologCFI();
6969 void unwindPushCFI(regNumber reg);
6970 void unwindAllocStackCFI(unsigned size);
6971 void unwindSetFrameRegCFI(regNumber reg, unsigned offset);
6972 void unwindSaveRegCFI(regNumber reg, unsigned offset);
6973 int mapRegNumToDwarfReg(regNumber reg);
6974 void createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR opcode, USHORT dwarfReg, INT offset = 0);
6975 #endif // UNIX_AMD64_ABI
6976 #elif defined(_TARGET_ARM_)
6978 void unwindPushPopMaskInt(regMaskTP mask, bool useOpsize16);
6979 void unwindPushPopMaskFloat(regMaskTP mask);
6980 void unwindSplit(FuncInfoDsc* func);
6982 #endif // _TARGET_ARM_
6984 #if !defined(__GNUC__)
6985 #pragma endregion // Note: region is NOT under !defined(__GNUC__)
6989 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6990 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6994 XX Info about SIMD types, methods and the SIMD assembly (i.e. the assembly XX
6995 XX that contains the distinguished, well-known SIMD type definitions). XX
6997 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6998 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7001 // Get highest available instruction set for floating point codegen
7002 InstructionSet getFloatingPointInstructionSet()
7004 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7007 return InstructionSet_AVX;
7012 return InstructionSet_SSE3_4;
7016 assert(canUseSSE2());
7017 return InstructionSet_SSE2;
7019 assert(!"getFPInstructionSet() is not implemented for target arch");
7021 return InstructionSet_NONE;
7025 // Get highest available instruction set for SIMD codegen
7026 InstructionSet getSIMDInstructionSet()
7028 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7029 return getFloatingPointInstructionSet();
7031 assert(!"Available instruction set(s) for SIMD codegen is not defined for target arch");
7033 return InstructionSet_NONE;
7039 // Should we support SIMD intrinsics?
7042 // Have we identified any SIMD types?
7043 // This is currently used by struct promotion to avoid getting type information for a struct
7044 // field to see if it is a SIMD type, if we haven't seen any SIMD types or operations in
7046 bool _usesSIMDTypes;
7047 bool usesSIMDTypes()
7049 return _usesSIMDTypes;
7051 void setUsesSIMDTypes(bool value)
7053 _usesSIMDTypes = value;
7056 // This is a temp lclVar allocated on the stack as TYP_SIMD. It is used to implement intrinsics
7057 // that require indexed access to the individual fields of the vector, which is not well supported
7058 // by the hardware. It is allocated when/if such situations are encountered during Lowering.
7059 unsigned lvaSIMDInitTempVarNum;
7062 CORINFO_CLASS_HANDLE SIMDFloatHandle;
7063 CORINFO_CLASS_HANDLE SIMDDoubleHandle;
7064 CORINFO_CLASS_HANDLE SIMDIntHandle;
7065 CORINFO_CLASS_HANDLE SIMDUShortHandle;
7066 CORINFO_CLASS_HANDLE SIMDUByteHandle;
7067 CORINFO_CLASS_HANDLE SIMDShortHandle;
7068 CORINFO_CLASS_HANDLE SIMDByteHandle;
7069 CORINFO_CLASS_HANDLE SIMDLongHandle;
7070 CORINFO_CLASS_HANDLE SIMDUIntHandle;
7071 CORINFO_CLASS_HANDLE SIMDULongHandle;
7072 CORINFO_CLASS_HANDLE SIMDVector2Handle;
7073 CORINFO_CLASS_HANDLE SIMDVector3Handle;
7074 CORINFO_CLASS_HANDLE SIMDVector4Handle;
7075 CORINFO_CLASS_HANDLE SIMDVectorHandle;
7077 // Get the handle for a SIMD type.
7078 CORINFO_CLASS_HANDLE gtGetStructHandleForSIMD(var_types simdType, var_types simdBaseType)
7080 if (simdBaseType == TYP_FLOAT)
7085 return SIMDVector2Handle;
7087 return SIMDVector3Handle;
7089 if ((getSIMDVectorType() == TYP_SIMD32) || (SIMDVector4Handle != NO_CLASS_HANDLE))
7091 return SIMDVector4Handle;
7100 assert(simdType == getSIMDVectorType());
7101 switch (simdBaseType)
7104 return SIMDFloatHandle;
7106 return SIMDDoubleHandle;
7108 return SIMDIntHandle;
7110 return SIMDUShortHandle;
7112 return SIMDUShortHandle;
7114 return SIMDUByteHandle;
7116 return SIMDShortHandle;
7118 return SIMDByteHandle;
7120 return SIMDLongHandle;
7122 return SIMDUIntHandle;
7124 return SIMDULongHandle;
7126 assert(!"Didn't find a class handle for simdType");
7128 return NO_CLASS_HANDLE;
7132 CORINFO_METHOD_HANDLE SIMDVectorFloat_set_Item;
7133 CORINFO_METHOD_HANDLE SIMDVectorFloat_get_Length;
7134 CORINFO_METHOD_HANDLE SIMDVectorFloat_op_Addition;
7136 // Returns true if the tree corresponds to a TYP_SIMD lcl var.
7137 // Note that both SIMD vector args and locals are mared as lvSIMDType = true, but
7138 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD or TYP_STRUCT.
7139 bool isSIMDTypeLocal(GenTree* tree)
7141 return tree->OperIsLocal() && lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7144 // Returns true if the type of the tree is a byref of TYP_SIMD
7145 bool isAddrOfSIMDType(GenTree* tree)
7147 if (tree->TypeGet() == TYP_BYREF || tree->TypeGet() == TYP_I_IMPL)
7149 switch (tree->OperGet())
7152 return varTypeIsSIMD(tree->gtGetOp1());
7154 case GT_LCL_VAR_ADDR:
7155 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7158 return isSIMDTypeLocal(tree);
7165 static bool isRelOpSIMDIntrinsic(SIMDIntrinsicID intrinsicId)
7167 return (intrinsicId == SIMDIntrinsicEqual || intrinsicId == SIMDIntrinsicLessThan ||
7168 intrinsicId == SIMDIntrinsicLessThanOrEqual || intrinsicId == SIMDIntrinsicGreaterThan ||
7169 intrinsicId == SIMDIntrinsicGreaterThanOrEqual);
7172 // Returns base type of a TYP_SIMD local.
7173 // Returns TYP_UNKNOWN if the local is not TYP_SIMD.
7174 var_types getBaseTypeOfSIMDLocal(GenTree* tree)
7176 if (isSIMDTypeLocal(tree))
7178 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvBaseType;
7184 bool isSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7186 return info.compCompHnd->isInSIMDModule(clsHnd);
7189 bool isSIMDClass(typeInfo* pTypeInfo)
7191 return pTypeInfo->IsStruct() && isSIMDClass(pTypeInfo->GetClassHandleForValueClass());
7194 // Get the base (element) type and size in bytes for a SIMD type. Returns TYP_UNKNOWN
7195 // if it is not a SIMD type or is an unsupported base type.
7196 var_types getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes = nullptr);
7198 var_types getBaseTypeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7200 return getBaseTypeAndSizeOfSIMDType(typeHnd, nullptr);
7203 // Get SIMD Intrinsic info given the method handle.
7204 // Also sets typeHnd, argCount, baseType and sizeBytes out params.
7205 const SIMDIntrinsicInfo* getSIMDIntrinsicInfo(CORINFO_CLASS_HANDLE* typeHnd,
7206 CORINFO_METHOD_HANDLE methodHnd,
7207 CORINFO_SIG_INFO* sig,
7210 var_types* baseType,
7211 unsigned* sizeBytes);
7213 // Pops and returns GenTree node from importers type stack.
7214 // Normalizes TYP_STRUCT value in case of GT_CALL, GT_RET_EXPR and arg nodes.
7215 GenTreePtr impSIMDPopStack(var_types type, bool expectAddr = false);
7217 // Create a GT_SIMD tree for a Get property of SIMD vector with a fixed index.
7218 GenTreeSIMD* impSIMDGetFixed(var_types simdType, var_types baseType, unsigned simdSize, int index);
7220 // Creates a GT_SIMD tree for Select operation
7221 GenTreePtr impSIMDSelect(CORINFO_CLASS_HANDLE typeHnd,
7223 unsigned simdVectorSize,
7228 // Creates a GT_SIMD tree for Min/Max operation
7229 GenTreePtr impSIMDMinMax(SIMDIntrinsicID intrinsicId,
7230 CORINFO_CLASS_HANDLE typeHnd,
7232 unsigned simdVectorSize,
7236 // Transforms operands and returns the SIMD intrinsic to be applied on
7237 // transformed operands to obtain given relop result.
7238 SIMDIntrinsicID impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId,
7239 CORINFO_CLASS_HANDLE typeHnd,
7240 unsigned simdVectorSize,
7241 var_types* baseType,
7245 // Creates a GT_SIMD tree for Abs intrinsic.
7246 GenTreePtr impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType, unsigned simdVectorSize, GenTree* op1);
7248 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7249 // Transforms operands and returns the SIMD intrinsic to be applied on
7250 // transformed operands to obtain == comparison result.
7251 SIMDIntrinsicID impSIMDLongRelOpEqual(CORINFO_CLASS_HANDLE typeHnd,
7252 unsigned simdVectorSize,
7256 // Transforms operands and returns the SIMD intrinsic to be applied on
7257 // transformed operands to obtain > comparison result.
7258 SIMDIntrinsicID impSIMDLongRelOpGreaterThan(CORINFO_CLASS_HANDLE typeHnd,
7259 unsigned simdVectorSize,
7263 // Transforms operands and returns the SIMD intrinsic to be applied on
7264 // transformed operands to obtain >= comparison result.
7265 SIMDIntrinsicID impSIMDLongRelOpGreaterThanOrEqual(CORINFO_CLASS_HANDLE typeHnd,
7266 unsigned simdVectorSize,
7270 // Transforms operands and returns the SIMD intrinsic to be applied on
7271 // transformed operands to obtain >= comparison result in case of int32
7272 // and small int base type vectors.
7273 SIMDIntrinsicID impSIMDIntegralRelOpGreaterThanOrEqual(
7274 CORINFO_CLASS_HANDLE typeHnd, unsigned simdVectorSize, var_types baseType, GenTree** op1, GenTree** op2);
7275 #endif // defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7277 void setLclRelatedToSIMDIntrinsic(GenTreePtr tree);
7278 bool areFieldsContiguous(GenTreePtr op1, GenTreePtr op2);
7279 bool areArrayElementsContiguous(GenTreePtr op1, GenTreePtr op2);
7280 bool areArgumentsContiguous(GenTreePtr op1, GenTreePtr op2);
7281 GenTreePtr createAddressNodeForSIMDInit(GenTreePtr tree, unsigned simdSize);
7283 // check methodHnd to see if it is a SIMD method that is expanded as an intrinsic in the JIT.
7284 GenTreePtr impSIMDIntrinsic(OPCODE opcode,
7285 GenTreePtr newobjThis,
7286 CORINFO_CLASS_HANDLE clsHnd,
7287 CORINFO_METHOD_HANDLE method,
7288 CORINFO_SIG_INFO* sig,
7291 GenTreePtr getOp1ForConstructor(OPCODE opcode, GenTreePtr newobjThis, CORINFO_CLASS_HANDLE clsHnd);
7293 // Whether SIMD vector occupies part of SIMD register.
7294 // SSE2: vector2f/3f are considered sub register SIMD types.
7295 // AVX: vector2f, 3f and 4f are all considered sub register SIMD types.
7296 bool isSubRegisterSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7298 unsigned sizeBytes = 0;
7299 var_types baseType = getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7300 return (baseType == TYP_FLOAT) && (sizeBytes < getSIMDVectorRegisterByteLength());
7303 bool isSubRegisterSIMDType(GenTreeSIMD* simdNode)
7305 return (simdNode->gtSIMDSize < getSIMDVectorRegisterByteLength());
7308 // Get the type for the hardware SIMD vector.
7309 // This is the maximum SIMD type supported for this target.
7310 var_types getSIMDVectorType()
7312 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7319 assert(canUseSSE2());
7323 assert(!"getSIMDVectorType() unimplemented on target arch");
7328 // Get the size of the SIMD type in bytes
7329 int getSIMDTypeSizeInBytes(CORINFO_CLASS_HANDLE typeHnd)
7331 unsigned sizeBytes = 0;
7332 (void)getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7336 // Get the the number of elements of basetype of SIMD vector given by its size and baseType
7337 static int getSIMDVectorLength(unsigned simdSize, var_types baseType);
7339 // Get the the number of elements of basetype of SIMD vector given by its type handle
7340 int getSIMDVectorLength(CORINFO_CLASS_HANDLE typeHnd);
7342 // Get preferred alignment of SIMD type.
7343 int getSIMDTypeAlignment(var_types simdType);
7345 // Get the number of bytes in a SIMD Vector for the current compilation.
7346 unsigned getSIMDVectorRegisterByteLength()
7348 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7351 return YMM_REGSIZE_BYTES;
7355 assert(canUseSSE2());
7356 return XMM_REGSIZE_BYTES;
7359 assert(!"getSIMDVectorRegisterByteLength() unimplemented on target arch");
7364 // The minimum and maximum possible number of bytes in a SIMD vector.
7365 unsigned int maxSIMDStructBytes()
7367 return getSIMDVectorRegisterByteLength();
7369 unsigned int minSIMDStructBytes()
7371 return emitTypeSize(TYP_SIMD8);
7374 #ifdef FEATURE_AVX_SUPPORT
7375 // (maxPossibleSIMDStructBytes is for use in a context that requires a compile-time constant.)
7376 static const unsigned maxPossibleSIMDStructBytes = 32;
7377 #else // !FEATURE_AVX_SUPPORT
7378 static const unsigned maxPossibleSIMDStructBytes = 16;
7379 #endif // !FEATURE_AVX_SUPPORT
7381 // Returns the codegen type for a given SIMD size.
7382 var_types getSIMDTypeForSize(unsigned size)
7384 var_types simdType = TYP_UNDEF;
7387 simdType = TYP_SIMD8;
7389 else if (size == 12)
7391 simdType = TYP_SIMD12;
7393 else if (size == 16)
7395 simdType = TYP_SIMD16;
7397 #ifdef FEATURE_AVX_SUPPORT
7398 else if (size == 32)
7400 simdType = TYP_SIMD32;
7402 #endif // FEATURE_AVX_SUPPORT
7405 noway_assert(!"Unexpected size for SIMD type");
7410 unsigned getSIMDInitTempVarNum()
7412 if (lvaSIMDInitTempVarNum == BAD_VAR_NUM)
7414 lvaSIMDInitTempVarNum = lvaGrabTempWithImplicitUse(false DEBUGARG("SIMDInitTempVar"));
7415 lvaTable[lvaSIMDInitTempVarNum].lvType = getSIMDVectorType();
7417 return lvaSIMDInitTempVarNum;
7420 #endif // FEATURE_SIMD
7423 //------------------------------------------------------------------------
7424 // largestEnregisterableStruct: The size in bytes of the largest struct that can be enregistered.
7426 // Notes: It is not guaranteed that the struct of this size or smaller WILL be a
7427 // candidate for enregistration.
7429 unsigned largestEnregisterableStructSize()
7432 unsigned vectorRegSize = getSIMDVectorRegisterByteLength();
7433 if (vectorRegSize > TARGET_POINTER_SIZE)
7435 return vectorRegSize;
7438 #endif // FEATURE_SIMD
7440 return TARGET_POINTER_SIZE;
7445 // These routines need not be enclosed under FEATURE_SIMD since lvIsSIMDType()
7446 // is defined for both FEATURE_SIMD and !FEATURE_SIMD apropriately. The use
7447 // of this routines also avoids the need of #ifdef FEATURE_SIMD specific code.
7449 // Is this var is of type simd struct?
7450 bool lclVarIsSIMDType(unsigned varNum)
7452 LclVarDsc* varDsc = lvaTable + varNum;
7453 return varDsc->lvIsSIMDType();
7456 // Is this Local node a SIMD local?
7457 bool lclVarIsSIMDType(GenTreeLclVarCommon* lclVarTree)
7459 return lclVarIsSIMDType(lclVarTree->gtLclNum);
7462 // Returns true if the TYP_SIMD locals on stack are aligned at their
7463 // preferred byte boundary specified by getSIMDTypeAlignment().
7465 // As per the Intel manual, the preferred alignment for AVX vectors is 32-bytes. On Amd64,
7466 // RSP/EBP is aligned at 16-bytes, therefore to align SIMD types at 32-bytes we need even
7467 // RSP/EBP to be 32-byte aligned. It is not clear whether additional stack space used in
7468 // aligning stack is worth the benefit and for now will use 16-byte alignment for AVX
7469 // 256-bit vectors with unaligned load/stores to/from memory. On x86, the stack frame
7470 // is aligned to 4 bytes. We need to extend existing support for double (8-byte) alignment
7471 // to 16 or 32 byte alignment for frames with local SIMD vars, if that is determined to be
7474 bool isSIMDTypeLocalAligned(unsigned varNum)
7476 #if defined(FEATURE_SIMD) && ALIGN_SIMD_TYPES
7477 if (lclVarIsSIMDType(varNum) && lvaTable[varNum].lvType != TYP_BYREF)
7480 int off = lvaFrameAddress(varNum, &ebpBased);
7481 // TODO-Cleanup: Can't this use the lvExactSize on the varDsc?
7482 int alignment = getSIMDTypeAlignment(lvaTable[varNum].lvType);
7483 bool isAligned = (alignment <= STACK_ALIGN) && ((off % alignment) == 0);
7486 #endif // FEATURE_SIMD
7491 // Whether SSE2 is available
7492 bool canUseSSE2() const
7494 #ifdef _TARGET_XARCH_
7495 return opts.compCanUseSSE2;
7501 // Whether SSE3, SSE3, SSE4.1 and SSE4.2 is available
7502 bool CanUseSSE3_4() const
7504 #ifdef _TARGET_XARCH_
7505 return opts.compCanUseSSE3_4;
7511 bool canUseAVX() const
7513 #ifdef FEATURE_AVX_SUPPORT
7514 return opts.compCanUseAVX;
7521 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7522 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7526 XX Generic info about the compilation and the method being compiled. XX
7527 XX It is responsible for driving the other phases. XX
7528 XX It is also responsible for all the memory management. XX
7530 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7531 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7535 Compiler* InlineeCompiler; // The Compiler instance for the inlinee
7537 InlineResult* compInlineResult; // The result of importing the inlinee method.
7539 bool compDoAggressiveInlining; // If true, mark every method as CORINFO_FLG_FORCEINLINE
7540 bool compJmpOpUsed; // Does the method do a JMP
7541 bool compLongUsed; // Does the method use TYP_LONG
7542 bool compFloatingPointUsed; // Does the method use TYP_FLOAT or TYP_DOUBLE
7543 bool compTailCallUsed; // Does the method do a tailcall
7544 bool compLocallocUsed; // Does the method use localloc.
7545 bool compQmarkUsed; // Does the method use GT_QMARK/GT_COLON
7546 bool compQmarkRationalized; // Is it allowed to use a GT_QMARK/GT_COLON node.
7547 bool compUnsafeCastUsed; // Does the method use LDIND/STIND to cast between scalar/refernce types
7549 // NOTE: These values are only reliable after
7550 // the importing is completely finished.
7552 ExpandArrayStack<GenTreePtr>* compQMarks; // The set of QMark nodes created in the current compilation, so
7553 // we can iterate over these efficiently.
7555 #if CPU_USES_BLOCK_MOVE
7556 bool compBlkOpUsed; // Does the method do a COPYBLK or INITBLK
7560 // State information - which phases have completed?
7561 // These are kept together for easy discoverability
7563 bool bRangeAllowStress;
7564 bool compCodeGenDone;
7565 int64_t compNumStatementLinksTraversed; // # of links traversed while doing debug checks
7566 bool fgNormalizeEHDone; // Has the flowgraph EH normalization phase been done?
7567 size_t compSizeEstimate; // The estimated size of the method as per `gtSetEvalOrder`.
7568 size_t compCycleEstimate; // The estimated cycle count of the method as per `gtSetEvalOrder`
7571 bool fgLocalVarLivenessDone; // Note that this one is used outside of debug.
7572 bool fgLocalVarLivenessChanged;
7574 bool compStackProbePrologDone;
7576 #ifndef LEGACY_BACKEND
7578 #endif // !LEGACY_BACKEND
7579 bool compRationalIRForm;
7581 bool compUsesThrowHelper; // There is a call to a THOROW_HELPER for the compiled method.
7583 bool compGeneratingProlog;
7584 bool compGeneratingEpilog;
7585 bool compNeedsGSSecurityCookie; // There is an unsafe buffer (or localloc) on the stack.
7586 // Insert cookie on frame and code to check the cookie, like VC++ -GS.
7587 bool compGSReorderStackLayout; // There is an unsafe buffer on the stack, reorder locals and make local
7588 // copies of susceptible parameters to avoid buffer overrun attacks through locals/params
7589 bool getNeedsGSSecurityCookie() const
7591 return compNeedsGSSecurityCookie;
7593 void setNeedsGSSecurityCookie()
7595 compNeedsGSSecurityCookie = true;
7598 FrameLayoutState lvaDoneFrameLayout; // The highest frame layout state that we've completed. During
7599 // frame layout calculations, this is the level we are currently
7602 //---------------------------- JITing options -----------------------------
7615 JitFlags* jitFlags; // all flags passed from the EE
7616 unsigned compFlags; // method attributes
7618 codeOptimize compCodeOpt; // what type of code optimizations
7622 #ifdef _TARGET_XARCH_
7623 bool compCanUseSSE2; // Allow CodeGen to use "movq XMM" instructions
7624 bool compCanUseSSE3_4; // Allow CodeGen to use SSE3, SSSE3, SSE4.1 and SSE4.2 instructions
7626 #ifdef FEATURE_AVX_SUPPORT
7627 bool compCanUseAVX; // Allow CodeGen to use AVX 256-bit vectors for SIMD operations
7628 #endif // FEATURE_AVX_SUPPORT
7629 #endif // _TARGET_XARCH_
7631 // optimize maximally and/or favor speed over size?
7633 #define DEFAULT_MIN_OPTS_CODE_SIZE 60000
7634 #define DEFAULT_MIN_OPTS_INSTR_COUNT 20000
7635 #define DEFAULT_MIN_OPTS_BB_COUNT 2000
7636 #define DEFAULT_MIN_OPTS_LV_NUM_COUNT 2000
7637 #define DEFAULT_MIN_OPTS_LV_REF_COUNT 8000
7639 // Maximun number of locals before turning off the inlining
7640 #define MAX_LV_NUM_COUNT_FOR_INLINING 512
7643 unsigned instrCount;
7644 unsigned lvRefCount;
7645 bool compMinOptsIsSet;
7647 bool compMinOptsIsUsed;
7649 inline bool MinOpts()
7651 assert(compMinOptsIsSet);
7652 compMinOptsIsUsed = true;
7655 inline bool IsMinOptsSet()
7657 return compMinOptsIsSet;
7660 inline bool MinOpts()
7664 inline bool IsMinOptsSet()
7666 return compMinOptsIsSet;
7669 inline void SetMinOpts(bool val)
7671 assert(!compMinOptsIsUsed);
7672 assert(!compMinOptsIsSet || (compMinOpts == val));
7674 compMinOptsIsSet = true;
7677 // true if the CLFLG_* for an optimization is set.
7678 inline bool OptEnabled(unsigned optFlag)
7680 return !!(compFlags & optFlag);
7683 #ifdef FEATURE_READYTORUN_COMPILER
7684 inline bool IsReadyToRun()
7686 return jitFlags->IsSet(JitFlags::JIT_FLAG_READYTORUN);
7689 inline bool IsReadyToRun()
7695 // true if we should use the PINVOKE_{BEGIN,END} helpers instead of generating
7696 // PInvoke transitions inline (e.g. when targeting CoreRT).
7697 inline bool ShouldUsePInvokeHelpers()
7699 #if COR_JIT_EE_VERSION > 460
7700 return jitFlags->IsSet(JitFlags::JIT_FLAG_USE_PINVOKE_HELPERS);
7706 // true if we should use insert the REVERSE_PINVOKE_{ENTER,EXIT} helpers in the method
7708 inline bool IsReversePInvoke()
7710 #if COR_JIT_EE_VERSION > 460
7711 return jitFlags->IsSet(JitFlags::JIT_FLAG_REVERSE_PINVOKE);
7717 // true if we must generate code compatible with JIT32 quirks
7718 inline bool IsJit32Compat()
7720 #if defined(_TARGET_X86_) && COR_JIT_EE_VERSION > 460
7721 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
7727 // true if we must generate code compatible with Jit64 quirks
7728 inline bool IsJit64Compat()
7730 #if defined(_TARGET_AMD64_) && COR_JIT_EE_VERSION > 460
7731 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
7732 #elif defined(_TARGET_AMD64_) && !defined(FEATURE_CORECLR)
7739 bool compScopeInfo; // Generate the LocalVar info ?
7740 bool compDbgCode; // Generate debugger-friendly code?
7741 bool compDbgInfo; // Gather debugging info?
7744 #ifdef PROFILING_SUPPORTED
7745 bool compNoPInvokeInlineCB;
7747 static const bool compNoPInvokeInlineCB;
7751 bool compGcChecks; // Check arguments and return values to ensure they are sane
7752 bool compStackCheckOnRet; // Check ESP on return to ensure it is correct
7753 bool compStackCheckOnCall; // Check ESP after every call to ensure it is correct
7757 bool compNeedSecurityCheck; // This flag really means where or not a security object needs
7758 // to be allocated on the stack.
7759 // It will be set to true in the following cases:
7760 // 1. When the method being compiled has a declarative security
7761 // (i.e. when CORINFO_FLG_NOSECURITYWRAP is reset for the current method).
7762 // This is also the case when we inject a prolog and epilog in the method.
7764 // 2. When the method being compiled has imperative security (i.e. the method
7765 // calls into another method that has CORINFO_FLG_SECURITYCHECK flag set).
7767 // 3. When opts.compDbgEnC is true. (See also Compiler::compCompile).
7769 // When this flag is set, jit will allocate a gc-reference local variable (lvaSecurityObject),
7770 // which gets reported as a GC root to stackwalker.
7771 // (See also ICodeManager::GetAddrOfSecurityObject.)
7778 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
7779 bool compEnablePCRelAddr; // Whether absolute addr be encoded as PC-rel offset by RyuJIT where possible
7783 #ifdef UNIX_AMD64_ABI
7784 // This flag is indicating if there is a need to align the frame.
7785 // On AMD64-Windows, if there are calls, 4 slots for the outgoing ars are allocated, except for
7786 // FastTailCall. This slots makes the frame size non-zero, so alignment logic will be called.
7787 // On AMD64-Unix, there are no such slots. There is a possibility to have calls in the method with frame size of
7788 // 0. The frame alignment logic won't kick in. This flags takes care of the AMD64-Unix case by remembering that
7789 // there are calls and making sure the frame alignment logic is executed.
7790 bool compNeedToAlignFrame;
7791 #endif // UNIX_AMD64_ABI
7793 bool compProcedureSplitting; // Separate cold code from hot code
7795 bool genFPorder; // Preserve FP order (operations are non-commutative)
7796 bool genFPopt; // Can we do frame-pointer-omission optimization?
7797 bool altJit; // True if we are an altjit and are compiling this method
7800 bool optRepeat; // Repeat optimizer phases k times
7804 bool compProcedureSplittingEH; // Separate cold code from hot code for functions with EH
7805 bool dspCode; // Display native code generated
7806 bool dspEHTable; // Display the EH table reported to the VM
7807 bool dspInstrs; // Display the IL instructions intermixed with the native code output
7808 bool dspEmit; // Display emitter output
7809 bool dspLines; // Display source-code lines intermixed with native code output
7810 bool dmpHex; // Display raw bytes in hex of native code output
7811 bool varNames; // Display variables names in native code output
7812 bool disAsm; // Display native code as it is generated
7813 bool disAsmSpilled; // Display native code when any register spilling occurs
7814 bool disDiffable; // Makes the Disassembly code 'diff-able'
7815 bool disAsm2; // Display native code after it is generated using external disassembler
7816 bool dspOrder; // Display names of each of the methods that we ngen/jit
7817 bool dspUnwind; // Display the unwind info output
7818 bool dspDiffable; // Makes the Jit Dump 'diff-able' (currently uses same COMPlus_* flag as disDiffable)
7819 bool compLongAddress; // Force using large pseudo instructions for long address
7820 // (IF_LARGEJMP/IF_LARGEADR/IF_LARGLDC)
7821 bool dspGCtbls; // Display the GC tables
7825 bool doLateDisasm; // Run the late disassembler
7826 #endif // LATE_DISASM
7828 #if DUMP_GC_TABLES && !defined(DEBUG) && defined(JIT32_GCENCODER)
7829 // Only the JIT32_GCENCODER implements GC dumping in non-DEBUG code.
7830 #pragma message("NOTE: this non-debug build has GC ptr table dumping always enabled!")
7831 static const bool dspGCtbls = true;
7834 // We need stack probes to guarantee that we won't trigger a stack overflow
7835 // when calling unmanaged code until they get a chance to set up a frame, because
7836 // the EE will have no idea where it is.
7838 // We will only be doing this currently for hosted environments. Unfortunately
7839 // we need to take care of stubs, so potentially, we will have to do the probes
7840 // for any call. We have a plan for not needing for stubs though
7841 bool compNeedStackProbes;
7843 #ifdef PROFILING_SUPPORTED
7844 // Whether to emit Enter/Leave/TailCall hooks using a dummy stub (DummyProfilerELTStub()).
7845 // This option helps make the JIT behave as if it is running under a profiler.
7846 bool compJitELTHookEnabled;
7847 #endif // PROFILING_SUPPORTED
7849 #if FEATURE_TAILCALL_OPT
7850 // Whether opportunistic or implicit tail call optimization is enabled.
7851 bool compTailCallOpt;
7852 // Whether optimization of transforming a recursive tail call into a loop is enabled.
7853 bool compTailCallLoopOpt;
7857 static const bool compUseSoftFP = true;
7858 #else // !ARM_SOFTFP
7859 static const bool compUseSoftFP = false;
7862 GCPollType compGCPollType;
7866 static bool s_pAltJitExcludeAssembliesListInitialized;
7867 static AssemblyNamesList2* s_pAltJitExcludeAssembliesList;
7872 template <typename T>
7875 return (p == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : p);
7878 template <typename T>
7881 return (o == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : o);
7884 static int dspTreeID(GenTree* tree)
7886 return tree->gtTreeID;
7888 static void printTreeID(GenTree* tree)
7890 if (tree == nullptr)
7896 printf("[%06d]", dspTreeID(tree));
7903 #define STRESS_MODES \
7907 /* "Variations" stress areas which we try to mix up with each other. */ \
7908 /* These should not be exhaustively used as they might */ \
7909 /* hide/trivialize other areas */ \
7912 STRESS_MODE(DBL_ALN) \
7913 STRESS_MODE(LCL_FLDS) \
7914 STRESS_MODE(UNROLL_LOOPS) \
7915 STRESS_MODE(MAKE_CSE) \
7916 STRESS_MODE(LEGACY_INLINE) \
7917 STRESS_MODE(CLONE_EXPR) \
7918 STRESS_MODE(USE_FCOMI) \
7919 STRESS_MODE(USE_CMOV) \
7921 STRESS_MODE(BB_PROFILE) \
7922 STRESS_MODE(OPT_BOOLS_GC) \
7923 STRESS_MODE(REMORPH_TREES) \
7924 STRESS_MODE(64RSLT_MUL) \
7925 STRESS_MODE(DO_WHILE_LOOPS) \
7926 STRESS_MODE(MIN_OPTS) \
7927 STRESS_MODE(REVERSE_FLAG) /* Will set GTF_REVERSE_OPS whenever we can */ \
7928 STRESS_MODE(REVERSE_COMMA) /* Will reverse commas created with gtNewCommaNode */ \
7929 STRESS_MODE(TAILCALL) /* Will make the call as a tailcall whenever legal */ \
7930 STRESS_MODE(CATCH_ARG) /* Will spill catch arg */ \
7931 STRESS_MODE(UNSAFE_BUFFER_CHECKS) \
7932 STRESS_MODE(NULL_OBJECT_CHECK) \
7933 STRESS_MODE(PINVOKE_RESTORE_ESP) \
7934 STRESS_MODE(RANDOM_INLINE) \
7935 STRESS_MODE(SWITCH_CMP_BR_EXPANSION) \
7936 STRESS_MODE(GENERIC_VARN) \
7938 /* After COUNT_VARN, stress level 2 does all of these all the time */ \
7940 STRESS_MODE(COUNT_VARN) \
7942 /* "Check" stress areas that can be exhaustively used if we */ \
7943 /* dont care about performance at all */ \
7945 STRESS_MODE(FORCE_INLINE) /* Treat every method as AggressiveInlining */ \
7946 STRESS_MODE(CHK_FLOW_UPDATE) \
7947 STRESS_MODE(EMITTER) \
7948 STRESS_MODE(CHK_REIMPORT) \
7949 STRESS_MODE(FLATFP) \
7950 STRESS_MODE(GENERIC_CHECK) \
7955 #define STRESS_MODE(mode) STRESS_##mode,
7962 static const LPCWSTR s_compStressModeNames[STRESS_COUNT + 1];
7963 BYTE compActiveStressModes[STRESS_COUNT];
7966 #define MAX_STRESS_WEIGHT 100
7968 bool compStressCompile(compStressArea stressArea, unsigned weightPercentage);
7972 bool compInlineStress()
7974 return compStressCompile(STRESS_LEGACY_INLINE, 50);
7977 bool compRandomInlineStress()
7979 return compStressCompile(STRESS_RANDOM_INLINE, 50);
7984 bool compTailCallStress()
7987 return (JitConfig.TailcallStress() != 0 || compStressCompile(STRESS_TAILCALL, 5));
7993 codeOptimize compCodeOpt()
7996 // Switching between size & speed has measurable throughput impact
7997 // (3.5% on NGen mscorlib when measured). It used to be enabled for
7998 // DEBUG, but should generate identical code between CHK & RET builds,
7999 // so that's not acceptable.
8000 // TODO-Throughput: Figure out what to do about size vs. speed & throughput.
8001 // Investigate the cause of the throughput regression.
8003 return opts.compCodeOpt;
8005 return BLENDED_CODE;
8009 //--------------------- Info about the procedure --------------------------
8013 COMP_HANDLE compCompHnd;
8014 CORINFO_MODULE_HANDLE compScopeHnd;
8015 CORINFO_CLASS_HANDLE compClassHnd;
8016 CORINFO_METHOD_HANDLE compMethodHnd;
8017 CORINFO_METHOD_INFO* compMethodInfo;
8019 BOOL hasCircularClassConstraints;
8020 BOOL hasCircularMethodConstraints;
8022 #if defined(DEBUG) || defined(LATE_DISASM)
8023 const char* compMethodName;
8024 const char* compClassName;
8025 const char* compFullName;
8026 #endif // defined(DEBUG) || defined(LATE_DISASM)
8028 #if defined(DEBUG) || defined(INLINE_DATA)
8029 // Method hash is logcally const, but computed
8031 mutable unsigned compMethodHashPrivate;
8032 unsigned compMethodHash() const;
8033 #endif // defined(DEBUG) || defined(INLINE_DATA)
8035 #ifdef PSEUDORANDOM_NOP_INSERTION
8036 // things for pseudorandom nop insertion
8037 unsigned compChecksum;
8041 // The following holds the FLG_xxxx flags for the method we're compiling.
8044 // The following holds the class attributes for the method we're compiling.
8045 unsigned compClassAttr;
8047 const BYTE* compCode;
8048 IL_OFFSET compILCodeSize; // The IL code size
8049 UNATIVE_OFFSET compNativeCodeSize; // The native code size, after instructions are issued. This
8050 // is less than (compTotalHotCodeSize + compTotalColdCodeSize) only if:
8051 // (1) the code is not hot/cold split, and we issued less code than we expected, or
8052 // (2) the code is hot/cold split, and we issued less code than we expected
8053 // in the cold section (the hot section will always be padded out to compTotalHotCodeSize).
8055 bool compIsStatic : 1; // Is the method static (no 'this' pointer)?
8056 bool compIsVarArgs : 1; // Does the method have varargs parameters?
8057 bool compIsContextful : 1; // contextful method
8058 bool compInitMem : 1; // Is the CORINFO_OPT_INIT_LOCALS bit set in the method info options?
8059 bool compUnwrapContextful : 1; // JIT should unwrap proxies when possible
8060 bool compProfilerCallback : 1; // JIT inserted a profiler Enter callback
8061 bool compPublishStubParam : 1; // EAX captured in prolog will be available through an instrinsic
8062 bool compRetBuffDefStack : 1; // The ret buff argument definitely points into the stack.
8064 var_types compRetType; // Return type of the method as declared in IL
8065 var_types compRetNativeType; // Normalized return type as per target arch ABI
8066 unsigned compILargsCount; // Number of arguments (incl. implicit but not hidden)
8067 unsigned compArgsCount; // Number of arguments (incl. implicit and hidden)
8068 unsigned compRetBuffArg; // position of hidden return param var (0, 1) (BAD_VAR_NUM means not present);
8069 int compTypeCtxtArg; // position of hidden param for type context for generic code (CORINFO_CALLCONV_PARAMTYPE)
8070 unsigned compThisArg; // position of implicit this pointer param (not to be confused with lvaArg0Var)
8071 unsigned compILlocalsCount; // Number of vars : args + locals (incl. implicit but not hidden)
8072 unsigned compLocalsCount; // Number of vars : args + locals (incl. implicit and hidden)
8073 unsigned compMaxStack;
8074 UNATIVE_OFFSET compTotalHotCodeSize; // Total number of bytes of Hot Code in the method
8075 UNATIVE_OFFSET compTotalColdCodeSize; // Total number of bytes of Cold Code in the method
8077 unsigned compCallUnmanaged; // count of unmanaged calls
8078 unsigned compLvFrameListRoot; // lclNum for the Frame root
8079 unsigned compXcptnsCount; // Number of exception-handling clauses read in the method's IL.
8080 // You should generally use compHndBBtabCount instead: it is the
8081 // current number of EH clauses (after additions like synchronized
8082 // methods and funclets, and removals like unreachable code deletion).
8084 bool compMatchedVM; // true if the VM is "matched": either the JIT is a cross-compiler
8085 // and the VM expects that, or the JIT is a "self-host" compiler
8086 // (e.g., x86 hosted targeting x86) and the VM expects that.
8088 /* The following holds IL scope information about local variables.
8091 unsigned compVarScopesCount;
8092 VarScopeDsc* compVarScopes;
8094 /* The following holds information about instr offsets for
8095 * which we need to report IP-mappings
8098 IL_OFFSET* compStmtOffsets; // sorted
8099 unsigned compStmtOffsetsCount;
8100 ICorDebugInfo::BoundaryTypes compStmtOffsetsImplicit;
8102 #define CPU_X86 0x0100 // The generic X86 CPU
8103 #define CPU_X86_PENTIUM_4 0x0110
8105 #define CPU_X64 0x0200 // The generic x64 CPU
8106 #define CPU_AMD_X64 0x0210 // AMD x64 CPU
8107 #define CPU_INTEL_X64 0x0240 // Intel x64 CPU
8109 #define CPU_ARM 0x0300 // The generic ARM CPU
8111 unsigned genCPU; // What CPU are we running on
8114 // Returns true if the method being compiled returns a non-void and non-struct value.
8115 // Note that lvaInitTypeRef() normalizes compRetNativeType for struct returns in a
8116 // single register as per target arch ABI (e.g on Amd64 Windows structs of size 1, 2,
8117 // 4 or 8 gets normalized to TYP_BYTE/TYP_SHORT/TYP_INT/TYP_LONG; On Arm HFA structs).
8118 // Methods returning such structs are considered to return non-struct return value and
8119 // this method returns true in that case.
8120 bool compMethodReturnsNativeScalarType()
8122 return (info.compRetType != TYP_VOID) && !varTypeIsStruct(info.compRetNativeType);
8125 // Returns true if the method being compiled returns RetBuf addr as its return value
8126 bool compMethodReturnsRetBufAddr()
8128 // There are cases where implicit RetBuf argument should be explicitly returned in a register.
8129 // In such cases the return type is changed to TYP_BYREF and appropriate IR is generated.
8131 // 1. Profiler Leave calllback expects the address of retbuf as return value for
8132 // methods with hidden RetBuf argument. impReturnInstruction() when profiler
8133 // callbacks are needed creates GT_RETURN(TYP_BYREF, op1 = Addr of RetBuf) for
8134 // methods with hidden RetBufArg.
8136 // 2. As per the System V ABI, the address of RetBuf needs to be returned by
8137 // methods with hidden RetBufArg in RAX. In such case GT_RETURN is of TYP_BYREF,
8138 // returning the address of RetBuf.
8140 // 3. Windows 64-bit native calling convention also requires the address of RetBuff
8141 // to be returned in RAX.
8142 CLANG_FORMAT_COMMENT_ANCHOR;
8144 #ifdef _TARGET_AMD64_
8145 return (info.compRetBuffArg != BAD_VAR_NUM);
8146 #else // !_TARGET_AMD64_
8147 return (compIsProfilerHookNeeded()) && (info.compRetBuffArg != BAD_VAR_NUM);
8148 #endif // !_TARGET_AMD64_
8151 // Returns true if the method returns a value in more than one return register
8152 // TODO-ARM-Bug: Deal with multi-register genReturnLocaled structs?
8153 // TODO-ARM64: Does this apply for ARM64 too?
8154 bool compMethodReturnsMultiRegRetType()
8156 #if FEATURE_MULTIREG_RET
8157 #if defined(_TARGET_X86_)
8158 // On x86 only 64-bit longs are returned in multiple registers
8159 return varTypeIsLong(info.compRetNativeType);
8160 #else // targets: X64-UNIX, ARM64 or ARM32
8161 // On all other targets that support multireg return values:
8162 // Methods returning a struct in multiple registers have a return value of TYP_STRUCT.
8163 // Such method's compRetNativeType is TYP_STRUCT without a hidden RetBufArg
8164 return varTypeIsStruct(info.compRetNativeType) && (info.compRetBuffArg == BAD_VAR_NUM);
8165 #endif // TARGET_XXX
8167 #else // not FEATURE_MULTIREG_RET
8169 // For this architecture there are no multireg returns
8172 #endif // FEATURE_MULTIREG_RET
8175 #if FEATURE_MULTIREG_ARGS
8176 // Given a GenTree node of TYP_STRUCT that represents a pass by value argument
8177 // return the gcPtr layout for the pointers sized fields
8178 void getStructGcPtrsFromOp(GenTreePtr op, BYTE* gcPtrsOut);
8179 #endif // FEATURE_MULTIREG_ARGS
8181 // Returns true if the method being compiled returns a value
8182 bool compMethodHasRetVal()
8184 return compMethodReturnsNativeScalarType() || compMethodReturnsRetBufAddr() ||
8185 compMethodReturnsMultiRegRetType();
8190 void compDispLocalVars();
8194 //-------------------------- Global Compiler Data ------------------------------------
8197 static unsigned s_compMethodsCount; // to produce unique label names
8198 unsigned compGenTreeID;
8201 BasicBlock* compCurBB; // the current basic block in process
8202 GenTreePtr compCurStmt; // the current statement in process
8204 unsigned compCurStmtNum; // to give all statements an increasing StmtNum when printing dumps
8207 // The following is used to create the 'method JIT info' block.
8208 size_t compInfoBlkSize;
8209 BYTE* compInfoBlkAddr;
8211 EHblkDsc* compHndBBtab; // array of EH data
8212 unsigned compHndBBtabCount; // element count of used elements in EH data array
8213 unsigned compHndBBtabAllocCount; // element count of allocated elements in EH data array
8215 #if defined(_TARGET_X86_)
8217 //-------------------------------------------------------------------------
8218 // Tracking of region covered by the monitor in synchronized methods
8219 void* syncStartEmitCookie; // the emitter cookie for first instruction after the call to MON_ENTER
8220 void* syncEndEmitCookie; // the emitter cookie for first instruction after the call to MON_EXIT
8222 #endif // !_TARGET_X86_
8224 Phases previousCompletedPhase; // the most recently completed phase
8226 //-------------------------------------------------------------------------
8227 // The following keeps track of how many bytes of local frame space we've
8228 // grabbed so far in the current function, and how many argument bytes we
8229 // need to pop when we return.
8232 unsigned compLclFrameSize; // secObject+lclBlk+locals+temps
8234 // Count of callee-saved regs we pushed in the prolog.
8235 // Does not include EBP for isFramePointerUsed() and double-aligned frames.
8236 // In case of Amd64 this doesn't include float regs saved on stack.
8237 unsigned compCalleeRegsPushed;
8239 #if defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87
8240 // Mask of callee saved float regs on stack.
8241 regMaskTP compCalleeFPRegsSavedMask;
8243 #ifdef _TARGET_AMD64_
8244 // Quirk for VS debug-launch scenario to work:
8245 // Bytes of padding between save-reg area and locals.
8246 #define VSQUIRK_STACK_PAD (2 * REGSIZE_BYTES)
8247 unsigned compVSQuirkStackPaddingNeeded;
8248 bool compQuirkForPPPflag;
8251 unsigned compArgSize; // total size of arguments in bytes (including register args (lvIsRegArg))
8253 unsigned compMapILargNum(unsigned ILargNum); // map accounting for hidden args
8254 unsigned compMapILvarNum(unsigned ILvarNum); // map accounting for hidden args
8255 unsigned compMap2ILvarNum(unsigned varNum); // map accounting for hidden args
8257 //-------------------------------------------------------------------------
8259 static void compStartup(); // One-time initialization
8260 static void compShutdown(); // One-time finalization
8262 void compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo);
8265 static void compDisplayStaticSizes(FILE* fout);
8267 //------------ Some utility functions --------------
8269 void* compGetHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
8270 void** ppIndirection); /* OUT */
8272 // Several JIT/EE interface functions return a CorInfoType, and also return a
8273 // class handle as an out parameter if the type is a value class. Returns the
8274 // size of the type these describe.
8275 unsigned compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd);
8278 // Components used by the compiler may write unit test suites, and
8279 // have them run within this method. They will be run only once per process, and only
8280 // in debug. (Perhaps should be under the control of a COMPlus_ flag.)
8281 // These should fail by asserting.
8282 void compDoComponentUnitTestsOnce();
8285 int compCompile(CORINFO_METHOD_HANDLE methodHnd,
8286 CORINFO_MODULE_HANDLE classPtr,
8287 COMP_HANDLE compHnd,
8288 CORINFO_METHOD_INFO* methodInfo,
8289 void** methodCodePtr,
8290 ULONG* methodCodeSize,
8291 JitFlags* compileFlags);
8292 void compCompileFinish();
8293 int compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
8294 COMP_HANDLE compHnd,
8295 CORINFO_METHOD_INFO* methodInfo,
8296 void** methodCodePtr,
8297 ULONG* methodCodeSize,
8298 JitFlags* compileFlags,
8299 CorInfoInstantiationVerification instVerInfo);
8301 ArenaAllocator* compGetAllocator();
8303 #if MEASURE_MEM_ALLOC
8305 static bool s_dspMemStats; // Display per-phase memory statistics for every function
8309 unsigned allocCnt; // # of allocs
8310 UINT64 allocSz; // total size of those alloc.
8311 UINT64 allocSzMax; // Maximum single allocation.
8312 UINT64 allocSzByKind[CMK_Count]; // Classified by "kind".
8313 UINT64 nraTotalSizeAlloc;
8314 UINT64 nraTotalSizeUsed;
8316 static const char* s_CompMemKindNames[]; // Names of the kinds.
8318 MemStats() : allocCnt(0), allocSz(0), allocSzMax(0), nraTotalSizeAlloc(0), nraTotalSizeUsed(0)
8320 for (int i = 0; i < CMK_Count; i++)
8322 allocSzByKind[i] = 0;
8325 MemStats(const MemStats& ms)
8326 : allocCnt(ms.allocCnt)
8327 , allocSz(ms.allocSz)
8328 , allocSzMax(ms.allocSzMax)
8329 , nraTotalSizeAlloc(ms.nraTotalSizeAlloc)
8330 , nraTotalSizeUsed(ms.nraTotalSizeUsed)
8332 for (int i = 0; i < CMK_Count; i++)
8334 allocSzByKind[i] = ms.allocSzByKind[i];
8338 // Until we have ubiquitous constructors.
8341 this->MemStats::MemStats();
8344 void AddAlloc(size_t sz, CompMemKind cmk)
8348 if (sz > allocSzMax)
8352 allocSzByKind[cmk] += sz;
8355 void Print(FILE* f); // Print these stats to f.
8356 void PrintByKind(FILE* f); // Do just the by-kind histogram part.
8358 MemStats genMemStats;
8360 struct AggregateMemStats : public MemStats
8364 AggregateMemStats() : MemStats(), nMethods(0)
8368 void Add(const MemStats& ms)
8371 allocCnt += ms.allocCnt;
8372 allocSz += ms.allocSz;
8373 allocSzMax = max(allocSzMax, ms.allocSzMax);
8374 for (int i = 0; i < CMK_Count; i++)
8376 allocSzByKind[i] += ms.allocSzByKind[i];
8378 nraTotalSizeAlloc += ms.nraTotalSizeAlloc;
8379 nraTotalSizeUsed += ms.nraTotalSizeUsed;
8382 void Print(FILE* f); // Print these stats to jitstdout.
8385 static CritSecObject s_memStatsLock; // This lock protects the data structures below.
8386 static MemStats s_maxCompMemStats; // Stats for the compilation with the largest amount allocated.
8387 static AggregateMemStats s_aggMemStats; // Aggregates statistics for all compilations.
8389 #endif // MEASURE_MEM_ALLOC
8391 #if LOOP_HOIST_STATS
8392 unsigned m_loopsConsidered;
8393 bool m_curLoopHasHoistedExpression;
8394 unsigned m_loopsWithHoistedExpressions;
8395 unsigned m_totalHoistedExpressions;
8397 void AddLoopHoistStats();
8398 void PrintPerMethodLoopHoistStats();
8400 static CritSecObject s_loopHoistStatsLock; // This lock protects the data structures below.
8401 static unsigned s_loopsConsidered;
8402 static unsigned s_loopsWithHoistedExpressions;
8403 static unsigned s_totalHoistedExpressions;
8405 static void PrintAggregateLoopHoistStats(FILE* f);
8406 #endif // LOOP_HOIST_STATS
8408 void* compGetMemArray(size_t numElem, size_t elemSize, CompMemKind cmk = CMK_Unknown);
8409 void* compGetMemArrayA(size_t numElem, size_t elemSize, CompMemKind cmk = CMK_Unknown);
8410 void* compGetMem(size_t sz, CompMemKind cmk = CMK_Unknown);
8411 void* compGetMemA(size_t sz, CompMemKind cmk = CMK_Unknown);
8412 static void* compGetMemCallback(void*, size_t, CompMemKind cmk = CMK_Unknown);
8413 void compFreeMem(void*);
8415 bool compIsForImportOnly();
8416 bool compIsForInlining();
8417 bool compDonotInline();
8420 const char* compLocalVarName(unsigned varNum, unsigned offs);
8421 VarName compVarName(regNumber reg, bool isFloatReg = false);
8422 const char* compRegVarName(regNumber reg, bool displayVar = false, bool isFloatReg = false);
8423 const char* compRegPairName(regPairNo regPair);
8424 const char* compRegNameForSize(regNumber reg, size_t size);
8425 const char* compFPregVarName(unsigned fpReg, bool displayVar = false);
8426 void compDspSrcLinesByNativeIP(UNATIVE_OFFSET curIP);
8427 void compDspSrcLinesByLineNum(unsigned line, bool seek = false);
8430 //-------------------------------------------------------------------------
8432 typedef ListNode<VarScopeDsc*> VarScopeListNode;
8434 struct VarScopeMapInfo
8436 VarScopeListNode* head;
8437 VarScopeListNode* tail;
8438 static VarScopeMapInfo* Create(VarScopeListNode* node, IAllocator* alloc)
8440 VarScopeMapInfo* info = new (alloc) VarScopeMapInfo;
8447 // Max value of scope count for which we would use linear search; for larger values we would use hashtable lookup.
8448 static const unsigned MAX_LINEAR_FIND_LCL_SCOPELIST = 32;
8450 typedef SimplerHashTable<unsigned, SmallPrimitiveKeyFuncs<unsigned>, VarScopeMapInfo*, JitSimplerHashBehavior>
8451 VarNumToScopeDscMap;
8453 // Map to keep variables' scope indexed by varNum containing it's scope dscs at the index.
8454 VarNumToScopeDscMap* compVarScopeMap;
8456 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned lifeBeg, unsigned lifeEnd);
8458 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned offs);
8460 VarScopeDsc* compFindLocalVarLinear(unsigned varNum, unsigned offs);
8462 void compInitVarScopeMap();
8464 VarScopeDsc** compEnterScopeList; // List has the offsets where variables
8465 // enter scope, sorted by instr offset
8466 unsigned compNextEnterScope;
8468 VarScopeDsc** compExitScopeList; // List has the offsets where variables
8469 // go out of scope, sorted by instr offset
8470 unsigned compNextExitScope;
8472 void compInitScopeLists();
8474 void compResetScopeLists();
8476 VarScopeDsc* compGetNextEnterScope(unsigned offs, bool scan = false);
8478 VarScopeDsc* compGetNextExitScope(unsigned offs, bool scan = false);
8480 void compProcessScopesUntil(unsigned offset,
8482 void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*),
8483 void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*));
8486 void compDispScopeLists();
8489 bool compIsProfilerHookNeeded();
8491 //-------------------------------------------------------------------------
8492 /* Statistical Data Gathering */
8494 void compJitStats(); // call this function and enable
8495 // various ifdef's below for statistical data
8498 void compCallArgStats();
8499 static void compDispCallArgStats(FILE* fout);
8502 //-------------------------------------------------------------------------
8509 ArenaAllocator* compAllocator;
8512 // This one presents an implementation of the "IAllocator" abstract class that uses "compAllocator",
8513 // suitable for use by utilcode collection types.
8514 IAllocator* compAsIAllocator;
8516 #if MEASURE_MEM_ALLOC
8517 IAllocator* compAsIAllocatorBitset; // An allocator that uses the CMK_bitset tracker.
8518 IAllocator* compAsIAllocatorGC; // An allocator that uses the CMK_GC tracker.
8519 IAllocator* compAsIAllocatorLoopHoist; // An allocator that uses the CMK_LoopHoist tracker.
8521 IAllocator* compAsIAllocatorDebugOnly; // An allocator that uses the CMK_DebugOnly tracker.
8523 #endif // MEASURE_MEM_ALLOC
8525 void compFunctionTraceStart();
8526 void compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, bool isNYI);
8529 size_t compMaxUncheckedOffsetForNullObject;
8531 void compInitOptions(JitFlags* compileFlags);
8533 void compSetProcessor();
8534 void compInitDebuggingInfo();
8535 void compSetOptimizationLevel();
8536 #ifdef _TARGET_ARMARCH_
8537 bool compRsvdRegCheck(FrameLayoutState curState);
8539 void compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags);
8541 // Clear annotations produced during optimizations; to be used between iterations when repeating opts.
8542 void ResetOptAnnotations();
8544 // Regenerate loop descriptors; to be used between iterations when repeating opts.
8545 void RecomputeLoopInfo();
8547 #ifdef PROFILING_SUPPORTED
8548 // Data required for generating profiler Enter/Leave/TailCall hooks
8550 bool compProfilerHookNeeded; // Whether profiler Enter/Leave/TailCall hook needs to be generated for the method
8551 void* compProfilerMethHnd; // Profiler handle of the method being compiled. Passed as param to ELT callbacks
8552 bool compProfilerMethHndIndirected; // Whether compProfilerHandle is pointer to the handle or is an actual handle
8555 #ifdef _TARGET_AMD64_
8556 bool compQuirkForPPP(); // Check if this method should be Quirked for the PPP issue
8559 // Assumes called as part of process shutdown; does any compiler-specific work associated with that.
8560 static void ProcessShutdownWork(ICorStaticInfo* statInfo);
8562 IAllocator* getAllocator()
8564 return compAsIAllocator;
8567 #if MEASURE_MEM_ALLOC
8568 IAllocator* getAllocatorBitset()
8570 return compAsIAllocatorBitset;
8572 IAllocator* getAllocatorGC()
8574 return compAsIAllocatorGC;
8576 IAllocator* getAllocatorLoopHoist()
8578 return compAsIAllocatorLoopHoist;
8580 #else // !MEASURE_MEM_ALLOC
8581 IAllocator* getAllocatorBitset()
8583 return compAsIAllocator;
8585 IAllocator* getAllocatorGC()
8587 return compAsIAllocator;
8589 IAllocator* getAllocatorLoopHoist()
8591 return compAsIAllocator;
8593 #endif // !MEASURE_MEM_ALLOC
8596 IAllocator* getAllocatorDebugOnly()
8598 #if MEASURE_MEM_ALLOC
8599 return compAsIAllocatorDebugOnly;
8600 #else // !MEASURE_MEM_ALLOC
8601 return compAsIAllocator;
8602 #endif // !MEASURE_MEM_ALLOC
8607 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8608 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8612 XX Checks for type compatibility and merges types XX
8614 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8615 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8619 // Set to TRUE if verification cannot be skipped for this method
8620 // If we detect unverifiable code, we will lazily check
8621 // canSkipMethodVerification() to see if verification is REALLY needed.
8622 BOOL tiVerificationNeeded;
8624 // It it initially TRUE, and it gets set to FALSE if we run into unverifiable code
8625 // Note that this is valid only if tiVerificationNeeded was ever TRUE.
8626 BOOL tiIsVerifiableCode;
8628 // Set to TRUE if runtime callout is needed for this method
8629 BOOL tiRuntimeCalloutNeeded;
8631 // Set to TRUE if security prolog/epilog callout is needed for this method
8632 // Note: This flag is different than compNeedSecurityCheck.
8633 // compNeedSecurityCheck means whether or not a security object needs
8634 // to be allocated on the stack, which is currently true for EnC as well.
8635 // tiSecurityCalloutNeeded means whether or not security callouts need
8636 // to be inserted in the jitted code.
8637 BOOL tiSecurityCalloutNeeded;
8639 // Returns TRUE if child is equal to or a subtype of parent for merge purposes
8640 // This support is necessary to suport attributes that are not described in
8641 // for example, signatures. For example, the permanent home byref (byref that
8642 // points to the gc heap), isn't a property of method signatures, therefore,
8643 // it is safe to have mismatches here (that tiCompatibleWith will not flag),
8644 // but when deciding if we need to reimport a block, we need to take these
8646 BOOL tiMergeCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
8648 // Returns TRUE if child is equal to or a subtype of parent.
8649 // normalisedForStack indicates that both types are normalised for the stack
8650 BOOL tiCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
8652 // Merges pDest and pSrc. Returns FALSE if merge is undefined.
8653 // *pDest is modified to represent the merged type. Sets "*changed" to true
8654 // if this changes "*pDest".
8655 BOOL tiMergeToCommonParent(typeInfo* pDest, const typeInfo* pSrc, bool* changed) const;
8657 // Set pDest from the primitive value type.
8658 // Eg. System.Int32 -> ELEMENT_TYPE_I4
8660 BOOL tiFromPrimitiveValueClass(typeInfo* pDest, const typeInfo* pVC) const;
8663 // <BUGNUM> VSW 471305
8664 // IJW allows assigning REF to BYREF. The following allows us to temporarily
8665 // bypass the assert check in gcMarkRegSetGCref and gcMarkRegSetByref
8666 // We use a "short" as we need to push/pop this scope.
8668 short compRegSetCheckLevel;
8672 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8673 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8675 XX IL verification stuff XX
8678 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8679 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8683 // The following is used to track liveness of local variables, initialization
8684 // of valueclass constructors, and type safe use of IL instructions.
8686 // dynamic state info needed for verification
8687 EntryState verCurrentState;
8689 // this ptr of object type .ctors are considered intited only after
8690 // the base class ctor is called, or an alternate ctor is called.
8691 // An uninited this ptr can be used to access fields, but cannot
8692 // be used to call a member function.
8693 BOOL verTrackObjCtorInitState;
8695 void verInitBBEntryState(BasicBlock* block, EntryState* currentState);
8697 // Requires that "tis" is not TIS_Bottom -- it's a definite init/uninit state.
8698 void verSetThisInit(BasicBlock* block, ThisInitState tis);
8699 void verInitCurrentState();
8700 void verResetCurrentState(BasicBlock* block, EntryState* currentState);
8702 // Merges the current verification state into the entry state of "block", return FALSE if that merge fails,
8703 // TRUE if it succeeds. Further sets "*changed" to true if this changes the entry state of "block".
8704 BOOL verMergeEntryStates(BasicBlock* block, bool* changed);
8706 void verConvertBBToThrowVerificationException(BasicBlock* block DEBUGARG(bool logMsg));
8707 void verHandleVerificationFailure(BasicBlock* block DEBUGARG(bool logMsg));
8708 typeInfo verMakeTypeInfo(CORINFO_CLASS_HANDLE clsHnd,
8709 bool bashStructToRef = false); // converts from jit type representation to typeInfo
8710 typeInfo verMakeTypeInfo(CorInfoType ciType,
8711 CORINFO_CLASS_HANDLE clsHnd); // converts from jit type representation to typeInfo
8712 BOOL verIsSDArray(typeInfo ti);
8713 typeInfo verGetArrayElemType(typeInfo ti);
8715 typeInfo verParseArgSigToTypeInfo(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args);
8716 BOOL verNeedsVerification();
8717 BOOL verIsByRefLike(const typeInfo& ti);
8718 BOOL verIsSafeToReturnByRef(const typeInfo& ti);
8720 // generic type variables range over types that satisfy IsBoxable
8721 BOOL verIsBoxable(const typeInfo& ti);
8723 void DECLSPEC_NORETURN verRaiseVerifyException(INDEBUG(const char* reason) DEBUGARG(const char* file)
8724 DEBUGARG(unsigned line));
8725 void verRaiseVerifyExceptionIfNeeded(INDEBUG(const char* reason) DEBUGARG(const char* file)
8726 DEBUGARG(unsigned line));
8727 bool verCheckTailCallConstraint(OPCODE opcode,
8728 CORINFO_RESOLVED_TOKEN* pResolvedToken,
8729 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call
8730 // on a type parameter?
8731 bool speculative // If true, won't throw if verificatoin fails. Instead it will
8732 // return false to the caller.
8733 // If false, it will throw.
8735 bool verIsBoxedValueType(typeInfo ti);
8737 void verVerifyCall(OPCODE opcode,
8738 CORINFO_RESOLVED_TOKEN* pResolvedToken,
8739 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
8741 bool readonlyCall, // is this a "readonly." call?
8742 const BYTE* delegateCreateStart,
8743 const BYTE* codeAddr,
8744 CORINFO_CALL_INFO* callInfo DEBUGARG(const char* methodName));
8746 BOOL verCheckDelegateCreation(const BYTE* delegateCreateStart, const BYTE* codeAddr, mdMemberRef& targetMemberRef);
8748 typeInfo verVerifySTIND(const typeInfo& ptr, const typeInfo& value, const typeInfo& instrType);
8749 typeInfo verVerifyLDIND(const typeInfo& ptr, const typeInfo& instrType);
8750 void verVerifyField(CORINFO_RESOLVED_TOKEN* pResolvedToken,
8751 const CORINFO_FIELD_INFO& fieldInfo,
8752 const typeInfo* tiThis,
8754 BOOL allowPlainStructAsThis = FALSE);
8755 void verVerifyCond(const typeInfo& tiOp1, const typeInfo& tiOp2, unsigned opcode);
8756 void verVerifyThisPtrInitialised();
8757 BOOL verIsCallToInitThisPtr(CORINFO_CLASS_HANDLE context, CORINFO_CLASS_HANDLE target);
8759 // Register allocator
8760 void raInitStackFP();
8761 void raEnregisterVarsPrePassStackFP();
8762 void raSetRegLclBirthDeath(GenTreePtr tree, VARSET_VALARG_TP lastlife, bool fromLDOBJ);
8763 void raEnregisterVarsPostPassStackFP();
8764 void raGenerateFPRefCounts();
8765 void raEnregisterVarsStackFP();
8766 void raUpdateHeightsForVarsStackFP(VARSET_VALARG_TP mask);
8768 regNumber raRegForVarStackFP(unsigned varTrackedIndex);
8769 void raAddPayloadStackFP(VARSET_VALARG_TP mask, unsigned weight);
8771 // returns true if enregistering v1 would save more mem accesses than v2
8772 bool raVarIsGreaterValueStackFP(LclVarDsc* lv1, LclVarDsc* lv2);
8775 void raDumpHeightsStackFP();
8776 void raDumpVariableRegIntfFloat();
8779 #if FEATURE_STACK_FP_X87
8781 // Currently, we use FP transition blocks in only 2 situations:
8783 // -conditional jump on longs where FP stack differs with target: it's not strictly
8784 // necessary, but its low frequency and the code would get complicated if we try to
8785 // inline the FP stack adjustment, as we have a lot of special casing going on to try
8786 // minimize the way we generate the jump code.
8787 // -case statements of switch where the FP stack differs with the one of evaluating the switch () statement
8788 // We do this as we want to codegen switch as a jumptable. Again, this is low frequency.
8790 // However, transition blocks have 2 problems
8792 // - Procedure splitting: current implementation of procedure splitting requires all basic blocks to
8793 // be known at codegen time, as it generates all hot blocks first and cold blocks later. This ties
8794 // us up in codegen and is a solvable problem (we could make procedure splitting generate blocks
8795 // in the right place without preordering them), this causes us to have to generate the transition
8796 // blocks in the cold area if we want procedure splitting.
8799 // - Thread abort exceptions and transition blocks. Transition blocks were designed under the assumption
8800 // that no exceptions can happen inside them. Unfortunately Thread.Abort can happen in any instruction,
8801 // and if we have handlers we will have to try to call them. Fixing this the right way would imply
8802 // having multiple try native code regions for a single try il region. This is doable and shouldnt be
8803 // a big change in the exception.
8805 // Given the low frequency of the cases where we have transition blocks, I've decided to dumb down
8806 // optimizations. For these 2 cases:
8808 // - When there is a chance that we will have FP transition blocks, we won't do procedure splitting.
8809 // - When a method has a handler, it won't enregister any FP variables that go thru a conditional long or
8810 // a switch statement.
8812 // If at any point we find we need to optimize this, we should throw work at unblocking the restrictions our
8813 // current procedure splitting and exception code have.
8814 bool compMayHaveTransitionBlocks;
8816 VARSET_TP raMaskDontEnregFloat; // mask for additional restrictions
8818 VARSET_TP raLclRegIntfFloat[REG_FPCOUNT];
8820 unsigned raCntStkStackFP;
8821 unsigned raCntWtdStkDblStackFP;
8822 unsigned raCntStkParamDblStackFP;
8824 // Payload in mem accesses for enregistering a variable (we dont want to mix with refcounts)
8825 // TODO: Do we want to put this in LclVarDsc?
8826 unsigned raPayloadStackFP[lclMAX_TRACKED];
8827 unsigned raHeightsStackFP[lclMAX_TRACKED][FP_VIRTUALREGISTERS + 1];
8829 // Useful for debugging
8830 unsigned raHeightsNonWeightedStackFP[lclMAX_TRACKED][FP_VIRTUALREGISTERS + 1];
8832 #endif // FEATURE_STACK_FP_X87
8835 // One line log function. Default level is 0. Increasing it gives you
8836 // more log information
8838 // levels are currently unused: #define JITDUMP(level,...) ();
8839 void JitLogEE(unsigned level, const char* fmt, ...);
8841 bool compDebugBreak;
8843 bool compJitHaltMethod();
8848 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8849 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8851 XX GS Security checks for unsafe buffers XX
8853 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8854 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8857 struct ShadowParamVarInfo
8859 FixedBitVect* assignGroup; // the closure set of variables whose values depend on each other
8860 unsigned shadowCopy; // Lcl var num, valid only if not set to NO_SHADOW_COPY
8862 static bool mayNeedShadowCopy(LclVarDsc* varDsc)
8864 #if defined(_TARGET_AMD64_) && !defined(LEGACY_BACKEND)
8865 // GS cookie logic to create shadow slots, create trees to copy reg args to shadow
8866 // slots and update all trees to refer to shadow slots is done immediately after
8867 // fgMorph(). Lsra could potentially mark a param as DoNotEnregister after JIT determines
8868 // not to shadow a parameter. Also, LSRA could potentially spill a param which is passed
8869 // in register. Therefore, conservatively all params may need a shadow copy. Note that
8870 // GS cookie logic further checks whether the param is a ptr or an unsafe buffer before
8871 // creating a shadow slot even though this routine returns true.
8873 // TODO-AMD64-CQ: Revisit this conservative approach as it could create more shadow slots than
8874 // required. There are two cases under which a reg arg could potentially be used from its
8876 // a) LSRA marks it as DoNotEnregister (see LinearScan::identifyCandidates())
8877 // b) LSRA spills it
8879 // Possible solution to address case (a)
8880 // - The conditions under which LSRA marks a varDsc as DoNotEnregister could be checked
8881 // in this routine. Note that live out of exception handler is something we may not be
8882 // able to do it here since GS cookie logic is invoked ahead of liveness computation.
8883 // Therefore, for methods with exception handling and need GS cookie check we might have
8884 // to take conservative approach.
8886 // Possible solution to address case (b)
8887 // - Whenver a parameter passed in an argument register needs to be spilled by LSRA, we
8888 // create a new spill temp if the method needs GS cookie check.
8889 return varDsc->lvIsParam;
8890 #else // !(defined(_TARGET_AMD64_) && defined(LEGACY_BACKEND))
8891 return varDsc->lvIsParam && !varDsc->lvIsRegArg;
8898 printf("assignGroup [%p]; shadowCopy: [%d];\n", assignGroup, shadowCopy);
8903 GSCookie* gsGlobalSecurityCookieAddr; // Address of global cookie for unsafe buffer checks
8904 GSCookie gsGlobalSecurityCookieVal; // Value of global cookie if addr is NULL
8905 ShadowParamVarInfo* gsShadowVarInfo; // Table used by shadow param analysis code
8907 void gsGSChecksInitCookie(); // Grabs cookie variable
8908 void gsCopyShadowParams(); // Identify vulnerable params and create dhadow copies
8909 bool gsFindVulnerableParams(); // Shadow param analysis code
8910 void gsParamsToShadows(); // Insert copy code and replave param uses by shadow
8912 static fgWalkPreFn gsMarkPtrsAndAssignGroups; // Shadow param analysis tree-walk
8913 static fgWalkPreFn gsReplaceShadowParams; // Shadow param replacement tree-walk
8915 #define DEFAULT_MAX_INLINE_SIZE 100 // Methods with > DEFAULT_MAX_INLINE_SIZE IL bytes will never be inlined.
8916 // This can be overwritten by setting complus_JITInlineSize env variable.
8918 #define DEFAULT_MAX_INLINE_DEPTH 20 // Methods at more than this level deep will not be inlined
8921 #ifdef FEATURE_JIT_METHOD_PERF
8922 JitTimer* pCompJitTimer; // Timer data structure (by phases) for current compilation.
8923 static CompTimeSummaryInfo s_compJitTimerSummary; // Summary of the Timer information for the whole run.
8925 static LPCWSTR JitTimeLogCsv(); // Retrieve the file name for CSV from ConfigDWORD.
8926 static LPCWSTR compJitTimeLogFilename; // If a log file for JIT time is desired, filename to write it to.
8928 inline void EndPhase(Phases phase); // Indicate the end of the given phase.
8930 #if MEASURE_CLRAPI_CALLS
8931 // Thin wrappers that call into JitTimer (if present).
8932 inline void CLRApiCallEnter(unsigned apix);
8933 inline void CLRApiCallLeave(unsigned apix);
8936 inline void CLR_API_Enter(API_ICorJitInfo_Names ename);
8937 inline void CLR_API_Leave(API_ICorJitInfo_Names ename);
8942 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8943 // These variables are associated with maintaining SQM data about compile time.
8944 unsigned __int64 m_compCyclesAtEndOfInlining; // The thread-virtualized cycle count at the end of the inlining phase
8945 // in the current compilation.
8946 unsigned __int64 m_compCycles; // Net cycle count for current compilation
8947 DWORD m_compTickCountAtEndOfInlining; // The result of GetTickCount() (# ms since some epoch marker) at the end of
8948 // the inlining phase in the current compilation.
8949 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8951 // Records the SQM-relevant (cycles and tick count). Should be called after inlining is complete.
8952 // (We do this after inlining because this marks the last point at which the JIT is likely to cause
8953 // type-loading and class initialization).
8954 void RecordStateAtEndOfInlining();
8955 // Assumes being called at the end of compilation. Update the SQM state.
8956 void RecordStateAtEndOfCompilation();
8958 #ifdef FEATURE_CLRSQM
8959 // Does anything SQM related necessary at process shutdown time.
8960 static void ProcessShutdownSQMWork(ICorStaticInfo* statInfo);
8961 #endif // FEATURE_CLRSQM
8964 #if FUNC_INFO_LOGGING
8965 static LPCWSTR compJitFuncInfoFilename; // If a log file for per-function information is required, this is the
8966 // filename to write it to.
8967 static FILE* compJitFuncInfoFile; // And this is the actual FILE* to write to.
8968 #endif // FUNC_INFO_LOGGING
8970 Compiler* prevCompiler; // Previous compiler on stack for TLS Compiler* linked list for reentrant compilers.
8972 // Is the compilation in a full trust context?
8973 bool compIsFullTrust();
8975 #ifndef FEATURE_TRACELOGGING
8976 // Should we actually fire the noway assert body and the exception handler?
8977 bool compShouldThrowOnNoway();
8978 #else // FEATURE_TRACELOGGING
8979 // Should we actually fire the noway assert body and the exception handler?
8980 bool compShouldThrowOnNoway(const char* filename, unsigned line);
8982 // Telemetry instance to use per method compilation.
8983 JitTelemetry compJitTelemetry;
8985 // Get common parameters that have to be logged with most telemetry data.
8986 void compGetTelemetryDefaults(const char** assemblyName,
8987 const char** scopeName,
8988 const char** methodName,
8989 unsigned* methodHash);
8990 #endif // !FEATURE_TRACELOGGING
8994 NodeToTestDataMap* m_nodeTestData;
8996 static const unsigned FIRST_LOOP_HOIST_CSE_CLASS = 1000;
8997 unsigned m_loopHoistCSEClass; // LoopHoist test annotations turn into CSE requirements; we
8998 // label them with CSE Class #'s starting at FIRST_LOOP_HOIST_CSE_CLASS.
8999 // Current kept in this.
9001 NodeToTestDataMap* GetNodeTestData()
9003 Compiler* compRoot = impInlineRoot();
9004 if (compRoot->m_nodeTestData == nullptr)
9006 compRoot->m_nodeTestData = new (getAllocatorDebugOnly()) NodeToTestDataMap(getAllocatorDebugOnly());
9008 return compRoot->m_nodeTestData;
9011 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, int, JitSimplerHashBehavior> NodeToIntMap;
9013 // Returns the set (i.e., the domain of the result map) of nodes that are keys in m_nodeTestData, and
9014 // currently occur in the AST graph.
9015 NodeToIntMap* FindReachableNodesInNodeTestData();
9017 // Node "from" is being eliminated, and being replaced by node "to". If "from" had any associated
9018 // test data, associate that data with "to".
9019 void TransferTestDataToNode(GenTreePtr from, GenTreePtr to);
9021 // Requires that "to" is a clone of "from". If any nodes in the "from" tree
9022 // have annotations, attach similar annotations to the corresponding nodes in "to".
9023 void CopyTestDataToCloneTree(GenTreePtr from, GenTreePtr to);
9025 // These are the methods that test that the various conditions implied by the
9026 // test attributes are satisfied.
9027 void JitTestCheckSSA(); // SSA builder tests.
9028 void JitTestCheckVN(); // Value numbering tests.
9031 // The "FieldSeqStore", for canonicalizing field sequences. See the definition of FieldSeqStore for
9033 FieldSeqStore* m_fieldSeqStore;
9035 FieldSeqStore* GetFieldSeqStore()
9037 Compiler* compRoot = impInlineRoot();
9038 if (compRoot->m_fieldSeqStore == nullptr)
9040 // Create a CompAllocator that labels sub-structure with CMK_FieldSeqStore, and use that for allocation.
9041 IAllocator* ialloc = new (this, CMK_FieldSeqStore) CompAllocator(this, CMK_FieldSeqStore);
9042 compRoot->m_fieldSeqStore = new (ialloc) FieldSeqStore(ialloc);
9044 return compRoot->m_fieldSeqStore;
9047 typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, FieldSeqNode*, JitSimplerHashBehavior> NodeToFieldSeqMap;
9049 // Some nodes of "TYP_BYREF" or "TYP_I_IMPL" actually represent the address of a field within a struct, but since
9050 // the offset of the field is zero, there's no "GT_ADD" node. We normally attach a field sequence to the constant
9051 // that is added, but what do we do when that constant is zero, and is thus not present? We use this mechanism to
9052 // attach the field sequence directly to the address node.
9053 NodeToFieldSeqMap* m_zeroOffsetFieldMap;
9055 NodeToFieldSeqMap* GetZeroOffsetFieldMap()
9057 // Don't need to worry about inlining here
9058 if (m_zeroOffsetFieldMap == nullptr)
9060 // Create a CompAllocator that labels sub-structure with CMK_ZeroOffsetFieldMap, and use that for
9062 IAllocator* ialloc = new (this, CMK_ZeroOffsetFieldMap) CompAllocator(this, CMK_ZeroOffsetFieldMap);
9063 m_zeroOffsetFieldMap = new (ialloc) NodeToFieldSeqMap(ialloc);
9065 return m_zeroOffsetFieldMap;
9068 // Requires that "op1" is a node of type "TYP_BYREF" or "TYP_I_IMPL". We are dereferencing this with the fields in
9069 // "fieldSeq", whose offsets are required all to be zero. Ensures that any field sequence annotation currently on
9070 // "op1" or its components is augmented by appending "fieldSeq". In practice, if "op1" is a GT_LCL_FLD, it has
9071 // a field sequence as a member; otherwise, it may be the addition of an a byref and a constant, where the const
9072 // has a field sequence -- in this case "fieldSeq" is appended to that of the constant; otherwise, we
9073 // record the the field sequence using the ZeroOffsetFieldMap described above.
9075 // One exception above is that "op1" is a node of type "TYP_REF" where "op1" is a GT_LCL_VAR.
9076 // This happens when System.Object vtable pointer is a regular field at offset 0 in System.Private.CoreLib in
9077 // CoreRT. Such case is handled same as the default case.
9078 void fgAddFieldSeqForZeroOffset(GenTreePtr op1, FieldSeqNode* fieldSeq);
9080 typedef SimplerHashTable<const GenTree*, PtrKeyFuncs<GenTree>, ArrayInfo, JitSimplerHashBehavior>
9082 NodeToArrayInfoMap* m_arrayInfoMap;
9084 NodeToArrayInfoMap* GetArrayInfoMap()
9086 Compiler* compRoot = impInlineRoot();
9087 if (compRoot->m_arrayInfoMap == nullptr)
9089 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9090 IAllocator* ialloc = new (this, CMK_ArrayInfoMap) CompAllocator(this, CMK_ArrayInfoMap);
9091 compRoot->m_arrayInfoMap = new (ialloc) NodeToArrayInfoMap(ialloc);
9093 return compRoot->m_arrayInfoMap;
9096 NodeToUnsignedMap* m_memorySsaMap[MemoryKindCount];
9098 // In some cases, we want to assign intermediate SSA #'s to memory states, and know what nodes create those memory
9099 // states. (We do this for try blocks, where, if the try block doesn't do a call that loses track of the memory
9100 // state, all the possible memory states are possible initial states of the corresponding catch block(s).)
9101 NodeToUnsignedMap* GetMemorySsaMap(MemoryKind memoryKind)
9103 if (memoryKind == GcHeap && byrefStatesMatchGcHeapStates)
9105 // Use the same map for GCHeap and ByrefExposed when their states match.
9106 memoryKind = ByrefExposed;
9109 assert(memoryKind < MemoryKindCount);
9110 Compiler* compRoot = impInlineRoot();
9111 if (compRoot->m_memorySsaMap[memoryKind] == nullptr)
9113 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9114 IAllocator* ialloc = new (this, CMK_ArrayInfoMap) CompAllocator(this, CMK_ArrayInfoMap);
9115 compRoot->m_memorySsaMap[memoryKind] = new (ialloc) NodeToUnsignedMap(ialloc);
9117 return compRoot->m_memorySsaMap[memoryKind];
9120 // The Refany type is the only struct type whose structure is implicitly assumed by IL. We need its fields.
9121 CORINFO_CLASS_HANDLE m_refAnyClass;
9122 CORINFO_FIELD_HANDLE GetRefanyDataField()
9124 if (m_refAnyClass == nullptr)
9126 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9128 return info.compCompHnd->getFieldInClass(m_refAnyClass, 0);
9130 CORINFO_FIELD_HANDLE GetRefanyTypeField()
9132 if (m_refAnyClass == nullptr)
9134 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9136 return info.compCompHnd->getFieldInClass(m_refAnyClass, 1);
9140 static BitSetSupport::BitSetOpCounter m_varsetOpCounter;
9142 #if ALLVARSET_COUNTOPS
9143 static BitSetSupport::BitSetOpCounter m_allvarsetOpCounter;
9146 static HelperCallProperties s_helperCallProperties;
9148 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
9149 static var_types GetTypeFromClassificationAndSizes(SystemVClassificationType classType, int size);
9150 static var_types GetEightByteType(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9152 static void GetStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9155 unsigned __int8* offset0,
9156 unsigned __int8* offset1);
9157 void fgMorphSystemVStructArgs(GenTreeCall* call, bool hasStructArgument);
9158 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
9160 void fgMorphMultiregStructArgs(GenTreeCall* call);
9161 GenTreePtr fgMorphMultiregStructArg(GenTreePtr arg, fgArgTabEntryPtr fgEntryPtr);
9163 }; // end of class Compiler
9165 // Inline methods of CompAllocator.
9166 void* CompAllocator::Alloc(size_t sz)
9168 #if MEASURE_MEM_ALLOC
9169 return m_comp->compGetMem(sz, m_cmk);
9171 return m_comp->compGetMem(sz);
9175 void* CompAllocator::ArrayAlloc(size_t elems, size_t elemSize)
9177 #if MEASURE_MEM_ALLOC
9178 return m_comp->compGetMemArray(elems, elemSize, m_cmk);
9180 return m_comp->compGetMemArray(elems, elemSize);
9184 // LclVarDsc constructor. Uses Compiler, so must come after Compiler definition.
9185 inline LclVarDsc::LclVarDsc(Compiler* comp)
9186 : // Initialize the ArgRegs to REG_STK.
9187 // The morph will do the right thing to change
9188 // to the right register if passed in register.
9191 #if FEATURE_MULTIREG_ARGS
9192 _lvOtherArgReg(REG_STK)
9194 #endif // FEATURE_MULTIREG_ARGS
9196 lvRefBlks(BlockSetOps::UninitVal())
9198 #endif // ASSERTION_PROP
9199 lvPerSsaData(comp->getAllocator())
9204 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9205 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9207 XX Miscellaneous Compiler stuff XX
9209 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9210 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9213 // Values used to mark the types a stack slot is used for
9215 const unsigned TYPE_REF_INT = 0x01; // slot used as a 32-bit int
9216 const unsigned TYPE_REF_LNG = 0x02; // slot used as a 64-bit long
9217 const unsigned TYPE_REF_FLT = 0x04; // slot used as a 32-bit float
9218 const unsigned TYPE_REF_DBL = 0x08; // slot used as a 64-bit float
9219 const unsigned TYPE_REF_PTR = 0x10; // slot used as a 32-bit pointer
9220 const unsigned TYPE_REF_BYR = 0x20; // slot used as a byref pointer
9221 const unsigned TYPE_REF_STC = 0x40; // slot used as a struct
9222 const unsigned TYPE_REF_TYPEMASK = 0x7F; // bits that represent the type
9224 // const unsigned TYPE_REF_ADDR_TAKEN = 0x80; // slots address was taken
9226 /*****************************************************************************
9228 * Variables to keep track of total code amounts.
9233 extern size_t grossVMsize;
9234 extern size_t grossNCsize;
9235 extern size_t totalNCsize;
9237 extern unsigned genMethodICnt;
9238 extern unsigned genMethodNCnt;
9239 extern size_t gcHeaderISize;
9240 extern size_t gcPtrMapISize;
9241 extern size_t gcHeaderNSize;
9242 extern size_t gcPtrMapNSize;
9244 #endif // DISPLAY_SIZES
9246 /*****************************************************************************
9248 * Variables to keep track of basic block counts (more data on 1 BB methods)
9251 #if COUNT_BASIC_BLOCKS
9252 extern Histogram bbCntTable;
9253 extern Histogram bbOneBBSizeTable;
9256 /*****************************************************************************
9258 * Used by optFindNaturalLoops to gather statistical information such as
9259 * - total number of natural loops
9260 * - number of loops with 1, 2, ... exit conditions
9261 * - number of loops that have an iterator (for like)
9262 * - number of loops that have a constant iterator
9267 extern unsigned totalLoopMethods; // counts the total number of methods that have natural loops
9268 extern unsigned maxLoopsPerMethod; // counts the maximum number of loops a method has
9269 extern unsigned totalLoopOverflows; // # of methods that identified more loops than we can represent
9270 extern unsigned totalLoopCount; // counts the total number of natural loops
9271 extern unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
9272 extern unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
9273 extern unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
9274 extern unsigned simpleTestLoopCount; // counts the # of loops with an iterator and a simple loop condition (iter <
9276 extern unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
9277 extern bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
9278 extern unsigned loopsThisMethod; // counts the number of loops in the current method
9279 extern bool loopOverflowThisMethod; // True if we exceeded the max # of loops in the method.
9280 extern Histogram loopCountTable; // Histogram of loop counts
9281 extern Histogram loopExitCountTable; // Histogram of loop exit counts
9283 #endif // COUNT_LOOPS
9285 /*****************************************************************************
9286 * variables to keep track of how many iterations we go in a dataflow pass
9291 extern unsigned CSEiterCount; // counts the # of iteration for the CSE dataflow
9292 extern unsigned CFiterCount; // counts the # of iteration for the Const Folding dataflow
9294 #endif // DATAFLOW_ITER
9296 #if MEASURE_BLOCK_SIZE
9297 extern size_t genFlowNodeSize;
9298 extern size_t genFlowNodeCnt;
9299 #endif // MEASURE_BLOCK_SIZE
9301 #if MEASURE_NODE_SIZE
9302 struct NodeSizeStats
9307 genTreeNodeSize = 0;
9308 genTreeNodeActualSize = 0;
9311 size_t genTreeNodeCnt;
9312 size_t genTreeNodeSize; // The size we allocate
9313 size_t genTreeNodeActualSize; // The actual size of the node. Note that the actual size will likely be smaller
9314 // than the allocated size, but we sometimes use SetOper()/ChangeOper() to change
9315 // a smaller node to a larger one. TODO-Cleanup: add stats on
9316 // SetOper()/ChangeOper() usage to quanitfy this.
9318 extern NodeSizeStats genNodeSizeStats; // Total node size stats
9319 extern NodeSizeStats genNodeSizeStatsPerFunc; // Per-function node size stats
9320 extern Histogram genTreeNcntHist;
9321 extern Histogram genTreeNsizHist;
9322 #endif // MEASURE_NODE_SIZE
9324 /*****************************************************************************
9325 * Count fatal errors (including noway_asserts).
9329 extern unsigned fatal_badCode;
9330 extern unsigned fatal_noWay;
9331 extern unsigned fatal_NOMEM;
9332 extern unsigned fatal_noWayAssertBody;
9334 extern unsigned fatal_noWayAssertBodyArgs;
9336 extern unsigned fatal_NYI;
9337 #endif // MEASURE_FATAL
9339 /*****************************************************************************
9343 #ifdef _TARGET_XARCH_
9345 const instruction INS_SHIFT_LEFT_LOGICAL = INS_shl;
9346 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_shr;
9347 const instruction INS_SHIFT_RIGHT_ARITHM = INS_sar;
9349 const instruction INS_AND = INS_and;
9350 const instruction INS_OR = INS_or;
9351 const instruction INS_XOR = INS_xor;
9352 const instruction INS_NEG = INS_neg;
9353 const instruction INS_TEST = INS_test;
9354 const instruction INS_MUL = INS_imul;
9355 const instruction INS_SIGNED_DIVIDE = INS_idiv;
9356 const instruction INS_UNSIGNED_DIVIDE = INS_div;
9357 const instruction INS_BREAKPOINT = INS_int3;
9358 const instruction INS_ADDC = INS_adc;
9359 const instruction INS_SUBC = INS_sbb;
9360 const instruction INS_NOT = INS_not;
9366 const instruction INS_SHIFT_LEFT_LOGICAL = INS_lsl;
9367 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_lsr;
9368 const instruction INS_SHIFT_RIGHT_ARITHM = INS_asr;
9370 const instruction INS_AND = INS_and;
9371 const instruction INS_OR = INS_orr;
9372 const instruction INS_XOR = INS_eor;
9373 const instruction INS_NEG = INS_rsb;
9374 const instruction INS_TEST = INS_tst;
9375 const instruction INS_MUL = INS_mul;
9376 const instruction INS_SIGNED_DIVIDE = INS_sdiv;
9377 const instruction INS_UNSIGNED_DIVIDE = INS_udiv;
9378 const instruction INS_BREAKPOINT = INS_bkpt;
9379 const instruction INS_ADDC = INS_adc;
9380 const instruction INS_SUBC = INS_sbc;
9381 const instruction INS_NOT = INS_mvn;
9385 #ifdef _TARGET_ARM64_
9387 const instruction INS_SHIFT_LEFT_LOGICAL = INS_lsl;
9388 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_lsr;
9389 const instruction INS_SHIFT_RIGHT_ARITHM = INS_asr;
9391 const instruction INS_AND = INS_and;
9392 const instruction INS_OR = INS_orr;
9393 const instruction INS_XOR = INS_eor;
9394 const instruction INS_NEG = INS_neg;
9395 const instruction INS_TEST = INS_tst;
9396 const instruction INS_MUL = INS_mul;
9397 const instruction INS_SIGNED_DIVIDE = INS_sdiv;
9398 const instruction INS_UNSIGNED_DIVIDE = INS_udiv;
9399 const instruction INS_BREAKPOINT = INS_bkpt;
9400 const instruction INS_ADDC = INS_adc;
9401 const instruction INS_SUBC = INS_sbc;
9402 const instruction INS_NOT = INS_mvn;
9406 /*****************************************************************************/
9408 extern const BYTE genTypeSizes[];
9409 extern const BYTE genTypeAlignments[];
9410 extern const BYTE genTypeStSzs[];
9411 extern const BYTE genActualTypes[];
9413 /*****************************************************************************/
9415 // VERY_LARGE_FRAME_SIZE_REG_MASK is the set of registers we need to use for
9416 // the probing loop generated for very large stack frames (see `getVeryLargeFrameSize`).
9419 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R4 | RBM_R5 | RBM_R6)
9420 #elif defined(_TARGET_ARM64_)
9421 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R9 | RBM_R10 | RBM_R11)
9424 /*****************************************************************************/
9426 #define REG_CORRUPT regNumber(REG_NA + 1)
9427 #define RBM_CORRUPT (RBM_ILLEGAL | regMaskTP(1))
9428 #define REG_PAIR_CORRUPT regPairNo(REG_PAIR_NONE + 1)
9430 /*****************************************************************************/
9432 extern BasicBlock dummyBB;
9434 /*****************************************************************************/
9435 /*****************************************************************************/
9437 // foreach_treenode_execution_order: An iterator that iterates through all the tree
9438 // nodes of a statement in execution order.
9439 // __stmt: a GT_STMT type GenTree*
9440 // __node: a GenTree*, already declared, that gets updated with each node in the statement, in execution order
9442 #define foreach_treenode_execution_order(__node, __stmt) \
9443 for ((__node) = (__stmt)->gtStmt.gtStmtList; (__node); (__node) = (__node)->gtNext)
9445 // foreach_block: An iterator over all blocks in the function.
9446 // __compiler: the Compiler* object
9447 // __block : a BasicBlock*, already declared, that gets updated each iteration.
9449 #define foreach_block(__compiler, __block) \
9450 for ((__block) = (__compiler)->fgFirstBB; (__block); (__block) = (__block)->bbNext)
9452 /*****************************************************************************/
9453 /*****************************************************************************/
9457 void dumpConvertedVarSet(Compiler* comp, VARSET_VALARG_TP vars);
9459 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9460 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9462 XX Debugging helpers XX
9464 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9465 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9468 /*****************************************************************************/
9469 /* The following functions are intended to be called from the debugger, to dump
9470 * various data structures. The can be used in the debugger Watch or Quick Watch
9471 * windows. They are designed to be short to type and take as few arguments as
9472 * possible. The 'c' versions take a Compiler*, whereas the 'd' versions use the TlsCompiler.
9473 * See the function definition comment for more details.
9476 void cBlock(Compiler* comp, BasicBlock* block);
9477 void cBlocks(Compiler* comp);
9478 void cBlocksV(Compiler* comp);
9479 void cTree(Compiler* comp, GenTree* tree);
9480 void cTrees(Compiler* comp);
9481 void cEH(Compiler* comp);
9482 void cVar(Compiler* comp, unsigned lclNum);
9483 void cVarDsc(Compiler* comp, LclVarDsc* varDsc);
9484 void cVars(Compiler* comp);
9485 void cVarsFinal(Compiler* comp);
9486 void cBlockPreds(Compiler* comp, BasicBlock* block);
9487 void cReach(Compiler* comp);
9488 void cDoms(Compiler* comp);
9489 void cLiveness(Compiler* comp);
9490 void cCVarSet(Compiler* comp, VARSET_VALARG_TP vars);
9492 void cFuncIR(Compiler* comp);
9493 void cBlockIR(Compiler* comp, BasicBlock* block);
9494 void cLoopIR(Compiler* comp, Compiler::LoopDsc* loop);
9495 void cTreeIR(Compiler* comp, GenTree* tree);
9496 int cTreeTypeIR(Compiler* comp, GenTree* tree);
9497 int cTreeKindsIR(Compiler* comp, GenTree* tree);
9498 int cTreeFlagsIR(Compiler* comp, GenTree* tree);
9499 int cOperandIR(Compiler* comp, GenTree* operand);
9500 int cLeafIR(Compiler* comp, GenTree* tree);
9501 int cIndirIR(Compiler* comp, GenTree* tree);
9502 int cListIR(Compiler* comp, GenTree* list);
9503 int cSsaNumIR(Compiler* comp, GenTree* tree);
9504 int cValNumIR(Compiler* comp, GenTree* tree);
9505 int cDependsIR(Compiler* comp, GenTree* comma, bool* first);
9507 void dBlock(BasicBlock* block);
9510 void dTree(GenTree* tree);
9513 void dVar(unsigned lclNum);
9514 void dVarDsc(LclVarDsc* varDsc);
9517 void dBlockPreds(BasicBlock* block);
9521 void dCVarSet(VARSET_VALARG_TP vars);
9523 void dVarSet(VARSET_VALARG_TP vars);
9524 void dRegMask(regMaskTP mask);
9527 void dBlockIR(BasicBlock* block);
9528 void dTreeIR(GenTree* tree);
9529 void dLoopIR(Compiler::LoopDsc* loop);
9530 void dLoopNumIR(unsigned loopNum);
9531 int dTabStopIR(int curr, int tabstop);
9532 int dTreeTypeIR(GenTree* tree);
9533 int dTreeKindsIR(GenTree* tree);
9534 int dTreeFlagsIR(GenTree* tree);
9535 int dOperandIR(GenTree* operand);
9536 int dLeafIR(GenTree* tree);
9537 int dIndirIR(GenTree* tree);
9538 int dListIR(GenTree* list);
9539 int dSsaNumIR(GenTree* tree);
9540 int dValNumIR(GenTree* tree);
9541 int dDependsIR(GenTree* comma);
9544 GenTree* dFindTree(GenTree* tree, unsigned id);
9545 GenTree* dFindTree(unsigned id);
9546 GenTreeStmt* dFindStmt(unsigned id);
9547 BasicBlock* dFindBlock(unsigned bbNum);
9551 #include "compiler.hpp" // All the shared inline functions
9553 /*****************************************************************************/
9554 #endif //_COMPILER_H_
9555 /*****************************************************************************/