1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XX Represents the method data we are currently JIT-compiling. XX
11 XX An instance of this class is created for every method we JIT. XX
12 XX This contains all the info needed for the method. So allocating a XX
13 XX a new instance per method makes it thread-safe. XX
14 XX It should be used to do all the memory management for the compiler run. XX
16 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
17 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
20 /*****************************************************************************/
23 /*****************************************************************************/
29 #include "jithashtable.h"
38 #include "cycletimer.h"
40 #include "arraystack.h"
42 #include "jitexpandarray.h"
43 #include "tinyarray.h"
46 #include "jittelemetry.h"
47 #include "namedintrinsiclist.h"
52 #include "codegeninterface.h"
54 #include "jitgcinfo.h"
56 #if DUMP_GC_TABLES && defined(JIT32_GCENCODER)
62 #include "hwintrinsic.h"
65 // This is only used locally in the JIT to indicate that
66 // a verification block should be inserted
67 #define SEH_VERIFICATION_EXCEPTION 0xe0564552 // VER
69 /*****************************************************************************
70 * Forward declarations
73 struct InfoHdr; // defined in GCInfo.h
74 struct escapeMapping_t; // defined in flowgraph.cpp
75 class emitter; // defined in emit.h
76 struct ShadowParamVarInfo; // defined in GSChecks.cpp
77 struct InitVarDscInfo; // defined in register_arg_convention.h
78 class FgStack; // defined in flowgraph.cpp
80 class CSE_DataFlow; // defined in OptCSE.cpp
86 class Lowering; // defined in lower.h
88 // The following are defined in this file, Compiler.h
92 /*****************************************************************************
98 /*****************************************************************************/
101 // Declare global operator new overloads that use the compiler's arena allocator
104 // I wanted to make the second argument optional, with default = CMK_Unknown, but that
105 // caused these to be ambiguous with the global placement new operators.
106 void* __cdecl operator new(size_t n, Compiler* context, CompMemKind cmk);
107 void* __cdecl operator new[](size_t n, Compiler* context, CompMemKind cmk);
108 void* __cdecl operator new(size_t n, void* p, const jitstd::placement_t& syntax_difference);
110 // Requires the definitions of "operator new" so including "LoopCloning.h" after the definitions.
111 #include "loopcloning.h"
113 /*****************************************************************************/
115 /* This is included here and not earlier as it needs the definition of "CSE"
116 * which is defined in the section above */
118 /*****************************************************************************/
120 unsigned genLog2(unsigned value);
121 unsigned genLog2(unsigned __int64 value);
123 var_types genActualType(var_types type);
124 var_types genUnsignedType(var_types type);
125 var_types genSignedType(var_types type);
127 unsigned ReinterpretHexAsDecimal(unsigned);
129 /*****************************************************************************/
131 const unsigned FLG_CCTOR = (CORINFO_FLG_CONSTRUCTOR | CORINFO_FLG_STATIC);
134 const int BAD_STK_OFFS = 0xBAADF00D; // for LclVarDsc::lvStkOffs
137 // The following holds the Local var info (scope information)
138 typedef const char* VarName; // Actual ASCII string
141 IL_OFFSET vsdLifeBeg; // instr offset of beg of life
142 IL_OFFSET vsdLifeEnd; // instr offset of end of life
143 unsigned vsdVarNum; // (remapped) LclVarDsc number
146 VarName vsdName; // name of the var
149 unsigned vsdLVnum; // 'which' in eeGetLVinfo().
150 // Also, it is the index of this entry in the info.compVarScopes array,
151 // which is useful since the array is also accessed via the
152 // compEnterScopeList and compExitScopeList sorted arrays.
155 // This is the location of a SSA definition.
161 DefLoc() : m_blk(nullptr), m_tree(nullptr)
165 DefLoc(BasicBlock* block, GenTree* tree) : m_blk(block), m_tree(tree)
170 // This class stores information associated with a LclVar SSA definition.
178 LclSsaVarDsc(BasicBlock* block, GenTree* tree) : m_defLoc(block, tree)
182 ValueNumPair m_vnPair;
186 // This class stores information associated with a memory SSA definition.
190 ValueNumPair m_vnPair;
193 //------------------------------------------------------------------------
194 // SsaDefArray: A resizable array of SSA definitions.
196 // Unlike an ordinary resizable array implementation, this allows only element
197 // addition (by calling AllocSsaNum) and has special handling for RESERVED_SSA_NUM
198 // (basically it's a 1-based array). The array doesn't impose any particular
199 // requirements on the elements it stores and AllocSsaNum forwards its arguments
200 // to the array element constructor, this way the array supports both LclSsaVarDsc
201 // and SsaMemDef elements.
203 template <typename T>
207 unsigned m_arraySize;
210 static_assert_no_msg(SsaConfig::RESERVED_SSA_NUM == 0);
211 static_assert_no_msg(SsaConfig::FIRST_SSA_NUM == 1);
213 // Get the minimum valid SSA number.
214 unsigned GetMinSsaNum() const
216 return SsaConfig::FIRST_SSA_NUM;
219 // Increase (double) the size of the array.
220 void GrowArray(CompAllocator alloc)
222 unsigned oldSize = m_arraySize;
223 unsigned newSize = max(2, oldSize * 2);
225 T* newArray = alloc.allocate<T>(newSize);
227 for (unsigned i = 0; i < oldSize; i++)
229 newArray[i] = m_array[i];
233 m_arraySize = newSize;
237 // Construct an empty SsaDefArray.
238 SsaDefArray() : m_array(nullptr), m_arraySize(0), m_count(0)
242 // Reset the array (used only if the SSA form is reconstructed).
248 // Allocate a new SSA number (starting with SsaConfig::FIRST_SSA_NUM).
249 template <class... Args>
250 unsigned AllocSsaNum(CompAllocator alloc, Args&&... args)
252 if (m_count == m_arraySize)
257 unsigned ssaNum = GetMinSsaNum() + m_count;
258 m_array[m_count++] = T(jitstd::forward<Args>(args)...);
260 // Ensure that the first SSA number we allocate is SsaConfig::FIRST_SSA_NUM
261 assert((ssaNum == SsaConfig::FIRST_SSA_NUM) || (m_count > 1));
266 // Get the number of SSA definitions in the array.
267 unsigned GetCount() const
272 // Get a pointer to the SSA definition at the specified index.
273 T* GetSsaDefByIndex(unsigned index)
275 assert(index < m_count);
276 return &m_array[index];
279 // Check if the specified SSA number is valid.
280 bool IsValidSsaNum(unsigned ssaNum) const
282 return (GetMinSsaNum() <= ssaNum) && (ssaNum < (GetMinSsaNum() + m_count));
285 // Get a pointer to the SSA definition associated with the specified SSA number.
286 T* GetSsaDef(unsigned ssaNum)
288 assert(ssaNum != SsaConfig::RESERVED_SSA_NUM);
289 return GetSsaDefByIndex(ssaNum - GetMinSsaNum());
295 RCS_INVALID, // not valid to get/set ref counts
296 RCS_EARLY, // early counts for struct promotion and struct passing
297 RCS_NORMAL, // normal ref counts (from lvaMarkRefs onward)
303 // The constructor. Most things can just be zero'ed.
305 // Initialize the ArgRegs to REG_STK.
306 // Morph will update if this local is passed in a register.
310 #if FEATURE_MULTIREG_ARGS
311 _lvOtherArgReg(REG_STK)
313 #endif // FEATURE_MULTIREG_ARGS
315 lvRefBlks(BlockSetOps::UninitVal())
317 #endif // ASSERTION_PROP
322 // note this only packs because var_types is a typedef of unsigned char
323 var_types lvType : 5; // TYP_INT/LONG/FLOAT/DOUBLE/REF
325 unsigned char lvIsParam : 1; // is this a parameter?
326 unsigned char lvIsRegArg : 1; // is this a register argument?
327 unsigned char lvFramePointerBased : 1; // 0 = off of REG_SPBASE (e.g., ESP), 1 = off of REG_FPBASE (e.g., EBP)
329 unsigned char lvStructGcCount : 3; // if struct, how many GC pointer (stop counting at 7). The only use of values >1
330 // is to help determine whether to use block init in the prolog.
331 unsigned char lvOnFrame : 1; // (part of) the variable lives on the frame
332 unsigned char lvRegister : 1; // assigned to live in a register? For RyuJIT backend, this is only set if the
333 // variable is in the same register for the entire function.
334 unsigned char lvTracked : 1; // is this a tracked variable?
335 bool lvTrackedNonStruct()
337 return lvTracked && lvType != TYP_STRUCT;
339 unsigned char lvPinned : 1; // is this a pinned variable?
341 unsigned char lvMustInit : 1; // must be initialized
342 unsigned char lvAddrExposed : 1; // The address of this variable is "exposed" -- passed as an argument, stored in a
343 // global location, etc.
344 // We cannot reason reliably about the value of the variable.
345 unsigned char lvDoNotEnregister : 1; // Do not enregister this variable.
346 unsigned char lvFieldAccessed : 1; // The var is a struct local, and a field of the variable is accessed. Affects
349 unsigned char lvInSsa : 1; // The variable is in SSA form (set by SsaBuilder)
352 // These further document the reasons for setting "lvDoNotEnregister". (Note that "lvAddrExposed" is one of the
354 // also, lvType == TYP_STRUCT prevents enregistration. At least one of the reasons should be true.
355 unsigned char lvVMNeedsStackAddr : 1; // The VM may have access to a stack-relative address of the variable, and
356 // read/write its value.
357 unsigned char lvLiveInOutOfHndlr : 1; // The variable was live in or out of an exception handler, and this required
358 // the variable to be
359 // in the stack (at least at those boundaries.)
360 unsigned char lvLclFieldExpr : 1; // The variable is not a struct, but was accessed like one (e.g., reading a
361 // particular byte from an int).
362 unsigned char lvLclBlockOpAddr : 1; // The variable was written to via a block operation that took its address.
363 unsigned char lvLiveAcrossUCall : 1; // The variable is live across an unmanaged call.
365 unsigned char lvIsCSE : 1; // Indicates if this LclVar is a CSE variable.
366 unsigned char lvHasLdAddrOp : 1; // has ldloca or ldarga opcode on this local.
367 unsigned char lvStackByref : 1; // This is a compiler temporary of TYP_BYREF that is known to point into our local
370 unsigned char lvHasILStoreOp : 1; // there is at least one STLOC or STARG on this local
371 unsigned char lvHasMultipleILStoreOp : 1; // there is more than one STLOC on this local
373 unsigned char lvIsTemp : 1; // Short-lifetime compiler temp (if lvIsParam is false), or implicit byref parameter
374 // (if lvIsParam is true)
376 unsigned char lvIsBoolean : 1; // set if variable is boolean
378 unsigned char lvSingleDef : 1; // variable has a single def
379 // before lvaMarkLocalVars: identifies ref type locals that can get type updates
380 // after lvaMarkLocalVars: identifies locals that are suitable for optAddCopies
383 unsigned char lvDisqualify : 1; // variable is no longer OK for add copy optimization
384 unsigned char lvVolatileHint : 1; // hint for AssertionProp
387 #ifndef _TARGET_64BIT_
388 unsigned char lvStructDoubleAlign : 1; // Must we double align this struct?
389 #endif // !_TARGET_64BIT_
390 #ifdef _TARGET_64BIT_
391 unsigned char lvQuirkToLong : 1; // Quirk to allocate this LclVar as a 64-bit long
394 unsigned char lvKeepType : 1; // Don't change the type of this variable
395 unsigned char lvNoLclFldStress : 1; // Can't apply local field stress on this one
397 unsigned char lvIsPtr : 1; // Might this be used in an address computation? (used by buffer overflow security
399 unsigned char lvIsUnsafeBuffer : 1; // Does this contain an unsafe buffer requiring buffer overflow security checks?
400 unsigned char lvPromoted : 1; // True when this local is a promoted struct, a normed struct, or a "split" long on a
401 // 32-bit target. For implicit byref parameters, this gets hijacked between
402 // fgRetypeImplicitByRefArgs and fgMarkDemotedImplicitByRefArgs to indicate whether
403 // references to the arg are being rewritten as references to a promoted shadow local.
404 unsigned char lvIsStructField : 1; // Is this local var a field of a promoted struct local?
405 unsigned char lvOverlappingFields : 1; // True when we have a struct with possibly overlapping fields
406 unsigned char lvContainsHoles : 1; // True when we have a promoted struct that contains holes
407 unsigned char lvCustomLayout : 1; // True when this struct has "CustomLayout"
409 unsigned char lvIsMultiRegArg : 1; // true if this is a multireg LclVar struct used in an argument context
410 unsigned char lvIsMultiRegRet : 1; // true if this is a multireg LclVar struct assigned from a multireg call
413 unsigned char _lvIsHfa : 1; // Is this a struct variable who's class handle is an HFA type
414 unsigned char _lvIsHfaRegArg : 1; // Is this a HFA argument variable? // TODO-CLEANUP: Remove this and replace
415 // with (lvIsRegArg && lvIsHfa())
416 unsigned char _lvHfaTypeIsFloat : 1; // Is the HFA type float or double?
417 #endif // FEATURE_HFA
420 // TODO-Cleanup: See the note on lvSize() - this flag is only in use by asserts that are checking for struct
421 // types, and is needed because of cases where TYP_STRUCT is bashed to an integral type.
422 // Consider cleaning this up so this workaround is not required.
423 unsigned char lvUnusedStruct : 1; // All references to this promoted struct are through its field locals.
424 // I.e. there is no longer any reference to the struct directly.
425 // In this case we can simply remove this struct local.
428 unsigned char lvLRACandidate : 1; // Tracked for linear scan register allocation purposes
431 // Note that both SIMD vector args and locals are marked as lvSIMDType = true, but the
432 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD*.
433 unsigned char lvSIMDType : 1; // This is a SIMD struct
434 unsigned char lvUsedInSIMDIntrinsic : 1; // This tells lclvar is used for simd intrinsic
435 var_types lvBaseType : 5; // Note: this only packs because var_types is a typedef of unsigned char
436 #endif // FEATURE_SIMD
437 unsigned char lvRegStruct : 1; // This is a reg-sized non-field-addressed struct.
439 unsigned char lvClassIsExact : 1; // lvClassHandle is the exact type
442 unsigned char lvClassInfoUpdated : 1; // true if this var has updated class handle or exactness
445 unsigned char lvImplicitlyReferenced : 1; // true if there are non-IR references to this local (prolog, epilog, gc,
449 unsigned lvFieldLclStart; // The index of the local var representing the first field in the promoted struct
450 // local. For implicit byref parameters, this gets hijacked between
451 // fgRetypeImplicitByRefArgs and fgMarkDemotedImplicitByRefArgs to point to the
452 // struct local created to model the parameter's struct promotion, if any.
453 unsigned lvParentLcl; // The index of the local var representing the parent (i.e. the promoted struct local).
454 // Valid on promoted struct local fields.
457 unsigned char lvFieldCnt; // Number of fields in the promoted VarDsc.
458 unsigned char lvFldOffset;
459 unsigned char lvFldOrdinal;
461 #if FEATURE_MULTIREG_ARGS
462 regNumber lvRegNumForSlot(unsigned slotNum)
468 else if (slotNum == 1)
470 return lvOtherArgReg;
474 assert(false && "Invalid slotNum!");
479 #endif // FEATURE_MULTIREG_ARGS
497 bool lvIsHfaRegArg() const
500 return _lvIsHfaRegArg;
506 void lvSetIsHfaRegArg(bool value = true)
509 _lvIsHfaRegArg = value;
513 bool lvHfaTypeIsFloat() const
516 return _lvHfaTypeIsFloat;
522 void lvSetHfaTypeIsFloat(bool value)
525 _lvHfaTypeIsFloat = value;
529 // on Arm64 - Returns 1-4 indicating the number of register slots used by the HFA
530 // on Arm32 - Returns the total number of single FP register slots used by the HFA, max is 8
532 unsigned lvHfaSlots() const
535 assert(varTypeIsStruct(lvType));
537 return lvExactSize / sizeof(float);
538 #else // _TARGET_ARM64_
539 if (lvHfaTypeIsFloat())
541 return lvExactSize / sizeof(float);
545 return lvExactSize / sizeof(double);
547 #endif // _TARGET_ARM64_
550 // lvIsMultiRegArgOrRet()
551 // returns true if this is a multireg LclVar struct used in an argument context
552 // or if this is a multireg LclVar struct assigned from a multireg call
553 bool lvIsMultiRegArgOrRet()
555 return lvIsMultiRegArg || lvIsMultiRegRet;
559 regNumberSmall _lvRegNum; // Used to store the register this variable is in (or, the low register of a
560 // register pair). It is set during codegen any time the
561 // variable is enregistered (lvRegister is only set
562 // to non-zero if the variable gets the same register assignment for its entire
564 #if !defined(_TARGET_64BIT_)
565 regNumberSmall _lvOtherReg; // Used for "upper half" of long var.
566 #endif // !defined(_TARGET_64BIT_)
568 regNumberSmall _lvArgReg; // The register in which this argument is passed.
570 #if FEATURE_MULTIREG_ARGS
571 regNumberSmall _lvOtherArgReg; // Used for the second part of the struct passed in a register.
572 // Note this is defined but not used by ARM32
573 #endif // FEATURE_MULTIREG_ARGS
575 regNumberSmall _lvArgInitReg; // the register into which the argument is moved at entry
578 // The register number is stored in a small format (8 bits), but the getters return and the setters take
579 // a full-size (unsigned) format, to localize the casts here.
581 /////////////////////
583 __declspec(property(get = GetRegNum, put = SetRegNum)) regNumber lvRegNum;
585 regNumber GetRegNum() const
587 return (regNumber)_lvRegNum;
590 void SetRegNum(regNumber reg)
592 _lvRegNum = (regNumberSmall)reg;
593 assert(_lvRegNum == reg);
596 /////////////////////
598 #if defined(_TARGET_64BIT_)
599 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
601 regNumber GetOtherReg() const
603 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
604 // "unreachable code" warnings
608 void SetOtherReg(regNumber reg)
610 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
611 // "unreachable code" warnings
613 #else // !_TARGET_64BIT_
614 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
616 regNumber GetOtherReg() const
618 return (regNumber)_lvOtherReg;
621 void SetOtherReg(regNumber reg)
623 _lvOtherReg = (regNumberSmall)reg;
624 assert(_lvOtherReg == reg);
626 #endif // !_TARGET_64BIT_
628 /////////////////////
630 __declspec(property(get = GetArgReg, put = SetArgReg)) regNumber lvArgReg;
632 regNumber GetArgReg() const
634 return (regNumber)_lvArgReg;
637 void SetArgReg(regNumber reg)
639 _lvArgReg = (regNumberSmall)reg;
640 assert(_lvArgReg == reg);
643 #if FEATURE_MULTIREG_ARGS
644 __declspec(property(get = GetOtherArgReg, put = SetOtherArgReg)) regNumber lvOtherArgReg;
646 regNumber GetOtherArgReg() const
648 return (regNumber)_lvOtherArgReg;
651 void SetOtherArgReg(regNumber reg)
653 _lvOtherArgReg = (regNumberSmall)reg;
654 assert(_lvOtherArgReg == reg);
656 #endif // FEATURE_MULTIREG_ARGS
659 // Is this is a SIMD struct?
660 bool lvIsSIMDType() const
665 // Is this is a SIMD struct which is used for SIMD intrinsic?
666 bool lvIsUsedInSIMDIntrinsic() const
668 return lvUsedInSIMDIntrinsic;
671 // If feature_simd not enabled, return false
672 bool lvIsSIMDType() const
676 bool lvIsUsedInSIMDIntrinsic() const
682 /////////////////////
684 __declspec(property(get = GetArgInitReg, put = SetArgInitReg)) regNumber lvArgInitReg;
686 regNumber GetArgInitReg() const
688 return (regNumber)_lvArgInitReg;
691 void SetArgInitReg(regNumber reg)
693 _lvArgInitReg = (regNumberSmall)reg;
694 assert(_lvArgInitReg == reg);
697 /////////////////////
699 bool lvIsRegCandidate() const
701 return lvLRACandidate != 0;
704 bool lvIsInReg() const
706 return lvIsRegCandidate() && (lvRegNum != REG_STK);
709 regMaskTP lvRegMask() const
711 regMaskTP regMask = RBM_NONE;
712 if (varTypeIsFloating(TypeGet()))
714 if (lvRegNum != REG_STK)
716 regMask = genRegMaskFloat(lvRegNum, TypeGet());
721 if (lvRegNum != REG_STK)
723 regMask = genRegMask(lvRegNum);
729 unsigned short lvVarIndex; // variable tracking index
732 unsigned short m_lvRefCnt; // unweighted (real) reference count. For implicit by reference
733 // parameters, this gets hijacked from fgMarkImplicitByRefArgs
734 // through fgMarkDemotedImplicitByRefArgs, to provide a static
735 // appearance count (computed during address-exposed analysis)
736 // that fgMakeOutgoingStructArgCopy consults during global morph
737 // to determine if eliding its copy is legal.
739 BasicBlock::weight_t m_lvRefCntWtd; // weighted reference count
742 unsigned short lvRefCnt(RefCountState state = RCS_NORMAL) const;
743 void incLvRefCnt(unsigned short delta, RefCountState state = RCS_NORMAL);
744 void setLvRefCnt(unsigned short newValue, RefCountState state = RCS_NORMAL);
746 BasicBlock::weight_t lvRefCntWtd(RefCountState state = RCS_NORMAL) const;
747 void incLvRefCntWtd(BasicBlock::weight_t delta, RefCountState state = RCS_NORMAL);
748 void setLvRefCntWtd(BasicBlock::weight_t newValue, RefCountState state = RCS_NORMAL);
750 int lvStkOffs; // stack offset of home
751 unsigned lvExactSize; // (exact) size of the type in bytes
753 // Is this a promoted struct?
754 // This method returns true only for structs (including SIMD structs), not for
755 // locals that are split on a 32-bit target.
756 // It is only necessary to use this:
757 // 1) if only structs are wanted, and
758 // 2) if Lowering has already been done.
759 // Otherwise lvPromoted is valid.
760 bool lvPromotedStruct()
762 #if !defined(_TARGET_64BIT_)
763 return (lvPromoted && !varTypeIsLong(lvType));
764 #else // defined(_TARGET_64BIT_)
766 #endif // defined(_TARGET_64BIT_)
769 unsigned lvSize() const // Size needed for storage representation. Only used for structs or TYP_BLK.
771 // TODO-Review: Sometimes we get called on ARM with HFA struct variables that have been promoted,
772 // where the struct itself is no longer used because all access is via its member fields.
773 // When that happens, the struct is marked as unused and its type has been changed to
774 // TYP_INT (to keep the GC tracking code from looking at it).
775 // See Compiler::raAssignVars() for details. For example:
776 // N002 ( 4, 3) [00EA067C] ------------- return struct $346
777 // N001 ( 3, 2) [00EA0628] ------------- lclVar struct(U) V03 loc2
778 // float V03.f1 (offs=0x00) -> V12 tmp7
779 // f8 (last use) (last use) $345
780 // Here, the "struct(U)" shows that the "V03 loc2" variable is unused. Not shown is that V03
781 // is now TYP_INT in the local variable table. It's not really unused, because it's in the tree.
783 assert(varTypeIsStruct(lvType) || (lvType == TYP_BLK) || (lvPromoted && lvUnusedStruct));
785 #if defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
786 // For 32-bit architectures, we make local variable SIMD12 types 16 bytes instead of just 12. We can't do
787 // this for arguments, which must be passed according the defined ABI. We don't want to do this for
788 // dependently promoted struct fields, but we don't know that here. See lvaMapSimd12ToSimd16().
789 // (Note that for 64-bits, we are already rounding up to 16.)
790 if ((lvType == TYP_SIMD12) && !lvIsParam)
792 assert(lvExactSize == 12);
795 #endif // defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
797 return roundUp(lvExactSize, TARGET_POINTER_SIZE);
800 size_t lvArgStackSize() const;
802 unsigned lvSlotNum; // original slot # (if remapped)
804 typeInfo lvVerTypeInfo; // type info needed for verification
806 CORINFO_CLASS_HANDLE lvClassHnd; // class handle for the local, or null if not known
808 CORINFO_FIELD_HANDLE lvFieldHnd; // field handle for promoted struct fields
810 BYTE* lvGcLayout; // GC layout info for structs
813 BlockSet lvRefBlks; // Set of blocks that contain refs
814 GenTree* lvDefStmt; // Pointer to the statement with the single definition
815 void lvaDisqualifyVar(); // Call to disqualify a local variable from use in optAddCopies
817 var_types TypeGet() const
819 return (var_types)lvType;
821 bool lvStackAligned() const
823 assert(lvIsStructField);
824 return ((lvFldOffset % TARGET_POINTER_SIZE) == 0);
826 bool lvNormalizeOnLoad() const
828 return varTypeIsSmall(TypeGet()) &&
829 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
830 (lvIsParam || lvAddrExposed || lvIsStructField);
833 bool lvNormalizeOnStore()
835 return varTypeIsSmall(TypeGet()) &&
836 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
837 !(lvIsParam || lvAddrExposed || lvIsStructField);
840 void incRefCnts(BasicBlock::weight_t weight,
842 RefCountState state = RCS_NORMAL,
843 bool propagate = true);
844 bool IsFloatRegType() const
846 return isFloatRegType(lvType) || lvIsHfaRegArg();
848 var_types GetHfaType() const
850 return lvIsHfa() ? (lvHfaTypeIsFloat() ? TYP_FLOAT : TYP_DOUBLE) : TYP_UNDEF;
852 void SetHfaType(var_types type)
854 assert(varTypeIsFloating(type));
855 lvSetHfaTypeIsFloat(type == TYP_FLOAT);
858 var_types lvaArgType();
860 SsaDefArray<LclSsaVarDsc> lvPerSsaData;
862 // Returns the address of the per-Ssa data for the given ssaNum (which is required
863 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
864 // not an SSA variable).
865 LclSsaVarDsc* GetPerSsaData(unsigned ssaNum)
867 return lvPerSsaData.GetSsaDef(ssaNum);
872 const char* lvReason;
874 void PrintVarReg() const
876 printf("%s", getRegName(lvRegNum));
880 }; // class LclVarDsc
883 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
884 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
888 XX The temporary lclVars allocated by the compiler for code generation XX
890 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
891 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
894 /*****************************************************************************
896 * The following keeps track of temporaries allocated in the stack frame
897 * during code-generation (after register allocation). These spill-temps are
898 * only used if we run out of registers while evaluating a tree.
900 * These are different from the more common temps allocated by lvaGrabTemp().
911 static const int BAD_TEMP_OFFSET = 0xDDDDDDDD; // used as a sentinel "bad value" for tdOffs in DEBUG
919 TempDsc(int _tdNum, unsigned _tdSize, var_types _tdType) : tdNum(_tdNum), tdSize((BYTE)_tdSize), tdType(_tdType)
923 0); // temps must have a negative number (so they have a different number from all local variables)
924 tdOffs = BAD_TEMP_OFFSET;
928 IMPL_LIMITATION("too many spill temps");
933 bool tdLegalOffset() const
935 return tdOffs != BAD_TEMP_OFFSET;
939 int tdTempOffs() const
941 assert(tdLegalOffset());
944 void tdSetTempOffs(int offs)
947 assert(tdLegalOffset());
949 void tdAdjustTempOffs(int offs)
952 assert(tdLegalOffset());
955 int tdTempNum() const
960 unsigned tdTempSize() const
964 var_types tdTempType() const
970 // interface to hide linearscan implementation from rest of compiler
971 class LinearScanInterface
974 virtual void doLinearScan() = 0;
975 virtual void recordVarLocationsAtStartOfBB(BasicBlock* bb) = 0;
976 virtual bool willEnregisterLocalVars() const = 0;
979 LinearScanInterface* getLinearScanAllocator(Compiler* comp);
981 // Information about arrays: their element type and size, and the offset of the first element.
982 // We label GT_IND's that are array indices with GTF_IND_ARR_INDEX, and, for such nodes,
983 // associate an array info via the map retrieved by GetArrayInfoMap(). This information is used,
984 // for example, in value numbering of array index expressions.
987 var_types m_elemType;
988 CORINFO_CLASS_HANDLE m_elemStructType;
990 unsigned m_elemOffset;
992 ArrayInfo() : m_elemType(TYP_UNDEF), m_elemStructType(nullptr), m_elemSize(0), m_elemOffset(0)
996 ArrayInfo(var_types elemType, unsigned elemSize, unsigned elemOffset, CORINFO_CLASS_HANDLE elemStructType)
997 : m_elemType(elemType), m_elemStructType(elemStructType), m_elemSize(elemSize), m_elemOffset(elemOffset)
1002 // This enumeration names the phases into which we divide compilation. The phases should completely
1003 // partition a compilation.
1006 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) enum_nm,
1007 #include "compphases.h"
1011 extern const char* PhaseNames[];
1012 extern const char* PhaseEnums[];
1013 extern const LPCWSTR PhaseShortNames[];
1015 // The following enum provides a simple 1:1 mapping to CLR API's
1016 enum API_ICorJitInfo_Names
1018 #define DEF_CLR_API(name) API_##name,
1019 #include "ICorJitInfo_API_names.h"
1023 //---------------------------------------------------------------
1024 // Compilation time.
1027 // A "CompTimeInfo" is a structure for tracking the compilation time of one or more methods.
1028 // We divide a compilation into a sequence of contiguous phases, and track the total (per-thread) cycles
1029 // of the compilation, as well as the cycles for each phase. We also track the number of bytecodes.
1030 // If there is a failure in reading a timer at any point, the "CompTimeInfo" becomes invalid, as indicated
1031 // by "m_timerFailure" being true.
1032 // If FEATURE_JIT_METHOD_PERF is not set, we define a minimal form of this, enough to let other code compile.
1035 #ifdef FEATURE_JIT_METHOD_PERF
1036 // The string names of the phases.
1037 static const char* PhaseNames[];
1039 static bool PhaseHasChildren[];
1040 static int PhaseParent[];
1041 static bool PhaseReportsIRSize[];
1043 unsigned m_byteCodeBytes;
1044 unsigned __int64 m_totalCycles;
1045 unsigned __int64 m_invokesByPhase[PHASE_NUMBER_OF];
1046 unsigned __int64 m_cyclesByPhase[PHASE_NUMBER_OF];
1047 #if MEASURE_CLRAPI_CALLS
1048 unsigned __int64 m_CLRinvokesByPhase[PHASE_NUMBER_OF];
1049 unsigned __int64 m_CLRcyclesByPhase[PHASE_NUMBER_OF];
1052 unsigned m_nodeCountAfterPhase[PHASE_NUMBER_OF];
1054 // For better documentation, we call EndPhase on
1055 // non-leaf phases. We should also call EndPhase on the
1056 // last leaf subphase; obviously, the elapsed cycles between the EndPhase
1057 // for the last leaf subphase and the EndPhase for an ancestor should be very small.
1058 // We add all such "redundant end phase" intervals to this variable below; we print
1059 // it out in a report, so we can verify that it is, indeed, very small. If it ever
1060 // isn't, this means that we're doing something significant between the end of the last
1061 // declared subphase and the end of its parent.
1062 unsigned __int64 m_parentPhaseEndSlop;
1063 bool m_timerFailure;
1065 #if MEASURE_CLRAPI_CALLS
1066 // The following measures the time spent inside each individual CLR API call.
1067 unsigned m_allClrAPIcalls;
1068 unsigned m_perClrAPIcalls[API_ICorJitInfo_Names::API_COUNT];
1069 unsigned __int64 m_allClrAPIcycles;
1070 unsigned __int64 m_perClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
1071 unsigned __int32 m_maxClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
1072 #endif // MEASURE_CLRAPI_CALLS
1074 CompTimeInfo(unsigned byteCodeBytes);
1078 #ifdef FEATURE_JIT_METHOD_PERF
1080 #if MEASURE_CLRAPI_CALLS
1081 struct WrapICorJitInfo;
1084 // This class summarizes the JIT time information over the course of a run: the number of methods compiled,
1085 // and the total and maximum timings. (These are instances of the "CompTimeInfo" type described above).
1086 // The operation of adding a single method's timing to the summary may be performed concurrently by several
1087 // threads, so it is protected by a lock.
1088 // This class is intended to be used as a singleton type, with only a single instance.
1089 class CompTimeSummaryInfo
1091 // This lock protects the fields of all CompTimeSummaryInfo(s) (of which we expect there to be one).
1092 static CritSecObject s_compTimeSummaryLock;
1096 CompTimeInfo m_total;
1097 CompTimeInfo m_maximum;
1099 int m_numFilteredMethods;
1100 CompTimeInfo m_filtered;
1102 // This can use what ever data you want to determine if the value to be added
1103 // belongs in the filtered section (it's always included in the unfiltered section)
1104 bool IncludedInFilteredData(CompTimeInfo& info);
1107 // This is the unique CompTimeSummaryInfo object for this instance of the runtime.
1108 static CompTimeSummaryInfo s_compTimeSummary;
1110 CompTimeSummaryInfo()
1111 : m_numMethods(0), m_totMethods(0), m_total(0), m_maximum(0), m_numFilteredMethods(0), m_filtered(0)
1115 // Assumes that "info" is a completed CompTimeInfo for a compilation; adds it to the summary.
1116 // This is thread safe.
1117 void AddInfo(CompTimeInfo& info, bool includePhases);
1119 // Print the summary information to "f".
1120 // This is not thread-safe; assumed to be called by only one thread.
1121 void Print(FILE* f);
1124 // A JitTimer encapsulates a CompTimeInfo for a single compilation. It also tracks the start of compilation,
1125 // and when the current phase started. This is intended to be part of a Compilation object. This is
1126 // disabled (FEATURE_JIT_METHOD_PERF not defined) when FEATURE_CORECLR is set, or on non-windows platforms.
1130 unsigned __int64 m_start; // Start of the compilation.
1131 unsigned __int64 m_curPhaseStart; // Start of the current phase.
1132 #if MEASURE_CLRAPI_CALLS
1133 unsigned __int64 m_CLRcallStart; // Start of the current CLR API call (if any).
1134 unsigned __int64 m_CLRcallInvokes; // CLR API invokes under current outer so far
1135 unsigned __int64 m_CLRcallCycles; // CLR API cycles under current outer so far.
1136 int m_CLRcallAPInum; // The enum/index of the current CLR API call (or -1).
1137 static double s_cyclesPerSec; // Cached for speedier measurements
1140 Phases m_lastPhase; // The last phase that was completed (or (Phases)-1 to start).
1142 CompTimeInfo m_info; // The CompTimeInfo for this compilation.
1144 static CritSecObject s_csvLock; // Lock to protect the time log file.
1145 void PrintCsvMethodStats(Compiler* comp);
1148 void* operator new(size_t);
1149 void* operator new[](size_t);
1150 void operator delete(void*);
1151 void operator delete[](void*);
1154 // Initialized the timer instance
1155 JitTimer(unsigned byteCodeSize);
1157 static JitTimer* Create(Compiler* comp, unsigned byteCodeSize)
1159 return ::new (comp, CMK_Unknown) JitTimer(byteCodeSize);
1162 static void PrintCsvHeader();
1164 // Ends the current phase (argument is for a redundant check).
1165 void EndPhase(Compiler* compiler, Phases phase);
1167 #if MEASURE_CLRAPI_CALLS
1168 // Start and end a timed CLR API call.
1169 void CLRApiCallEnter(unsigned apix);
1170 void CLRApiCallLeave(unsigned apix);
1171 #endif // MEASURE_CLRAPI_CALLS
1173 // Completes the timing of the current method, which is assumed to have "byteCodeBytes" bytes of bytecode,
1174 // and adds it to "sum".
1175 void Terminate(Compiler* comp, CompTimeSummaryInfo& sum, bool includePhases);
1177 // Attempts to query the cycle counter of the current thread. If successful, returns "true" and sets
1178 // *cycles to the cycle counter value. Otherwise, returns false and sets the "m_timerFailure" flag of
1179 // "m_info" to true.
1180 bool GetThreadCycles(unsigned __int64* cycles)
1182 bool res = CycleTimer::GetThreadCyclesS(cycles);
1185 m_info.m_timerFailure = true;
1190 #endif // FEATURE_JIT_METHOD_PERF
1192 //------------------- Function/Funclet info -------------------------------
1193 enum FuncKind : BYTE
1195 FUNC_ROOT, // The main/root function (always id==0)
1196 FUNC_HANDLER, // a funclet associated with an EH handler (finally, fault, catch, filter handler)
1197 FUNC_FILTER, // a funclet associated with an EH filter
1206 BYTE funFlags; // Currently unused, just here for padding
1207 unsigned short funEHIndex; // index, into the ebd table, of innermost EH clause corresponding to this
1208 // funclet. It is only valid if funKind field indicates this is a
1209 // EH-related funclet: FUNC_HANDLER or FUNC_FILTER
1211 #if defined(_TARGET_AMD64_)
1213 // TODO-AMD64-Throughput: make the AMD64 info more like the ARM info to avoid having this large static array.
1214 emitLocation* startLoc;
1215 emitLocation* endLoc;
1216 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1217 emitLocation* coldEndLoc;
1218 UNWIND_INFO unwindHeader;
1219 // Maximum of 255 UNWIND_CODE 'nodes' and then the unwind header. If there are an odd
1220 // number of codes, the VM or Zapper will 4-byte align the whole thing.
1221 BYTE unwindCodes[offsetof(UNWIND_INFO, UnwindCode) + (0xFF * sizeof(UNWIND_CODE))];
1222 unsigned unwindCodeSlot;
1224 #elif defined(_TARGET_X86_)
1226 #if defined(_TARGET_UNIX_)
1227 emitLocation* startLoc;
1228 emitLocation* endLoc;
1229 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1230 emitLocation* coldEndLoc;
1231 #endif // _TARGET_UNIX_
1233 #elif defined(_TARGET_ARMARCH_)
1235 UnwindInfo uwi; // Unwind information for this function/funclet's hot section
1236 UnwindInfo* uwiCold; // Unwind information for this function/funclet's cold section
1237 // Note: we only have a pointer here instead of the actual object,
1238 // to save memory in the JIT case (compared to the NGEN case),
1239 // where we don't have any cold section.
1240 // Note 2: we currently don't support hot/cold splitting in functions
1241 // with EH, so uwiCold will be NULL for all funclets.
1243 #if defined(_TARGET_UNIX_)
1244 emitLocation* startLoc;
1245 emitLocation* endLoc;
1246 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1247 emitLocation* coldEndLoc;
1248 #endif // _TARGET_UNIX_
1250 #endif // _TARGET_ARMARCH_
1252 #if defined(_TARGET_UNIX_)
1253 jitstd::vector<CFI_CODE>* cfiCodes;
1254 #endif // _TARGET_UNIX_
1256 // Eventually we may want to move rsModifiedRegsMask, lvaOutgoingArgSize, and anything else
1257 // that isn't shared between the main function body and funclets.
1260 struct fgArgTabEntry
1262 GenTree* node; // Initially points at the Op1 field of 'parent', but if the argument is replaced with an GT_ASG or
1263 // placeholder it will point at the actual argument in the gtCallLateArgs list.
1264 GenTree* parent; // Points at the GT_LIST node in the gtCallArgs for this argument
1266 unsigned argNum; // The original argument number, also specifies the required argument evaluation order from the IL
1269 regNumberSmall regNums[MAX_ARG_REG_COUNT]; // The registers to use when passing this argument, set to REG_STK for
1270 // arguments passed on the stack
1272 unsigned numRegs; // Count of number of registers that this argument uses.
1273 // Note that on ARM, if we have a double hfa, this reflects the number
1274 // of DOUBLE registers.
1276 // A slot is a pointer sized region in the OutArg area.
1277 unsigned slotNum; // When an argument is passed in the OutArg area this is the slot number in the OutArg area
1278 unsigned numSlots; // Count of number of slots that this argument uses
1280 unsigned alignment; // 1 or 2 (slots/registers)
1282 unsigned _lateArgInx; // index into gtCallLateArgs list; UINT_MAX if this is not a late arg.
1284 unsigned tmpNum; // the LclVar number if we had to force evaluation of this arg
1286 var_types argType; // The type used to pass this argument. This is generally the original argument type, but when a
1287 // struct is passed as a scalar type, this is that type.
1288 // Note that if a struct is passed by reference, this will still be the struct type.
1290 bool needTmp : 1; // True when we force this argument's evaluation into a temp LclVar
1291 bool needPlace : 1; // True when we must replace this argument with a placeholder node
1292 bool isTmp : 1; // True when we setup a temp LclVar for this argument due to size issues with the struct
1293 bool processed : 1; // True when we have decided the evaluation order for this argument in the gtCallLateArgs
1294 bool isBackFilled : 1; // True when the argument fills a register slot skipped due to alignment requirements of
1295 // previous arguments.
1296 bool isNonStandard : 1; // True if it is an arg that is passed in a reg other than a standard arg reg, or is forced
1297 // to be on the stack despite its arg list position.
1298 bool isStruct : 1; // True if this is a struct arg
1299 bool _isVararg : 1; // True if the argument is in a vararg context.
1300 bool passedByRef : 1; // True iff the argument is passed by reference.
1301 #ifdef FEATURE_ARG_SPLIT
1302 bool _isSplit : 1; // True when this argument is split between the registers and OutArg area
1303 #endif // FEATURE_ARG_SPLIT
1305 bool _isHfaArg : 1; // True when the argument is an HFA type.
1306 bool _isDoubleHfa : 1; // True when the argument is an HFA, with an element type of DOUBLE.
1311 bool isLate = (_lateArgInx != UINT_MAX);
1315 __declspec(property(get = getLateArgInx, put = setLateArgInx)) unsigned lateArgInx;
1316 unsigned getLateArgInx()
1318 assert(isLateArg());
1321 void setLateArgInx(unsigned inx)
1325 __declspec(property(get = getRegNum)) regNumber regNum;
1326 regNumber getRegNum()
1328 return (regNumber)regNums[0];
1330 __declspec(property(get = getOtherRegNum)) regNumber otherRegNum;
1331 regNumber getOtherRegNum()
1333 return (regNumber)regNums[1];
1336 #if defined(UNIX_AMD64_ABI)
1337 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
1340 void setRegNum(unsigned int i, regNumber regNum)
1342 assert(i < MAX_ARG_REG_COUNT);
1343 regNums[i] = (regNumberSmall)regNum;
1345 regNumber getRegNum(unsigned int i)
1347 assert(i < MAX_ARG_REG_COUNT);
1348 return (regNumber)regNums[i];
1351 __declspec(property(get = getIsSplit, put = setIsSplit)) bool isSplit;
1354 #ifdef FEATURE_ARG_SPLIT
1356 #else // FEATURE_ARG_SPLIT
1360 void setIsSplit(bool value)
1362 #ifdef FEATURE_ARG_SPLIT
1367 __declspec(property(get = getIsVararg, put = setIsVararg)) bool isVararg;
1370 #ifdef FEATURE_VARARG
1376 void setIsVararg(bool value)
1378 #ifdef FEATURE_VARARG
1380 #endif // FEATURE_VARARG
1383 __declspec(property(get = getIsHfaArg)) bool isHfaArg;
1393 __declspec(property(get = getIsHfaRegArg)) bool isHfaRegArg;
1394 bool getIsHfaRegArg()
1397 return _isHfaArg && isPassedInRegisters();
1403 __declspec(property(get = getHfaType)) var_types hfaType;
1404 var_types getHfaType()
1407 return _isHfaArg ? (_isDoubleHfa ? TYP_DOUBLE : TYP_FLOAT) : TYP_UNDEF;
1413 void setHfaType(var_types type, unsigned hfaSlots)
1416 if (type != TYP_UNDEF)
1418 // We must already have set the passing mode.
1419 assert(numRegs != 0 || numSlots != 0);
1420 // We originally set numRegs according to the size of the struct, but if the size of the
1421 // hfaType is not the same as the pointer size, we need to correct it.
1422 // Note that hfaSlots is the number of registers we will use. For ARM, that is twice
1423 // the number of "double registers".
1424 unsigned numHfaRegs = hfaSlots;
1425 if (isPassedInRegisters())
1428 if (type == TYP_DOUBLE)
1430 // Must be an even number of registers.
1431 assert((numRegs & 1) == 0);
1432 numHfaRegs = hfaSlots / 2;
1434 #endif // _TARGET_ARM_
1437 // This should already be set correctly.
1438 assert(numRegs == numHfaRegs);
1439 assert(_isDoubleHfa == (type == TYP_DOUBLE));
1443 numRegs = numHfaRegs;
1446 _isDoubleHfa = (type == TYP_DOUBLE);
1449 #endif // FEATURE_HFA
1453 void SetIsBackFilled(bool backFilled)
1455 isBackFilled = backFilled;
1458 bool IsBackFilled() const
1460 return isBackFilled;
1462 #else // !_TARGET_ARM_
1463 void SetIsBackFilled(bool backFilled)
1467 bool IsBackFilled() const
1471 #endif // !_TARGET_ARM_
1473 bool isPassedInRegisters()
1475 return !isSplit && (numRegs != 0);
1478 bool isPassedInFloatRegisters()
1483 return isValidFloatArgReg(regNum);
1487 bool isSingleRegOrSlot()
1489 return !isSplit && ((numRegs == 1) || (numSlots == 1));
1492 // Returns the number of "slots" used, where for this purpose a
1493 // register counts as a slot.
1494 unsigned getSlotCount()
1498 assert(isPassedInRegisters());
1499 assert(numRegs == 1);
1501 else if (regNum == REG_STK)
1503 assert(!isPassedInRegisters());
1504 assert(numRegs == 0);
1508 assert(numRegs > 0);
1510 return numSlots + numRegs;
1513 // Returns the size as a multiple of pointer-size.
1514 // For targets without HFAs, this is the same as getSlotCount().
1517 unsigned size = getSlotCount();
1520 // We counted the number of regs, but if they are DOUBLE hfa regs we have to double the size.
1521 if (isHfaRegArg && (hfaType == TYP_DOUBLE))
1526 #elif defined(_TARGET_ARM64_)
1527 // We counted the number of regs, but if they are FLOAT hfa regs we have to halve the size.
1528 if (isHfaRegArg && (hfaType == TYP_FLOAT))
1530 // Round up in case of odd HFA count.
1531 size = (size + 1) >> 1;
1533 #endif // _TARGET_ARM64_
1538 // Set the register numbers for a multireg argument.
1539 // There's nothing to do on x64/Ux because the structDesc has already been used to set the
1540 // register numbers.
1541 void SetMultiRegNums()
1543 #if FEATURE_MULTIREG_ARGS && !defined(UNIX_AMD64_ABI)
1549 regNumber argReg = getRegNum(0);
1551 unsigned int regSize = (hfaType == TYP_DOUBLE) ? 2 : 1;
1553 unsigned int regSize = 1;
1555 for (unsigned int regIndex = 1; regIndex < numRegs; regIndex++)
1557 argReg = (regNumber)(argReg + regSize);
1558 setRegNum(regIndex, argReg);
1560 #endif // FEATURE_MULTIREG_ARGS && !defined(UNIX_AMD64_ABI)
1563 // Check that the value of 'isStruct' is consistent.
1564 // A struct arg must be one of the following:
1565 // - A node of struct type,
1566 // - A GT_FIELD_LIST, or
1567 // - A node of a scalar type, passed in a single register or slot
1568 // (or two slots in the case of a struct pass on the stack as TYP_DOUBLE).
1570 void checkIsStruct()
1574 if (!varTypeIsStruct(node) && !node->OperIs(GT_FIELD_LIST))
1576 // This is the case where we are passing a struct as a primitive type.
1577 // On most targets, this is always a single register or slot.
1578 // However, on ARM this could be two slots if it is TYP_DOUBLE.
1579 bool isPassedAsPrimitiveType = ((numRegs == 1) || ((numRegs == 0) && (numSlots == 1)));
1581 if (!isPassedAsPrimitiveType)
1583 if (node->TypeGet() == TYP_DOUBLE && numRegs == 0 && (numSlots == 2))
1585 isPassedAsPrimitiveType = true;
1588 #endif // _TARGET_ARM_
1589 assert(isPassedAsPrimitiveType);
1594 assert(!varTypeIsStruct(node));
1603 //-------------------------------------------------------------------------
1605 // The class fgArgInfo is used to handle the arguments
1606 // when morphing a GT_CALL node.
1611 Compiler* compiler; // Back pointer to the compiler instance so that we can allocate memory
1612 GenTreeCall* callTree; // Back pointer to the GT_CALL node for this fgArgInfo
1613 unsigned argCount; // Updatable arg count value
1614 unsigned nextSlotNum; // Updatable slot count value
1615 unsigned stkLevel; // Stack depth when we make this call (for x86)
1617 #if defined(UNIX_X86_ABI)
1618 bool alignmentDone; // Updateable flag, set to 'true' after we've done any required alignment.
1619 unsigned stkSizeBytes; // Size of stack used by this call, in bytes. Calculated during fgMorphArgs().
1620 unsigned padStkAlign; // Stack alignment in bytes required before arguments are pushed for this call.
1621 // Computed dynamically during codegen, based on stkSizeBytes and the current
1622 // stack level (genStackLevel) when the first stack adjustment is made for
1626 #if FEATURE_FIXED_OUT_ARGS
1627 unsigned outArgSize; // Size of the out arg area for the call, will be at least MIN_ARG_AREA_FOR_CALL
1630 unsigned argTableSize; // size of argTable array (equal to the argCount when done with fgMorphArgs)
1631 bool hasRegArgs; // true if we have one or more register arguments
1632 bool hasStackArgs; // true if we have one or more stack arguments
1633 bool argsComplete; // marker for state
1634 bool argsSorted; // marker for state
1635 fgArgTabEntry** argTable; // variable sized array of per argument descrption: (i.e. argTable[argTableSize])
1638 void AddArg(fgArgTabEntry* curArgTabEntry);
1641 fgArgInfo(Compiler* comp, GenTreeCall* call, unsigned argCount);
1642 fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall);
1644 fgArgTabEntry* AddRegArg(unsigned argNum,
1651 bool isVararg = false);
1653 #ifdef UNIX_AMD64_ABI
1654 fgArgTabEntry* AddRegArg(unsigned argNum,
1660 const bool isStruct,
1661 const bool isVararg,
1662 const regNumber otherRegNum,
1663 const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* const structDescPtr = nullptr);
1664 #endif // UNIX_AMD64_ABI
1666 fgArgTabEntry* AddStkArg(unsigned argNum,
1672 bool isVararg = false);
1674 void RemorphReset();
1675 void UpdateRegArg(fgArgTabEntry* argEntry, GenTree* node, bool reMorphing);
1676 void UpdateStkArg(fgArgTabEntry* argEntry, GenTree* node, bool reMorphing);
1678 void SplitArg(unsigned argNum, unsigned numRegs, unsigned numSlots);
1680 void EvalToTmp(fgArgTabEntry* curArgTabEntry, unsigned tmpNum, GenTree* newNode);
1682 void ArgsComplete();
1686 void EvalArgsToTemps();
1692 fgArgTabEntry** ArgTable()
1696 unsigned GetNextSlotNum()
1706 return hasStackArgs;
1708 bool AreArgsComplete() const
1710 return argsComplete;
1712 #if FEATURE_FIXED_OUT_ARGS
1713 unsigned GetOutArgSize() const
1717 void SetOutArgSize(unsigned newVal)
1719 outArgSize = newVal;
1721 #endif // FEATURE_FIXED_OUT_ARGS
1723 #if defined(UNIX_X86_ABI)
1724 void ComputeStackAlignment(unsigned curStackLevelInBytes)
1726 padStkAlign = AlignmentPad(curStackLevelInBytes, STACK_ALIGN);
1729 unsigned GetStkAlign()
1734 void SetStkSizeBytes(unsigned newStkSizeBytes)
1736 stkSizeBytes = newStkSizeBytes;
1739 unsigned GetStkSizeBytes() const
1741 return stkSizeBytes;
1744 bool IsStkAlignmentDone() const
1746 return alignmentDone;
1749 void SetStkAlignmentDone()
1751 alignmentDone = true;
1753 #endif // defined(UNIX_X86_ABI)
1755 // Get the fgArgTabEntry for the arg at position argNum.
1756 fgArgTabEntry* GetArgEntry(unsigned argNum, bool reMorphing = true)
1758 fgArgTabEntry* curArgTabEntry = nullptr;
1762 // The arg table has not yet been sorted.
1763 curArgTabEntry = argTable[argNum];
1764 assert(curArgTabEntry->argNum == argNum);
1765 return curArgTabEntry;
1768 for (unsigned i = 0; i < argCount; i++)
1770 curArgTabEntry = argTable[i];
1771 if (curArgTabEntry->argNum == argNum)
1773 return curArgTabEntry;
1776 noway_assert(!"GetArgEntry: argNum not found");
1780 // Get the node for the arg at position argIndex.
1781 // Caller must ensure that this index is a valid arg index.
1782 GenTree* GetArgNode(unsigned argIndex)
1784 return GetArgEntry(argIndex)->node;
1787 void Dump(Compiler* compiler);
1791 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1792 // We have the ability to mark source expressions with "Test Labels."
1793 // These drive assertions within the JIT, or internal JIT testing. For example, we could label expressions
1794 // that should be CSE defs, and other expressions that should uses of those defs, with a shared label.
1796 enum TestLabel // This must be kept identical to System.Runtime.CompilerServices.JitTestLabel.TestLabel.
1799 TL_VN, // Defines a "VN equivalence class". (For full VN, including exceptions thrown).
1800 TL_VNNorm, // Like above, but uses the non-exceptional value of the expression.
1801 TL_CSE_Def, // This must be identified in the JIT as a CSE def
1802 TL_CSE_Use, // This must be identified in the JIT as a CSE use
1803 TL_LoopHoist, // Expression must (or must not) be hoisted out of the loop.
1806 struct TestLabelAndNum
1811 TestLabelAndNum() : m_tl(TestLabel(0)), m_num(0)
1816 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, TestLabelAndNum> NodeToTestDataMap;
1818 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1822 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1823 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1825 XX The big guy. The sections are currently organized as : XX
1827 XX o GenTree and BasicBlock XX
1839 XX o PrologScopeInfo XX
1840 XX o CodeGenerator XX
1845 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1846 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1849 struct HWIntrinsicInfo;
1853 friend class emitter;
1854 friend class UnwindInfo;
1855 friend class UnwindFragmentInfo;
1856 friend class UnwindEpilogInfo;
1857 friend class JitTimer;
1858 friend class LinearScan;
1859 friend class fgArgInfo;
1860 friend class Rationalizer;
1862 friend class Lowering;
1863 friend class CSE_DataFlow;
1864 friend class CSE_Heuristic;
1865 friend class CodeGenInterface;
1866 friend class CodeGen;
1867 friend class LclVarDsc;
1868 friend class TempDsc;
1870 friend class ObjectAllocator;
1871 friend class LocalAddressVisitor;
1872 friend struct GenTree;
1874 #ifdef FEATURE_HW_INTRINSICS
1875 friend struct HWIntrinsicInfo;
1876 #endif // FEATURE_HW_INTRINSICS
1878 #ifndef _TARGET_64BIT_
1879 friend class DecomposeLongs;
1880 #endif // !_TARGET_64BIT_
1883 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1884 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1886 XX Misc structs definitions XX
1888 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1889 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1893 hashBvGlobalData hbvGlobalData; // Used by the hashBv bitvector package.
1912 bool dumpIRDataflow;
1913 bool dumpIRBlockHeaders;
1915 LPCWSTR dumpIRPhase;
1916 LPCWSTR dumpIRFormat;
1918 bool shouldUseVerboseTrees();
1919 bool asciiTrees; // If true, dump trees using only ASCII characters
1920 bool shouldDumpASCIITrees();
1921 bool verboseSsa; // If true, produce especially verbose dump output in SSA construction.
1922 bool shouldUseVerboseSsa();
1923 bool treesBeforeAfterMorph; // If true, print trees before/after morphing (paired by an intra-compilation id:
1924 int morphNum; // This counts the the trees that have been morphed, allowing us to label each uniquely.
1926 const char* VarNameToStr(VarName name)
1931 DWORD expensiveDebugCheckLevel;
1934 #if FEATURE_MULTIREG_RET
1935 GenTree* impAssignMultiRegTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass);
1936 #endif // FEATURE_MULTIREG_RET
1938 GenTree* impAssignSmallStructTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass);
1941 bool isSingleFloat32Struct(CORINFO_CLASS_HANDLE hClass);
1942 #endif // ARM_SOFTFP
1944 //-------------------------------------------------------------------------
1945 // Functions to handle homogeneous floating-point aggregates (HFAs) in ARM.
1946 // HFAs are one to four element structs where each element is the same
1947 // type, either all float or all double. They are treated specially
1948 // in the ARM Procedure Call Standard, specifically, they are passed in
1949 // floating-point registers instead of the general purpose registers.
1952 bool IsHfa(CORINFO_CLASS_HANDLE hClass);
1953 bool IsHfa(GenTree* tree);
1955 var_types GetHfaType(GenTree* tree);
1956 unsigned GetHfaCount(GenTree* tree);
1958 var_types GetHfaType(CORINFO_CLASS_HANDLE hClass);
1959 unsigned GetHfaCount(CORINFO_CLASS_HANDLE hClass);
1961 bool IsMultiRegReturnedType(CORINFO_CLASS_HANDLE hClass);
1963 //-------------------------------------------------------------------------
1964 // The following is used for validating format of EH table
1968 typedef struct EHNodeDsc* pEHNodeDsc;
1970 EHNodeDsc* ehnTree; // root of the tree comprising the EHnodes.
1971 EHNodeDsc* ehnNext; // root of the tree comprising the EHnodes.
1984 EHBlockType ehnBlockType; // kind of EH block
1985 IL_OFFSET ehnStartOffset; // IL offset of start of the EH block
1986 IL_OFFSET ehnEndOffset; // IL offset past end of the EH block. (TODO: looks like verInsertEhNode() sets this to
1987 // the last IL offset, not "one past the last one", i.e., the range Start to End is
1989 pEHNodeDsc ehnNext; // next (non-nested) block in sequential order
1990 pEHNodeDsc ehnChild; // leftmost nested block
1992 pEHNodeDsc ehnTryNode; // for filters and handlers, the corresponding try node
1993 pEHNodeDsc ehnHandlerNode; // for a try node, the corresponding handler node
1995 pEHNodeDsc ehnFilterNode; // if this is a try node and has a filter, otherwise 0
1996 pEHNodeDsc ehnEquivalent; // if blockType=tryNode, start offset and end offset is same,
1998 void ehnSetTryNodeType()
2000 ehnBlockType = TryNode;
2002 void ehnSetFilterNodeType()
2004 ehnBlockType = FilterNode;
2006 void ehnSetHandlerNodeType()
2008 ehnBlockType = HandlerNode;
2010 void ehnSetFinallyNodeType()
2012 ehnBlockType = FinallyNode;
2014 void ehnSetFaultNodeType()
2016 ehnBlockType = FaultNode;
2019 BOOL ehnIsTryBlock()
2021 return ehnBlockType == TryNode;
2023 BOOL ehnIsFilterBlock()
2025 return ehnBlockType == FilterNode;
2027 BOOL ehnIsHandlerBlock()
2029 return ehnBlockType == HandlerNode;
2031 BOOL ehnIsFinallyBlock()
2033 return ehnBlockType == FinallyNode;
2035 BOOL ehnIsFaultBlock()
2037 return ehnBlockType == FaultNode;
2040 // returns true if there is any overlap between the two nodes
2041 static BOOL ehnIsOverlap(pEHNodeDsc node1, pEHNodeDsc node2)
2043 if (node1->ehnStartOffset < node2->ehnStartOffset)
2045 return (node1->ehnEndOffset >= node2->ehnStartOffset);
2049 return (node1->ehnStartOffset <= node2->ehnEndOffset);
2053 // fails with BADCODE if inner is not completely nested inside outer
2054 static BOOL ehnIsNested(pEHNodeDsc inner, pEHNodeDsc outer)
2056 return ((inner->ehnStartOffset >= outer->ehnStartOffset) && (inner->ehnEndOffset <= outer->ehnEndOffset));
2060 //-------------------------------------------------------------------------
2061 // Exception handling functions
2064 #if !FEATURE_EH_FUNCLETS
2066 bool ehNeedsShadowSPslots()
2068 return (info.compXcptnsCount || opts.compDbgEnC);
2071 // 0 for methods with no EH
2072 // 1 for methods with non-nested EH, or where only the try blocks are nested
2073 // 2 for a method with a catch within a catch
2075 unsigned ehMaxHndNestingCount;
2077 #endif // !FEATURE_EH_FUNCLETS
2079 static bool jitIsBetween(unsigned value, unsigned start, unsigned end);
2080 static bool jitIsBetweenInclusive(unsigned value, unsigned start, unsigned end);
2082 bool bbInCatchHandlerILRange(BasicBlock* blk);
2083 bool bbInFilterILRange(BasicBlock* blk);
2084 bool bbInTryRegions(unsigned regionIndex, BasicBlock* blk);
2085 bool bbInExnFlowRegions(unsigned regionIndex, BasicBlock* blk);
2086 bool bbInHandlerRegions(unsigned regionIndex, BasicBlock* blk);
2087 bool bbInCatchHandlerRegions(BasicBlock* tryBlk, BasicBlock* hndBlk);
2088 unsigned short bbFindInnermostCommonTryRegion(BasicBlock* bbOne, BasicBlock* bbTwo);
2090 unsigned short bbFindInnermostTryRegionContainingHandlerRegion(unsigned handlerIndex);
2091 unsigned short bbFindInnermostHandlerRegionContainingTryRegion(unsigned tryIndex);
2093 // Returns true if "block" is the start of a try region.
2094 bool bbIsTryBeg(BasicBlock* block);
2096 // Returns true if "block" is the start of a handler or filter region.
2097 bool bbIsHandlerBeg(BasicBlock* block);
2099 // Returns true iff "block" is where control flows if an exception is raised in the
2100 // try region, and sets "*regionIndex" to the index of the try for the handler.
2101 // Differs from "IsHandlerBeg" in the case of filters, where this is true for the first
2102 // block of the filter, but not for the filter's handler.
2103 bool bbIsExFlowBlock(BasicBlock* block, unsigned* regionIndex);
2105 bool ehHasCallableHandlers();
2107 // Return the EH descriptor for the given region index.
2108 EHblkDsc* ehGetDsc(unsigned regionIndex);
2110 // Return the EH index given a region descriptor.
2111 unsigned ehGetIndex(EHblkDsc* ehDsc);
2113 // Return the EH descriptor index of the enclosing try, for the given region index.
2114 unsigned ehGetEnclosingTryIndex(unsigned regionIndex);
2116 // Return the EH descriptor index of the enclosing handler, for the given region index.
2117 unsigned ehGetEnclosingHndIndex(unsigned regionIndex);
2119 // Return the EH descriptor for the most nested 'try' region this BasicBlock is a member of (or nullptr if this
2120 // block is not in a 'try' region).
2121 EHblkDsc* ehGetBlockTryDsc(BasicBlock* block);
2123 // Return the EH descriptor for the most nested filter or handler region this BasicBlock is a member of (or nullptr
2124 // if this block is not in a filter or handler region).
2125 EHblkDsc* ehGetBlockHndDsc(BasicBlock* block);
2127 // Return the EH descriptor for the most nested region that may handle exceptions raised in this BasicBlock (or
2128 // nullptr if this block's exceptions propagate to caller).
2129 EHblkDsc* ehGetBlockExnFlowDsc(BasicBlock* block);
2131 EHblkDsc* ehIsBlockTryLast(BasicBlock* block);
2132 EHblkDsc* ehIsBlockHndLast(BasicBlock* block);
2133 bool ehIsBlockEHLast(BasicBlock* block);
2135 bool ehBlockHasExnFlowDsc(BasicBlock* block);
2137 // Return the region index of the most nested EH region this block is in.
2138 unsigned ehGetMostNestedRegionIndex(BasicBlock* block, bool* inTryRegion);
2140 // Find the true enclosing try index, ignoring 'mutual protect' try. Uses IL ranges to check.
2141 unsigned ehTrueEnclosingTryIndexIL(unsigned regionIndex);
2143 // Return the index of the most nested enclosing region for a particular EH region. Returns NO_ENCLOSING_INDEX
2144 // if there is no enclosing region. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion'
2145 // is set to 'true' if the enclosing region is a 'try', or 'false' if the enclosing region is a handler.
2146 // (It can never be a filter.)
2147 unsigned ehGetEnclosingRegionIndex(unsigned regionIndex, bool* inTryRegion);
2149 // A block has been deleted. Update the EH table appropriately.
2150 void ehUpdateForDeletedBlock(BasicBlock* block);
2152 // Determine whether a block can be deleted while preserving the EH normalization rules.
2153 bool ehCanDeleteEmptyBlock(BasicBlock* block);
2155 // Update the 'last' pointers in the EH table to reflect new or deleted blocks in an EH region.
2156 void ehUpdateLastBlocks(BasicBlock* oldLast, BasicBlock* newLast);
2158 // For a finally handler, find the region index that the BBJ_CALLFINALLY lives in that calls the handler,
2159 // or NO_ENCLOSING_INDEX if the BBJ_CALLFINALLY lives in the main function body. Normally, the index
2160 // is the same index as the handler (and the BBJ_CALLFINALLY lives in the 'try' region), but for AMD64 the
2161 // BBJ_CALLFINALLY lives in the enclosing try or handler region, whichever is more nested, or the main function
2162 // body. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion' is set to 'true' if the
2163 // BBJ_CALLFINALLY lives in the returned index's 'try' region, or 'false' if lives in the handler region. (It never
2164 // lives in a filter.)
2165 unsigned ehGetCallFinallyRegionIndex(unsigned finallyIndex, bool* inTryRegion);
2167 // Find the range of basic blocks in which all BBJ_CALLFINALLY will be found that target the 'finallyIndex' region's
2168 // handler. Set begBlk to the first block, and endBlk to the block after the last block of the range
2169 // (nullptr if the last block is the last block in the program).
2170 // Precondition: 'finallyIndex' is the EH region of a try/finally clause.
2171 void ehGetCallFinallyBlockRange(unsigned finallyIndex, BasicBlock** begBlk, BasicBlock** endBlk);
2174 // Given a BBJ_CALLFINALLY block and the EH region index of the finally it is calling, return
2175 // 'true' if the BBJ_CALLFINALLY is in the correct EH region.
2176 bool ehCallFinallyInCorrectRegion(BasicBlock* blockCallFinally, unsigned finallyIndex);
2179 #if FEATURE_EH_FUNCLETS
2180 // Do we need a PSPSym in the main function? For codegen purposes, we only need one
2181 // if there is a filter that protects a region with a nested EH clause (such as a
2182 // try/catch nested in the 'try' body of a try/filter/filter-handler). See
2183 // genFuncletProlog() for more details. However, the VM seems to use it for more
2184 // purposes, maybe including debugging. Until we are sure otherwise, always create
2185 // a PSPSym for functions with any EH.
2186 bool ehNeedsPSPSym() const
2190 #else // _TARGET_X86_
2191 return compHndBBtabCount > 0;
2192 #endif // _TARGET_X86_
2195 bool ehAnyFunclets(); // Are there any funclets in this function?
2196 unsigned ehFuncletCount(); // Return the count of funclets in the function
2198 unsigned bbThrowIndex(BasicBlock* blk); // Get the index to use as the cache key for sharing throw blocks
2199 #else // !FEATURE_EH_FUNCLETS
2200 bool ehAnyFunclets()
2204 unsigned ehFuncletCount()
2209 unsigned bbThrowIndex(BasicBlock* blk)
2211 return blk->bbTryIndex;
2212 } // Get the index to use as the cache key for sharing throw blocks
2213 #endif // !FEATURE_EH_FUNCLETS
2215 // Returns a flowList representing the "EH predecessors" of "blk". These are the normal predecessors of
2216 // "blk", plus one special case: if "blk" is the first block of a handler, considers the predecessor(s) of the first
2217 // first block of the corresponding try region to be "EH predecessors". (If there is a single such predecessor,
2218 // for example, we want to consider that the immediate dominator of the catch clause start block, so it's
2219 // convenient to also consider it a predecessor.)
2220 flowList* BlockPredsWithEH(BasicBlock* blk);
2222 // This table is useful for memoization of the method above.
2223 typedef JitHashTable<BasicBlock*, JitPtrKeyFuncs<BasicBlock>, flowList*> BlockToFlowListMap;
2224 BlockToFlowListMap* m_blockToEHPreds;
2225 BlockToFlowListMap* GetBlockToEHPreds()
2227 if (m_blockToEHPreds == nullptr)
2229 m_blockToEHPreds = new (getAllocator()) BlockToFlowListMap(getAllocator());
2231 return m_blockToEHPreds;
2234 void* ehEmitCookie(BasicBlock* block);
2235 UNATIVE_OFFSET ehCodeOffset(BasicBlock* block);
2237 EHblkDsc* ehInitHndRange(BasicBlock* src, IL_OFFSET* hndBeg, IL_OFFSET* hndEnd, bool* inFilter);
2239 EHblkDsc* ehInitTryRange(BasicBlock* src, IL_OFFSET* tryBeg, IL_OFFSET* tryEnd);
2241 EHblkDsc* ehInitHndBlockRange(BasicBlock* blk, BasicBlock** hndBeg, BasicBlock** hndLast, bool* inFilter);
2243 EHblkDsc* ehInitTryBlockRange(BasicBlock* blk, BasicBlock** tryBeg, BasicBlock** tryLast);
2245 void fgSetTryEnd(EHblkDsc* handlerTab, BasicBlock* newTryLast);
2247 void fgSetHndEnd(EHblkDsc* handlerTab, BasicBlock* newHndLast);
2249 void fgSkipRmvdBlocks(EHblkDsc* handlerTab);
2251 void fgAllocEHTable();
2253 void fgRemoveEHTableEntry(unsigned XTnum);
2255 #if FEATURE_EH_FUNCLETS
2257 EHblkDsc* fgAddEHTableEntry(unsigned XTnum);
2259 #endif // FEATURE_EH_FUNCLETS
2263 #endif // !FEATURE_EH
2265 void fgSortEHTable();
2267 // Causes the EH table to obey some well-formedness conditions, by inserting
2268 // empty BB's when necessary:
2269 // * No block is both the first block of a handler and the first block of a try.
2270 // * No block is the first block of multiple 'try' regions.
2271 // * No block is the last block of multiple EH regions.
2272 void fgNormalizeEH();
2273 bool fgNormalizeEHCase1();
2274 bool fgNormalizeEHCase2();
2275 bool fgNormalizeEHCase3();
2278 void dispIncomingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
2279 void dispOutgoingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
2280 void fgVerifyHandlerTab();
2281 void fgDispHandlerTab();
2284 bool fgNeedToSortEHTable;
2286 void verInitEHTree(unsigned numEHClauses);
2287 void verInsertEhNode(CORINFO_EH_CLAUSE* clause, EHblkDsc* handlerTab);
2288 void verInsertEhNodeInTree(EHNodeDsc** ppRoot, EHNodeDsc* node);
2289 void verInsertEhNodeParent(EHNodeDsc** ppRoot, EHNodeDsc* node);
2290 void verCheckNestingLevel(EHNodeDsc* initRoot);
2293 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2294 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2296 XX GenTree and BasicBlock XX
2298 XX Functions to allocate and display the GenTrees and BasicBlocks XX
2300 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2301 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2304 // Functions to create nodes
2305 GenTreeStmt* gtNewStmt(GenTree* expr = nullptr, IL_OFFSETX offset = BAD_IL_OFFSET);
2308 GenTree* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, bool doSimplifications = TRUE);
2310 // For binary opers.
2311 GenTree* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2);
2313 GenTree* gtNewQmarkNode(var_types type, GenTree* cond, GenTree* colon);
2315 GenTree* gtNewLargeOperNode(genTreeOps oper,
2316 var_types type = TYP_I_IMPL,
2317 GenTree* op1 = nullptr,
2318 GenTree* op2 = nullptr);
2320 GenTreeIntCon* gtNewIconNode(ssize_t value, var_types type = TYP_INT);
2322 GenTree* gtNewPhysRegNode(regNumber reg, var_types type);
2324 GenTree* gtNewJmpTableNode();
2326 GenTree* gtNewIndOfIconHandleNode(var_types indType, size_t value, unsigned iconFlags, bool isInvariant);
2328 GenTree* gtNewIconHandleNode(size_t value, unsigned flags, FieldSeqNode* fields = nullptr);
2330 unsigned gtTokenToIconFlags(unsigned token);
2332 GenTree* gtNewIconEmbHndNode(void* value, void* pValue, unsigned flags, void* compileTimeHandle);
2334 GenTree* gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd);
2335 GenTree* gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd);
2336 GenTree* gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd);
2337 GenTree* gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd);
2339 GenTree* gtNewStringLiteralNode(InfoAccessType iat, void* pValue);
2341 GenTree* gtNewLconNode(__int64 value);
2343 GenTree* gtNewDconNode(double value, var_types type = TYP_DOUBLE);
2345 GenTree* gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle);
2347 GenTree* gtNewZeroConNode(var_types type);
2349 GenTree* gtNewOneConNode(var_types type);
2352 GenTree* gtNewSIMDVectorZero(var_types simdType, var_types baseType, unsigned size);
2353 GenTree* gtNewSIMDVectorOne(var_types simdType, var_types baseType, unsigned size);
2356 GenTree* gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, unsigned size, bool isVolatile, bool isCopyBlock);
2358 GenTree* gtNewPutArgReg(var_types type, GenTree* arg, regNumber argReg);
2360 GenTree* gtNewBitCastNode(var_types type, GenTree* arg);
2363 void gtBlockOpInit(GenTree* result, GenTree* dst, GenTree* srcOrFillVal, bool isVolatile);
2366 GenTree* gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr);
2367 void gtSetObjGcInfo(GenTreeObj* objNode);
2368 GenTree* gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTree* addr);
2369 GenTree* gtNewBlockVal(GenTree* addr, unsigned size);
2371 GenTree* gtNewCpObjNode(GenTree* dst, GenTree* src, CORINFO_CLASS_HANDLE structHnd, bool isVolatile);
2373 GenTreeArgList* gtNewListNode(GenTree* op1, GenTreeArgList* op2);
2375 GenTreeCall* gtNewCallNode(gtCallTypes callType,
2376 CORINFO_METHOD_HANDLE handle,
2378 GenTreeArgList* args,
2379 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2381 GenTreeCall* gtNewIndCallNode(GenTree* addr,
2383 GenTreeArgList* args,
2384 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2386 GenTreeCall* gtNewHelperCallNode(unsigned helper, var_types type, GenTreeArgList* args = nullptr);
2388 GenTree* gtNewLclvNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));
2389 GenTree* gtNewLclLNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));
2392 GenTreeSIMD* gtNewSIMDNode(
2393 var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
2394 GenTreeSIMD* gtNewSIMDNode(
2395 var_types type, GenTree* op1, GenTree* op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
2396 void SetOpLclRelatedToSIMDIntrinsic(GenTree* op);
2399 #ifdef FEATURE_HW_INTRINSICS
2400 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2401 NamedIntrinsic hwIntrinsicID,
2404 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
2405 var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
2406 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
2407 var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
2408 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2412 NamedIntrinsic hwIntrinsicID,
2415 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2420 NamedIntrinsic hwIntrinsicID,
2423 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID);
2424 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type,
2427 NamedIntrinsic hwIntrinsicID);
2428 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(
2429 var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID);
2430 GenTree* gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd);
2431 CORINFO_CLASS_HANDLE gtGetStructHandleForHWSIMD(var_types simdType, var_types simdBaseType);
2432 #endif // FEATURE_HW_INTRINSICS
2434 GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset);
2435 GenTree* gtNewInlineCandidateReturnExpr(GenTree* inlineCandidate, var_types type);
2437 GenTree* gtNewFieldRef(var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj = nullptr, DWORD offset = 0);
2439 GenTree* gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree* indexOp);
2441 GenTreeArrLen* gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset);
2443 GenTree* gtNewIndir(var_types typ, GenTree* addr);
2445 GenTreeArgList* gtNewArgList(GenTree* op);
2446 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2);
2447 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2, GenTree* op3);
2448 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2, GenTree* op3, GenTree* op4);
2450 static fgArgTabEntry* gtArgEntryByArgNum(GenTreeCall* call, unsigned argNum);
2451 static fgArgTabEntry* gtArgEntryByNode(GenTreeCall* call, GenTree* node);
2452 fgArgTabEntry* gtArgEntryByLateArgIndex(GenTreeCall* call, unsigned lateArgInx);
2453 static GenTree* gtArgNodeByLateArgInx(GenTreeCall* call, unsigned lateArgInx);
2454 bool gtArgIsThisPtr(fgArgTabEntry* argEntry);
2456 GenTree* gtNewAssignNode(GenTree* dst, GenTree* src);
2458 GenTree* gtNewTempAssign(unsigned tmp,
2460 GenTree** pAfterStmt = nullptr,
2461 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
2462 BasicBlock* block = nullptr);
2464 GenTree* gtNewRefCOMfield(GenTree* objPtr,
2465 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2466 CORINFO_ACCESS_FLAGS access,
2467 CORINFO_FIELD_INFO* pFieldInfo,
2469 CORINFO_CLASS_HANDLE structType,
2472 GenTree* gtNewNothingNode();
2474 GenTree* gtNewArgPlaceHolderNode(var_types type, CORINFO_CLASS_HANDLE clsHnd);
2476 GenTree* gtUnusedValNode(GenTree* expr);
2478 GenTreeCast* gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
2480 GenTreeCast* gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
2482 GenTreeAllocObj* gtNewAllocObjNode(
2483 unsigned int helper, bool helperHasSideEffects, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTree* op1);
2485 GenTreeAllocObj* gtNewAllocObjNode(CORINFO_RESOLVED_TOKEN* pResolvedToken, BOOL useParent);
2487 GenTree* gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* lookupTree);
2489 //------------------------------------------------------------------------
2490 // Other GenTree functions
2492 GenTree* gtClone(GenTree* tree, bool complexOK = false);
2494 // If `tree` is a lclVar with lclNum `varNum`, return an IntCns with value `varVal`; otherwise,
2495 // create a copy of `tree`, adding specified flags, replacing uses of lclVar `deepVarNum` with
2496 // IntCnses with value `deepVarVal`.
2497 GenTree* gtCloneExpr(
2498 GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal);
2500 // Create a copy of `tree`, optionally adding specifed flags, and optionally mapping uses of local
2501 // `varNum` to int constants with value `varVal`.
2502 GenTree* gtCloneExpr(GenTree* tree, unsigned addFlags = 0, unsigned varNum = BAD_VAR_NUM, int varVal = 0)
2504 return gtCloneExpr(tree, addFlags, varNum, varVal, varNum, varVal);
2507 // Internal helper for cloning a call
2508 GenTreeCall* gtCloneExprCallHelper(GenTreeCall* call,
2509 unsigned addFlags = 0,
2510 unsigned deepVarNum = BAD_VAR_NUM,
2511 int deepVarVal = 0);
2513 // Create copy of an inline or guarded devirtualization candidate tree.
2514 GenTreeCall* gtCloneCandidateCall(GenTreeCall* call);
2516 GenTree* gtReplaceTree(GenTree* stmt, GenTree* tree, GenTree* replacementTree);
2518 void gtUpdateSideEffects(GenTree* stmt, GenTree* tree);
2520 void gtUpdateTreeAncestorsSideEffects(GenTree* tree);
2522 void gtUpdateStmtSideEffects(GenTree* stmt);
2524 void gtUpdateNodeSideEffects(GenTree* tree);
2526 void gtUpdateNodeOperSideEffects(GenTree* tree);
2528 // Returns "true" iff the complexity (not formally defined, but first interpretation
2529 // is #of nodes in subtree) of "tree" is greater than "limit".
2530 // (This is somewhat redundant with the "gtCostEx/gtCostSz" fields, but can be used
2531 // before they have been set.)
2532 bool gtComplexityExceeds(GenTree** tree, unsigned limit);
2534 bool gtCompareTree(GenTree* op1, GenTree* op2);
2536 GenTree* gtReverseCond(GenTree* tree);
2538 bool gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly);
2540 bool gtHasLocalsWithAddrOp(GenTree* tree);
2542 unsigned gtSetListOrder(GenTree* list, bool regs, bool isListCallArgs);
2544 void gtWalkOp(GenTree** op1, GenTree** op2, GenTree* base, bool constOnly);
2547 unsigned gtHashValue(GenTree* tree);
2549 GenTree* gtWalkOpEffectiveVal(GenTree* op);
2552 void gtPrepareCost(GenTree* tree);
2553 bool gtIsLikelyRegVar(GenTree* tree);
2555 // Returns true iff the secondNode can be swapped with firstNode.
2556 bool gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode);
2558 // Given an address expression, compute its costs and addressing mode opportunities,
2559 // and mark addressing mode candidates as GTF_DONT_CSE.
2560 // TODO-Throughput - Consider actually instantiating these early, to avoid
2561 // having to re-run the algorithm that looks for them (might also improve CQ).
2562 bool gtMarkAddrMode(GenTree* addr, int* costEx, int* costSz, var_types type);
2564 unsigned gtSetEvalOrder(GenTree* tree);
2566 void gtSetStmtInfo(GenTree* stmt);
2568 // Returns "true" iff "node" has any of the side effects in "flags".
2569 bool gtNodeHasSideEffects(GenTree* node, unsigned flags);
2571 // Returns "true" iff "tree" or its (transitive) children have any of the side effects in "flags".
2572 bool gtTreeHasSideEffects(GenTree* tree, unsigned flags);
2574 // Appends 'expr' in front of 'list'
2575 // 'list' will typically start off as 'nullptr'
2576 // when 'list' is non-null a GT_COMMA node is used to insert 'expr'
2577 GenTree* gtBuildCommaList(GenTree* list, GenTree* expr);
2579 void gtExtractSideEffList(GenTree* expr,
2581 unsigned flags = GTF_SIDE_EFFECT,
2582 bool ignoreRoot = false);
2584 GenTree* gtGetThisArg(GenTreeCall* call);
2586 // Static fields of struct types (and sometimes the types that those are reduced to) are represented by having the
2587 // static field contain an object pointer to the boxed struct. This simplifies the GC implementation...but
2588 // complicates the JIT somewhat. This predicate returns "true" iff a node with type "fieldNodeType", representing
2589 // the given "fldHnd", is such an object pointer.
2590 bool gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd);
2592 // Return true if call is a recursive call; return false otherwise.
2593 // Note when inlining, this looks for calls back to the root method.
2594 bool gtIsRecursiveCall(GenTreeCall* call)
2596 return gtIsRecursiveCall(call->gtCallMethHnd);
2599 bool gtIsRecursiveCall(CORINFO_METHOD_HANDLE callMethodHandle)
2601 return (callMethodHandle == impInlineRoot()->info.compMethodHnd);
2604 //-------------------------------------------------------------------------
2606 GenTree* gtFoldExpr(GenTree* tree);
2609 // TODO-Amd64-Unix: Remove this when the clang optimizer is fixed and/or the method implementation is
2610 // refactored in a simpler code. This is a workaround for a bug in the clang-3.5 optimizer. The issue is that in
2611 // release build the optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner case
2612 // of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div operation instead of 64 bit) - see
2613 // the implementation of the method in gentree.cpp. For the case of lval1 and lval2 equal to MIN_LONG
2614 // (0x8000000000000000) this results in raising a SIGFPE. The method implementation is rather complex. Disable
2615 // optimizations for now.
2616 __attribute__((optnone))
2618 gtFoldExprConst(GenTree* tree);
2619 GenTree* gtFoldExprSpecial(GenTree* tree);
2620 GenTree* gtFoldExprCompare(GenTree* tree);
2621 GenTree* gtCreateHandleCompare(genTreeOps oper,
2624 CorInfoInlineTypeCheck typeCheckInliningResult);
2625 GenTree* gtFoldExprCall(GenTreeCall* call);
2626 GenTree* gtFoldTypeCompare(GenTree* tree);
2627 GenTree* gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2);
2629 // Options to control behavior of gtTryRemoveBoxUpstreamEffects
2630 enum BoxRemovalOptions
2632 BR_REMOVE_AND_NARROW, // remove effects, minimize remaining work, return possibly narrowed source tree
2633 BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE, // remove effects and minimize remaining work, return type handle tree
2634 BR_REMOVE_BUT_NOT_NARROW, // remove effects, return original source tree
2635 BR_DONT_REMOVE, // check if removal is possible, return copy source tree
2636 BR_DONT_REMOVE_WANT_TYPE_HANDLE, // check if removal is possible, return type handle tree
2637 BR_MAKE_LOCAL_COPY // revise box to copy to temp local and return local's address
2640 GenTree* gtTryRemoveBoxUpstreamEffects(GenTree* tree, BoxRemovalOptions options = BR_REMOVE_AND_NARROW);
2641 GenTree* gtOptimizeEnumHasFlag(GenTree* thisOp, GenTree* flagOp);
2643 //-------------------------------------------------------------------------
2644 // Get the handle, if any.
2645 CORINFO_CLASS_HANDLE gtGetStructHandleIfPresent(GenTree* tree);
2646 // Get the handle, and assert if not found.
2647 CORINFO_CLASS_HANDLE gtGetStructHandle(GenTree* tree);
2648 // Get the handle for a ref type.
2649 CORINFO_CLASS_HANDLE gtGetClassHandle(GenTree* tree, bool* pIsExact, bool* pIsNonNull);
2650 // Get the class handle for an helper call
2651 CORINFO_CLASS_HANDLE gtGetHelperCallClassHandle(GenTreeCall* call, bool* pIsExact, bool* pIsNonNull);
2652 // Get the element handle for an array of ref type.
2653 CORINFO_CLASS_HANDLE gtGetArrayElementClassHandle(GenTree* array);
2654 // Get a class handle from a helper call argument
2655 CORINFO_CLASS_HANDLE gtGetHelperArgClassHandle(GenTree* array,
2656 unsigned* runtimeLookupCount = nullptr,
2657 GenTree** handleTree = nullptr);
2658 // Get the class handle for a field
2659 CORINFO_CLASS_HANDLE gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull);
2660 // Check if this tree is a gc static base helper call
2661 bool gtIsStaticGCBaseHelperCall(GenTree* tree);
2663 //-------------------------------------------------------------------------
2664 // Functions to display the trees
2667 void gtDispNode(GenTree* tree, IndentStack* indentStack, __in_z const char* msg, bool isLIR);
2669 void gtDispVN(GenTree* tree);
2670 void gtDispConst(GenTree* tree);
2671 void gtDispLeaf(GenTree* tree, IndentStack* indentStack);
2672 void gtDispNodeName(GenTree* tree);
2673 void gtDispRegVal(GenTree* tree);
2685 void gtDispChild(GenTree* child,
2686 IndentStack* indentStack,
2688 __in_opt const char* msg = nullptr,
2689 bool topOnly = false);
2690 void gtDispTree(GenTree* tree,
2691 IndentStack* indentStack = nullptr,
2692 __in_opt const char* msg = nullptr,
2693 bool topOnly = false,
2694 bool isLIR = false);
2695 void gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut);
2696 int gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining);
2697 char* gtGetLclVarName(unsigned lclNum);
2698 void gtDispLclVar(unsigned varNum, bool padForBiggestDisp = true);
2699 void gtDispTreeList(GenTree* tree, IndentStack* indentStack = nullptr);
2700 void gtGetArgMsg(GenTreeCall* call, GenTree* arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength);
2701 void gtGetLateArgMsg(GenTreeCall* call, GenTree* arg, int argNum, int listCount, char* bufp, unsigned bufLength);
2702 void gtDispArgList(GenTreeCall* call, IndentStack* indentStack);
2703 void gtDispFieldSeq(FieldSeqNode* pfsn);
2705 void gtDispRange(LIR::ReadOnlyRange const& range);
2707 void gtDispTreeRange(LIR::Range& containingRange, GenTree* tree);
2709 void gtDispLIRNode(GenTree* node, const char* prefixMsg = nullptr);
2721 typedef fgWalkResult(fgWalkPreFn)(GenTree** pTree, fgWalkData* data);
2722 typedef fgWalkResult(fgWalkPostFn)(GenTree** pTree, fgWalkData* data);
2725 static fgWalkPreFn gtAssertColonCond;
2727 static fgWalkPreFn gtMarkColonCond;
2728 static fgWalkPreFn gtClearColonCond;
2730 GenTree** gtFindLink(GenTree* stmt, GenTree* node);
2731 bool gtHasCatchArg(GenTree* tree);
2733 typedef ArrayStack<GenTree*> GenTreeStack;
2735 static bool gtHasCallOnStack(GenTreeStack* parentStack);
2737 //=========================================================================
2738 // BasicBlock functions
2740 // This is a debug flag we will use to assert when creating block during codegen
2741 // as this interferes with procedure splitting. If you know what you're doing, set
2742 // it to true before creating the block. (DEBUG only)
2743 bool fgSafeBasicBlockCreation;
2746 BasicBlock* bbNewBasicBlock(BBjumpKinds jumpKind);
2749 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2750 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2754 XX The variables to be used by the code generator. XX
2756 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2757 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2761 // For both PROMOTION_TYPE_NONE and PROMOTION_TYPE_DEPENDENT the struct will
2762 // be placed in the stack frame and it's fields must be laid out sequentially.
2764 // For PROMOTION_TYPE_INDEPENDENT each of the struct's fields is replaced by
2765 // a local variable that can be enregistered or placed in the stack frame.
2766 // The fields do not need to be laid out sequentially
2768 enum lvaPromotionType
2770 PROMOTION_TYPE_NONE, // The struct local is not promoted
2771 PROMOTION_TYPE_INDEPENDENT, // The struct local is promoted,
2772 // and its field locals are independent of its parent struct local.
2773 PROMOTION_TYPE_DEPENDENT // The struct local is promoted,
2774 // but its field locals depend on its parent struct local.
2777 static int __cdecl RefCntCmp(const void* op1, const void* op2);
2778 static int __cdecl WtdRefCntCmp(const void* op1, const void* op2);
2780 /*****************************************************************************/
2782 enum FrameLayoutState
2785 INITIAL_FRAME_LAYOUT,
2786 PRE_REGALLOC_FRAME_LAYOUT,
2787 REGALLOC_FRAME_LAYOUT,
2788 TENTATIVE_FRAME_LAYOUT,
2793 RefCountState lvaRefCountState; // Current local ref count state
2795 bool lvaLocalVarRefCounted() const
2797 return lvaRefCountState == RCS_NORMAL;
2800 bool lvaTrackedFixed; // true: We cannot add new 'tracked' variable
2801 unsigned lvaCount; // total number of locals
2803 unsigned lvaRefCount; // total number of references to locals
2804 LclVarDsc* lvaTable; // variable descriptor table
2805 unsigned lvaTableCnt; // lvaTable size (>= lvaCount)
2807 LclVarDsc** lvaRefSorted; // table sorted by refcount
2809 unsigned short lvaTrackedCount; // actual # of locals being tracked
2810 unsigned lvaTrackedCountInSizeTUnits; // min # of size_t's sufficient to hold a bit for all the locals being tracked
2813 VARSET_TP lvaTrackedVars; // set of tracked variables
2815 #ifndef _TARGET_64BIT_
2816 VARSET_TP lvaLongVars; // set of long (64-bit) variables
2818 VARSET_TP lvaFloatVars; // set of floating-point (32-bit and 64-bit) variables
2820 unsigned lvaCurEpoch; // VarSets are relative to a specific set of tracked var indices.
2821 // It that changes, this changes. VarSets from different epochs
2822 // cannot be meaningfully combined.
2824 unsigned GetCurLVEpoch()
2829 // reverse map of tracked number to var number
2830 unsigned* lvaTrackedToVarNum;
2834 // # of procs compiled a with double-aligned stack
2835 static unsigned s_lvaDoubleAlignedProcsCount;
2839 // Getters and setters for address-exposed and do-not-enregister local var properties.
2840 bool lvaVarAddrExposed(unsigned varNum);
2841 void lvaSetVarAddrExposed(unsigned varNum);
2842 bool lvaVarDoNotEnregister(unsigned varNum);
2844 // Reasons why we can't enregister. Some of these correspond to debug properties of local vars.
2845 enum DoNotEnregisterReason
2850 DNER_VMNeedsStackAddr,
2851 DNER_LiveInOutOfHandler,
2852 DNER_LiveAcrossUnmanagedCall,
2853 DNER_BlockOp, // Is read or written via a block operation that explicitly takes the address.
2854 DNER_IsStructArg, // Is a struct passed as an argument in a way that requires a stack location.
2855 DNER_DepField, // It is a field of a dependently promoted struct
2856 DNER_NoRegVars, // opts.compFlags & CLFLG_REGVAR is not set
2857 DNER_MinOptsGC, // It is a GC Ref and we are compiling MinOpts
2858 #if !defined(_TARGET_64BIT_)
2859 DNER_LongParamField, // It is a decomposed field of a long parameter.
2861 #ifdef JIT32_GCENCODER
2866 void lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregisterReason reason));
2868 unsigned lvaVarargsHandleArg;
2870 unsigned lvaVarargsBaseOfStkArgs; // Pointer (computed based on incoming varargs handle) to the start of the stack
2872 #endif // _TARGET_X86_
2874 unsigned lvaInlinedPInvokeFrameVar; // variable representing the InlinedCallFrame
2875 unsigned lvaReversePInvokeFrameVar; // variable representing the reverse PInvoke frame
2876 #if FEATURE_FIXED_OUT_ARGS
2877 unsigned lvaPInvokeFrameRegSaveVar; // variable representing the RegSave for PInvoke inlining.
2879 unsigned lvaMonAcquired; // boolean variable introduced into in synchronized methods
2880 // that tracks whether the lock has been taken
2882 unsigned lvaArg0Var; // The lclNum of arg0. Normally this will be info.compThisArg.
2883 // However, if there is a "ldarga 0" or "starg 0" in the IL,
2884 // we will redirect all "ldarg(a) 0" and "starg 0" to this temp.
2886 unsigned lvaInlineeReturnSpillTemp; // The temp to spill the non-VOID return expression
2887 // in case there are multiple BBJ_RETURN blocks in the inlinee
2888 // or if the inlinee has GC ref locals.
2890 #if FEATURE_FIXED_OUT_ARGS
2891 unsigned lvaOutgoingArgSpaceVar; // dummy TYP_LCLBLK var for fixed outgoing argument space
2892 PhasedVar<unsigned> lvaOutgoingArgSpaceSize; // size of fixed outgoing argument space
2893 #endif // FEATURE_FIXED_OUT_ARGS
2896 // On architectures whose ABIs allow structs to be passed in registers, struct promotion will sometimes
2897 // require us to "rematerialize" a struct from it's separate constituent field variables. Packing several sub-word
2898 // field variables into an argument register is a hard problem. It's easier to reserve a word of memory into which
2899 // such field can be copied, after which the assembled memory word can be read into the register. We will allocate
2900 // this variable to be this scratch word whenever struct promotion occurs.
2901 unsigned lvaPromotedStructAssemblyScratchVar;
2902 #endif // _TARGET_ARM_
2904 #if defined(DEBUG) && defined(_TARGET_XARCH_)
2906 unsigned lvaReturnSpCheck; // Stores SP to confirm it is not corrupted on return.
2908 #endif // defined(DEBUG) && defined(_TARGET_XARCH_)
2910 #if defined(DEBUG) && defined(_TARGET_X86_)
2912 unsigned lvaCallSpCheck; // Stores SP to confirm it is not corrupted after every call.
2914 #endif // defined(DEBUG) && defined(_TARGET_X86_)
2916 unsigned lvaGenericsContextUseCount;
2918 bool lvaKeepAliveAndReportThis(); // Synchronized instance method of a reference type, or
2919 // CORINFO_GENERICS_CTXT_FROM_THIS?
2920 bool lvaReportParamTypeArg(); // Exceptions and CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG?
2922 //-------------------------------------------------------------------------
2923 // All these frame offsets are inter-related and must be kept in sync
2925 #if !FEATURE_EH_FUNCLETS
2926 // This is used for the callable handlers
2927 unsigned lvaShadowSPslotsVar; // TYP_BLK variable for all the shadow SP slots
2928 #endif // FEATURE_EH_FUNCLETS
2930 int lvaCachedGenericContextArgOffs;
2931 int lvaCachedGenericContextArgOffset(); // For CORINFO_CALLCONV_PARAMTYPE and if generic context is passed as
2934 #ifdef JIT32_GCENCODER
2936 unsigned lvaLocAllocSPvar; // variable which stores the value of ESP after the the last alloca/localloc
2938 #endif // JIT32_GCENCODER
2940 unsigned lvaNewObjArrayArgs; // variable with arguments for new MD array helper
2942 // TODO-Review: Prior to reg predict we reserve 24 bytes for Spill temps.
2943 // after the reg predict we will use a computed maxTmpSize
2944 // which is based upon the number of spill temps predicted by reg predict
2945 // All this is necessary because if we under-estimate the size of the spill
2946 // temps we could fail when encoding instructions that reference stack offsets for ARM.
2948 // Pre codegen max spill temp size.
2949 static const unsigned MAX_SPILL_TEMP_SIZE = 24;
2951 //-------------------------------------------------------------------------
2953 unsigned lvaGetMaxSpillTempSize();
2955 bool lvaIsPreSpilled(unsigned lclNum, regMaskTP preSpillMask);
2956 #endif // _TARGET_ARM_
2957 void lvaAssignFrameOffsets(FrameLayoutState curState);
2958 void lvaFixVirtualFrameOffsets();
2959 void lvaUpdateArgsWithInitialReg();
2960 void lvaAssignVirtualFrameOffsetsToArgs();
2961 #ifdef UNIX_AMD64_ABI
2962 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs, int* callerArgOffset);
2963 #else // !UNIX_AMD64_ABI
2964 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs);
2965 #endif // !UNIX_AMD64_ABI
2966 void lvaAssignVirtualFrameOffsetsToLocals();
2967 int lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, int stkOffs);
2968 #ifdef _TARGET_AMD64_
2969 // Returns true if compCalleeRegsPushed (including RBP if used as frame pointer) is even.
2970 bool lvaIsCalleeSavedIntRegCountEven();
2972 void lvaAlignFrame();
2973 void lvaAssignFrameOffsetsToPromotedStructs();
2974 int lvaAllocateTemps(int stkOffs, bool mustDoubleAlign);
2977 void lvaDumpRegLocation(unsigned lclNum);
2978 void lvaDumpFrameLocation(unsigned lclNum);
2979 void lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t refCntWtdWidth = 6);
2980 void lvaTableDump(FrameLayoutState curState = NO_FRAME_LAYOUT); // NO_FRAME_LAYOUT means use the current frame
2981 // layout state defined by lvaDoneFrameLayout
2984 // Limit frames size to 1GB. The maximum is 2GB in theory - make it intentionally smaller
2985 // to avoid bugs from borderline cases.
2986 #define MAX_FrameSize 0x3FFFFFFF
2987 void lvaIncrementFrameSize(unsigned size);
2989 unsigned lvaFrameSize(FrameLayoutState curState);
2991 // Returns the caller-SP-relative offset for the SP/FP relative offset determined by FP based.
2992 int lvaToCallerSPRelativeOffset(int offs, bool isFpBased);
2994 // Returns the caller-SP-relative offset for the local variable "varNum."
2995 int lvaGetCallerSPRelativeOffset(unsigned varNum);
2997 // Returns the SP-relative offset for the local variable "varNum". Illegal to ask this for functions with localloc.
2998 int lvaGetSPRelativeOffset(unsigned varNum);
3000 int lvaToInitialSPRelativeOffset(unsigned offset, bool isFpBased);
3001 int lvaGetInitialSPRelativeOffset(unsigned varNum);
3003 //------------------------ For splitting types ----------------------------
3005 void lvaInitTypeRef();
3007 void lvaInitArgs(InitVarDscInfo* varDscInfo);
3008 void lvaInitThisPtr(InitVarDscInfo* varDscInfo);
3009 void lvaInitRetBuffArg(InitVarDscInfo* varDscInfo);
3010 void lvaInitUserArgs(InitVarDscInfo* varDscInfo);
3011 void lvaInitGenericsCtxt(InitVarDscInfo* varDscInfo);
3012 void lvaInitVarArgsHandle(InitVarDscInfo* varDscInfo);
3014 void lvaInitVarDsc(LclVarDsc* varDsc,
3016 CorInfoType corInfoType,
3017 CORINFO_CLASS_HANDLE typeHnd,
3018 CORINFO_ARG_LIST_HANDLE varList,
3019 CORINFO_SIG_INFO* varSig);
3021 static unsigned lvaTypeRefMask(var_types type);
3023 var_types lvaGetActualType(unsigned lclNum);
3024 var_types lvaGetRealType(unsigned lclNum);
3026 //-------------------------------------------------------------------------
3030 LclVarDsc* lvaGetDesc(unsigned lclNum)
3032 assert(lclNum < lvaCount);
3033 return &lvaTable[lclNum];
3036 LclVarDsc* lvaGetDesc(GenTreeLclVarCommon* lclVar)
3038 assert(lclVar->GetLclNum() < lvaCount);
3039 return &lvaTable[lclVar->GetLclNum()];
3042 unsigned lvaLclSize(unsigned varNum);
3043 unsigned lvaLclExactSize(unsigned varNum);
3045 bool lvaHaveManyLocals() const;
3047 unsigned lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason));
3048 unsigned lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason));
3049 unsigned lvaGrabTempWithImplicitUse(bool shortLifetime DEBUGARG(const char* reason));
3052 void lvaSortByRefCount();
3053 void lvaDumpRefCounts();
3055 void lvaMarkLocalVars(); // Local variable ref-counting
3056 void lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers);
3057 void lvaMarkLocalVars(BasicBlock* block, bool isRecompute);
3059 void lvaAllocOutgoingArgSpaceVar(); // Set up lvaOutgoingArgSpaceVar
3061 VARSET_VALRET_TP lvaStmtLclMask(GenTree* stmt);
3064 struct lvaStressLclFldArgs
3066 Compiler* m_pCompiler;
3070 static fgWalkPreFn lvaStressLclFldCB;
3071 void lvaStressLclFld();
3073 void lvaDispVarSet(VARSET_VALARG_TP set, VARSET_VALARG_TP allVars);
3074 void lvaDispVarSet(VARSET_VALARG_TP set);
3079 int lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset, bool isFloatUsage);
3081 int lvaFrameAddress(int varNum, bool* pFPbased);
3084 bool lvaIsParameter(unsigned varNum);
3085 bool lvaIsRegArgument(unsigned varNum);
3086 BOOL lvaIsOriginalThisArg(unsigned varNum); // Is this varNum the original this argument?
3087 BOOL lvaIsOriginalThisReadOnly(); // return TRUE if there is no place in the code
3088 // that writes to arg0
3090 // Struct parameters that are passed by reference are marked as both lvIsParam and lvIsTemp
3091 // (this is an overload of lvIsTemp because there are no temp parameters).
3092 // For x64 this is 3, 5, 6, 7, >8 byte structs that are passed by reference.
3093 // For ARM64, this is structs larger than 16 bytes that are passed by reference.
3094 bool lvaIsImplicitByRefLocal(unsigned varNum)
3096 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
3097 LclVarDsc* varDsc = &(lvaTable[varNum]);
3098 if (varDsc->lvIsParam && varDsc->lvIsTemp)
3100 assert(varTypeIsStruct(varDsc) || (varDsc->lvType == TYP_BYREF));
3103 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
3107 // Returns true if this local var is a multireg struct
3108 bool lvaIsMultiregStruct(LclVarDsc* varDsc, bool isVararg);
3110 // If the local is a TYP_STRUCT, get/set a class handle describing it
3111 CORINFO_CLASS_HANDLE lvaGetStruct(unsigned varNum);
3112 void lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool unsafeValueClsCheck, bool setTypeInfo = true);
3113 void lvaSetStructUsedAsVarArg(unsigned varNum);
3115 // If the local is TYP_REF, set or update the associated class information.
3116 void lvaSetClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
3117 void lvaSetClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
3118 void lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
3119 void lvaUpdateClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
3121 #define MAX_NumOfFieldsInPromotableStruct 4 // Maximum number of fields in promotable struct
3123 // Info about struct type fields.
3124 struct lvaStructFieldInfo
3126 CORINFO_FIELD_HANDLE fldHnd;
3127 unsigned char fldOffset;
3128 unsigned char fldOrdinal;
3131 CORINFO_CLASS_HANDLE fldTypeHnd;
3133 lvaStructFieldInfo()
3134 : fldHnd(nullptr), fldOffset(0), fldOrdinal(0), fldType(TYP_UNDEF), fldSize(0), fldTypeHnd(nullptr)
3139 // Info about a struct type, instances of which may be candidates for promotion.
3140 struct lvaStructPromotionInfo
3142 CORINFO_CLASS_HANDLE typeHnd;
3147 unsigned char fieldCnt;
3148 lvaStructFieldInfo fields[MAX_NumOfFieldsInPromotableStruct];
3150 lvaStructPromotionInfo(CORINFO_CLASS_HANDLE typeHnd = nullptr)
3153 , containsHoles(false)
3154 , customLayout(false)
3155 , fieldsSorted(false)
3161 static int __cdecl lvaFieldOffsetCmp(const void* field1, const void* field2);
3163 // This class is responsible for checking validity and profitability of struct promotion.
3164 // If it is both legal and profitable, then TryPromoteStructVar promotes the struct and initializes
3165 // nessesary information for fgMorphStructField to use.
3166 class StructPromotionHelper
3169 StructPromotionHelper(Compiler* compiler);
3171 bool CanPromoteStructType(CORINFO_CLASS_HANDLE typeHnd);
3172 bool TryPromoteStructVar(unsigned lclNum);
3175 void CheckRetypedAsScalar(CORINFO_FIELD_HANDLE fieldHnd, var_types requestedType);
3179 bool GetRequiresScratchVar();
3180 #endif // _TARGET_ARM_
3183 bool CanPromoteStructVar(unsigned lclNum);
3184 bool ShouldPromoteStructVar(unsigned lclNum);
3185 void PromoteStructVar(unsigned lclNum);
3186 void SortStructFields();
3188 lvaStructFieldInfo GetFieldInfo(CORINFO_FIELD_HANDLE fieldHnd, BYTE ordinal);
3189 bool TryPromoteStructField(lvaStructFieldInfo& outerFieldInfo);
3193 lvaStructPromotionInfo structPromotionInfo;
3196 bool requiresScratchVar;
3197 #endif // _TARGET_ARM_
3200 typedef JitHashTable<CORINFO_FIELD_HANDLE, JitPtrKeyFuncs<CORINFO_FIELD_STRUCT_>, var_types>
3201 RetypedAsScalarFieldsMap;
3202 RetypedAsScalarFieldsMap retypedFieldsMap;
3206 StructPromotionHelper* structPromotionHelper;
3208 #if !defined(_TARGET_64BIT_)
3209 void lvaPromoteLongVars();
3210 #endif // !defined(_TARGET_64BIT_)
3211 unsigned lvaGetFieldLocal(const LclVarDsc* varDsc, unsigned int fldOffset);
3212 lvaPromotionType lvaGetPromotionType(const LclVarDsc* varDsc);
3213 lvaPromotionType lvaGetPromotionType(unsigned varNum);
3214 lvaPromotionType lvaGetParentPromotionType(const LclVarDsc* varDsc);
3215 lvaPromotionType lvaGetParentPromotionType(unsigned varNum);
3216 bool lvaIsFieldOfDependentlyPromotedStruct(const LclVarDsc* varDsc);
3217 bool lvaIsGCTracked(const LclVarDsc* varDsc);
3219 #if defined(FEATURE_SIMD)
3220 bool lvaMapSimd12ToSimd16(const LclVarDsc* varDsc)
3222 assert(varDsc->lvType == TYP_SIMD12);
3223 assert(varDsc->lvExactSize == 12);
3225 #if defined(_TARGET_64BIT_)
3226 assert(varDsc->lvSize() == 16);
3227 #endif // defined(_TARGET_64BIT_)
3229 // We make local variable SIMD12 types 16 bytes instead of just 12. lvSize()
3230 // already does this calculation. However, we also need to prevent mapping types if the var is a
3231 // dependently promoted struct field, which must remain its exact size within its parent struct.
3232 // However, we don't know this until late, so we may have already pretended the field is bigger
3234 if ((varDsc->lvSize() == 16) && !lvaIsFieldOfDependentlyPromotedStruct(varDsc))
3243 #endif // defined(FEATURE_SIMD)
3245 BYTE* lvaGetGcLayout(unsigned varNum);
3246 bool lvaTypeIsGC(unsigned varNum);
3247 unsigned lvaGSSecurityCookie; // LclVar number
3248 bool lvaTempsHaveLargerOffsetThanVars();
3250 // Returns "true" iff local variable "lclNum" is in SSA form.
3251 bool lvaInSsa(unsigned lclNum)
3253 assert(lclNum < lvaCount);
3254 return lvaTable[lclNum].lvInSsa;
3257 unsigned lvaSecurityObject; // variable representing the security object on the stack
3258 unsigned lvaStubArgumentVar; // variable representing the secret stub argument coming in EAX
3260 #if FEATURE_EH_FUNCLETS
3261 unsigned lvaPSPSym; // variable representing the PSPSym
3264 InlineInfo* impInlineInfo;
3265 InlineStrategy* m_inlineStrategy;
3267 // The Compiler* that is the root of the inlining tree of which "this" is a member.
3268 Compiler* impInlineRoot();
3270 #if defined(DEBUG) || defined(INLINE_DATA)
3271 unsigned __int64 getInlineCycleCount()
3273 return m_compCycles;
3275 #endif // defined(DEBUG) || defined(INLINE_DATA)
3277 bool fgNoStructPromotion; // Set to TRUE to turn off struct promotion for this method.
3278 bool fgNoStructParamPromotion; // Set to TRUE to turn off struct promotion for parameters this method.
3280 //=========================================================================
3282 //=========================================================================
3285 //---------------- Local variable ref-counting ----------------------------
3287 void lvaMarkLclRefs(GenTree* tree, BasicBlock* block, GenTreeStmt* stmt, bool isRecompute);
3288 bool IsDominatedByExceptionalEntry(BasicBlock* block);
3289 void SetVolatileHint(LclVarDsc* varDsc);
3291 // Keeps the mapping from SSA #'s to VN's for the implicit memory variables.
3292 SsaDefArray<SsaMemDef> lvMemoryPerSsaData;
3295 // Returns the address of the per-Ssa data for memory at the given ssaNum (which is required
3296 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
3297 // not an SSA variable).
3298 SsaMemDef* GetMemoryPerSsaData(unsigned ssaNum)
3300 return lvMemoryPerSsaData.GetSsaDef(ssaNum);
3304 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3305 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3309 XX Imports the given method and converts it to semantic trees XX
3311 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3312 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3318 void impImport(BasicBlock* method);
3320 CORINFO_CLASS_HANDLE impGetRefAnyClass();
3321 CORINFO_CLASS_HANDLE impGetRuntimeArgumentHandle();
3322 CORINFO_CLASS_HANDLE impGetTypeHandleClass();
3323 CORINFO_CLASS_HANDLE impGetStringClass();
3324 CORINFO_CLASS_HANDLE impGetObjectClass();
3326 // Returns underlying type of handles returned by ldtoken instruction
3327 var_types GetRuntimeHandleUnderlyingType()
3329 // RuntimeTypeHandle is backed by raw pointer on CoreRT and by object reference on other runtimes
3330 return IsTargetAbi(CORINFO_CORERT_ABI) ? TYP_I_IMPL : TYP_REF;
3333 void impDevirtualizeCall(GenTreeCall* call,
3334 CORINFO_METHOD_HANDLE* method,
3335 unsigned* methodFlags,
3336 CORINFO_CONTEXT_HANDLE* contextHandle,
3337 CORINFO_CONTEXT_HANDLE* exactContextHandle,
3338 bool isLateDevirtualization,
3339 bool isExplicitTailCall);
3341 //=========================================================================
3343 //=========================================================================
3346 //-------------------- Stack manipulation ---------------------------------
3348 unsigned impStkSize; // Size of the full stack
3350 #define SMALL_STACK_SIZE 16 // number of elements in impSmallStack
3352 struct SavedStack // used to save/restore stack contents.
3354 unsigned ssDepth; // number of values on stack
3355 StackEntry* ssTrees; // saved tree values
3358 bool impIsPrimitive(CorInfoType type);
3359 bool impILConsumesAddr(const BYTE* codeAddr, CORINFO_METHOD_HANDLE fncHandle, CORINFO_MODULE_HANDLE scpHandle);
3361 void impResolveToken(const BYTE* addr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CorInfoTokenKind kind);
3363 void impPushOnStack(GenTree* tree, typeInfo ti);
3364 void impPushNullObjRefOnStack();
3365 StackEntry impPopStack();
3366 StackEntry& impStackTop(unsigned n = 0);
3367 unsigned impStackHeight();
3369 void impSaveStackState(SavedStack* savePtr, bool copy);
3370 void impRestoreStackState(SavedStack* savePtr);
3372 GenTree* impImportLdvirtftn(GenTree* thisPtr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3374 void impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken);
3376 void impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3378 bool impCanPInvokeInline();
3379 bool impCanPInvokeInlineCallSite(BasicBlock* block);
3380 void impCheckForPInvokeCall(
3381 GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block);
3382 GenTreeCall* impImportIndirectCall(CORINFO_SIG_INFO* sig, IL_OFFSETX ilOffset = BAD_IL_OFFSET);
3383 void impPopArgsForUnmanagedCall(GenTree* call, CORINFO_SIG_INFO* sig);
3385 void impInsertHelperCall(CORINFO_HELPER_DESC* helperCall);
3386 void impHandleAccessAllowed(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
3387 void impHandleAccessAllowedInternal(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
3389 var_types impImportCall(OPCODE opcode,
3390 CORINFO_RESOLVED_TOKEN* pResolvedToken,
3391 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call on a
3393 GenTree* newobjThis,
3395 CORINFO_CALL_INFO* callInfo,
3396 IL_OFFSET rawILOffset);
3398 CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(CORINFO_METHOD_HANDLE specialIntrinsicHandle);
3400 bool impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo);
3402 GenTree* impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HANDLE retClsHnd);
3404 GenTree* impFixupStructReturnType(GenTree* op, CORINFO_CLASS_HANDLE retClsHnd);
3407 var_types impImportJitTestLabelMark(int numArgs);
3410 GenTree* impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken);
3412 GenTree* impImportStaticReadOnlyField(void* fldAddr, var_types lclTyp);
3414 GenTree* impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3415 CORINFO_ACCESS_FLAGS access,
3416 CORINFO_FIELD_INFO* pFieldInfo,
3419 static void impBashVarAddrsToI(GenTree* tree1, GenTree* tree2 = nullptr);
3421 GenTree* impImplicitIorI4Cast(GenTree* tree, var_types dstTyp);
3423 GenTree* impImplicitR4orR8Cast(GenTree* tree, var_types dstTyp);
3425 void impImportLeave(BasicBlock* block);
3426 void impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr);
3427 GenTree* impIntrinsic(GenTree* newobjThis,
3428 CORINFO_CLASS_HANDLE clsHnd,
3429 CORINFO_METHOD_HANDLE method,
3430 CORINFO_SIG_INFO* sig,
3431 unsigned methodFlags,
3435 CORINFO_RESOLVED_TOKEN* pContstrainedResolvedToken,
3436 CORINFO_THIS_TRANSFORM constraintCallThisTransform,
3437 CorInfoIntrinsics* pIntrinsicID,
3438 bool* isSpecialIntrinsic = nullptr);
3439 GenTree* impMathIntrinsic(CORINFO_METHOD_HANDLE method,
3440 CORINFO_SIG_INFO* sig,
3442 CorInfoIntrinsics intrinsicID,
3444 NamedIntrinsic lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method);
3446 #ifdef FEATURE_HW_INTRINSICS
3447 GenTree* impHWIntrinsic(NamedIntrinsic intrinsic,
3448 CORINFO_METHOD_HANDLE method,
3449 CORINFO_SIG_INFO* sig,
3451 GenTree* impUnsupportedHWIntrinsic(unsigned helper,
3452 CORINFO_METHOD_HANDLE method,
3453 CORINFO_SIG_INFO* sig,
3457 bool compSupportsHWIntrinsic(InstructionSet isa);
3459 #ifdef _TARGET_XARCH_
3460 GenTree* impBaseIntrinsic(NamedIntrinsic intrinsic,
3461 CORINFO_METHOD_HANDLE method,
3462 CORINFO_SIG_INFO* sig,
3464 GenTree* impSSEIntrinsic(NamedIntrinsic intrinsic,
3465 CORINFO_METHOD_HANDLE method,
3466 CORINFO_SIG_INFO* sig,
3468 GenTree* impSSE2Intrinsic(NamedIntrinsic intrinsic,
3469 CORINFO_METHOD_HANDLE method,
3470 CORINFO_SIG_INFO* sig,
3472 GenTree* impSSE42Intrinsic(NamedIntrinsic intrinsic,
3473 CORINFO_METHOD_HANDLE method,
3474 CORINFO_SIG_INFO* sig,
3476 GenTree* impAvxOrAvx2Intrinsic(NamedIntrinsic intrinsic,
3477 CORINFO_METHOD_HANDLE method,
3478 CORINFO_SIG_INFO* sig,
3480 GenTree* impAESIntrinsic(NamedIntrinsic intrinsic,
3481 CORINFO_METHOD_HANDLE method,
3482 CORINFO_SIG_INFO* sig,
3484 GenTree* impBMI1OrBMI2Intrinsic(NamedIntrinsic intrinsic,
3485 CORINFO_METHOD_HANDLE method,
3486 CORINFO_SIG_INFO* sig,
3488 GenTree* impFMAIntrinsic(NamedIntrinsic intrinsic,
3489 CORINFO_METHOD_HANDLE method,
3490 CORINFO_SIG_INFO* sig,
3492 GenTree* impLZCNTIntrinsic(NamedIntrinsic intrinsic,
3493 CORINFO_METHOD_HANDLE method,
3494 CORINFO_SIG_INFO* sig,
3496 GenTree* impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic,
3497 CORINFO_METHOD_HANDLE method,
3498 CORINFO_SIG_INFO* sig,
3500 GenTree* impPOPCNTIntrinsic(NamedIntrinsic intrinsic,
3501 CORINFO_METHOD_HANDLE method,
3502 CORINFO_SIG_INFO* sig,
3506 GenTree* getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE argClass);
3507 GenTree* impNonConstFallback(NamedIntrinsic intrinsic, var_types simdType, var_types baseType);
3508 GenTree* addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* lastOp, bool mustExpand);
3509 #endif // _TARGET_XARCH_
3510 #ifdef _TARGET_ARM64_
3511 InstructionSet lookupHWIntrinsicISA(const char* className);
3512 NamedIntrinsic lookupHWIntrinsic(const char* className, const char* methodName);
3513 bool impCheckImmediate(GenTree* immediateOp, unsigned int max);
3514 #endif // _TARGET_ARM64_
3515 #endif // FEATURE_HW_INTRINSICS
3516 GenTree* impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
3517 CORINFO_SIG_INFO* sig,
3520 CorInfoIntrinsics intrinsicID);
3521 GenTree* impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig);
3523 GenTree* impMethodPointer(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3525 GenTree* impTransformThis(GenTree* thisPtr,
3526 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
3527 CORINFO_THIS_TRANSFORM transform);
3529 //----------------- Manipulating the trees and stmts ----------------------
3531 GenTree* impTreeList; // Trees for the BB being imported
3532 GenTree* impTreeLast; // The last tree for the current BB
3537 CHECK_SPILL_ALL = -1,
3538 CHECK_SPILL_NONE = -2
3541 void impBeginTreeList();
3542 void impEndTreeList(BasicBlock* block, GenTree* firstStmt, GenTree* lastStmt);
3543 void impEndTreeList(BasicBlock* block);
3544 void impAppendStmtCheck(GenTree* stmt, unsigned chkLevel);
3545 void impAppendStmt(GenTree* stmt, unsigned chkLevel);
3546 void impInsertStmtBefore(GenTree* stmt, GenTree* stmtBefore);
3547 GenTree* impAppendTree(GenTree* tree, unsigned chkLevel, IL_OFFSETX offset);
3548 void impInsertTreeBefore(GenTree* tree, IL_OFFSETX offset, GenTree* stmtBefore);
3549 void impAssignTempGen(unsigned tmp,
3552 GenTree** pAfterStmt = nullptr,
3553 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3554 BasicBlock* block = nullptr);
3555 void impAssignTempGen(unsigned tmpNum,
3557 CORINFO_CLASS_HANDLE structHnd,
3559 GenTree** pAfterStmt = nullptr,
3560 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3561 BasicBlock* block = nullptr);
3562 GenTree* impCloneExpr(GenTree* tree,
3564 CORINFO_CLASS_HANDLE structHnd,
3566 GenTree** pAfterStmt DEBUGARG(const char* reason));
3567 GenTree* impAssignStruct(GenTree* dest,
3569 CORINFO_CLASS_HANDLE structHnd,
3571 GenTree** pAfterStmt = nullptr,
3572 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3573 BasicBlock* block = nullptr);
3574 GenTree* impAssignStructPtr(GenTree* dest,
3576 CORINFO_CLASS_HANDLE structHnd,
3578 GenTree** pAfterStmt = nullptr,
3579 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3580 BasicBlock* block = nullptr);
3582 GenTree* impGetStructAddr(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, unsigned curLevel, bool willDeref);
3584 var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd,
3585 BYTE* gcLayout = nullptr,
3586 unsigned* numGCVars = nullptr,
3587 var_types* simdBaseType = nullptr);
3589 GenTree* impNormStructVal(GenTree* structVal,
3590 CORINFO_CLASS_HANDLE structHnd,
3592 bool forceNormalization = false);
3594 GenTree* impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3595 BOOL* pRuntimeLookup = nullptr,
3596 BOOL mustRestoreHandle = FALSE,
3597 BOOL importParent = FALSE);
3599 GenTree* impParentClassTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3600 BOOL* pRuntimeLookup = nullptr,
3601 BOOL mustRestoreHandle = FALSE)
3603 return impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, TRUE);
3606 GenTree* impLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3607 CORINFO_LOOKUP* pLookup,
3609 void* compileTimeHandle);
3611 GenTree* getRuntimeContextTree(CORINFO_RUNTIME_LOOKUP_KIND kind);
3613 GenTree* impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3614 CORINFO_LOOKUP* pLookup,
3615 void* compileTimeHandle);
3617 GenTree* impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP* pLookup, unsigned flags, void* compileTimeHandle);
3619 GenTreeCall* impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3620 CorInfoHelpFunc helper,
3622 GenTreeArgList* arg = nullptr,
3623 CORINFO_LOOKUP_KIND* pGenericLookupKind = nullptr);
3625 GenTree* impCastClassOrIsInstToTree(GenTree* op1,
3627 CORINFO_RESOLVED_TOKEN* pResolvedToken,
3630 GenTree* impOptimizeCastClassOrIsInst(GenTree* op1, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isCastClass);
3632 bool VarTypeIsMultiByteAndCanEnreg(
3633 var_types type, CORINFO_CLASS_HANDLE typeClass, unsigned* typeSize, bool forReturn, bool isVarArg);
3635 bool IsIntrinsicImplementedByUserCall(CorInfoIntrinsics intrinsicId);
3636 bool IsTargetIntrinsic(CorInfoIntrinsics intrinsicId);
3637 bool IsMathIntrinsic(CorInfoIntrinsics intrinsicId);
3638 bool IsMathIntrinsic(GenTree* tree);
3641 //----------------- Importing the method ----------------------------------
3643 CORINFO_CONTEXT_HANDLE impTokenLookupContextHandle; // The context used for looking up tokens.
3646 unsigned impCurOpcOffs;
3647 const char* impCurOpcName;
3648 bool impNestedStackSpill;
3650 // For displaying instrs with generated native code (-n:B)
3651 GenTree* impLastILoffsStmt; // oldest stmt added for which we did not gtStmtLastILoffs
3652 void impNoteLastILoffs();
3655 /* IL offset of the stmt currently being imported. It gets set to
3656 BAD_IL_OFFSET after it has been set in the appended trees. Then it gets
3657 updated at IL offsets for which we have to report mapping info.
3658 It also includes flag bits, so use jitGetILoffs()
3659 to get the actual IL offset value.
3662 IL_OFFSETX impCurStmtOffs;
3663 void impCurStmtOffsSet(IL_OFFSET offs);
3665 void impNoteBranchOffs();
3667 unsigned impInitBlockLineInfo();
3669 GenTree* impCheckForNullPointer(GenTree* obj);
3670 bool impIsThis(GenTree* obj);
3671 bool impIsLDFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3672 bool impIsDUP_LDVIRTFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3673 bool impIsAnySTLOC(OPCODE opcode)
3675 return ((opcode == CEE_STLOC) || (opcode == CEE_STLOC_S) ||
3676 ((opcode >= CEE_STLOC_0) && (opcode <= CEE_STLOC_3)));
3679 GenTreeArgList* impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenTreeArgList* prefixTree = nullptr);
3681 GenTreeArgList* impPopRevList(unsigned count, CORINFO_SIG_INFO* sig, unsigned skipReverseCount = 0);
3684 * Get current IL offset with stack-empty info incoporated
3686 IL_OFFSETX impCurILOffset(IL_OFFSET offs, bool callInstruction = false);
3688 //---------------- Spilling the importer stack ----------------------------
3690 // The maximum number of bytes of IL processed without clean stack state.
3691 // It allows to limit the maximum tree size and depth.
3692 static const unsigned MAX_TREE_SIZE = 200;
3693 bool impCanSpillNow(OPCODE prevOpcode);
3699 SavedStack pdSavedStack;
3700 ThisInitState pdThisPtrInit;
3703 PendingDsc* impPendingList; // list of BBs currently waiting to be imported.
3704 PendingDsc* impPendingFree; // Freed up dscs that can be reused
3706 // We keep a byte-per-block map (dynamically extended) in the top-level Compiler object of a compilation.
3707 JitExpandArray<BYTE> impPendingBlockMembers;
3709 // Return the byte for "b" (allocating/extending impPendingBlockMembers if necessary.)
3710 // Operates on the map in the top-level ancestor.
3711 BYTE impGetPendingBlockMember(BasicBlock* blk)
3713 return impInlineRoot()->impPendingBlockMembers.Get(blk->bbInd());
3716 // Set the byte for "b" to "val" (allocating/extending impPendingBlockMembers if necessary.)
3717 // Operates on the map in the top-level ancestor.
3718 void impSetPendingBlockMember(BasicBlock* blk, BYTE val)
3720 impInlineRoot()->impPendingBlockMembers.Set(blk->bbInd(), val);
3723 bool impCanReimport;
3725 bool impSpillStackEntry(unsigned level,
3729 bool bAssertOnRecursion,
3734 void impSpillStackEnsure(bool spillLeaves = false);
3735 void impEvalSideEffects();
3736 void impSpillSpecialSideEff();
3737 void impSpillSideEffects(bool spillGlobEffects, unsigned chkLevel DEBUGARG(const char* reason));
3738 void impSpillValueClasses();
3739 void impSpillEvalStack();
3740 static fgWalkPreFn impFindValueClasses;
3741 void impSpillLclRefs(ssize_t lclNum);
3743 BasicBlock* impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_HANDLE clsHnd, bool isSingleBlockFilter);
3745 void impImportBlockCode(BasicBlock* block);
3747 void impReimportMarkBlock(BasicBlock* block);
3748 void impReimportMarkSuccessors(BasicBlock* block);
3750 void impVerifyEHBlock(BasicBlock* block, bool isTryStart);
3752 void impImportBlockPending(BasicBlock* block);
3754 // Similar to impImportBlockPending, but assumes that block has already been imported once and is being
3755 // reimported for some reason. It specifically does *not* look at verCurrentState to set the EntryState
3756 // for the block, but instead, just re-uses the block's existing EntryState.
3757 void impReimportBlockPending(BasicBlock* block);
3759 var_types impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTree** pOp1, GenTree** pOp2);
3761 void impImportBlock(BasicBlock* block);
3763 // Assumes that "block" is a basic block that completes with a non-empty stack. We will assign the values
3764 // on the stack to local variables (the "spill temp" variables). The successor blocks will assume that
3765 // its incoming stack contents are in those locals. This requires "block" and its successors to agree on
3766 // the variables that will be used -- and for all the predecessors of those successors, and the
3767 // successors of those predecessors, etc. Call such a set of blocks closed under alternating
3768 // successor/predecessor edges a "spill clique." A block is a "predecessor" or "successor" member of the
3769 // clique (or, conceivably, both). Each block has a specified sequence of incoming and outgoing spill
3770 // temps. If "block" already has its outgoing spill temps assigned (they are always a contiguous series
3771 // of local variable numbers, so we represent them with the base local variable number), returns that.
3772 // Otherwise, picks a set of spill temps, and propagates this choice to all blocks in the spill clique of
3773 // which "block" is a member (asserting, in debug mode, that no block in this clique had its spill temps
3774 // chosen already. More precisely, that the incoming or outgoing spill temps are not chosen, depending
3775 // on which kind of member of the clique the block is).
3776 unsigned impGetSpillTmpBase(BasicBlock* block);
3778 // Assumes that "block" is a basic block that completes with a non-empty stack. We have previously
3779 // assigned the values on the stack to local variables (the "spill temp" variables). The successor blocks
3780 // will assume that its incoming stack contents are in those locals. This requires "block" and its
3781 // successors to agree on the variables and their types that will be used. The CLI spec allows implicit
3782 // conversions between 'int' and 'native int' or 'float' and 'double' stack types. So one predecessor can
3783 // push an int and another can push a native int. For 64-bit we have chosen to implement this by typing
3784 // the "spill temp" as native int, and then importing (or re-importing as needed) so that all the
3785 // predecessors in the "spill clique" push a native int (sign-extending if needed), and all the
3786 // successors receive a native int. Similarly float and double are unified to double.
3787 // This routine is called after a type-mismatch is detected, and it will walk the spill clique to mark
3788 // blocks for re-importation as appropriate (both successors, so they get the right incoming type, and
3789 // predecessors, so they insert an upcast if needed).
3790 void impReimportSpillClique(BasicBlock* block);
3792 // When we compute a "spill clique" (see above) these byte-maps are allocated to have a byte per basic
3793 // block, and represent the predecessor and successor members of the clique currently being computed.
3794 // *** Access to these will need to be locked in a parallel compiler.
3795 JitExpandArray<BYTE> impSpillCliquePredMembers;
3796 JitExpandArray<BYTE> impSpillCliqueSuccMembers;
3804 // Abstract class for receiving a callback while walking a spill clique
3805 class SpillCliqueWalker
3808 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk) = 0;
3811 // This class is used for setting the bbStkTempsIn and bbStkTempsOut on the blocks within a spill clique
3812 class SetSpillTempsBase : public SpillCliqueWalker
3817 SetSpillTempsBase(unsigned baseTmp) : m_baseTmp(baseTmp)
3820 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3823 // This class is used for implementing impReimportSpillClique part on each block within the spill clique
3824 class ReimportSpillClique : public SpillCliqueWalker
3829 ReimportSpillClique(Compiler* pComp) : m_pComp(pComp)
3832 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3835 // This is the heart of the algorithm for walking spill cliques. It invokes callback->Visit for each
3836 // predecessor or successor within the spill clique
3837 void impWalkSpillCliqueFromPred(BasicBlock* pred, SpillCliqueWalker* callback);
3839 // For a BasicBlock that has already been imported, the EntryState has an array of GenTrees for the
3840 // incoming locals. This walks that list an resets the types of the GenTrees to match the types of
3841 // the VarDscs. They get out of sync when we have int/native int issues (see impReimportSpillClique).
3842 void impRetypeEntryStateTemps(BasicBlock* blk);
3844 BYTE impSpillCliqueGetMember(SpillCliqueDir predOrSucc, BasicBlock* blk);
3845 void impSpillCliqueSetMember(SpillCliqueDir predOrSucc, BasicBlock* blk, BYTE val);
3847 void impPushVar(GenTree* op, typeInfo tiRetVal);
3848 void impLoadVar(unsigned lclNum, IL_OFFSET offset, typeInfo tiRetVal);
3849 void impLoadVar(unsigned lclNum, IL_OFFSET offset)
3851 impLoadVar(lclNum, offset, lvaTable[lclNum].lvVerTypeInfo);
3853 void impLoadArg(unsigned ilArgNum, IL_OFFSET offset);
3854 void impLoadLoc(unsigned ilLclNum, IL_OFFSET offset);
3855 bool impReturnInstruction(BasicBlock* block, int prefixFlags, OPCODE& opcode);
3858 void impMarkLclDstNotPromotable(unsigned tmpNum, GenTree* op, CORINFO_CLASS_HANDLE hClass);
3861 // A free list of linked list nodes used to represent to-do stacks of basic blocks.
3862 struct BlockListNode
3865 BlockListNode* m_next;
3866 BlockListNode(BasicBlock* blk, BlockListNode* next = nullptr) : m_blk(blk), m_next(next)
3869 void* operator new(size_t sz, Compiler* comp);
3871 BlockListNode* impBlockListNodeFreeList;
3873 void FreeBlockListNode(BlockListNode* node);
3875 bool impIsValueType(typeInfo* pTypeInfo);
3876 var_types mangleVarArgsType(var_types type);
3879 regNumber getCallArgIntRegister(regNumber floatReg);
3880 regNumber getCallArgFloatRegister(regNumber intReg);
3881 #endif // FEATURE_VARARG
3884 static unsigned jitTotalMethodCompiled;
3888 static LONG jitNestingLevel;
3891 static BOOL impIsAddressInLocal(GenTree* tree, GenTree** lclVarTreeOut);
3893 void impMakeDiscretionaryInlineObservations(InlineInfo* pInlineInfo, InlineResult* inlineResult);
3895 // STATIC inlining decision based on the IL code.
3896 void impCanInlineIL(CORINFO_METHOD_HANDLE fncHandle,
3897 CORINFO_METHOD_INFO* methInfo,
3899 InlineResult* inlineResult);
3901 void impCheckCanInline(GenTreeCall* call,
3902 CORINFO_METHOD_HANDLE fncHandle,
3904 CORINFO_CONTEXT_HANDLE exactContextHnd,
3905 InlineCandidateInfo** ppInlineCandidateInfo,
3906 InlineResult* inlineResult);
3908 void impInlineRecordArgInfo(InlineInfo* pInlineInfo,
3911 InlineResult* inlineResult);
3913 void impInlineInitVars(InlineInfo* pInlineInfo);
3915 unsigned impInlineFetchLocal(unsigned lclNum DEBUGARG(const char* reason));
3917 GenTree* impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, InlLclVarInfo* lclTypeInfo);
3919 BOOL impInlineIsThis(GenTree* tree, InlArgInfo* inlArgInfo);
3921 BOOL impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTree* additionalTreesToBeEvaluatedBefore,
3922 GenTree* variableBeingDereferenced,
3923 InlArgInfo* inlArgInfo);
3925 void impMarkInlineCandidate(GenTree* call,
3926 CORINFO_CONTEXT_HANDLE exactContextHnd,
3927 bool exactContextNeedsRuntimeLookup,
3928 CORINFO_CALL_INFO* callInfo);
3930 void impMarkInlineCandidateHelper(GenTreeCall* call,
3931 CORINFO_CONTEXT_HANDLE exactContextHnd,
3932 bool exactContextNeedsRuntimeLookup,
3933 CORINFO_CALL_INFO* callInfo);
3935 bool impTailCallRetTypeCompatible(var_types callerRetType,
3936 CORINFO_CLASS_HANDLE callerRetTypeClass,
3937 var_types calleeRetType,
3938 CORINFO_CLASS_HANDLE calleeRetTypeClass);
3940 bool impIsTailCallILPattern(bool tailPrefixed,
3942 const BYTE* codeAddrOfNextOpcode,
3943 const BYTE* codeEnd,
3945 bool* IsCallPopRet = nullptr);
3947 bool impIsImplicitTailCallCandidate(
3948 OPCODE curOpcode, const BYTE* codeAddrOfNextOpcode, const BYTE* codeEnd, int prefixFlags, bool isRecursive);
3950 CORINFO_RESOLVED_TOKEN* impAllocateToken(CORINFO_RESOLVED_TOKEN token);
3953 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3954 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3958 XX Info about the basic-blocks, their contents and the flow analysis XX
3960 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3961 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3965 BasicBlock* fgFirstBB; // Beginning of the basic block list
3966 BasicBlock* fgLastBB; // End of the basic block list
3967 BasicBlock* fgFirstColdBlock; // First block to be placed in the cold section
3968 #if FEATURE_EH_FUNCLETS
3969 BasicBlock* fgFirstFuncletBB; // First block of outlined funclets (to allow block insertion before the funclets)
3971 BasicBlock* fgFirstBBScratch; // Block inserted for initialization stuff. Is nullptr if no such block has been
3973 BasicBlockList* fgReturnBlocks; // list of BBJ_RETURN blocks
3974 unsigned fgEdgeCount; // # of control flow edges between the BBs
3975 unsigned fgBBcount; // # of BBs in the method
3977 unsigned fgBBcountAtCodegen; // # of BBs in the method at the start of codegen
3979 unsigned fgBBNumMax; // The max bbNum that has been assigned to basic blocks
3980 unsigned fgDomBBcount; // # of BBs for which we have dominator and reachability information
3981 BasicBlock** fgBBInvPostOrder; // The flow graph stored in an array sorted in topological order, needed to compute
3982 // dominance. Indexed by block number. Size: fgBBNumMax + 1.
3984 // After the dominance tree is computed, we cache a DFS preorder number and DFS postorder number to compute
3985 // dominance queries in O(1). fgDomTreePreOrder and fgDomTreePostOrder are arrays giving the block's preorder and
3986 // postorder number, respectively. The arrays are indexed by basic block number. (Note that blocks are numbered
3987 // starting from one. Thus, we always waste element zero. This makes debugging easier and makes the code less likely
3988 // to suffer from bugs stemming from forgetting to add or subtract one from the block number to form an array
3989 // index). The arrays are of size fgBBNumMax + 1.
3990 unsigned* fgDomTreePreOrder;
3991 unsigned* fgDomTreePostOrder;
3993 bool fgBBVarSetsInited;
3995 // Allocate array like T* a = new T[fgBBNumMax + 1];
3996 // Using helper so we don't keep forgetting +1.
3997 template <typename T>
3998 T* fgAllocateTypeForEachBlk(CompMemKind cmk = CMK_Unknown)
4000 return getAllocator(cmk).allocate<T>(fgBBNumMax + 1);
4003 // BlockSets are relative to a specific set of BasicBlock numbers. If that changes
4004 // (if the blocks are renumbered), this changes. BlockSets from different epochs
4005 // cannot be meaningfully combined. Note that new blocks can be created with higher
4006 // block numbers without changing the basic block epoch. These blocks *cannot*
4007 // participate in a block set until the blocks are all renumbered, causing the epoch
4008 // to change. This is useful if continuing to use previous block sets is valuable.
4009 // If the epoch is zero, then it is uninitialized, and block sets can't be used.
4010 unsigned fgCurBBEpoch;
4012 unsigned GetCurBasicBlockEpoch()
4014 return fgCurBBEpoch;
4017 // The number of basic blocks in the current epoch. When the blocks are renumbered,
4018 // this is fgBBcount. As blocks are added, fgBBcount increases, fgCurBBEpochSize remains
4019 // the same, until a new BasicBlock epoch is created, such as when the blocks are all renumbered.
4020 unsigned fgCurBBEpochSize;
4022 // The number of "size_t" elements required to hold a bitset large enough for fgCurBBEpochSize
4023 // bits. This is precomputed to avoid doing math every time BasicBlockBitSetTraits::GetArrSize() is called.
4024 unsigned fgBBSetCountInSizeTUnits;
4026 void NewBasicBlockEpoch()
4028 INDEBUG(unsigned oldEpochArrSize = fgBBSetCountInSizeTUnits);
4030 // We have a new epoch. Compute and cache the size needed for new BlockSets.
4032 fgCurBBEpochSize = fgBBNumMax + 1;
4033 fgBBSetCountInSizeTUnits =
4034 roundUp(fgCurBBEpochSize, (unsigned)(sizeof(size_t) * 8)) / unsigned(sizeof(size_t) * 8);
4037 // All BlockSet objects are now invalid!
4038 fgReachabilitySetsValid = false; // the bbReach sets are now invalid!
4039 fgEnterBlksSetValid = false; // the fgEnterBlks set is now invalid!
4043 unsigned epochArrSize = BasicBlockBitSetTraits::GetArrSize(this, sizeof(size_t));
4044 printf("\nNew BlockSet epoch %d, # of blocks (including unused BB00): %u, bitset array size: %u (%s)",
4045 fgCurBBEpoch, fgCurBBEpochSize, epochArrSize, (epochArrSize <= 1) ? "short" : "long");
4046 if ((fgCurBBEpoch != 1) && ((oldEpochArrSize <= 1) != (epochArrSize <= 1)))
4048 // If we're not just establishing the first epoch, and the epoch array size has changed such that we're
4049 // going to change our bitset representation from short (just a size_t bitset) to long (a pointer to an
4050 // array of size_t bitsets), then print that out.
4051 printf("; NOTE: BlockSet size was previously %s!", (oldEpochArrSize <= 1) ? "short" : "long");
4058 void EnsureBasicBlockEpoch()
4060 if (fgCurBBEpochSize != fgBBNumMax + 1)
4062 NewBasicBlockEpoch();
4066 BasicBlock* fgNewBasicBlock(BBjumpKinds jumpKind);
4067 void fgEnsureFirstBBisScratch();
4068 bool fgFirstBBisScratch();
4069 bool fgBBisScratch(BasicBlock* block);
4071 void fgExtendEHRegionBefore(BasicBlock* block);
4072 void fgExtendEHRegionAfter(BasicBlock* block);
4074 BasicBlock* fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
4076 BasicBlock* fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
4078 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
4081 BasicBlock* nearBlk,
4082 bool putInFilter = false,
4083 bool runRarely = false,
4084 bool insertAtEnd = false);
4086 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
4088 bool runRarely = false,
4089 bool insertAtEnd = false);
4091 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind);
4093 BasicBlock* fgNewBBinRegionWorker(BBjumpKinds jumpKind,
4094 BasicBlock* afterBlk,
4095 unsigned xcptnIndex,
4096 bool putInTryRegion);
4098 void fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk);
4099 void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk);
4100 void fgUnlinkBlock(BasicBlock* block);
4102 unsigned fgMeasureIR();
4104 bool fgModified; // True if the flow graph has been modified recently
4105 bool fgComputePredsDone; // Have we computed the bbPreds list
4106 bool fgCheapPredsValid; // Is the bbCheapPreds list valid?
4107 bool fgDomsComputed; // Have we computed the dominator sets?
4108 bool fgOptimizedFinally; // Did we optimize any try-finallys?
4110 bool fgHasSwitch; // any BBJ_SWITCH jumps?
4112 BlockSet fgEnterBlks; // Set of blocks which have a special transfer of control; the "entry" blocks plus EH handler
4116 bool fgReachabilitySetsValid; // Are the bbReach sets valid?
4117 bool fgEnterBlksSetValid; // Is the fgEnterBlks set valid?
4120 bool fgRemoveRestOfBlock; // true if we know that we will throw
4121 bool fgStmtRemoved; // true if we remove statements -> need new DFA
4123 // There are two modes for ordering of the trees.
4124 // - In FGOrderTree, the dominant ordering is the tree order, and the nodes contained in
4125 // each tree and sub-tree are contiguous, and can be traversed (in gtNext/gtPrev order)
4126 // by traversing the tree according to the order of the operands.
4127 // - In FGOrderLinear, the dominant ordering is the linear order.
4134 FlowGraphOrder fgOrder;
4136 // The following are boolean flags that keep track of the state of internal data structures
4138 bool fgStmtListThreaded; // true if the node list is now threaded
4139 bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
4140 bool fgEdgeWeightsComputed; // true after we have called fgComputeEdgeWeights
4141 bool fgHaveValidEdgeWeights; // true if we were successful in computing all of the edge weights
4142 bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
4143 bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
4144 bool fgNeedsUpdateFlowGraph; // true if we need to run fgUpdateFlowGraph
4145 BasicBlock::weight_t fgCalledCount; // count of the number of times this method was called
4146 // This is derived from the profile data
4147 // or is BB_UNITY_WEIGHT when we don't have profile data
4149 #if FEATURE_EH_FUNCLETS
4150 bool fgFuncletsCreated; // true if the funclet creation phase has been run
4151 #endif // FEATURE_EH_FUNCLETS
4153 bool fgGlobalMorph; // indicates if we are during the global morphing phase
4154 // since fgMorphTree can be called from several places
4156 bool impBoxTempInUse; // the temp below is valid and available
4157 unsigned impBoxTemp; // a temporary that is used for boxing
4160 bool jitFallbackCompile; // Are we doing a fallback compile? That is, have we executed a NO_WAY assert,
4161 // and we are trying to compile again in a "safer", minopts mode?
4165 unsigned impInlinedCodeSize;
4168 //-------------------------------------------------------------------------
4174 void fgTransformIndirectCalls();
4178 void fgRemoveEmptyTry();
4180 void fgRemoveEmptyFinally();
4182 void fgMergeFinallyChains();
4184 void fgCloneFinally();
4186 void fgCleanupContinuation(BasicBlock* continuation);
4188 void fgUpdateFinallyTargetFlags();
4190 void fgClearAllFinallyTargetBits();
4192 void fgAddFinallyTargetFlags();
4194 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
4195 // Sometimes we need to defer updating the BBF_FINALLY_TARGET bit. fgNeedToAddFinallyTargetBits signals
4196 // when this is necessary.
4197 bool fgNeedToAddFinallyTargetBits;
4198 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
4200 bool fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block,
4201 BasicBlock* handler,
4202 BlockToBlockMap& continuationMap);
4204 GenTree* fgGetCritSectOfStaticMethod();
4206 #if FEATURE_EH_FUNCLETS
4208 void fgAddSyncMethodEnterExit();
4210 GenTree* fgCreateMonitorTree(unsigned lvaMonitorBool, unsigned lvaThisVar, BasicBlock* block, bool enter);
4212 void fgConvertSyncReturnToLeave(BasicBlock* block);
4214 #endif // FEATURE_EH_FUNCLETS
4216 void fgAddReversePInvokeEnterExit();
4218 bool fgMoreThanOneReturnBlock();
4220 // The number of separate return points in the method.
4221 unsigned fgReturnCount;
4223 void fgAddInternal();
4225 bool fgFoldConditional(BasicBlock* block);
4227 void fgMorphStmts(BasicBlock* block, bool* lnot, bool* loadw);
4228 void fgMorphBlocks();
4230 bool fgMorphBlockStmt(BasicBlock* block, GenTreeStmt* stmt DEBUGARG(const char* msg));
4232 void fgSetOptions();
4235 static fgWalkPreFn fgAssertNoQmark;
4236 void fgPreExpandQmarkChecks(GenTree* expr);
4237 void fgPostExpandQmarkChecks();
4238 static void fgCheckQmarkAllowedForm(GenTree* tree);
4241 IL_OFFSET fgFindBlockILOffset(BasicBlock* block);
4243 BasicBlock* fgSplitBlockAtBeginning(BasicBlock* curr);
4244 BasicBlock* fgSplitBlockAtEnd(BasicBlock* curr);
4245 BasicBlock* fgSplitBlockAfterStatement(BasicBlock* curr, GenTree* stmt);
4246 BasicBlock* fgSplitBlockAfterNode(BasicBlock* curr, GenTree* node); // for LIR
4247 BasicBlock* fgSplitEdge(BasicBlock* curr, BasicBlock* succ);
4249 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, BasicBlock* block, IL_OFFSETX offs);
4250 GenTreeStmt* fgNewStmtFromTree(GenTree* tree);
4251 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, BasicBlock* block);
4252 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, IL_OFFSETX offs);
4254 GenTree* fgGetTopLevelQmark(GenTree* expr, GenTree** ppDst = nullptr);
4255 void fgExpandQmarkForCastInstOf(BasicBlock* block, GenTree* stmt);
4256 void fgExpandQmarkStmt(BasicBlock* block, GenTree* expr);
4257 void fgExpandQmarkNodes();
4261 // Do "simple lowering." This functionality is (conceptually) part of "general"
4262 // lowering that is distributed between fgMorph and the lowering phase of LSRA.
4263 void fgSimpleLowering();
4265 GenTree* fgInitThisClass();
4267 GenTreeCall* fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper);
4269 GenTreeCall* fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls);
4271 bool backendRequiresLocalVarLifetimes()
4273 return !opts.MinOpts() || m_pLinearScan->willEnregisterLocalVars();
4276 void fgLocalVarLiveness();
4278 void fgLocalVarLivenessInit();
4280 void fgPerNodeLocalVarLiveness(GenTree* node);
4281 void fgPerBlockLocalVarLiveness();
4283 VARSET_VALRET_TP fgGetHandlerLiveVars(BasicBlock* block);
4285 void fgLiveVarAnalysis(bool updateInternalOnly = false);
4287 void fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call);
4289 void fgComputeLifeTrackedLocalUse(VARSET_TP& life, LclVarDsc& varDsc, GenTreeLclVarCommon* node);
4290 bool fgComputeLifeTrackedLocalDef(VARSET_TP& life,
4291 VARSET_VALARG_TP keepAliveVars,
4293 GenTreeLclVarCommon* node);
4294 void fgComputeLifeUntrackedLocal(VARSET_TP& life,
4295 VARSET_VALARG_TP keepAliveVars,
4297 GenTreeLclVarCommon* lclVarNode);
4298 bool fgComputeLifeLocal(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTree* lclVarNode);
4300 void fgComputeLife(VARSET_TP& life,
4303 VARSET_VALARG_TP volatileVars,
4304 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
4306 void fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALARG_TP volatileVars);
4308 bool fgRemoveDeadStore(GenTree** pTree,
4310 VARSET_VALARG_TP life,
4312 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
4314 // For updating liveset during traversal AFTER fgComputeLife has completed
4315 VARSET_VALRET_TP fgGetVarBits(GenTree* tree);
4316 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tree);
4318 // Returns the set of live variables after endTree,
4319 // assuming that liveSet is the set of live variables BEFORE tree.
4320 // Requires that fgComputeLife has completed, and that tree is in the same
4321 // statement as endTree, and that it comes before endTree in execution order
4323 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tree, GenTree* endTree)
4325 VARSET_TP newLiveSet(VarSetOps::MakeCopy(this, liveSet));
4326 while (tree != nullptr && tree != endTree->gtNext)
4328 VarSetOps::AssignNoCopy(this, newLiveSet, fgUpdateLiveSet(newLiveSet, tree));
4329 tree = tree->gtNext;
4331 assert(tree == endTree->gtNext);
4335 void fgInterBlockLocalVarLiveness();
4337 // The presence of a partial definition presents some difficulties for SSA: this is both a use of some SSA name
4338 // of "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
4339 // whether to treat that as the use or def. It chooses the "use", and thus the old SSA name. This map allows us
4340 // to record/recover the "def" SSA number, given the lcl var node for "x" in such a tree.
4341 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, unsigned> NodeToUnsignedMap;
4342 NodeToUnsignedMap* m_opAsgnVarDefSsaNums;
4343 NodeToUnsignedMap* GetOpAsgnVarDefSsaNums()
4345 if (m_opAsgnVarDefSsaNums == nullptr)
4347 m_opAsgnVarDefSsaNums = new (getAllocator()) NodeToUnsignedMap(getAllocator());
4349 return m_opAsgnVarDefSsaNums;
4352 // Requires value numbering phase to have completed. Returns the value number ("gtVN") of the
4353 // "tree," EXCEPT in the case of GTF_VAR_USEASG, because the tree node's gtVN member is the
4354 // "use" VN. Performs a lookup into the map of (use asg tree -> def VN.) to return the "def's"
4356 inline ValueNum GetUseAsgDefVNOrTreeVN(GenTree* tree);
4358 // Requires that "lcl" has the GTF_VAR_DEF flag set. Returns the SSA number of "lcl".
4359 // Except: assumes that lcl is a def, and if it is
4360 // a partial def (GTF_VAR_USEASG), looks up and returns the SSA number for the "def",
4361 // rather than the "use" SSA number recorded in the tree "lcl".
4362 inline unsigned GetSsaNumForLocalVarDef(GenTree* lcl);
4364 // Performs SSA conversion.
4367 // Reset any data structures to the state expected by "fgSsaBuild", so it can be run again.
4368 void fgResetForSsa();
4370 unsigned fgSsaPassesCompleted; // Number of times fgSsaBuild has been run.
4372 // Returns "true" if a struct temp of the given type requires needs zero init in this block
4373 inline bool fgStructTempNeedsExplicitZeroInit(LclVarDsc* varDsc, BasicBlock* block);
4375 // The value numbers for this compilation.
4376 ValueNumStore* vnStore;
4379 ValueNumStore* GetValueNumStore()
4384 // Do value numbering (assign a value number to each
4386 void fgValueNumber();
4388 // Computes new GcHeap VN via the assignment H[elemTypeEq][arrVN][inx][fldSeq] = rhsVN.
4389 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
4390 // The 'indType' is the indirection type of the lhs of the assignment and will typically
4391 // match the element type of the array or fldSeq. When this type doesn't match
4392 // or if the fldSeq is 'NotAField' we invalidate the array contents H[elemTypeEq][arrVN]
4394 ValueNum fgValueNumberArrIndexAssign(CORINFO_CLASS_HANDLE elemTypeEq,
4397 FieldSeqNode* fldSeq,
4401 // Requires that "tree" is a GT_IND marked as an array index, and that its address argument
4402 // has been parsed to yield the other input arguments. If evaluation of the address
4403 // can raise exceptions, those should be captured in the exception set "excVN."
4404 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
4405 // Marks "tree" with the VN for H[elemTypeEq][arrVN][inx][fldSeq] (for the liberal VN; a new unique
4406 // VN for the conservative VN.) Also marks the tree's argument as the address of an array element.
4407 // The type tree->TypeGet() will typically match the element type of the array or fldSeq.
4408 // When this type doesn't match or if the fldSeq is 'NotAField' we return a new unique VN
4410 ValueNum fgValueNumberArrIndexVal(GenTree* tree,
4411 CORINFO_CLASS_HANDLE elemTypeEq,
4415 FieldSeqNode* fldSeq);
4417 // Requires "funcApp" to be a VNF_PtrToArrElem, and "addrXvn" to represent the exception set thrown
4418 // by evaluating the array index expression "tree". Returns the value number resulting from
4419 // dereferencing the array in the current GcHeap state. If "tree" is non-null, it must be the
4420 // "GT_IND" that does the dereference, and it is given the returned value number.
4421 ValueNum fgValueNumberArrIndexVal(GenTree* tree, struct VNFuncApp* funcApp, ValueNum addrXvn);
4423 // Compute the value number for a byref-exposed load of the given type via the given pointerVN.
4424 ValueNum fgValueNumberByrefExposedLoad(var_types type, ValueNum pointerVN);
4426 unsigned fgVNPassesCompleted; // Number of times fgValueNumber has been run.
4428 // Utility functions for fgValueNumber.
4430 // Perform value-numbering for the trees in "blk".
4431 void fgValueNumberBlock(BasicBlock* blk);
4433 // Requires that "entryBlock" is the entry block of loop "loopNum", and that "loopNum" is the
4434 // innermost loop of which "entryBlock" is the entry. Returns the value number that should be
4435 // assumed for the memoryKind at the start "entryBlk".
4436 ValueNum fgMemoryVNForLoopSideEffects(MemoryKind memoryKind, BasicBlock* entryBlock, unsigned loopNum);
4438 // Called when an operation (performed by "tree", described by "msg") may cause the GcHeap to be mutated.
4439 // As GcHeap is a subset of ByrefExposed, this will also annotate the ByrefExposed mutation.
4440 void fgMutateGcHeap(GenTree* tree DEBUGARG(const char* msg));
4442 // Called when an operation (performed by "tree", described by "msg") may cause an address-exposed local to be
4444 void fgMutateAddressExposedLocal(GenTree* tree DEBUGARG(const char* msg));
4446 // For a GC heap store at curTree, record the new curMemoryVN's and update curTree's MemorySsaMap.
4447 // As GcHeap is a subset of ByrefExposed, this will also record the ByrefExposed store.
4448 void recordGcHeapStore(GenTree* curTree, ValueNum gcHeapVN DEBUGARG(const char* msg));
4450 // For a store to an address-exposed local at curTree, record the new curMemoryVN and update curTree's MemorySsaMap.
4451 void recordAddressExposedLocalStore(GenTree* curTree, ValueNum memoryVN DEBUGARG(const char* msg));
4453 // Tree caused an update in the current memory VN. If "tree" has an associated heap SSA #, record that
4454 // value in that SSA #.
4455 void fgValueNumberRecordMemorySsa(MemoryKind memoryKind, GenTree* tree);
4457 // The input 'tree' is a leaf node that is a constant
4458 // Assign the proper value number to the tree
4459 void fgValueNumberTreeConst(GenTree* tree);
4461 // Assumes that all inputs to "tree" have had value numbers assigned; assigns a VN to tree.
4462 // (With some exceptions: the VN of the lhs of an assignment is assigned as part of the
4464 void fgValueNumberTree(GenTree* tree);
4466 // Does value-numbering for a block assignment.
4467 void fgValueNumberBlockAssignment(GenTree* tree);
4469 // Does value-numbering for a cast tree.
4470 void fgValueNumberCastTree(GenTree* tree);
4472 // Does value-numbering for an intrinsic tree.
4473 void fgValueNumberIntrinsic(GenTree* tree);
4475 // Does value-numbering for a call. We interpret some helper calls.
4476 void fgValueNumberCall(GenTreeCall* call);
4478 // The VN of some nodes in "args" may have changed -- reassign VNs to the arg list nodes.
4479 void fgUpdateArgListVNs(GenTreeArgList* args);
4481 // Does value-numbering for a helper "call" that has a VN function symbol "vnf".
4482 void fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc);
4484 // Requires "helpCall" to be a helper call. Assigns it a value number;
4485 // we understand the semantics of some of the calls. Returns "true" if
4486 // the call may modify the heap (we assume arbitrary memory side effects if so).
4487 bool fgValueNumberHelperCall(GenTreeCall* helpCall);
4489 // Requires that "helpFunc" is one of the pure Jit Helper methods.
4490 // Returns the corresponding VNFunc to use for value numbering
4491 VNFunc fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc);
4493 // Adds the exception set for the current tree node which has a memory indirection operation
4494 void fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree* baseAddr);
4496 // Adds the exception sets for the current tree node which is performing a division or modulus operation
4497 void fgValueNumberAddExceptionSetForDivision(GenTree* tree);
4499 // Adds the exception set for the current tree node which is performing a overflow checking operation
4500 void fgValueNumberAddExceptionSetForOverflow(GenTree* tree);
4502 // Adds the exception set for the current tree node which is performing a ckfinite operation
4503 void fgValueNumberAddExceptionSetForCkFinite(GenTree* tree);
4505 // Adds the exception sets for the current tree node
4506 void fgValueNumberAddExceptionSet(GenTree* tree);
4508 // These are the current value number for the memory implicit variables while
4509 // doing value numbering. These are the value numbers under the "liberal" interpretation
4510 // of memory values; the "conservative" interpretation needs no VN, since every access of
4511 // memory yields an unknown value.
4512 ValueNum fgCurMemoryVN[MemoryKindCount];
4514 // Return a "pseudo"-class handle for an array element type. If "elemType" is TYP_STRUCT,
4515 // requires "elemStructType" to be non-null (and to have a low-order zero). Otherwise, low order bit
4516 // is 1, and the rest is an encoding of "elemTyp".
4517 static CORINFO_CLASS_HANDLE EncodeElemType(var_types elemTyp, CORINFO_CLASS_HANDLE elemStructType)
4519 if (elemStructType != nullptr)
4521 assert(varTypeIsStruct(elemTyp) || elemTyp == TYP_REF || elemTyp == TYP_BYREF ||
4522 varTypeIsIntegral(elemTyp));
4523 assert((size_t(elemStructType) & 0x1) == 0x0); // Make sure the encoding below is valid.
4524 return elemStructType;
4528 assert(elemTyp != TYP_STRUCT);
4529 elemTyp = varTypeUnsignedToSigned(elemTyp);
4530 return CORINFO_CLASS_HANDLE(size_t(elemTyp) << 1 | 0x1);
4533 // If "clsHnd" is the result of an "EncodePrim" call, returns true and sets "*pPrimType" to the
4534 // var_types it represents. Otherwise, returns TYP_STRUCT (on the assumption that "clsHnd" is
4535 // the struct type of the element).
4536 static var_types DecodeElemType(CORINFO_CLASS_HANDLE clsHnd)
4538 size_t clsHndVal = size_t(clsHnd);
4539 if (clsHndVal & 0x1)
4541 return var_types(clsHndVal >> 1);
4549 // Convert a BYTE which represents the VM's CorInfoGCtype to the JIT's var_types
4550 var_types getJitGCType(BYTE gcType);
4552 enum structPassingKind
4554 SPK_Unknown, // Invalid value, never returned
4555 SPK_PrimitiveType, // The struct is passed/returned using a primitive type.
4556 SPK_EnclosingType, // Like SPK_Primitive type, but used for return types that
4557 // require a primitive type temp that is larger than the struct size.
4558 // Currently used for structs of size 3, 5, 6, or 7 bytes.
4559 SPK_ByValue, // The struct is passed/returned by value (using the ABI rules)
4560 // for ARM64 and UNIX_X64 in multiple registers. (when all of the
4561 // parameters registers are used, then the stack will be used)
4562 // for X86 passed on the stack, for ARM32 passed in registers
4563 // or the stack or split between registers and the stack.
4564 SPK_ByValueAsHfa, // The struct is passed/returned as an HFA in multiple registers.
4566 }; // The struct is passed/returned by reference to a copy/buffer.
4568 // Get the "primitive" type that is is used when we are given a struct of size 'structSize'.
4569 // For pointer sized structs the 'clsHnd' is used to determine if the struct contains GC ref.
4570 // A "primitive" type is one of the scalar types: byte, short, int, long, ref, float, double
4571 // If we can't or shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
4573 // isVarArg is passed for use on Windows Arm64 to change the decision returned regarding
4576 var_types getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS_HANDLE clsHnd, bool isVarArg);
4578 // Get the type that is used to pass values of the given struct type.
4579 // isVarArg is passed for use on Windows Arm64 to change the decision returned regarding
4582 var_types getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4583 structPassingKind* wbPassStruct,
4585 unsigned structSize);
4587 // Get the type that is used to return values of the given struct type.
4588 // If the size is unknown, pass 0 and it will be determined from 'clsHnd'.
4589 var_types getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4590 structPassingKind* wbPassStruct = nullptr,
4591 unsigned structSize = 0);
4594 // Print a representation of "vnp" or "vn" on standard output.
4595 // If "level" is non-zero, we also print out a partial expansion of the value.
4596 void vnpPrint(ValueNumPair vnp, unsigned level);
4597 void vnPrint(ValueNum vn, unsigned level);
4600 bool fgDominate(BasicBlock* b1, BasicBlock* b2); // Return true if b1 dominates b2
4602 // Dominator computation member functions
4603 // Not exposed outside Compiler
4605 bool fgReachable(BasicBlock* b1, BasicBlock* b2); // Returns true if block b1 can reach block b2
4607 void fgComputeDoms(); // Computes the immediate dominators for each basic block in the
4608 // flow graph. We first assume the fields bbIDom on each
4609 // basic block are invalid. This computation is needed later
4610 // by fgBuildDomTree to build the dominance tree structure.
4611 // Based on: A Simple, Fast Dominance Algorithm
4612 // by Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
4614 void fgCompDominatedByExceptionalEntryBlocks();
4616 BlockSet_ValRet_T fgGetDominatorSet(BasicBlock* block); // Returns a set of blocks that dominate the given block.
4617 // Note: this is relatively slow compared to calling fgDominate(),
4618 // especially if dealing with a single block versus block check.
4620 void fgComputeReachabilitySets(); // Compute bbReach sets. (Also sets BBF_GC_SAFE_POINT flag on blocks.)
4622 void fgComputeEnterBlocksSet(); // Compute the set of entry blocks, 'fgEnterBlks'.
4624 bool fgRemoveUnreachableBlocks(); // Remove blocks determined to be unreachable by the bbReach sets.
4626 void fgComputeReachability(); // Perform flow graph node reachability analysis.
4628 BasicBlock* fgIntersectDom(BasicBlock* a, BasicBlock* b); // Intersect two immediate dominator sets.
4630 void fgDfsInvPostOrder(); // In order to compute dominance using fgIntersectDom, the flow graph nodes must be
4631 // processed in topological sort, this function takes care of that.
4633 void fgDfsInvPostOrderHelper(BasicBlock* block, BlockSet& visited, unsigned* count);
4635 BlockSet_ValRet_T fgDomFindStartNodes(); // Computes which basic blocks don't have incoming edges in the flow graph.
4636 // Returns this as a set.
4638 BlockSet_ValRet_T fgDomTreeEntryNodes(BasicBlockList** domTree); // Computes which nodes in the dominance forest are
4639 // root nodes. Returns this as a set.
4642 void fgDispDomTree(BasicBlockList** domTree); // Helper that prints out the Dominator Tree in debug builds.
4645 void fgBuildDomTree(); // Once we compute all the immediate dominator sets for each node in the flow graph
4646 // (performed by fgComputeDoms), this procedure builds the dominance tree represented
4649 // In order to speed up the queries of the form 'Does A dominates B', we can perform a DFS preorder and postorder
4650 // traversal of the dominance tree and the dominance query will become A dominates B iif preOrder(A) <= preOrder(B)
4651 // && postOrder(A) >= postOrder(B) making the computation O(1).
4652 void fgTraverseDomTree(unsigned bbNum, BasicBlockList** domTree, unsigned* preNum, unsigned* postNum);
4654 // When the flow graph changes, we need to update the block numbers, predecessor lists, reachability sets, and
4656 void fgUpdateChangedFlowGraph();
4659 // Compute the predecessors of the blocks in the control flow graph.
4660 void fgComputePreds();
4662 // Remove all predecessor information.
4663 void fgRemovePreds();
4665 // Compute the cheap flow graph predecessors lists. This is used in some early phases
4666 // before the full predecessors lists are computed.
4667 void fgComputeCheapPreds();
4670 void fgAddCheapPred(BasicBlock* block, BasicBlock* blockPred);
4672 void fgRemoveCheapPred(BasicBlock* block, BasicBlock* blockPred);
4682 // Initialize the per-block variable sets (used for liveness analysis).
4683 void fgInitBlockVarSets();
4685 // true if we've gone through and created GC Poll calls.
4686 bool fgGCPollsCreated;
4687 void fgMarkGCPollBlocks();
4688 void fgCreateGCPolls();
4689 bool fgCreateGCPoll(GCPollType pollType, BasicBlock* block);
4691 // Requires that "block" is a block that returns from
4692 // a finally. Returns the number of successors (jump targets of
4693 // of blocks in the covered "try" that did a "LEAVE".)
4694 unsigned fgNSuccsOfFinallyRet(BasicBlock* block);
4696 // Requires that "block" is a block that returns (in the sense of BBJ_EHFINALLYRET) from
4697 // a finally. Returns its "i"th successor (jump targets of
4698 // of blocks in the covered "try" that did a "LEAVE".)
4699 // Requires that "i" < fgNSuccsOfFinallyRet(block).
4700 BasicBlock* fgSuccOfFinallyRet(BasicBlock* block, unsigned i);
4703 // Factor out common portions of the impls of the methods above.
4704 void fgSuccOfFinallyRetWork(BasicBlock* block, unsigned i, BasicBlock** bres, unsigned* nres);
4707 // For many purposes, it is desirable to be able to enumerate the *distinct* targets of a switch statement,
4708 // skipping duplicate targets. (E.g., in flow analyses that are only interested in the set of possible targets.)
4709 // SwitchUniqueSuccSet contains the non-duplicated switch targets.
4710 // (Code that modifies the jump table of a switch has an obligation to call Compiler::UpdateSwitchTableTarget,
4711 // which in turn will call the "UpdateTarget" method of this type if a SwitchUniqueSuccSet has already
4712 // been computed for the switch block. If a switch block is deleted or is transformed into a non-switch,
4713 // we leave the entry associated with the block, but it will no longer be accessed.)
4714 struct SwitchUniqueSuccSet
4716 unsigned numDistinctSuccs; // Number of distinct targets of the switch.
4717 BasicBlock** nonDuplicates; // Array of "numDistinctSuccs", containing all the distinct switch target
4720 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4721 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4722 // remove it from "this", and ensure that "to" is a member. Use "alloc" to do any required allocation.
4723 void UpdateTarget(CompAllocator alloc, BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4726 typedef JitHashTable<BasicBlock*, JitPtrKeyFuncs<BasicBlock>, SwitchUniqueSuccSet> BlockToSwitchDescMap;
4729 // Maps BasicBlock*'s that end in switch statements to SwitchUniqueSuccSets that allow
4730 // iteration over only the distinct successors.
4731 BlockToSwitchDescMap* m_switchDescMap;
4734 BlockToSwitchDescMap* GetSwitchDescMap(bool createIfNull = true)
4736 if ((m_switchDescMap == nullptr) && createIfNull)
4738 m_switchDescMap = new (getAllocator()) BlockToSwitchDescMap(getAllocator());
4740 return m_switchDescMap;
4743 // Invalidate the map of unique switch block successors. For example, since the hash key of the map
4744 // depends on block numbers, we must invalidate the map when the blocks are renumbered, to ensure that
4745 // we don't accidentally look up and return the wrong switch data.
4746 void InvalidateUniqueSwitchSuccMap()
4748 m_switchDescMap = nullptr;
4751 // Requires "switchBlock" to be a block that ends in a switch. Returns
4752 // the corresponding SwitchUniqueSuccSet.
4753 SwitchUniqueSuccSet GetDescriptorForSwitch(BasicBlock* switchBlk);
4755 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4756 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4757 // remove it from "this", and ensure that "to" is a member.
4758 void UpdateSwitchTableTarget(BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4760 // Remove the "SwitchUniqueSuccSet" of "switchBlk" in the BlockToSwitchDescMap.
4761 void fgInvalidateSwitchDescMapEntry(BasicBlock* switchBlk);
4763 BasicBlock* fgFirstBlockOfHandler(BasicBlock* block);
4765 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred);
4767 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred, flowList*** ptrToPred);
4769 flowList* fgSpliceOutPred(BasicBlock* block, BasicBlock* blockPred);
4771 flowList* fgRemoveRefPred(BasicBlock* block, BasicBlock* blockPred);
4773 flowList* fgRemoveAllRefPreds(BasicBlock* block, BasicBlock* blockPred);
4775 flowList* fgRemoveAllRefPreds(BasicBlock* block, flowList** ptrToPred);
4777 void fgRemoveBlockAsPred(BasicBlock* block);
4779 void fgChangeSwitchBlock(BasicBlock* oldSwitchBlock, BasicBlock* newSwitchBlock);
4781 void fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* newTarget, BasicBlock* oldTarget);
4783 void fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, BasicBlock* oldTarget);
4785 void fgReplacePred(BasicBlock* block, BasicBlock* oldPred, BasicBlock* newPred);
4787 flowList* fgAddRefPred(BasicBlock* block,
4788 BasicBlock* blockPred,
4789 flowList* oldEdge = nullptr,
4790 bool initializingPreds = false); // Only set to 'true' when we are computing preds in
4793 void fgFindBasicBlocks();
4795 bool fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt);
4797 bool fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionIndex, bool putInTryRegion);
4799 BasicBlock* fgFindInsertPoint(unsigned regionIndex,
4800 bool putInTryRegion,
4801 BasicBlock* startBlk,
4803 BasicBlock* nearBlk,
4804 BasicBlock* jumpBlk,
4807 unsigned fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNesting = nullptr);
4809 void fgRemoveEmptyBlocks();
4811 void fgRemoveStmt(BasicBlock* block, GenTree* stmt);
4813 bool fgCheckRemoveStmt(BasicBlock* block, GenTree* stmt);
4815 void fgCreateLoopPreHeader(unsigned lnum);
4817 void fgUnreachableBlock(BasicBlock* block);
4819 void fgRemoveConditionalJump(BasicBlock* block);
4821 BasicBlock* fgLastBBInMainFunction();
4823 BasicBlock* fgEndBBAfterMainFunction();
4825 void fgUnlinkRange(BasicBlock* bBeg, BasicBlock* bEnd);
4827 void fgRemoveBlock(BasicBlock* block, bool unreachable);
4829 bool fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4831 void fgCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4833 void fgUpdateLoopsAfterCompacting(BasicBlock* block, BasicBlock* bNext);
4835 BasicBlock* fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst);
4837 bool fgRenumberBlocks();
4839 bool fgExpandRarelyRunBlocks();
4841 bool fgEhAllowsMoveBlock(BasicBlock* bBefore, BasicBlock* bAfter);
4843 void fgMoveBlocksAfter(BasicBlock* bStart, BasicBlock* bEnd, BasicBlock* insertAfterBlk);
4845 enum FG_RELOCATE_TYPE
4847 FG_RELOCATE_TRY, // relocate the 'try' region
4848 FG_RELOCATE_HANDLER // relocate the handler region (including the filter if necessary)
4850 BasicBlock* fgRelocateEHRange(unsigned regionIndex, FG_RELOCATE_TYPE relocateType);
4852 #if FEATURE_EH_FUNCLETS
4853 #if defined(_TARGET_ARM_)
4854 void fgClearFinallyTargetBit(BasicBlock* block);
4855 #endif // defined(_TARGET_ARM_)
4856 bool fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block);
4857 bool fgAnyIntraHandlerPreds(BasicBlock* block);
4858 void fgInsertFuncletPrologBlock(BasicBlock* block);
4859 void fgCreateFuncletPrologBlocks();
4860 void fgCreateFunclets();
4861 #else // !FEATURE_EH_FUNCLETS
4862 bool fgRelocateEHRegions();
4863 #endif // !FEATURE_EH_FUNCLETS
4865 bool fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* target);
4867 bool fgBlockEndFavorsTailDuplication(BasicBlock* block);
4869 bool fgBlockIsGoodTailDuplicationCandidate(BasicBlock* block);
4871 bool fgOptimizeEmptyBlock(BasicBlock* block);
4873 bool fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBlock* bDest);
4875 bool fgOptimizeBranch(BasicBlock* bJump);
4877 bool fgOptimizeSwitchBranches(BasicBlock* block);
4879 bool fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev);
4881 bool fgOptimizeSwitchJumps();
4883 void fgPrintEdgeWeights();
4885 void fgComputeBlockAndEdgeWeights();
4886 BasicBlock::weight_t fgComputeMissingBlockWeights();
4887 void fgComputeCalledCount(BasicBlock::weight_t returnWeight);
4888 void fgComputeEdgeWeights();
4890 void fgReorderBlocks();
4892 void fgDetermineFirstColdBlock();
4894 bool fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc = nullptr);
4896 bool fgUpdateFlowGraph(bool doTailDup = false);
4898 void fgFindOperOrder();
4900 // method that returns if you should split here
4901 typedef bool(fgSplitPredicate)(GenTree* tree, GenTree* parent, fgWalkData* data);
4903 void fgSetBlockOrder();
4905 void fgRemoveReturnBlock(BasicBlock* block);
4907 /* Helper code that has been factored out */
4908 inline void fgConvertBBToThrowBB(BasicBlock* block);
4910 bool fgCastNeeded(GenTree* tree, var_types toType);
4911 GenTree* fgDoNormalizeOnStore(GenTree* tree);
4912 GenTree* fgMakeTmpArgNode(fgArgTabEntry* curArgTabEntry);
4914 // The following check for loops that don't execute calls
4915 bool fgLoopCallMarked;
4917 void fgLoopCallTest(BasicBlock* srcBB, BasicBlock* dstBB);
4918 void fgLoopCallMark();
4920 void fgMarkLoopHead(BasicBlock* block);
4922 unsigned fgGetCodeEstimate(BasicBlock* block);
4925 const char* fgProcessEscapes(const char* nameIn, escapeMapping_t* map);
4926 FILE* fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, LPCWSTR type);
4927 bool fgDumpFlowGraph(Phases phase);
4929 #endif // DUMP_FLOWGRAPHS
4934 void fgDispBBLiveness(BasicBlock* block);
4935 void fgDispBBLiveness();
4936 void fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth = 0);
4937 void fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, bool dumpTrees);
4938 void fgDispBasicBlocks(bool dumpTrees = false);
4939 void fgDumpStmtTree(GenTree* stmt, unsigned bbNum);
4940 void fgDumpBlock(BasicBlock* block);
4941 void fgDumpTrees(BasicBlock* firstBlock, BasicBlock* lastBlock);
4943 static fgWalkPreFn fgStress64RsltMulCB;
4944 void fgStress64RsltMul();
4945 void fgDebugCheckUpdate();
4946 void fgDebugCheckBBlist(bool checkBBNum = false, bool checkBBRefs = true);
4947 void fgDebugCheckBlockLinks();
4948 void fgDebugCheckLinks(bool morphTrees = false);
4949 void fgDebugCheckStmtsList(BasicBlock* block, bool morphTrees);
4950 void fgDebugCheckNodeLinks(BasicBlock* block, GenTree* stmt);
4951 void fgDebugCheckNodesUniqueness();
4953 void fgDebugCheckFlags(GenTree* tree);
4954 void fgDebugCheckFlagsHelper(GenTree* tree, unsigned treeFlags, unsigned chkFlags);
4955 void fgDebugCheckTryFinallyExits();
4958 static GenTree* fgGetFirstNode(GenTree* tree);
4960 //--------------------- Walking the trees in the IR -----------------------
4965 fgWalkPreFn* wtprVisitorFn;
4966 fgWalkPostFn* wtpoVisitorFn;
4967 void* pCallbackData; // user-provided data
4968 bool wtprLclsOnly; // whether to only visit lclvar nodes
4969 GenTree* parent; // parent of current node, provided to callback
4970 GenTreeStack* parentStack; // stack of parent nodes, if asked for
4972 bool printModified; // callback can use this
4976 fgWalkResult fgWalkTreePre(GenTree** pTree,
4977 fgWalkPreFn* visitor,
4978 void* pCallBackData = nullptr,
4979 bool lclVarsOnly = false,
4980 bool computeStack = false);
4982 fgWalkResult fgWalkTree(GenTree** pTree,
4983 fgWalkPreFn* preVisitor,
4984 fgWalkPostFn* postVisitor,
4985 void* pCallBackData = nullptr);
4987 void fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData);
4991 fgWalkResult fgWalkTreePost(GenTree** pTree,
4992 fgWalkPostFn* visitor,
4993 void* pCallBackData = nullptr,
4994 bool computeStack = false);
4996 // An fgWalkPreFn that looks for expressions that have inline throws in
4997 // minopts mode. Basically it looks for tress with gtOverflowEx() or
4998 // GTF_IND_RNGCHK. It returns WALK_ABORT if one is found. It
4999 // returns WALK_SKIP_SUBTREES if GTF_EXCEPT is not set (assumes flags
5000 // properly propagated to parent trees). It returns WALK_CONTINUE
5002 static fgWalkResult fgChkThrowCB(GenTree** pTree, Compiler::fgWalkData* data);
5003 static fgWalkResult fgChkLocAllocCB(GenTree** pTree, Compiler::fgWalkData* data);
5004 static fgWalkResult fgChkQmarkCB(GenTree** pTree, Compiler::fgWalkData* data);
5006 /**************************************************************************
5008 *************************************************************************/
5011 friend class SsaBuilder;
5012 friend struct ValueNumberState;
5014 //--------------------- Detect the basic blocks ---------------------------
5016 BasicBlock** fgBBs; // Table of pointers to the BBs
5018 void fgInitBBLookup();
5019 BasicBlock* fgLookupBB(unsigned addr);
5021 void fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, FixedBitVect* jumpTarget);
5023 void fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock);
5025 void fgLinkBasicBlocks();
5027 unsigned fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, FixedBitVect* jumpTarget);
5029 void fgCheckBasicBlockControlFlow();
5031 void fgControlFlowPermitted(BasicBlock* blkSrc,
5032 BasicBlock* blkDest,
5033 BOOL IsLeave = false /* is the src a leave block */);
5035 bool fgFlowToFirstBlockOfInnerTry(BasicBlock* blkSrc, BasicBlock* blkDest, bool sibling);
5037 void fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, bool isInlining);
5039 void fgAdjustForAddressExposedOrWrittenThis();
5041 bool fgProfileData_ILSizeMismatch;
5042 ICorJitInfo::ProfileBuffer* fgProfileBuffer;
5043 ULONG fgProfileBufferCount;
5044 ULONG fgNumProfileRuns;
5046 unsigned fgStressBBProf()
5049 unsigned result = JitConfig.JitStressBBProf();
5052 if (compStressCompile(STRESS_BB_PROFILE, 15))
5063 bool fgHaveProfileData();
5064 bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weight);
5065 void fgInstrumentMethod();
5068 // fgIsUsingProfileWeights - returns true if we have real profile data for this method
5069 // or if we have some fake profile data for the stress mode
5070 bool fgIsUsingProfileWeights()
5072 return (fgHaveProfileData() || fgStressBBProf());
5075 // fgProfileRunsCount - returns total number of scenario runs for the profile data
5076 // or BB_UNITY_WEIGHT when we aren't using profile data.
5077 unsigned fgProfileRunsCount()
5079 return fgIsUsingProfileWeights() ? fgNumProfileRuns : BB_UNITY_WEIGHT;
5082 //-------- Insert a statement at the start or end of a basic block --------
5086 static bool fgBlockContainsStatementBounded(BasicBlock* block, GenTree* stmt, bool answerOnBoundExceeded = true);
5090 GenTreeStmt* fgInsertStmtAtEnd(BasicBlock* block, GenTree* node);
5092 public: // Used by linear scan register allocation
5093 GenTreeStmt* fgInsertStmtNearEnd(BasicBlock* block, GenTree* node);
5096 GenTree* fgInsertStmtAtBeg(BasicBlock* block, GenTree* stmt);
5097 GenTree* fgInsertStmtAfter(BasicBlock* block, GenTree* insertionPoint, GenTree* stmt);
5099 public: // Used by linear scan register allocation
5100 GenTree* fgInsertStmtBefore(BasicBlock* block, GenTree* insertionPoint, GenTree* stmt);
5103 GenTree* fgInsertStmtListAfter(BasicBlock* block, GenTree* stmtAfter, GenTree* stmtList);
5105 // Create a new temporary variable to hold the result of *ppTree,
5106 // and transform the graph accordingly.
5107 GenTree* fgInsertCommaFormTemp(GenTree** ppTree, CORINFO_CLASS_HANDLE structType = nullptr);
5108 GenTree* fgMakeMultiUse(GenTree** ppTree);
5111 // Recognize a bitwise rotation pattern and convert into a GT_ROL or a GT_ROR node.
5112 GenTree* fgRecognizeAndMorphBitwiseRotation(GenTree* tree);
5113 bool fgOperIsBitwiseRotationRoot(genTreeOps oper);
5115 //-------- Determine the order in which the trees will be evaluated -------
5117 unsigned fgTreeSeqNum;
5118 GenTree* fgTreeSeqLst;
5119 GenTree* fgTreeSeqBeg;
5121 GenTree* fgSetTreeSeq(GenTree* tree, GenTree* prev = nullptr, bool isLIR = false);
5122 void fgSetTreeSeqHelper(GenTree* tree, bool isLIR);
5123 void fgSetTreeSeqFinish(GenTree* tree, bool isLIR);
5124 void fgSetStmtSeq(GenTree* tree);
5125 void fgSetBlockOrder(BasicBlock* block);
5127 //------------------------- Morphing --------------------------------------
5129 unsigned fgPtrArgCntMax;
5132 //------------------------------------------------------------------------
5133 // fgGetPtrArgCntMax: Return the maximum number of pointer-sized stack arguments that calls inside this method
5134 // can push on the stack. This value is calculated during morph.
5137 // Returns fgPtrArgCntMax, that is a private field.
5139 unsigned fgGetPtrArgCntMax() const
5141 return fgPtrArgCntMax;
5144 //------------------------------------------------------------------------
5145 // fgSetPtrArgCntMax: Set the maximum number of pointer-sized stack arguments that calls inside this method
5146 // can push on the stack. This function is used during StackLevelSetter to fix incorrect morph calculations.
5148 void fgSetPtrArgCntMax(unsigned argCntMax)
5150 fgPtrArgCntMax = argCntMax;
5153 bool compCanEncodePtrArgCntMax();
5156 hashBv* fgOutgoingArgTemps;
5157 hashBv* fgCurrentlyInUseArgTemps;
5159 void fgSetRngChkTarget(GenTree* tree, bool delay = true);
5161 BasicBlock* fgSetRngChkTargetInner(SpecialCodeKind kind, bool delay);
5164 void fgMoveOpsLeft(GenTree* tree);
5167 bool fgIsCommaThrow(GenTree* tree, bool forFolding = false);
5169 bool fgIsThrow(GenTree* tree);
5171 bool fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2);
5172 bool fgIsBlockCold(BasicBlock* block);
5174 GenTree* fgMorphCastIntoHelper(GenTree* tree, int helper, GenTree* oper);
5176 GenTree* fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeArgList* args, bool morphArgs = true);
5178 GenTree* fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType, unsigned lclOffs);
5180 // A "MorphAddrContext" carries information from the surrounding context. If we are evaluating a byref address,
5181 // it is useful to know whether the address will be immediately dereferenced, or whether the address value will
5182 // be used, perhaps by passing it as an argument to a called method. This affects how null checking is done:
5183 // for sufficiently small offsets, we can rely on OS page protection to implicitly null-check addresses that we
5184 // know will be dereferenced. To know that reliance on implicit null checking is sound, we must further know that
5185 // all offsets between the top-level indirection and the bottom are constant, and that their sum is sufficiently
5186 // small; hence the other fields of MorphAddrContext.
5187 enum MorphAddrContextKind
5192 struct MorphAddrContext
5194 MorphAddrContextKind m_kind;
5195 bool m_allConstantOffsets; // Valid only for "m_kind == MACK_Ind". True iff all offsets between
5196 // top-level indirection and here have been constants.
5197 size_t m_totalOffset; // Valid only for "m_kind == MACK_Ind", and if "m_allConstantOffsets" is true.
5198 // In that case, is the sum of those constant offsets.
5200 MorphAddrContext(MorphAddrContextKind kind) : m_kind(kind), m_allConstantOffsets(true), m_totalOffset(0)
5205 // A MACK_CopyBlock context is immutable, so we can just make one of these and share it.
5206 static MorphAddrContext s_CopyBlockMAC;
5209 GenTree* getSIMDStructFromField(GenTree* tree,
5210 var_types* baseTypeOut,
5212 unsigned* simdSizeOut,
5213 bool ignoreUsedInSIMDIntrinsic = false);
5214 GenTree* fgMorphFieldAssignToSIMDIntrinsicSet(GenTree* tree);
5215 GenTree* fgMorphFieldToSIMDIntrinsicGet(GenTree* tree);
5216 bool fgMorphCombineSIMDFieldAssignments(BasicBlock* block, GenTree* stmt);
5217 void impMarkContiguousSIMDFieldAssignments(GenTree* stmt);
5219 // fgPreviousCandidateSIMDFieldAsgStmt is only used for tracking previous simd field assignment
5220 // in function: Complier::impMarkContiguousSIMDFieldAssignments.
5221 GenTree* fgPreviousCandidateSIMDFieldAsgStmt;
5223 #endif // FEATURE_SIMD
5224 GenTree* fgMorphArrayIndex(GenTree* tree);
5225 GenTree* fgMorphCast(GenTree* tree);
5226 GenTree* fgUnwrapProxy(GenTree* objRef);
5227 GenTreeFieldList* fgMorphLclArgToFieldlist(GenTreeLclVarCommon* lcl);
5228 void fgInitArgInfo(GenTreeCall* call);
5229 GenTreeCall* fgMorphArgs(GenTreeCall* call);
5230 GenTreeArgList* fgMorphArgList(GenTreeArgList* args, MorphAddrContext* mac);
5232 void fgMakeOutgoingStructArgCopy(GenTreeCall* call,
5235 CORINFO_CLASS_HANDLE copyBlkClass);
5237 void fgFixupStructReturn(GenTree* call);
5238 GenTree* fgMorphLocalVar(GenTree* tree, bool forceRemorph);
5241 bool fgAddrCouldBeNull(GenTree* addr);
5244 GenTree* fgMorphField(GenTree* tree, MorphAddrContext* mac);
5245 bool fgCanFastTailCall(GenTreeCall* call);
5246 bool fgCheckStmtAfterTailCall();
5247 void fgMorphTailCall(GenTreeCall* call, void* pfnCopyArgs);
5248 GenTree* fgGetStubAddrArg(GenTreeCall* call);
5249 void fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCall* recursiveTailCall);
5250 GenTree* fgAssignRecursiveCallArgToCallerParam(GenTree* arg,
5251 fgArgTabEntry* argTabEntry,
5253 IL_OFFSETX callILOffset,
5254 GenTree* tmpAssignmentInsertionPoint,
5255 GenTree* paramAssignmentInsertionPoint);
5256 static int fgEstimateCallStackSize(GenTreeCall* call);
5257 GenTree* fgMorphCall(GenTreeCall* call);
5258 void fgMorphCallInline(GenTreeCall* call, InlineResult* result);
5259 void fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result);
5261 void fgNoteNonInlineCandidate(GenTreeStmt* stmt, GenTreeCall* call);
5262 static fgWalkPreFn fgFindNonInlineCandidate;
5264 GenTree* fgOptimizeDelegateConstructor(GenTreeCall* call,
5265 CORINFO_CONTEXT_HANDLE* ExactContextHnd,
5266 CORINFO_RESOLVED_TOKEN* ldftnToken);
5267 GenTree* fgMorphLeaf(GenTree* tree);
5268 void fgAssignSetVarDef(GenTree* tree);
5269 GenTree* fgMorphOneAsgBlockOp(GenTree* tree);
5270 GenTree* fgMorphInitBlock(GenTree* tree);
5271 GenTree* fgMorphPromoteLocalInitBlock(GenTreeLclVar* destLclNode, GenTree* initVal, unsigned blockSize);
5272 GenTree* fgMorphBlkToInd(GenTreeBlk* tree, var_types type);
5273 GenTree* fgMorphGetStructAddr(GenTree** pTree, CORINFO_CLASS_HANDLE clsHnd, bool isRValue = false);
5274 GenTree* fgMorphBlkNode(GenTree* tree, bool isDest);
5275 GenTree* fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigned blockWidth, bool isDest);
5276 void fgMorphUnsafeBlk(GenTreeObj* obj);
5277 GenTree* fgMorphCopyBlock(GenTree* tree);
5278 GenTree* fgMorphForRegisterFP(GenTree* tree);
5279 GenTree* fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac = nullptr);
5280 GenTree* fgMorphModToSubMulDiv(GenTreeOp* tree);
5281 GenTree* fgMorphSmpOpOptional(GenTreeOp* tree);
5282 GenTree* fgMorphRecognizeBoxNullable(GenTree* compare);
5284 GenTree* fgMorphToEmulatedFP(GenTree* tree);
5285 GenTree* fgMorphConst(GenTree* tree);
5288 GenTree* fgMorphTree(GenTree* tree, MorphAddrContext* mac = nullptr);
5291 #if LOCAL_ASSERTION_PROP
5292 void fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTree* tree));
5293 void fgKillDependentAssertions(unsigned lclNum DEBUGARG(GenTree* tree));
5295 void fgMorphTreeDone(GenTree* tree, GenTree* oldTree = nullptr DEBUGARG(int morphNum = 0));
5297 GenTreeStmt* fgMorphStmt;
5299 unsigned fgGetBigOffsetMorphingTemp(var_types type); // We cache one temp per type to be
5300 // used when morphing big offset.
5302 //----------------------- Liveness analysis -------------------------------
5304 VARSET_TP fgCurUseSet; // vars used by block (before an assignment)
5305 VARSET_TP fgCurDefSet; // vars assigned by block (before a use)
5307 MemoryKindSet fgCurMemoryUse; // True iff the current basic block uses memory.
5308 MemoryKindSet fgCurMemoryDef; // True iff the current basic block modifies memory.
5309 MemoryKindSet fgCurMemoryHavoc; // True if the current basic block is known to set memory to a "havoc" value.
5311 bool byrefStatesMatchGcHeapStates; // True iff GcHeap and ByrefExposed memory have all the same def points.
5313 void fgMarkUseDef(GenTreeLclVarCommon* tree);
5315 void fgBeginScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
5316 void fgEndScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
5318 void fgMarkInScope(BasicBlock* block, VARSET_VALARG_TP inScope);
5319 void fgUnmarkInScope(BasicBlock* block, VARSET_VALARG_TP unmarkScope);
5321 void fgExtendDbgScopes();
5322 void fgExtendDbgLifetimes();
5325 void fgDispDebugScopes();
5328 //-------------------------------------------------------------------------
5330 // The following keeps track of any code we've added for things like array
5331 // range checking or explicit calls to enable GC, and so on.
5336 AddCodeDsc* acdNext;
5337 BasicBlock* acdDstBlk; // block to which we jump
5339 SpecialCodeKind acdKind; // what kind of a special block is this?
5340 #if !FEATURE_FIXED_OUT_ARGS
5341 bool acdStkLvlInit; // has acdStkLvl value been already set?
5343 #endif // !FEATURE_FIXED_OUT_ARGS
5347 static unsigned acdHelper(SpecialCodeKind codeKind);
5349 AddCodeDsc* fgAddCodeList;
5351 bool fgRngChkThrowAdded;
5352 AddCodeDsc* fgExcptnTargetCache[SCK_COUNT];
5354 BasicBlock* fgRngChkTarget(BasicBlock* block, SpecialCodeKind kind);
5356 BasicBlock* fgAddCodeRef(BasicBlock* srcBlk, unsigned refData, SpecialCodeKind kind);
5359 AddCodeDsc* fgFindExcptnTarget(SpecialCodeKind kind, unsigned refData);
5361 bool fgUseThrowHelperBlocks();
5363 AddCodeDsc* fgGetAdditionalCodeDescriptors()
5365 return fgAddCodeList;
5369 bool fgIsCodeAdded();
5371 bool fgIsThrowHlpBlk(BasicBlock* block);
5373 #if !FEATURE_FIXED_OUT_ARGS
5374 unsigned fgThrowHlpBlkStkLevel(BasicBlock* block);
5375 #endif // !FEATURE_FIXED_OUT_ARGS
5377 unsigned fgBigOffsetMorphingTemps[TYP_COUNT];
5379 unsigned fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo);
5380 void fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* result);
5381 void fgInsertInlineeBlocks(InlineInfo* pInlineInfo);
5382 GenTree* fgInlinePrependStatements(InlineInfo* inlineInfo);
5383 void fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, GenTree* stmt);
5385 #if FEATURE_MULTIREG_RET
5386 GenTree* fgGetStructAsStructPtr(GenTree* tree);
5387 GenTree* fgAssignStructInlineeToVar(GenTree* child, CORINFO_CLASS_HANDLE retClsHnd);
5388 void fgAttachStructInlineeToAsg(GenTree* tree, GenTree* child, CORINFO_CLASS_HANDLE retClsHnd);
5389 #endif // FEATURE_MULTIREG_RET
5391 static fgWalkPreFn fgUpdateInlineReturnExpressionPlaceHolder;
5392 static fgWalkPostFn fgLateDevirtualization;
5395 static fgWalkPreFn fgDebugCheckInlineCandidates;
5397 void CheckNoTransformableIndirectCallsRemain();
5398 static fgWalkPreFn fgDebugCheckForTransformableIndirectCalls;
5401 void fgPromoteStructs();
5402 void fgMorphStructField(GenTree* tree, GenTree* parent);
5403 void fgMorphLocalField(GenTree* tree, GenTree* parent);
5405 // Identify which parameters are implicit byrefs, and flag their LclVarDscs.
5406 void fgMarkImplicitByRefArgs();
5408 // Change implicit byrefs' types from struct to pointer, and for any that were
5409 // promoted, create new promoted struct temps.
5410 void fgRetypeImplicitByRefArgs();
5412 // Rewrite appearances of implicit byrefs (manifest the implied additional level of indirection).
5413 bool fgMorphImplicitByRefArgs(GenTree* tree);
5414 GenTree* fgMorphImplicitByRefArgs(GenTree* tree, bool isAddr);
5416 // Clear up annotations for any struct promotion temps created for implicit byrefs.
5417 void fgMarkDemotedImplicitByRefArgs();
5419 void fgMarkAddressExposedLocals();
5421 static fgWalkPreFn fgUpdateSideEffectsPre;
5422 static fgWalkPostFn fgUpdateSideEffectsPost;
5424 // The given local variable, required to be a struct variable, is being assigned via
5425 // a "lclField", to make it masquerade as an integral type in the ABI. Make sure that
5426 // the variable is not enregistered, and is therefore not promoted independently.
5427 void fgLclFldAssign(unsigned lclNum);
5429 static fgWalkPreFn gtHasLocalsWithAddrOpCB;
5431 enum TypeProducerKind
5433 TPK_Unknown = 0, // May not be a RuntimeType
5434 TPK_Handle = 1, // RuntimeType via handle
5435 TPK_GetType = 2, // RuntimeType via Object.get_Type()
5436 TPK_Null = 3, // Tree value is null
5437 TPK_Other = 4 // RuntimeType via other means
5440 TypeProducerKind gtGetTypeProducerKind(GenTree* tree);
5441 bool gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call);
5442 bool gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper = nullptr);
5443 bool gtIsActiveCSE_Candidate(GenTree* tree);
5446 bool fgPrintInlinedMethods;
5449 bool fgIsBigOffset(size_t offset);
5451 bool fgNeedReturnSpillTemp();
5454 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5455 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5459 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5460 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5466 void optRemoveRangeCheck(GenTree* tree, GenTree* stmt);
5467 bool optIsRangeCheckRemovable(GenTree* tree);
5470 static fgWalkPreFn optValidRangeCheckIndex;
5471 static fgWalkPreFn optRemoveTreeVisitor; // Helper passed to Compiler::fgWalkAllTreesPre() to decrement the LclVar
5474 void optRemoveTree(GenTree* deadTree, GenTree* keepList);
5476 /**************************************************************************
5478 *************************************************************************/
5481 // Do hoisting for all loops.
5482 void optHoistLoopCode();
5484 // To represent sets of VN's that have already been hoisted in outer loops.
5485 typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, bool> VNToBoolMap;
5486 typedef VNToBoolMap VNSet;
5488 struct LoopHoistContext
5491 // The set of variables hoisted in the current loop (or nullptr if there are none).
5492 VNSet* m_pHoistedInCurLoop;
5495 // Value numbers of expressions that have been hoisted in parent loops in the loop nest.
5496 VNSet m_hoistedInParentLoops;
5497 // Value numbers of expressions that have been hoisted in the current (or most recent) loop in the nest.
5498 // Previous decisions on loop-invariance of value numbers in the current loop.
5499 VNToBoolMap m_curLoopVnInvariantCache;
5501 VNSet* GetHoistedInCurLoop(Compiler* comp)
5503 if (m_pHoistedInCurLoop == nullptr)
5505 m_pHoistedInCurLoop = new (comp->getAllocatorLoopHoist()) VNSet(comp->getAllocatorLoopHoist());
5507 return m_pHoistedInCurLoop;
5510 VNSet* ExtractHoistedInCurLoop()
5512 VNSet* res = m_pHoistedInCurLoop;
5513 m_pHoistedInCurLoop = nullptr;
5517 LoopHoistContext(Compiler* comp)
5518 : m_pHoistedInCurLoop(nullptr)
5519 , m_hoistedInParentLoops(comp->getAllocatorLoopHoist())
5520 , m_curLoopVnInvariantCache(comp->getAllocatorLoopHoist())
5525 // Do hoisting for loop "lnum" (an index into the optLoopTable), and all loops nested within it.
5526 // Tracks the expressions that have been hoisted by containing loops by temporary recording their
5527 // value numbers in "m_hoistedInParentLoops". This set is not modified by the call.
5528 void optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);
5530 // Do hoisting for a particular loop ("lnum" is an index into the optLoopTable.)
5531 // Assumes that expressions have been hoisted in containing loops if their value numbers are in
5532 // "m_hoistedInParentLoops".
5534 void optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt);
5536 // Hoist all expressions in "blk" that are invariant in loop "lnum" (an index into the optLoopTable)
5537 // outside of that loop. Exempt expressions whose value number is in "m_hoistedInParentLoops"; add VN's of hoisted
5538 // expressions to "hoistInLoop".
5539 void optHoistLoopExprsForBlock(BasicBlock* blk, unsigned lnum, LoopHoistContext* hoistCtxt);
5541 // Return true if the tree looks profitable to hoist out of loop 'lnum'.
5542 bool optIsProfitableToHoistableTree(GenTree* tree, unsigned lnum);
5544 // Hoist all proper sub-expressions of "tree" (which occurs in "stmt", which occurs in "blk")
5545 // that are invariant in loop "lnum" (an index into the optLoopTable)
5546 // outside of that loop. Exempt expressions whose value number is in "hoistedInParents"; add VN's of hoisted
5547 // expressions to "hoistInLoop".
5548 // Returns "true" iff "tree" is loop-invariant (wrt "lnum").
5549 // Assumes that the value of "*firstBlockAndBeforeSideEffect" indicates that we're in the first block, and before
5550 // any possible globally visible side effects. Assume is called in evaluation order, and updates this.
5551 bool optHoistLoopExprsForTree(GenTree* tree,
5553 LoopHoistContext* hoistCtxt,
5554 bool* firstBlockAndBeforeSideEffect,
5556 bool* pCctorDependent);
5558 // Performs the hoisting 'tree' into the PreHeader for loop 'lnum'
5559 void optHoistCandidate(GenTree* tree, unsigned lnum, LoopHoistContext* hoistCtxt);
5561 // Returns true iff the ValueNum "vn" represents a value that is loop-invariant in "lnum".
5562 // Constants and init values are always loop invariant.
5563 // VNPhi's connect VN's to the SSA definition, so we can know if the SSA def occurs in the loop.
5564 bool optVNIsLoopInvariant(ValueNum vn, unsigned lnum, VNToBoolMap* recordedVNs);
5566 // Returns "true" iff "tree" is valid at the head of loop "lnum", in the context of the hoist substitution
5567 // "subst". If "tree" is a local SSA var, it is valid if its SSA definition occurs outside of the loop, or
5568 // if it is in the domain of "subst" (meaning that it's definition has been previously hoisted, with a "standin"
5569 // local.) If tree is a constant, it is valid. Otherwise, if it is an operator, it is valid iff its children are.
5570 bool optTreeIsValidAtLoopHead(GenTree* tree, unsigned lnum);
5572 // If "blk" is the entry block of a natural loop, returns true and sets "*pLnum" to the index of the loop
5573 // in the loop table.
5574 bool optBlockIsLoopEntry(BasicBlock* blk, unsigned* pLnum);
5576 // Records the set of "side effects" of all loops: fields (object instance and static)
5577 // written to, and SZ-array element type equivalence classes updated.
5578 void optComputeLoopSideEffects();
5581 // Requires "lnum" to be the index of an outermost loop in the loop table. Traverses the body of that loop,
5582 // including all nested loops, and records the set of "side effects" of the loop: fields (object instance and
5583 // static) written to, and SZ-array element type equivalence classes updated.
5584 void optComputeLoopNestSideEffects(unsigned lnum);
5586 // Add the side effects of "blk" (which is required to be within a loop) to all loops of which it is a part.
5587 void optComputeLoopSideEffectsOfBlock(BasicBlock* blk);
5589 // Hoist the expression "expr" out of loop "lnum".
5590 void optPerformHoistExpr(GenTree* expr, unsigned lnum);
5593 void optOptimizeBools();
5596 GenTree* optIsBoolCond(GenTree* condBranch, GenTree** compPtr, bool* boolPtr);
5598 void optOptimizeBoolsGcStress(BasicBlock* condBlock);
5601 void optOptimizeLayout(); // Optimize the BasicBlock layout of the method
5603 void optOptimizeLoops(); // for "while-do" loops duplicates simple loop conditions and transforms
5604 // the loop into a "do-while" loop
5605 // Also finds all natural loops and records them in the loop table
5607 // Optionally clone loops in the loop table.
5608 void optCloneLoops();
5610 // Clone loop "loopInd" in the loop table.
5611 void optCloneLoop(unsigned loopInd, LoopCloneContext* context);
5613 // Ensure that loop "loopInd" has a unique head block. (If the existing entry has
5614 // non-loop predecessors other than the head entry, create a new, empty block that goes (only) to the entry,
5615 // and redirects the preds of the entry to this new block.) Sets the weight of the newly created block to
5617 void optEnsureUniqueHead(unsigned loopInd, unsigned ambientWeight);
5619 void optUnrollLoops(); // Unrolls loops (needs to have cost info)
5622 // This enumeration describes what is killed by a call.
5626 CALLINT_NONE, // no interference (most helpers)
5627 CALLINT_REF_INDIRS, // kills GC ref indirections (SETFIELD OBJ)
5628 CALLINT_SCL_INDIRS, // kills non GC ref indirections (SETFIELD non-OBJ)
5629 CALLINT_ALL_INDIRS, // kills both GC ref and non GC ref indirections (SETFIELD STRUCT)
5630 CALLINT_ALL, // kills everything (normal method call)
5634 // A "LoopDsc" describes a ("natural") loop. We (currently) require the body of a loop to be a contiguous (in
5635 // bbNext order) sequence of basic blocks. (At times, we may require the blocks in a loop to be "properly numbered"
5636 // in bbNext order; we use comparisons on the bbNum to decide order.)
5637 // The blocks that define the body are
5638 // first <= top <= entry <= bottom .
5639 // The "head" of the loop is a block outside the loop that has "entry" as a successor. We only support loops with a
5640 // single 'head' block. The meanings of these blocks are given in the definitions below. Also see the picture at
5641 // Compiler::optFindNaturalLoops().
5644 BasicBlock* lpHead; // HEAD of the loop (not part of the looping of the loop) -- has ENTRY as a successor.
5645 BasicBlock* lpFirst; // FIRST block (in bbNext order) reachable within this loop. (May be part of a nested
5646 // loop, but not the outer loop.)
5647 BasicBlock* lpTop; // loop TOP (the back edge from lpBottom reaches here) (in most cases FIRST and TOP are the
5649 BasicBlock* lpEntry; // the ENTRY in the loop (in most cases TOP or BOTTOM)
5650 BasicBlock* lpBottom; // loop BOTTOM (from here we have a back edge to the TOP)
5651 BasicBlock* lpExit; // if a single exit loop this is the EXIT (in most cases BOTTOM)
5653 callInterf lpAsgCall; // "callInterf" for calls in the loop
5654 ALLVARSET_TP lpAsgVars; // set of vars assigned within the loop (all vars, not just tracked)
5655 varRefKinds lpAsgInds : 8; // set of inds modified within the loop
5657 unsigned short lpFlags; // Mask of the LPFLG_* constants
5659 unsigned char lpExitCnt; // number of exits from the loop
5661 unsigned char lpParent; // The index of the most-nested loop that completely contains this one,
5662 // or else BasicBlock::NOT_IN_LOOP if no such loop exists.
5663 unsigned char lpChild; // The index of a nested loop, or else BasicBlock::NOT_IN_LOOP if no child exists.
5664 // (Actually, an "immediately" nested loop --
5665 // no other child of this loop is a parent of lpChild.)
5666 unsigned char lpSibling; // The index of another loop that is an immediate child of lpParent,
5667 // or else BasicBlock::NOT_IN_LOOP. One can enumerate all the children of a loop
5668 // by following "lpChild" then "lpSibling" links.
5670 #define LPFLG_DO_WHILE 0x0001 // it's a do-while loop (i.e ENTRY is at the TOP)
5671 #define LPFLG_ONE_EXIT 0x0002 // the loop has only one exit
5673 #define LPFLG_ITER 0x0004 // for (i = icon or lclVar; test_condition(); i++)
5674 #define LPFLG_HOISTABLE 0x0008 // the loop is in a form that is suitable for hoisting expressions
5675 #define LPFLG_CONST 0x0010 // for (i=icon;i<icon;i++){ ... } - constant loop
5677 #define LPFLG_VAR_INIT 0x0020 // iterator is initialized with a local var (var # found in lpVarInit)
5678 #define LPFLG_CONST_INIT 0x0040 // iterator is initialized with a constant (found in lpConstInit)
5680 #define LPFLG_VAR_LIMIT 0x0100 // iterator is compared with a local var (var # found in lpVarLimit)
5681 #define LPFLG_CONST_LIMIT 0x0200 // iterator is compared with a constant (found in lpConstLimit)
5682 #define LPFLG_ARRLEN_LIMIT 0x0400 // iterator is compared with a.len or a[i].len (found in lpArrLenLimit)
5683 #define LPFLG_SIMD_LIMIT 0x0080 // iterator is compared with Vector<T>.Count (found in lpConstLimit)
5685 #define LPFLG_HAS_PREHEAD 0x0800 // lpHead is known to be a preHead for this loop
5686 #define LPFLG_REMOVED 0x1000 // has been removed from the loop table (unrolled or optimized away)
5687 #define LPFLG_DONT_UNROLL 0x2000 // do not unroll this loop
5689 #define LPFLG_ASGVARS_YES 0x4000 // "lpAsgVars" has been computed
5690 #define LPFLG_ASGVARS_INC 0x8000 // "lpAsgVars" is incomplete -- vars beyond those representable in an AllVarSet
5691 // type are assigned to.
5693 bool lpLoopHasMemoryHavoc[MemoryKindCount]; // The loop contains an operation that we assume has arbitrary
5694 // memory side effects. If this is set, the fields below
5695 // may not be accurate (since they become irrelevant.)
5696 bool lpContainsCall; // True if executing the loop body *may* execute a call
5698 VARSET_TP lpVarInOut; // The set of variables that are IN or OUT during the execution of this loop
5699 VARSET_TP lpVarUseDef; // The set of variables that are USE or DEF during the execution of this loop
5701 int lpHoistedExprCount; // The register count for the non-FP expressions from inside this loop that have been
5703 int lpLoopVarCount; // The register count for the non-FP LclVars that are read/written inside this loop
5704 int lpVarInOutCount; // The register count for the non-FP LclVars that are alive inside or accross this loop
5706 int lpHoistedFPExprCount; // The register count for the FP expressions from inside this loop that have been
5708 int lpLoopVarFPCount; // The register count for the FP LclVars that are read/written inside this loop
5709 int lpVarInOutFPCount; // The register count for the FP LclVars that are alive inside or accross this loop
5711 typedef JitHashTable<CORINFO_FIELD_HANDLE, JitPtrKeyFuncs<struct CORINFO_FIELD_STRUCT_>, bool> FieldHandleSet;
5712 FieldHandleSet* lpFieldsModified; // This has entries (mappings to "true") for all static field and object
5713 // instance fields modified
5716 typedef JitHashTable<CORINFO_CLASS_HANDLE, JitPtrKeyFuncs<struct CORINFO_CLASS_STRUCT_>, bool> ClassHandleSet;
5717 ClassHandleSet* lpArrayElemTypesModified; // Bits set indicate the set of sz array element types such that
5718 // arrays of that type are modified
5721 // Adds the variable liveness information for 'blk' to 'this' LoopDsc
5722 void AddVariableLiveness(Compiler* comp, BasicBlock* blk);
5724 inline void AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd);
5725 // This doesn't *always* take a class handle -- it can also take primitive types, encoded as class handles
5726 // (shifted left, with a low-order bit set to distinguish.)
5727 // Use the {Encode/Decode}ElemType methods to construct/destruct these.
5728 inline void AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd);
5730 /* The following values are set only for iterator loops, i.e. has the flag LPFLG_ITER set */
5732 GenTree* lpIterTree; // The "i = i <op> const" tree
5733 unsigned lpIterVar(); // iterator variable #
5734 int lpIterConst(); // the constant with which the iterator is incremented
5735 genTreeOps lpIterOper(); // the type of the operation on the iterator (ASG_ADD, ASG_SUB, etc.)
5736 void VERIFY_lpIterTree();
5738 var_types lpIterOperType(); // For overflow instructions
5741 int lpConstInit; // initial constant value of iterator : Valid if LPFLG_CONST_INIT
5742 unsigned lpVarInit; // initial local var number to which we initialize the iterator : Valid if
5746 /* The following is for LPFLG_ITER loops only (i.e. the loop condition is "i RELOP const or var" */
5748 GenTree* lpTestTree; // pointer to the node containing the loop test
5749 genTreeOps lpTestOper(); // the type of the comparison between the iterator and the limit (GT_LE, GT_GE, etc.)
5750 void VERIFY_lpTestTree();
5752 bool lpIsReversed(); // true if the iterator node is the second operand in the loop condition
5753 GenTree* lpIterator(); // the iterator node in the loop test
5754 GenTree* lpLimit(); // the limit node in the loop test
5756 int lpConstLimit(); // limit constant value of iterator - loop condition is "i RELOP const" : Valid if
5757 // LPFLG_CONST_LIMIT
5758 unsigned lpVarLimit(); // the lclVar # in the loop condition ( "i RELOP lclVar" ) : Valid if
5760 bool lpArrLenLimit(Compiler* comp, ArrIndex* index); // The array length in the loop condition ( "i RELOP
5761 // arr.len" or "i RELOP arr[i][j].len" ) : Valid if
5762 // LPFLG_ARRLEN_LIMIT
5764 // Returns "true" iff "*this" contains the blk.
5765 bool lpContains(BasicBlock* blk)
5767 return lpFirst->bbNum <= blk->bbNum && blk->bbNum <= lpBottom->bbNum;
5769 // Returns "true" iff "*this" (properly) contains the range [first, bottom] (allowing firsts
5770 // to be equal, but requiring bottoms to be different.)
5771 bool lpContains(BasicBlock* first, BasicBlock* bottom)
5773 return lpFirst->bbNum <= first->bbNum && bottom->bbNum < lpBottom->bbNum;
5776 // Returns "true" iff "*this" (properly) contains "lp2" (allowing firsts to be equal, but requiring
5777 // bottoms to be different.)
5778 bool lpContains(const LoopDsc& lp2)
5780 return lpContains(lp2.lpFirst, lp2.lpBottom);
5783 // Returns "true" iff "*this" is (properly) contained by the range [first, bottom]
5784 // (allowing firsts to be equal, but requiring bottoms to be different.)
5785 bool lpContainedBy(BasicBlock* first, BasicBlock* bottom)
5787 return first->bbNum <= lpFirst->bbNum && lpBottom->bbNum < bottom->bbNum;
5790 // Returns "true" iff "*this" is (properly) contained by "lp2"
5791 // (allowing firsts to be equal, but requiring bottoms to be different.)
5792 bool lpContainedBy(const LoopDsc& lp2)
5794 return lpContains(lp2.lpFirst, lp2.lpBottom);
5797 // Returns "true" iff "*this" is disjoint from the range [top, bottom].
5798 bool lpDisjoint(BasicBlock* first, BasicBlock* bottom)
5800 return bottom->bbNum < lpFirst->bbNum || lpBottom->bbNum < first->bbNum;
5802 // Returns "true" iff "*this" is disjoint from "lp2".
5803 bool lpDisjoint(const LoopDsc& lp2)
5805 return lpDisjoint(lp2.lpFirst, lp2.lpBottom);
5807 // Returns "true" iff the loop is well-formed (see code for defn).
5810 return lpFirst->bbNum <= lpTop->bbNum && lpTop->bbNum <= lpEntry->bbNum &&
5811 lpEntry->bbNum <= lpBottom->bbNum &&
5812 (lpHead->bbNum < lpTop->bbNum || lpHead->bbNum > lpBottom->bbNum);
5817 bool fgMightHaveLoop(); // returns true if there are any backedges
5818 bool fgHasLoops; // True if this method has any loops, set in fgComputeReachability
5821 LoopDsc* optLoopTable; // loop descriptor table
5822 unsigned char optLoopCount; // number of tracked loops
5824 bool optRecordLoop(BasicBlock* head,
5830 unsigned char exitCnt);
5833 unsigned optCallCount; // number of calls made in the method
5834 unsigned optIndirectCallCount; // number of virtual, interface and indirect calls made in the method
5835 unsigned optNativeCallCount; // number of Pinvoke/Native calls made in the method
5836 unsigned optLoopsCloned; // number of loops cloned in the current method.
5839 unsigned optFindLoopNumberFromBeginBlock(BasicBlock* begBlk);
5840 void optPrintLoopInfo(unsigned loopNum,
5842 BasicBlock* lpFirst,
5844 BasicBlock* lpEntry,
5845 BasicBlock* lpBottom,
5846 unsigned char lpExitCnt,
5848 unsigned parentLoop = BasicBlock::NOT_IN_LOOP);
5849 void optPrintLoopInfo(unsigned lnum);
5850 void optPrintLoopRecording(unsigned lnum);
5852 void optCheckPreds();
5855 void optSetBlockWeights();
5857 void optMarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk, bool excludeEndBlk);
5859 void optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk);
5861 void optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmarkLoop = false);
5863 bool optIsLoopTestEvalIntoTemp(GenTree* test, GenTree** newTest);
5864 unsigned optIsLoopIncrTree(GenTree* incr);
5865 bool optCheckIterInLoopTest(unsigned loopInd, GenTree* test, BasicBlock* from, BasicBlock* to, unsigned iterVar);
5866 bool optComputeIterInfo(GenTree* incr, BasicBlock* from, BasicBlock* to, unsigned* pIterVar);
5867 bool optPopulateInitInfo(unsigned loopInd, GenTree* init, unsigned iterVar);
5868 bool optExtractInitTestIncr(
5869 BasicBlock* head, BasicBlock* bottom, BasicBlock* exit, GenTree** ppInit, GenTree** ppTest, GenTree** ppIncr);
5871 void optFindNaturalLoops();
5873 // Ensures that all the loops in the loop nest rooted at "loopInd" (an index into the loop table) are 'canonical' --
5874 // each loop has a unique "top." Returns "true" iff the flowgraph has been modified.
5875 bool optCanonicalizeLoopNest(unsigned char loopInd);
5877 // Ensures that the loop "loopInd" (an index into the loop table) is 'canonical' -- it has a unique "top,"
5878 // unshared with any other loop. Returns "true" iff the flowgraph has been modified
5879 bool optCanonicalizeLoop(unsigned char loopInd);
5881 // Requires "l1" to be a valid loop table index, and not "BasicBlock::NOT_IN_LOOP". Requires "l2" to be
5882 // a valid loop table index, or else "BasicBlock::NOT_IN_LOOP". Returns true
5883 // iff "l2" is not NOT_IN_LOOP, and "l1" contains "l2".
5884 bool optLoopContains(unsigned l1, unsigned l2);
5886 // Requires "loopInd" to be a valid index into the loop table.
5887 // Updates the loop table by changing loop "loopInd", whose head is required
5888 // to be "from", to be "to". Also performs this transformation for any
5889 // loop nested in "loopInd" that shares the same head as "loopInd".
5890 void optUpdateLoopHead(unsigned loopInd, BasicBlock* from, BasicBlock* to);
5892 // Updates the successors of "blk": if "blk2" is a successor of "blk", and there is a mapping for "blk2->blk3" in
5893 // "redirectMap", change "blk" so that "blk3" is this successor. Note that the predecessor lists are not updated.
5894 void optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap);
5896 // Marks the containsCall information to "lnum" and any parent loops.
5897 void AddContainsCallAllContainingLoops(unsigned lnum);
5898 // Adds the variable liveness information from 'blk' to "lnum" and any parent loops.
5899 void AddVariableLivenessAllContainingLoops(unsigned lnum, BasicBlock* blk);
5900 // Adds "fldHnd" to the set of modified fields of "lnum" and any parent loops.
5901 void AddModifiedFieldAllContainingLoops(unsigned lnum, CORINFO_FIELD_HANDLE fldHnd);
5902 // Adds "elemType" to the set of modified array element types of "lnum" and any parent loops.
5903 void AddModifiedElemTypeAllContainingLoops(unsigned lnum, CORINFO_CLASS_HANDLE elemType);
5905 // Requires that "from" and "to" have the same "bbJumpKind" (perhaps because "to" is a clone
5906 // of "from".) Copies the jump destination from "from" to "to".
5907 void optCopyBlkDest(BasicBlock* from, BasicBlock* to);
5909 // The depth of the loop described by "lnum" (an index into the loop table.) (0 == top level)
5910 unsigned optLoopDepth(unsigned lnum)
5912 unsigned par = optLoopTable[lnum].lpParent;
5913 if (par == BasicBlock::NOT_IN_LOOP)
5919 return 1 + optLoopDepth(par);
5923 void fgOptWhileLoop(BasicBlock* block);
5925 bool optComputeLoopRep(int constInit,
5928 genTreeOps iterOper,
5930 genTreeOps testOper,
5933 unsigned* iterCount);
5936 static fgWalkPreFn optIsVarAssgCB;
5939 bool optIsVarAssigned(BasicBlock* beg, BasicBlock* end, GenTree* skip, unsigned var);
5941 bool optIsVarAssgLoop(unsigned lnum, unsigned var);
5943 int optIsSetAssgLoop(unsigned lnum, ALLVARSET_VALARG_TP vars, varRefKinds inds = VR_NONE);
5945 bool optNarrowTree(GenTree* tree, var_types srct, var_types dstt, ValueNumPair vnpNarrow, bool doit);
5947 /**************************************************************************
5948 * Optimization conditions
5949 *************************************************************************/
5951 bool optFastCodeOrBlendedLoop(BasicBlock::weight_t bbWeight);
5952 bool optPentium4(void);
5953 bool optAvoidIncDec(BasicBlock::weight_t bbWeight);
5954 bool optAvoidIntMult(void);
5959 // The following is the upper limit on how many expressions we'll keep track
5960 // of for the CSE analysis.
5962 static const unsigned MAX_CSE_CNT = EXPSET_SZ;
5964 static const int MIN_CSE_COST = 2;
5966 // Keeps tracked cse indices
5967 BitVecTraits* cseTraits;
5970 /* Generic list of nodes - used by the CSE logic */
5980 treeStmtLst* tslNext;
5981 GenTree* tslTree; // tree node
5982 GenTree* tslStmt; // statement containing the tree
5983 BasicBlock* tslBlock; // block containing the statement
5986 // The following logic keeps track of expressions via a simple hash table.
5990 CSEdsc* csdNextInBucket; // used by the hash table
5992 unsigned csdHashKey; // the orginal hashkey
5994 unsigned csdIndex; // 1..optCSECandidateCount
5995 char csdLiveAcrossCall; // 0 or 1
5997 unsigned short csdDefCount; // definition count
5998 unsigned short csdUseCount; // use count (excluding the implicit uses at defs)
6000 unsigned csdDefWtCnt; // weighted def count
6001 unsigned csdUseWtCnt; // weighted use count (excluding the implicit uses at defs)
6003 GenTree* csdTree; // treenode containing the 1st occurance
6004 GenTree* csdStmt; // stmt containing the 1st occurance
6005 BasicBlock* csdBlock; // block containing the 1st occurance
6007 treeStmtLst* csdTreeList; // list of matching tree nodes: head
6008 treeStmtLst* csdTreeLast; // list of matching tree nodes: tail
6010 ValueNum defExcSetPromise; // The exception set that is now required for all defs of this CSE.
6011 // This will be set to NoVN if we decide to abandon this CSE
6013 ValueNum defExcSetCurrent; // The set of exceptions we currently can use for CSE uses.
6015 ValueNum defConservNormVN; // if all def occurrences share the same conservative normal value
6016 // number, this will reflect it; otherwise, NoVN.
6019 static const size_t s_optCSEhashSize;
6020 CSEdsc** optCSEhash;
6023 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, GenTree*> NodeToNodeMap;
6025 NodeToNodeMap* optCseCheckedBoundMap; // Maps bound nodes to ancestor compares that should be
6026 // re-numbered with the bound to improve range check elimination
6028 // Given a compare, look for a cse candidate checked bound feeding it and add a map entry if found.
6029 void optCseUpdateCheckedBoundMap(GenTree* compare);
6033 CSEdsc* optCSEfindDsc(unsigned index);
6034 bool optUnmarkCSE(GenTree* tree);
6036 // user defined callback data for the tree walk function optCSE_MaskHelper()
6037 struct optCSE_MaskData
6039 EXPSET_TP CSE_defMask;
6040 EXPSET_TP CSE_useMask;
6043 // Treewalk helper for optCSE_DefMask and optCSE_UseMask
6044 static fgWalkPreFn optCSE_MaskHelper;
6046 // This function walks all the node for an given tree
6047 // and return the mask of CSE definitions and uses for the tree
6049 void optCSE_GetMaskData(GenTree* tree, optCSE_MaskData* pMaskData);
6051 // Given a binary tree node return true if it is safe to swap the order of evaluation for op1 and op2.
6052 bool optCSE_canSwap(GenTree* firstNode, GenTree* secondNode);
6053 bool optCSE_canSwap(GenTree* tree);
6055 static int __cdecl optCSEcostCmpEx(const void* op1, const void* op2);
6056 static int __cdecl optCSEcostCmpSz(const void* op1, const void* op2);
6058 void optCleanupCSEs();
6061 void optEnsureClearCSEInfo();
6064 #endif // FEATURE_ANYCSE
6066 #if FEATURE_VALNUM_CSE
6067 /**************************************************************************
6068 * Value Number based CSEs
6069 *************************************************************************/
6072 void optOptimizeValnumCSEs();
6075 void optValnumCSE_Init();
6076 unsigned optValnumCSE_Index(GenTree* tree, GenTree* stmt);
6077 unsigned optValnumCSE_Locate();
6078 void optValnumCSE_InitDataFlow();
6079 void optValnumCSE_DataFlow();
6080 void optValnumCSE_Availablity();
6081 void optValnumCSE_Heuristic();
6083 #endif // FEATURE_VALNUM_CSE
6086 bool optDoCSE; // True when we have found a duplicate CSE tree
6087 bool optValnumCSE_phase; // True when we are executing the optValnumCSE_phase
6088 unsigned optCSECandidateTotal; // Grand total of CSE candidates for both Lexical and ValNum
6089 unsigned optCSECandidateCount; // Count of CSE's candidates, reset for Lexical and ValNum CSE's
6090 unsigned optCSEstart; // The first local variable number that is a CSE
6091 unsigned optCSEcount; // The total count of CSE's introduced.
6092 unsigned optCSEweight; // The weight of the current block when we are
6093 // scanning for CSE expressions
6095 bool optIsCSEcandidate(GenTree* tree);
6097 // lclNumIsTrueCSE returns true if the LclVar was introduced by the CSE phase of the compiler
6099 bool lclNumIsTrueCSE(unsigned lclNum) const
6101 return ((optCSEcount > 0) && (lclNum >= optCSEstart) && (lclNum < optCSEstart + optCSEcount));
6104 // lclNumIsCSE returns true if the LclVar should be treated like a CSE with regards to constant prop.
6106 bool lclNumIsCSE(unsigned lclNum) const
6108 return lvaTable[lclNum].lvIsCSE;
6112 bool optConfigDisableCSE();
6113 bool optConfigDisableCSE2();
6115 void optOptimizeCSEs();
6117 #endif // FEATURE_ANYCSE
6125 unsigned ivaVar; // Variable we are interested in, or -1
6126 ALLVARSET_TP ivaMaskVal; // Set of variables assigned to. This is a set of all vars, not tracked vars.
6127 bool ivaMaskIncomplete; // Variables not representable in ivaMaskVal were assigned to.
6128 varRefKinds ivaMaskInd; // What kind of indirect assignments are there?
6129 callInterf ivaMaskCall; // What kind of calls are there?
6132 static callInterf optCallInterf(GenTreeCall* call);
6135 // VN based copy propagation.
6136 typedef ArrayStack<GenTree*> GenTreePtrStack;
6137 typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, GenTreePtrStack*> LclNumToGenTreePtrStack;
6139 // Kill set to track variables with intervening definitions.
6140 VARSET_TP optCopyPropKillSet;
6142 // Copy propagation functions.
6143 void optCopyProp(BasicBlock* block, GenTree* stmt, GenTree* tree, LclNumToGenTreePtrStack* curSsaName);
6144 void optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
6145 void optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
6146 bool optIsSsaLocal(GenTree* tree);
6147 int optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2);
6148 void optVnCopyProp();
6149 INDEBUG(void optDumpCopyPropStack(LclNumToGenTreePtrStack* curSsaName));
6151 /**************************************************************************
6152 * Early value propagation
6153 *************************************************************************/
6159 SSAName(unsigned lvNum, unsigned ssaNum) : m_lvNum(lvNum), m_ssaNum(ssaNum)
6163 static unsigned GetHashCode(SSAName ssaNm)
6165 return (ssaNm.m_lvNum << 16) | (ssaNm.m_ssaNum);
6168 static bool Equals(SSAName ssaNm1, SSAName ssaNm2)
6170 return (ssaNm1.m_lvNum == ssaNm2.m_lvNum) && (ssaNm1.m_ssaNum == ssaNm2.m_ssaNum);
6174 #define OMF_HAS_NEWARRAY 0x00000001 // Method contains 'new' of an array
6175 #define OMF_HAS_NEWOBJ 0x00000002 // Method contains 'new' of an object type.
6176 #define OMF_HAS_ARRAYREF 0x00000004 // Method contains array element loads or stores.
6177 #define OMF_HAS_VTABLEREF 0x00000008 // Method contains method table reference.
6178 #define OMF_HAS_NULLCHECK 0x00000010 // Method contains null check.
6179 #define OMF_HAS_FATPOINTER 0x00000020 // Method contains call, that needs fat pointer transformation.
6180 #define OMF_HAS_OBJSTACKALLOC 0x00000040 // Method contains an object allocated on the stack.
6181 #define OMF_HAS_GUARDEDDEVIRT 0x00000080 // Method contains guarded devirtualization candidate
6183 bool doesMethodHaveFatPointer()
6185 return (optMethodFlags & OMF_HAS_FATPOINTER) != 0;
6188 void setMethodHasFatPointer()
6190 optMethodFlags |= OMF_HAS_FATPOINTER;
6193 void clearMethodHasFatPointer()
6195 optMethodFlags &= ~OMF_HAS_FATPOINTER;
6198 void addFatPointerCandidate(GenTreeCall* call);
6200 bool doesMethodHaveGuardedDevirtualization()
6202 return (optMethodFlags & OMF_HAS_GUARDEDDEVIRT) != 0;
6205 void setMethodHasGuardedDevirtualization()
6207 optMethodFlags |= OMF_HAS_GUARDEDDEVIRT;
6210 void clearMethodHasGuardedDevirtualization()
6212 optMethodFlags &= ~OMF_HAS_GUARDEDDEVIRT;
6215 void addGuardedDevirtualizationCandidate(GenTreeCall* call,
6216 CORINFO_METHOD_HANDLE methodHandle,
6217 CORINFO_CLASS_HANDLE classHandle,
6218 unsigned methodAttr,
6219 unsigned classAttr);
6221 unsigned optMethodFlags;
6223 // Recursion bound controls how far we can go backwards tracking for a SSA value.
6224 // No throughput diff was found with backward walk bound between 3-8.
6225 static const int optEarlyPropRecurBound = 5;
6227 enum class optPropKind
6235 bool gtIsVtableRef(GenTree* tree);
6236 GenTree* getArrayLengthFromAllocation(GenTree* tree);
6237 GenTree* getObjectHandleNodeFromAllocation(GenTree* tree);
6238 GenTree* optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropKind valueKind, int walkDepth);
6239 GenTree* optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind);
6240 GenTree* optEarlyPropRewriteTree(GenTree* tree);
6241 bool optDoEarlyPropForBlock(BasicBlock* block);
6242 bool optDoEarlyPropForFunc();
6243 void optEarlyProp();
6244 void optFoldNullCheck(GenTree* tree);
6245 bool optCanMoveNullCheckPastTree(GenTree* tree, bool isInsideTry);
6248 /**************************************************************************
6249 * Value/Assertion propagation
6250 *************************************************************************/
6252 // Data structures for assertion prop
6253 BitVecTraits* apTraits;
6256 enum optAssertionKind
6273 O1K_CONSTANT_LOOP_BND,
6294 optAssertionKind assertionKind;
6297 unsigned lclNum; // assigned to or property of this local var number
6305 struct AssertionDscOp1
6307 optOp1Kind kind; // a normal LclVar, or Exact-type or Subtype
6314 struct AssertionDscOp2
6316 optOp2Kind kind; // a const or copy assignment
6320 ssize_t iconVal; // integer
6321 unsigned iconFlags; // gtFlags
6323 struct Range // integer subrange
6337 bool IsCheckedBoundArithBound()
6339 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_BOUND_OPER_BND);
6341 bool IsCheckedBoundBound()
6343 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_BOUND_LOOP_BND);
6345 bool IsConstantBound()
6347 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) &&
6348 op1.kind == O1K_CONSTANT_LOOP_BND);
6350 bool IsBoundsCheckNoThrow()
6352 return ((assertionKind == OAK_NO_THROW) && (op1.kind == O1K_ARR_BND));
6355 bool IsCopyAssertion()
6357 return ((assertionKind == OAK_EQUAL) && (op1.kind == O1K_LCLVAR) && (op2.kind == O2K_LCLVAR_COPY));
6360 static bool SameKind(AssertionDsc* a1, AssertionDsc* a2)
6362 return a1->assertionKind == a2->assertionKind && a1->op1.kind == a2->op1.kind &&
6363 a1->op2.kind == a2->op2.kind;
6366 static bool ComplementaryKind(optAssertionKind kind, optAssertionKind kind2)
6368 if (kind == OAK_EQUAL)
6370 return kind2 == OAK_NOT_EQUAL;
6372 else if (kind == OAK_NOT_EQUAL)
6374 return kind2 == OAK_EQUAL;
6379 static ssize_t GetLowerBoundForIntegralType(var_types type)
6398 static ssize_t GetUpperBoundForIntegralType(var_types type)
6421 bool HasSameOp1(AssertionDsc* that, bool vnBased)
6423 if (op1.kind != that->op1.kind)
6427 else if (op1.kind == O1K_ARR_BND)
6430 return (op1.bnd.vnIdx == that->op1.bnd.vnIdx) && (op1.bnd.vnLen == that->op1.bnd.vnLen);
6434 return ((vnBased && (op1.vn == that->op1.vn)) ||
6435 (!vnBased && (op1.lcl.lclNum == that->op1.lcl.lclNum)));
6439 bool HasSameOp2(AssertionDsc* that, bool vnBased)
6441 if (op2.kind != that->op2.kind)
6447 case O2K_IND_CNS_INT:
6449 return ((op2.u1.iconVal == that->op2.u1.iconVal) && (op2.u1.iconFlags == that->op2.u1.iconFlags));
6451 case O2K_CONST_LONG:
6452 return (op2.lconVal == that->op2.lconVal);
6454 case O2K_CONST_DOUBLE:
6455 // exact match because of positive and negative zero.
6456 return (memcmp(&op2.dconVal, &that->op2.dconVal, sizeof(double)) == 0);
6458 case O2K_LCLVAR_COPY:
6460 return (op2.lcl.lclNum == that->op2.lcl.lclNum) &&
6461 (!vnBased || op2.lcl.ssaNum == that->op2.lcl.ssaNum);
6464 return ((op2.u2.loBound == that->op2.u2.loBound) && (op2.u2.hiBound == that->op2.u2.hiBound));
6467 // we will return false
6471 assert(!"Unexpected value for op2.kind in AssertionDsc.");
6477 bool Complementary(AssertionDsc* that, bool vnBased)
6479 return ComplementaryKind(assertionKind, that->assertionKind) && HasSameOp1(that, vnBased) &&
6480 HasSameOp2(that, vnBased);
6483 bool Equals(AssertionDsc* that, bool vnBased)
6485 if (assertionKind != that->assertionKind)
6489 else if (assertionKind == OAK_NO_THROW)
6491 assert(op2.kind == O2K_INVALID);
6492 return HasSameOp1(that, vnBased);
6496 return HasSameOp1(that, vnBased) && HasSameOp2(that, vnBased);
6502 static fgWalkPreFn optAddCopiesCallback;
6503 static fgWalkPreFn optVNAssertionPropCurStmtVisitor;
6504 unsigned optAddCopyLclNum;
6505 GenTree* optAddCopyAsgnNode;
6507 bool optLocalAssertionProp; // indicates that we are performing local assertion prop
6508 bool optAssertionPropagated; // set to true if we modified the trees
6509 bool optAssertionPropagatedCurrentStmt;
6511 GenTree* optAssertionPropCurrentTree;
6513 AssertionIndex* optComplementaryAssertionMap;
6514 JitExpandArray<ASSERT_TP>* optAssertionDep; // table that holds dependent assertions (assertions
6515 // using the value of a local var) for each local var
6516 AssertionDsc* optAssertionTabPrivate; // table that holds info about value assignments
6517 AssertionIndex optAssertionCount; // total number of assertions in the assertion table
6518 AssertionIndex optMaxAssertionCount;
6521 void optVnNonNullPropCurStmt(BasicBlock* block, GenTree* stmt, GenTree* tree);
6522 fgWalkResult optVNConstantPropCurStmt(BasicBlock* block, GenTree* stmt, GenTree* tree);
6523 GenTree* optVNConstantPropOnJTrue(BasicBlock* block, GenTree* stmt, GenTree* test);
6524 GenTree* optVNConstantPropOnTree(BasicBlock* block, GenTree* stmt, GenTree* tree);
6525 GenTree* optPrepareTreeForReplacement(GenTree* extractTree, GenTree* replaceTree);
6527 AssertionIndex GetAssertionCount()
6529 return optAssertionCount;
6531 ASSERT_TP* bbJtrueAssertionOut;
6532 typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, ASSERT_TP> ValueNumToAssertsMap;
6533 ValueNumToAssertsMap* optValueNumToAsserts;
6535 // Assertion prop helpers.
6536 ASSERT_TP& GetAssertionDep(unsigned lclNum);
6537 AssertionDsc* optGetAssertion(AssertionIndex assertIndex);
6538 void optAssertionInit(bool isLocalProp);
6539 void optAssertionTraitsInit(AssertionIndex assertionCount);
6540 #if LOCAL_ASSERTION_PROP
6541 void optAssertionReset(AssertionIndex limit);
6542 void optAssertionRemove(AssertionIndex index);
6545 // Assertion prop data flow functions.
6546 void optAssertionPropMain();
6547 GenTree* optVNAssertionPropCurStmt(BasicBlock* block, GenTree* stmt);
6548 bool optIsTreeKnownIntValue(bool vnBased, GenTree* tree, ssize_t* pConstant, unsigned* pIconFlags);
6549 ASSERT_TP* optInitAssertionDataflowFlags();
6550 ASSERT_TP* optComputeAssertionGen();
6552 // Assertion Gen functions.
6553 void optAssertionGen(GenTree* tree);
6554 AssertionIndex optAssertionGenPhiDefn(GenTree* tree);
6555 AssertionInfo optCreateJTrueBoundsAssertion(GenTree* tree);
6556 AssertionInfo optAssertionGenJtrue(GenTree* tree);
6557 AssertionIndex optCreateJtrueAssertions(GenTree* op1, GenTree* op2, Compiler::optAssertionKind assertionKind);
6558 AssertionIndex optFindComplementary(AssertionIndex assertionIndex);
6559 void optMapComplementary(AssertionIndex assertionIndex, AssertionIndex index);
6561 // Assertion creation functions.
6562 AssertionIndex optCreateAssertion(GenTree* op1, GenTree* op2, optAssertionKind assertionKind);
6563 AssertionIndex optCreateAssertion(GenTree* op1,
6565 optAssertionKind assertionKind,
6566 AssertionDsc* assertion);
6567 void optCreateComplementaryAssertion(AssertionIndex assertionIndex, GenTree* op1, GenTree* op2);
6569 bool optAssertionVnInvolvesNan(AssertionDsc* assertion);
6570 AssertionIndex optAddAssertion(AssertionDsc* assertion);
6571 void optAddVnAssertionMapping(ValueNum vn, AssertionIndex index);
6573 void optPrintVnAssertionMapping();
6575 ASSERT_TP optGetVnMappedAssertions(ValueNum vn);
6577 // Used for respective assertion propagations.
6578 AssertionIndex optAssertionIsSubrange(GenTree* tree, var_types toType, ASSERT_VALARG_TP assertions);
6579 AssertionIndex optAssertionIsSubtype(GenTree* tree, GenTree* methodTableArg, ASSERT_VALARG_TP assertions);
6580 AssertionIndex optAssertionIsNonNullInternal(GenTree* op, ASSERT_VALARG_TP assertions);
6581 bool optAssertionIsNonNull(GenTree* op,
6582 ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased) DEBUGARG(AssertionIndex* pIndex));
6584 // Used for Relop propagation.
6585 AssertionIndex optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP assertions, GenTree* op1, GenTree* op2);
6586 AssertionIndex optGlobalAssertionIsEqualOrNotEqualZero(ASSERT_VALARG_TP assertions, GenTree* op1);
6587 AssertionIndex optLocalAssertionIsEqualOrNotEqual(
6588 optOp1Kind op1Kind, unsigned lclNum, optOp2Kind op2Kind, ssize_t cnsVal, ASSERT_VALARG_TP assertions);
6590 // Assertion prop for lcl var functions.
6591 bool optAssertionProp_LclVarTypeCheck(GenTree* tree, LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc);
6592 GenTree* optCopyAssertionProp(AssertionDsc* curAssertion,
6594 GenTree* stmt DEBUGARG(AssertionIndex index));
6595 GenTree* optConstantAssertionProp(AssertionDsc* curAssertion,
6597 GenTree* stmt DEBUGARG(AssertionIndex index));
6599 // Assertion propagation functions.
6600 GenTree* optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6601 GenTree* optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6602 GenTree* optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6603 GenTree* optAssertionProp_Cast(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6604 GenTree* optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, GenTree* stmt);
6605 GenTree* optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6606 GenTree* optAssertionProp_Comma(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6607 GenTree* optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6608 GenTree* optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6609 GenTree* optAssertionPropLocal_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6610 GenTree* optAssertionProp_Update(GenTree* newTree, GenTree* tree, GenTree* stmt);
6611 GenTree* optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, GenTree* stmt);
6613 // Implied assertion functions.
6614 void optImpliedAssertions(AssertionIndex assertionIndex, ASSERT_TP& activeAssertions);
6615 void optImpliedByTypeOfAssertions(ASSERT_TP& activeAssertions);
6616 void optImpliedByCopyAssertion(AssertionDsc* copyAssertion, AssertionDsc* depAssertion, ASSERT_TP& result);
6617 void optImpliedByConstAssertion(AssertionDsc* curAssertion, ASSERT_TP& result);
6620 void optPrintAssertion(AssertionDsc* newAssertion, AssertionIndex assertionIndex = 0);
6621 void optDebugCheckAssertion(AssertionDsc* assertion);
6622 void optDebugCheckAssertions(AssertionIndex AssertionIndex);
6624 void optAddCopies();
6625 #endif // ASSERTION_PROP
6627 /**************************************************************************
6629 *************************************************************************/
6632 struct LoopCloneVisitorInfo
6634 LoopCloneContext* context;
6637 LoopCloneVisitorInfo(LoopCloneContext* context, unsigned loopNum, GenTree* stmt)
6638 : context(context), loopNum(loopNum), stmt(nullptr)
6643 bool optIsStackLocalInvariant(unsigned loopNum, unsigned lclNum);
6644 bool optExtractArrIndex(GenTree* tree, ArrIndex* result, unsigned lhsNum);
6645 bool optReconstructArrIndex(GenTree* tree, ArrIndex* result, unsigned lhsNum);
6646 bool optIdentifyLoopOptInfo(unsigned loopNum, LoopCloneContext* context);
6647 static fgWalkPreFn optCanOptimizeByLoopCloningVisitor;
6648 fgWalkResult optCanOptimizeByLoopCloning(GenTree* tree, LoopCloneVisitorInfo* info);
6649 void optObtainLoopCloningOpts(LoopCloneContext* context);
6650 bool optIsLoopClonable(unsigned loopInd);
6652 bool optCanCloneLoops();
6655 void optDebugLogLoopCloning(BasicBlock* block, GenTree* insertBefore);
6657 void optPerformStaticOptimizations(unsigned loopNum, LoopCloneContext* context DEBUGARG(bool fastPath));
6658 bool optComputeDerefConditions(unsigned loopNum, LoopCloneContext* context);
6659 bool optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext* context);
6660 BasicBlock* optInsertLoopChoiceConditions(LoopCloneContext* context,
6666 ssize_t optGetArrayRefScaleAndIndex(GenTree* mul, GenTree** pIndex DEBUGARG(bool bRngChk));
6668 bool optReachWithoutCall(BasicBlock* srcBB, BasicBlock* dstBB);
6671 bool optLoopsMarked;
6674 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6675 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6679 XX Does the register allocation and puts the remaining lclVars on the stack XX
6681 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6682 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6686 regNumber raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc);
6688 void raMarkStkVars();
6691 // Some things are used by both LSRA and regpredict allocators.
6693 FrameType rpFrameType;
6694 bool rpMustCreateEBPCalled; // Set to true after we have called rpMustCreateEBPFrame once
6696 bool rpMustCreateEBPFrame(INDEBUG(const char** wbReason));
6699 Lowering* m_pLowering; // Lowering; needed to Lower IR that's added or modified after Lowering.
6700 LinearScanInterface* m_pLinearScan; // Linear Scan allocator
6702 /* raIsVarargsStackArg is called by raMaskStkVars and by
6703 lvaSortByRefCount. It identifies the special case
6704 where a varargs function has a parameter passed on the
6705 stack, other than the special varargs handle. Such parameters
6706 require special treatment, because they cannot be tracked
6707 by the GC (their offsets in the stack are not known
6711 bool raIsVarargsStackArg(unsigned lclNum)
6715 LclVarDsc* varDsc = &lvaTable[lclNum];
6717 assert(varDsc->lvIsParam);
6719 return (info.compIsVarArgs && !varDsc->lvIsRegArg && (lclNum != lvaVarargsHandleArg));
6721 #else // _TARGET_X86_
6725 #endif // _TARGET_X86_
6729 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6730 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6734 XX Get to the class and method info from the Execution Engine given XX
6735 XX tokens for the class and method XX
6737 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6738 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6744 void eeGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6745 CORINFO_RESOLVED_TOKEN* pConstrainedToken,
6746 CORINFO_CALLINFO_FLAGS flags,
6747 CORINFO_CALL_INFO* pResult);
6748 inline CORINFO_CALLINFO_FLAGS addVerifyFlag(CORINFO_CALLINFO_FLAGS flags);
6750 void eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6751 CORINFO_ACCESS_FLAGS flags,
6752 CORINFO_FIELD_INFO* pResult);
6756 BOOL eeIsValueClass(CORINFO_CLASS_HANDLE clsHnd);
6758 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(TRACK_LSRA_STATS)
6760 bool IsSuperPMIException(unsigned code)
6762 // Copied from NDP\clr\src\ToolBox\SuperPMI\SuperPMI-Shared\ErrorHandling.h
6764 const unsigned EXCEPTIONCODE_DebugBreakorAV = 0xe0421000;
6765 const unsigned EXCEPTIONCODE_MC = 0xe0422000;
6766 const unsigned EXCEPTIONCODE_LWM = 0xe0423000;
6767 const unsigned EXCEPTIONCODE_SASM = 0xe0424000;
6768 const unsigned EXCEPTIONCODE_SSYM = 0xe0425000;
6769 const unsigned EXCEPTIONCODE_CALLUTILS = 0xe0426000;
6770 const unsigned EXCEPTIONCODE_TYPEUTILS = 0xe0427000;
6771 const unsigned EXCEPTIONCODE_ASSERT = 0xe0440000;
6775 case EXCEPTIONCODE_DebugBreakorAV:
6776 case EXCEPTIONCODE_MC:
6777 case EXCEPTIONCODE_LWM:
6778 case EXCEPTIONCODE_SASM:
6779 case EXCEPTIONCODE_SSYM:
6780 case EXCEPTIONCODE_CALLUTILS:
6781 case EXCEPTIONCODE_TYPEUTILS:
6782 case EXCEPTIONCODE_ASSERT:
6789 const char* eeGetMethodName(CORINFO_METHOD_HANDLE hnd, const char** className);
6790 const char* eeGetMethodFullName(CORINFO_METHOD_HANDLE hnd);
6792 bool eeIsNativeMethod(CORINFO_METHOD_HANDLE method);
6793 CORINFO_METHOD_HANDLE eeGetMethodHandleForNative(CORINFO_METHOD_HANDLE method);
6796 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6797 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig, bool* isPinned);
6798 unsigned eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6800 // VOM info, method sigs
6802 void eeGetSig(unsigned sigTok,
6803 CORINFO_MODULE_HANDLE scope,
6804 CORINFO_CONTEXT_HANDLE context,
6805 CORINFO_SIG_INFO* retSig);
6807 void eeGetCallSiteSig(unsigned sigTok,
6808 CORINFO_MODULE_HANDLE scope,
6809 CORINFO_CONTEXT_HANDLE context,
6810 CORINFO_SIG_INFO* retSig);
6812 void eeGetMethodSig(CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* retSig, CORINFO_CLASS_HANDLE owner = nullptr);
6814 // Method entry-points, instrs
6816 CORINFO_METHOD_HANDLE eeMarkNativeTarget(CORINFO_METHOD_HANDLE method);
6818 CORINFO_EE_INFO eeInfo;
6819 bool eeInfoInitialized;
6821 CORINFO_EE_INFO* eeGetEEInfo();
6823 // Gets the offset of a SDArray's first element
6824 unsigned eeGetArrayDataOffset(var_types type);
6825 // Gets the offset of a MDArray's first element
6826 unsigned eeGetMDArrayDataOffset(var_types type, unsigned rank);
6828 GenTree* eeGetPInvokeCookie(CORINFO_SIG_INFO* szMetaSig);
6830 // Returns the page size for the target machine as reported by the EE.
6831 target_size_t eeGetPageSize()
6833 return (target_size_t)eeGetEEInfo()->osPageSize;
6836 // Returns the frame size at which we will generate a loop to probe the stack.
6837 target_size_t getVeryLargeFrameSize()
6840 // The looping probe code is 40 bytes, whereas the straight-line probing for
6841 // the (0x2000..0x3000) case is 44, so use looping for anything 0x2000 bytes
6842 // or greater, to generate smaller code.
6843 return 2 * eeGetPageSize();
6845 return 3 * eeGetPageSize();
6849 //------------------------------------------------------------------------
6850 // VirtualStubParam: virtual stub dispatch extra parameter (slot address).
6852 // It represents Abi and target specific registers for the parameter.
6854 class VirtualStubParamInfo
6857 VirtualStubParamInfo(bool isCoreRTABI)
6859 #if defined(_TARGET_X86_)
6862 #elif defined(_TARGET_AMD64_)
6873 #elif defined(_TARGET_ARM_)
6884 #elif defined(_TARGET_ARM64_)
6888 #error Unsupported or unset target architecture
6892 regNumber GetReg() const
6897 _regMask_enum GetRegMask() const
6904 _regMask_enum regMask;
6907 VirtualStubParamInfo* virtualStubParamInfo;
6909 bool IsTargetAbi(CORINFO_RUNTIME_ABI abi)
6911 return eeGetEEInfo()->targetAbi == abi;
6914 bool generateCFIUnwindCodes()
6916 #if defined(_TARGET_UNIX_)
6917 return IsTargetAbi(CORINFO_CORERT_ABI);
6923 // Debugging support - Line number info
6925 void eeGetStmtOffsets();
6927 unsigned eeBoundariesCount;
6929 struct boundariesDsc
6931 UNATIVE_OFFSET nativeIP;
6933 unsigned sourceReason;
6934 } * eeBoundaries; // Boundaries to report to EE
6935 void eeSetLIcount(unsigned count);
6936 void eeSetLIinfo(unsigned which, UNATIVE_OFFSET offs, unsigned srcIP, bool stkEmpty, bool callInstruction);
6940 static void eeDispILOffs(IL_OFFSET offs);
6941 static void eeDispLineInfo(const boundariesDsc* line);
6942 void eeDispLineInfos();
6945 // Debugging support - Local var info
6949 unsigned eeVarsCount;
6951 struct VarResultInfo
6953 UNATIVE_OFFSET startOffset;
6954 UNATIVE_OFFSET endOffset;
6956 CodeGenInterface::siVarLoc loc;
6958 void eeSetLVcount(unsigned count);
6959 void eeSetLVinfo(unsigned which,
6960 UNATIVE_OFFSET startOffs,
6961 UNATIVE_OFFSET length,
6966 const CodeGenInterface::siVarLoc* loc);
6970 void eeDispVar(ICorDebugInfo::NativeVarInfo* var);
6971 void eeDispVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars);
6974 // ICorJitInfo wrappers
6976 void eeReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize);
6978 void eeAllocUnwindInfo(BYTE* pHotCode,
6984 CorJitFuncKind funcKind);
6986 void eeSetEHcount(unsigned cEH);
6988 void eeSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause);
6990 WORD eeGetRelocTypeHint(void* target);
6992 // ICorStaticInfo wrapper functions
6994 bool eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken);
6996 #if defined(UNIX_AMD64_ABI)
6998 static void dumpSystemVClassificationType(SystemVClassificationType ct);
7001 void eeGetSystemVAmd64PassStructInRegisterDescriptor(
7002 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
7003 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr);
7004 #endif // UNIX_AMD64_ABI
7006 template <typename ParamType>
7007 bool eeRunWithErrorTrap(void (*function)(ParamType*), ParamType* param)
7009 return eeRunWithErrorTrapImp(reinterpret_cast<void (*)(void*)>(function), reinterpret_cast<void*>(param));
7012 bool eeRunWithErrorTrapImp(void (*function)(void*), void* param);
7014 // Utility functions
7016 const char* eeGetFieldName(CORINFO_FIELD_HANDLE fieldHnd, const char** classNamePtr = nullptr);
7019 const wchar_t* eeGetCPString(size_t stringHandle);
7022 const char* eeGetClassName(CORINFO_CLASS_HANDLE clsHnd);
7024 static CORINFO_METHOD_HANDLE eeFindHelper(unsigned helper);
7025 static CorInfoHelpFunc eeGetHelperNum(CORINFO_METHOD_HANDLE method);
7027 static fgWalkPreFn CountSharedStaticHelper;
7028 static bool IsSharedStaticHelper(GenTree* tree);
7029 static bool IsTreeAlwaysHoistable(GenTree* tree);
7030 static bool IsGcSafePoint(GenTree* tree);
7032 static CORINFO_FIELD_HANDLE eeFindJitDataOffs(unsigned jitDataOffs);
7033 // returns true/false if 'field' is a Jit Data offset
7034 static bool eeIsJitDataOffs(CORINFO_FIELD_HANDLE field);
7035 // returns a number < 0 if 'field' is not a Jit Data offset, otherwise the data offset (limited to 2GB)
7036 static int eeGetJitDataOffs(CORINFO_FIELD_HANDLE field);
7038 /*****************************************************************************/
7041 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7042 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7046 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7047 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7051 CodeGenInterface* codeGen;
7053 // The following holds information about instr offsets in terms of generated code.
7057 IPmappingDsc* ipmdNext; // next line# record
7058 IL_OFFSETX ipmdILoffsx; // the instr offset
7059 emitLocation ipmdNativeLoc; // the emitter location of the native code corresponding to the IL offset
7060 bool ipmdIsLabel; // Can this code be a branch label?
7063 // Record the instr offset mapping to the generated code
7065 IPmappingDsc* genIPmappingList;
7066 IPmappingDsc* genIPmappingLast;
7068 // Managed RetVal - A side hash table meant to record the mapping from a
7069 // GT_CALL node to its IL offset. This info is used to emit sequence points
7070 // that can be used by debugger to determine the native offset at which the
7071 // managed RetVal will be available.
7073 // In fact we can store IL offset in a GT_CALL node. This was ruled out in
7074 // favor of a side table for two reasons: 1) We need IL offset for only those
7075 // GT_CALL nodes (created during importation) that correspond to an IL call and
7076 // whose return type is other than TYP_VOID. 2) GT_CALL node is a frequently used
7077 // structure and IL offset is needed only when generating debuggable code. Therefore
7078 // it is desirable to avoid memory size penalty in retail scenarios.
7079 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, IL_OFFSETX> CallSiteILOffsetTable;
7080 CallSiteILOffsetTable* genCallSite2ILOffsetMap;
7082 unsigned genReturnLocal; // Local number for the return value when applicable.
7083 BasicBlock* genReturnBB; // jumped to when not optimizing for speed.
7085 // The following properties are part of CodeGenContext. Getters are provided here for
7086 // convenience and backward compatibility, but the properties can only be set by invoking
7087 // the setter on CodeGenContext directly.
7089 __declspec(property(get = getEmitter)) emitter* genEmitter;
7090 emitter* getEmitter()
7092 return codeGen->getEmitter();
7095 bool isFramePointerUsed() const
7097 return codeGen->isFramePointerUsed();
7100 __declspec(property(get = getInterruptible, put = setInterruptible)) bool genInterruptible;
7101 bool getInterruptible()
7103 return codeGen->genInterruptible;
7105 void setInterruptible(bool value)
7107 codeGen->setInterruptible(value);
7110 #ifdef _TARGET_ARMARCH_
7111 __declspec(property(get = getHasTailCalls, put = setHasTailCalls)) bool hasTailCalls;
7112 bool getHasTailCalls()
7114 return codeGen->hasTailCalls;
7116 void setHasTailCalls(bool value)
7118 codeGen->setHasTailCalls(value);
7120 #endif // _TARGET_ARMARCH_
7123 const bool genDoubleAlign()
7125 return codeGen->doDoubleAlign();
7127 DWORD getCanDoubleAlign();
7128 bool shouldDoubleAlign(unsigned refCntStk,
7130 unsigned refCntWtdReg,
7131 unsigned refCntStkParam,
7132 unsigned refCntWtdStkDbl);
7133 #endif // DOUBLE_ALIGN
7135 __declspec(property(get = getFullPtrRegMap, put = setFullPtrRegMap)) bool genFullPtrRegMap;
7136 bool getFullPtrRegMap()
7138 return codeGen->genFullPtrRegMap;
7140 void setFullPtrRegMap(bool value)
7142 codeGen->setFullPtrRegMap(value);
7145 // Things that MAY belong either in CodeGen or CodeGenContext
7147 #if FEATURE_EH_FUNCLETS
7148 FuncInfoDsc* compFuncInfos;
7149 unsigned short compCurrFuncIdx;
7150 unsigned short compFuncInfoCount;
7152 unsigned short compFuncCount()
7154 assert(fgFuncletsCreated);
7155 return compFuncInfoCount;
7158 #else // !FEATURE_EH_FUNCLETS
7160 // This is a no-op when there are no funclets!
7161 void genUpdateCurrentFunclet(BasicBlock* block)
7166 FuncInfoDsc compFuncInfoRoot;
7168 static const unsigned compCurrFuncIdx = 0;
7170 unsigned short compFuncCount()
7175 #endif // !FEATURE_EH_FUNCLETS
7177 FuncInfoDsc* funCurrentFunc();
7178 void funSetCurrentFunc(unsigned funcIdx);
7179 FuncInfoDsc* funGetFunc(unsigned funcIdx);
7180 unsigned int funGetFuncIdx(BasicBlock* block);
7184 VARSET_TP compCurLife; // current live variables
7185 GenTree* compCurLifeTree; // node after which compCurLife has been computed
7187 template <bool ForCodeGen>
7188 void compChangeLife(VARSET_VALARG_TP newLife);
7190 void genChangeLife(VARSET_VALARG_TP newLife)
7192 compChangeLife</*ForCodeGen*/ true>(newLife);
7195 template <bool ForCodeGen>
7196 inline void compUpdateLife(VARSET_VALARG_TP newLife);
7198 // Gets a register mask that represent the kill set for a helper call since
7199 // not all JIT Helper calls follow the standard ABI on the target architecture.
7200 regMaskTP compHelperCallKillSet(CorInfoHelpFunc helper);
7202 // Gets a register mask that represent the kill set for a NoGC helper call.
7203 regMaskTP compNoGCHelperCallKillSet(CorInfoHelpFunc helper);
7206 // Requires that "varDsc" be a promoted struct local variable being passed as an argument, beginning at
7207 // "firstArgRegNum", which is assumed to have already been aligned to the register alignment restriction of the
7208 // struct type. Adds bits to "*pArgSkippedRegMask" for any argument registers *not* used in passing "varDsc" --
7209 // i.e., internal "holes" caused by internal alignment constraints. For example, if the struct contained an int and
7210 // a double, and we at R0 (on ARM), then R1 would be skipped, and the bit for R1 would be added to the mask.
7211 void fgAddSkippedRegsInPromotedStructArg(LclVarDsc* varDsc, unsigned firstArgRegNum, regMaskTP* pArgSkippedRegMask);
7212 #endif // _TARGET_ARM_
7214 // 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
7216 static GenTree* fgIsIndirOfAddrOfLocal(GenTree* tree);
7218 // This map is indexed by GT_OBJ nodes that are address of promoted struct variables, which
7219 // have been annotated with the GTF_VAR_DEATH flag. If such a node is *not* mapped in this
7220 // table, one may assume that all the (tracked) field vars die at this GT_OBJ. Otherwise,
7221 // the node maps to a pointer to a VARSET_TP, containing set bits for each of the tracked field
7222 // vars of the promoted struct local that go dead at the given node (the set bits are the bits
7223 // for the tracked var indices of the field vars, as in a live var set).
7225 // The map is allocated on demand so all map operations should use one of the following three
7228 NodeToVarsetPtrMap* m_promotedStructDeathVars;
7230 NodeToVarsetPtrMap* GetPromotedStructDeathVars()
7232 if (m_promotedStructDeathVars == nullptr)
7234 m_promotedStructDeathVars = new (getAllocator()) NodeToVarsetPtrMap(getAllocator());
7236 return m_promotedStructDeathVars;
7239 void ClearPromotedStructDeathVars()
7241 if (m_promotedStructDeathVars != nullptr)
7243 m_promotedStructDeathVars->RemoveAll();
7247 bool LookupPromotedStructDeathVars(GenTree* tree, VARSET_TP** bits)
7250 bool result = false;
7252 if (m_promotedStructDeathVars != nullptr)
7254 result = m_promotedStructDeathVars->Lookup(tree, bits);
7261 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7262 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7266 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7267 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7270 #if !defined(__GNUC__)
7271 #pragma region Unwind information
7276 // Infrastructure functions: start/stop/reserve/emit.
7279 void unwindBegProlog();
7280 void unwindEndProlog();
7281 void unwindBegEpilog();
7282 void unwindEndEpilog();
7283 void unwindReserve();
7284 void unwindEmit(void* pHotCode, void* pColdCode);
7287 // Specific unwind information functions: called by code generation to indicate a particular
7288 // prolog or epilog unwindable instruction has been generated.
7291 void unwindPush(regNumber reg);
7292 void unwindAllocStack(unsigned size);
7293 void unwindSetFrameReg(regNumber reg, unsigned offset);
7294 void unwindSaveReg(regNumber reg, unsigned offset);
7296 #if defined(_TARGET_ARM_)
7297 void unwindPushMaskInt(regMaskTP mask);
7298 void unwindPushMaskFloat(regMaskTP mask);
7299 void unwindPopMaskInt(regMaskTP mask);
7300 void unwindPopMaskFloat(regMaskTP mask);
7301 void unwindBranch16(); // The epilog terminates with a 16-bit branch (e.g., "bx lr")
7302 void unwindNop(unsigned codeSizeInBytes); // Generate unwind NOP code. 'codeSizeInBytes' is 2 or 4 bytes. Only
7303 // called via unwindPadding().
7304 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7305 // instruction and the current location.
7306 #endif // _TARGET_ARM_
7308 #if defined(_TARGET_ARM64_)
7310 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7311 // instruction and the current location.
7312 void unwindSaveReg(regNumber reg, int offset); // str reg, [sp, #offset]
7313 void unwindSaveRegPreindexed(regNumber reg, int offset); // str reg, [sp, #offset]!
7314 void unwindSaveRegPair(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]
7315 void unwindSaveRegPairPreindexed(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]!
7316 void unwindSaveNext(); // unwind code: save_next
7317 void unwindReturn(regNumber reg); // ret lr
7318 #endif // defined(_TARGET_ARM64_)
7321 // Private "helper" functions for the unwind implementation.
7325 #if FEATURE_EH_FUNCLETS
7326 void unwindGetFuncLocations(FuncInfoDsc* func,
7327 bool getHotSectionData,
7328 /* OUT */ emitLocation** ppStartLoc,
7329 /* OUT */ emitLocation** ppEndLoc);
7330 #endif // FEATURE_EH_FUNCLETS
7332 void unwindReserveFunc(FuncInfoDsc* func);
7333 void unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
7335 #if defined(_TARGET_AMD64_) || (defined(_TARGET_X86_) && FEATURE_EH_FUNCLETS)
7337 void unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode);
7338 void unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode);
7340 #endif // _TARGET_AMD64_ || (_TARGET_X86_ && FEATURE_EH_FUNCLETS)
7342 UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func);
7344 #if defined(_TARGET_AMD64_)
7346 void unwindBegPrologWindows();
7347 void unwindPushWindows(regNumber reg);
7348 void unwindAllocStackWindows(unsigned size);
7349 void unwindSetFrameRegWindows(regNumber reg, unsigned offset);
7350 void unwindSaveRegWindows(regNumber reg, unsigned offset);
7352 #ifdef UNIX_AMD64_ABI
7353 void unwindSaveRegCFI(regNumber reg, unsigned offset);
7354 #endif // UNIX_AMD64_ABI
7355 #elif defined(_TARGET_ARM_)
7357 void unwindPushPopMaskInt(regMaskTP mask, bool useOpsize16);
7358 void unwindPushPopMaskFloat(regMaskTP mask);
7360 #endif // _TARGET_ARM_
7362 #if defined(_TARGET_UNIX_)
7363 int mapRegNumToDwarfReg(regNumber reg);
7364 void createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR opcode, USHORT dwarfReg, INT offset = 0);
7365 void unwindPushPopCFI(regNumber reg);
7366 void unwindBegPrologCFI();
7367 void unwindPushPopMaskCFI(regMaskTP regMask, bool isFloat);
7368 void unwindAllocStackCFI(unsigned size);
7369 void unwindSetFrameRegCFI(regNumber reg, unsigned offset);
7370 void unwindEmitFuncCFI(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
7372 void DumpCfiInfo(bool isHotCode,
7373 UNATIVE_OFFSET startOffset,
7374 UNATIVE_OFFSET endOffset,
7376 const CFI_CODE* const pCfiCode);
7379 #endif // _TARGET_UNIX_
7381 #if !defined(__GNUC__)
7382 #pragma endregion // Note: region is NOT under !defined(__GNUC__)
7386 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7387 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7391 XX Info about SIMD types, methods and the SIMD assembly (i.e. the assembly XX
7392 XX that contains the distinguished, well-known SIMD type definitions). XX
7394 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7395 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7398 // Get highest available level for SIMD codegen
7399 SIMDLevel getSIMDSupportLevel()
7401 #if defined(_TARGET_XARCH_)
7402 if (compSupports(InstructionSet_AVX2))
7404 return SIMD_AVX2_Supported;
7407 if (compSupports(InstructionSet_SSE42))
7409 return SIMD_SSE4_Supported;
7413 return SIMD_SSE2_Supported;
7415 assert(!"Available instruction set(s) for SIMD codegen is not defined for target arch");
7417 return SIMD_Not_Supported;
7423 // Should we support SIMD intrinsics?
7426 // Have we identified any SIMD types?
7427 // This is currently used by struct promotion to avoid getting type information for a struct
7428 // field to see if it is a SIMD type, if we haven't seen any SIMD types or operations in
7430 bool _usesSIMDTypes;
7431 bool usesSIMDTypes()
7433 return _usesSIMDTypes;
7435 void setUsesSIMDTypes(bool value)
7437 _usesSIMDTypes = value;
7440 // This is a temp lclVar allocated on the stack as TYP_SIMD. It is used to implement intrinsics
7441 // that require indexed access to the individual fields of the vector, which is not well supported
7442 // by the hardware. It is allocated when/if such situations are encountered during Lowering.
7443 unsigned lvaSIMDInitTempVarNum;
7445 struct SIMDHandlesCache
7448 CORINFO_CLASS_HANDLE SIMDFloatHandle;
7449 CORINFO_CLASS_HANDLE SIMDDoubleHandle;
7450 CORINFO_CLASS_HANDLE SIMDIntHandle;
7451 CORINFO_CLASS_HANDLE SIMDUShortHandle;
7452 CORINFO_CLASS_HANDLE SIMDUByteHandle;
7453 CORINFO_CLASS_HANDLE SIMDShortHandle;
7454 CORINFO_CLASS_HANDLE SIMDByteHandle;
7455 CORINFO_CLASS_HANDLE SIMDLongHandle;
7456 CORINFO_CLASS_HANDLE SIMDUIntHandle;
7457 CORINFO_CLASS_HANDLE SIMDULongHandle;
7458 CORINFO_CLASS_HANDLE SIMDVector2Handle;
7459 CORINFO_CLASS_HANDLE SIMDVector3Handle;
7460 CORINFO_CLASS_HANDLE SIMDVector4Handle;
7461 CORINFO_CLASS_HANDLE SIMDVectorHandle;
7463 #ifdef FEATURE_HW_INTRINSICS
7464 #if defined(_TARGET_ARM64_)
7465 CORINFO_CLASS_HANDLE Vector64FloatHandle;
7466 CORINFO_CLASS_HANDLE Vector64IntHandle;
7467 CORINFO_CLASS_HANDLE Vector64UShortHandle;
7468 CORINFO_CLASS_HANDLE Vector64UByteHandle;
7469 CORINFO_CLASS_HANDLE Vector64ShortHandle;
7470 CORINFO_CLASS_HANDLE Vector64ByteHandle;
7471 CORINFO_CLASS_HANDLE Vector64UIntHandle;
7472 #endif // defined(_TARGET_ARM64_)
7473 CORINFO_CLASS_HANDLE Vector128FloatHandle;
7474 CORINFO_CLASS_HANDLE Vector128DoubleHandle;
7475 CORINFO_CLASS_HANDLE Vector128IntHandle;
7476 CORINFO_CLASS_HANDLE Vector128UShortHandle;
7477 CORINFO_CLASS_HANDLE Vector128UByteHandle;
7478 CORINFO_CLASS_HANDLE Vector128ShortHandle;
7479 CORINFO_CLASS_HANDLE Vector128ByteHandle;
7480 CORINFO_CLASS_HANDLE Vector128LongHandle;
7481 CORINFO_CLASS_HANDLE Vector128UIntHandle;
7482 CORINFO_CLASS_HANDLE Vector128ULongHandle;
7483 #if defined(_TARGET_XARCH_)
7484 CORINFO_CLASS_HANDLE Vector256FloatHandle;
7485 CORINFO_CLASS_HANDLE Vector256DoubleHandle;
7486 CORINFO_CLASS_HANDLE Vector256IntHandle;
7487 CORINFO_CLASS_HANDLE Vector256UShortHandle;
7488 CORINFO_CLASS_HANDLE Vector256UByteHandle;
7489 CORINFO_CLASS_HANDLE Vector256ShortHandle;
7490 CORINFO_CLASS_HANDLE Vector256ByteHandle;
7491 CORINFO_CLASS_HANDLE Vector256LongHandle;
7492 CORINFO_CLASS_HANDLE Vector256UIntHandle;
7493 CORINFO_CLASS_HANDLE Vector256ULongHandle;
7494 #endif // defined(_TARGET_XARCH_)
7495 #endif // FEATURE_HW_INTRINSICS
7499 memset(this, 0, sizeof(*this));
7503 SIMDHandlesCache* m_simdHandleCache;
7505 // Get an appropriate "zero" for the given type and class handle.
7506 GenTree* gtGetSIMDZero(var_types simdType, var_types baseType, CORINFO_CLASS_HANDLE simdHandle);
7508 // Get the handle for a SIMD type.
7509 CORINFO_CLASS_HANDLE gtGetStructHandleForSIMD(var_types simdType, var_types simdBaseType)
7511 if (m_simdHandleCache == nullptr)
7513 // This may happen if the JIT generates SIMD node on its own, without importing them.
7514 // Otherwise getBaseTypeAndSizeOfSIMDType should have created the cache.
7515 return NO_CLASS_HANDLE;
7518 if (simdBaseType == TYP_FLOAT)
7523 return m_simdHandleCache->SIMDVector2Handle;
7525 return m_simdHandleCache->SIMDVector3Handle;
7527 if ((getSIMDVectorType() == TYP_SIMD32) ||
7528 (m_simdHandleCache->SIMDVector4Handle != NO_CLASS_HANDLE))
7530 return m_simdHandleCache->SIMDVector4Handle;
7539 assert(emitTypeSize(simdType) <= maxSIMDStructBytes());
7540 switch (simdBaseType)
7543 return m_simdHandleCache->SIMDFloatHandle;
7545 return m_simdHandleCache->SIMDDoubleHandle;
7547 return m_simdHandleCache->SIMDIntHandle;
7549 return m_simdHandleCache->SIMDUShortHandle;
7551 return m_simdHandleCache->SIMDUByteHandle;
7553 return m_simdHandleCache->SIMDShortHandle;
7555 return m_simdHandleCache->SIMDByteHandle;
7557 return m_simdHandleCache->SIMDLongHandle;
7559 return m_simdHandleCache->SIMDUIntHandle;
7561 return m_simdHandleCache->SIMDULongHandle;
7563 assert(!"Didn't find a class handle for simdType");
7565 return NO_CLASS_HANDLE;
7568 // Returns true if this is a SIMD type that should be considered an opaque
7569 // vector type (i.e. do not analyze or promote its fields).
7570 // Note that all but the fixed vector types are opaque, even though they may
7571 // actually be declared as having fields.
7572 bool isOpaqueSIMDType(CORINFO_CLASS_HANDLE structHandle)
7574 return ((m_simdHandleCache != nullptr) && (structHandle != m_simdHandleCache->SIMDVector2Handle) &&
7575 (structHandle != m_simdHandleCache->SIMDVector3Handle) &&
7576 (structHandle != m_simdHandleCache->SIMDVector4Handle));
7579 // Returns true if the tree corresponds to a TYP_SIMD lcl var.
7580 // Note that both SIMD vector args and locals are mared as lvSIMDType = true, but
7581 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD or TYP_STRUCT.
7582 bool isSIMDTypeLocal(GenTree* tree)
7584 return tree->OperIsLocal() && lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7587 // Returns true if the lclVar is an opaque SIMD type.
7588 bool isOpaqueSIMDLclVar(LclVarDsc* varDsc)
7590 if (!varDsc->lvSIMDType)
7594 return isOpaqueSIMDType(varDsc->lvVerTypeInfo.GetClassHandle());
7597 // Returns true if the type of the tree is a byref of TYP_SIMD
7598 bool isAddrOfSIMDType(GenTree* tree)
7600 if (tree->TypeGet() == TYP_BYREF || tree->TypeGet() == TYP_I_IMPL)
7602 switch (tree->OperGet())
7605 return varTypeIsSIMD(tree->gtGetOp1());
7607 case GT_LCL_VAR_ADDR:
7608 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7611 return isSIMDTypeLocal(tree);
7618 static bool isRelOpSIMDIntrinsic(SIMDIntrinsicID intrinsicId)
7620 return (intrinsicId == SIMDIntrinsicEqual || intrinsicId == SIMDIntrinsicLessThan ||
7621 intrinsicId == SIMDIntrinsicLessThanOrEqual || intrinsicId == SIMDIntrinsicGreaterThan ||
7622 intrinsicId == SIMDIntrinsicGreaterThanOrEqual);
7625 // Returns base type of a TYP_SIMD local.
7626 // Returns TYP_UNKNOWN if the local is not TYP_SIMD.
7627 var_types getBaseTypeOfSIMDLocal(GenTree* tree)
7629 if (isSIMDTypeLocal(tree))
7631 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvBaseType;
7637 bool isSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7639 return info.compCompHnd->isInSIMDModule(clsHnd);
7642 bool isIntrinsicType(CORINFO_CLASS_HANDLE clsHnd)
7644 return (info.compCompHnd->getClassAttribs(clsHnd) & CORINFO_FLG_INTRINSIC_TYPE) != 0;
7647 const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName)
7649 return info.compCompHnd->getClassNameFromMetadata(cls, namespaceName);
7652 CORINFO_CLASS_HANDLE getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index)
7654 return info.compCompHnd->getTypeInstantiationArgument(cls, index);
7657 bool isSIMDClass(typeInfo* pTypeInfo)
7659 return pTypeInfo->IsStruct() && isSIMDClass(pTypeInfo->GetClassHandleForValueClass());
7662 bool isHWSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7664 #ifdef FEATURE_HW_INTRINSICS
7665 if (isIntrinsicType(clsHnd))
7667 const char* namespaceName = nullptr;
7668 (void)getClassNameFromMetadata(clsHnd, &namespaceName);
7669 return strcmp(namespaceName, "System.Runtime.Intrinsics") == 0;
7671 #endif // FEATURE_HW_INTRINSICS
7675 bool isHWSIMDClass(typeInfo* pTypeInfo)
7677 #ifdef FEATURE_HW_INTRINSICS
7678 return pTypeInfo->IsStruct() && isHWSIMDClass(pTypeInfo->GetClassHandleForValueClass());
7684 bool isSIMDorHWSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7686 return isSIMDClass(clsHnd) || isHWSIMDClass(clsHnd);
7689 bool isSIMDorHWSIMDClass(typeInfo* pTypeInfo)
7691 return isSIMDClass(pTypeInfo) || isHWSIMDClass(pTypeInfo);
7694 // Get the base (element) type and size in bytes for a SIMD type. Returns TYP_UNKNOWN
7695 // if it is not a SIMD type or is an unsupported base type.
7696 var_types getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes = nullptr);
7698 var_types getBaseTypeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7700 return getBaseTypeAndSizeOfSIMDType(typeHnd, nullptr);
7703 // Get SIMD Intrinsic info given the method handle.
7704 // Also sets typeHnd, argCount, baseType and sizeBytes out params.
7705 const SIMDIntrinsicInfo* getSIMDIntrinsicInfo(CORINFO_CLASS_HANDLE* typeHnd,
7706 CORINFO_METHOD_HANDLE methodHnd,
7707 CORINFO_SIG_INFO* sig,
7710 var_types* baseType,
7711 unsigned* sizeBytes);
7713 // Pops and returns GenTree node from importers type stack.
7714 // Normalizes TYP_STRUCT value in case of GT_CALL, GT_RET_EXPR and arg nodes.
7715 GenTree* impSIMDPopStack(var_types type, bool expectAddr = false, CORINFO_CLASS_HANDLE structType = nullptr);
7717 // Create a GT_SIMD tree for a Get property of SIMD vector with a fixed index.
7718 GenTreeSIMD* impSIMDGetFixed(var_types simdType, var_types baseType, unsigned simdSize, int index);
7720 // Creates a GT_SIMD tree for Select operation
7721 GenTree* impSIMDSelect(CORINFO_CLASS_HANDLE typeHnd,
7723 unsigned simdVectorSize,
7728 // Creates a GT_SIMD tree for Min/Max operation
7729 GenTree* impSIMDMinMax(SIMDIntrinsicID intrinsicId,
7730 CORINFO_CLASS_HANDLE typeHnd,
7732 unsigned simdVectorSize,
7736 // Transforms operands and returns the SIMD intrinsic to be applied on
7737 // transformed operands to obtain given relop result.
7738 SIMDIntrinsicID impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId,
7739 CORINFO_CLASS_HANDLE typeHnd,
7740 unsigned simdVectorSize,
7741 var_types* baseType,
7745 // Creates a GT_SIMD tree for Abs intrinsic.
7746 GenTree* impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType, unsigned simdVectorSize, GenTree* op1);
7748 #if defined(_TARGET_XARCH_)
7750 // Transforms operands and returns the SIMD intrinsic to be applied on
7751 // transformed operands to obtain == comparison result.
7752 SIMDIntrinsicID impSIMDLongRelOpEqual(CORINFO_CLASS_HANDLE typeHnd,
7753 unsigned simdVectorSize,
7757 // Transforms operands and returns the SIMD intrinsic to be applied on
7758 // transformed operands to obtain > comparison result.
7759 SIMDIntrinsicID impSIMDLongRelOpGreaterThan(CORINFO_CLASS_HANDLE typeHnd,
7760 unsigned simdVectorSize,
7764 // Transforms operands and returns the SIMD intrinsic to be applied on
7765 // transformed operands to obtain >= comparison result.
7766 SIMDIntrinsicID impSIMDLongRelOpGreaterThanOrEqual(CORINFO_CLASS_HANDLE typeHnd,
7767 unsigned simdVectorSize,
7771 // Transforms operands and returns the SIMD intrinsic to be applied on
7772 // transformed operands to obtain >= comparison result in case of int32
7773 // and small int base type vectors.
7774 SIMDIntrinsicID impSIMDIntegralRelOpGreaterThanOrEqual(
7775 CORINFO_CLASS_HANDLE typeHnd, unsigned simdVectorSize, var_types baseType, GenTree** op1, GenTree** op2);
7777 #endif // defined(_TARGET_XARCH_)
7779 void setLclRelatedToSIMDIntrinsic(GenTree* tree);
7780 bool areFieldsContiguous(GenTree* op1, GenTree* op2);
7781 bool areArrayElementsContiguous(GenTree* op1, GenTree* op2);
7782 bool areArgumentsContiguous(GenTree* op1, GenTree* op2);
7783 GenTree* createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize);
7785 // check methodHnd to see if it is a SIMD method that is expanded as an intrinsic in the JIT.
7786 GenTree* impSIMDIntrinsic(OPCODE opcode,
7787 GenTree* newobjThis,
7788 CORINFO_CLASS_HANDLE clsHnd,
7789 CORINFO_METHOD_HANDLE method,
7790 CORINFO_SIG_INFO* sig,
7791 unsigned methodFlags,
7794 GenTree* getOp1ForConstructor(OPCODE opcode, GenTree* newobjThis, CORINFO_CLASS_HANDLE clsHnd);
7796 // Whether SIMD vector occupies part of SIMD register.
7797 // SSE2: vector2f/3f are considered sub register SIMD types.
7798 // AVX: vector2f, 3f and 4f are all considered sub register SIMD types.
7799 bool isSubRegisterSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7801 unsigned sizeBytes = 0;
7802 var_types baseType = getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7803 return (baseType == TYP_FLOAT) && (sizeBytes < getSIMDVectorRegisterByteLength());
7806 bool isSubRegisterSIMDType(GenTreeSIMD* simdNode)
7808 return (simdNode->gtSIMDSize < getSIMDVectorRegisterByteLength());
7811 // Get the type for the hardware SIMD vector.
7812 // This is the maximum SIMD type supported for this target.
7813 var_types getSIMDVectorType()
7815 #if defined(_TARGET_XARCH_)
7816 if (getSIMDSupportLevel() == SIMD_AVX2_Supported)
7822 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7825 #elif defined(_TARGET_ARM64_)
7828 assert(!"getSIMDVectorType() unimplemented on target arch");
7833 // Get the size of the SIMD type in bytes
7834 int getSIMDTypeSizeInBytes(CORINFO_CLASS_HANDLE typeHnd)
7836 unsigned sizeBytes = 0;
7837 (void)getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7841 // Get the the number of elements of basetype of SIMD vector given by its size and baseType
7842 static int getSIMDVectorLength(unsigned simdSize, var_types baseType);
7844 // Get the the number of elements of basetype of SIMD vector given by its type handle
7845 int getSIMDVectorLength(CORINFO_CLASS_HANDLE typeHnd);
7847 // Get preferred alignment of SIMD type.
7848 int getSIMDTypeAlignment(var_types simdType);
7850 // Get the number of bytes in a System.Numeric.Vector<T> for the current compilation.
7851 // Note - cannot be used for System.Runtime.Intrinsic
7852 unsigned getSIMDVectorRegisterByteLength()
7854 #if defined(_TARGET_XARCH_)
7855 if (getSIMDSupportLevel() == SIMD_AVX2_Supported)
7857 return YMM_REGSIZE_BYTES;
7861 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7862 return XMM_REGSIZE_BYTES;
7864 #elif defined(_TARGET_ARM64_)
7865 return FP_REGSIZE_BYTES;
7867 assert(!"getSIMDVectorRegisterByteLength() unimplemented on target arch");
7872 // The minimum and maximum possible number of bytes in a SIMD vector.
7874 // maxSIMDStructBytes
7875 // The minimum SIMD size supported by System.Numeric.Vectors or System.Runtime.Intrinsic
7876 // SSE: 16-byte Vector<T> and Vector128<T>
7877 // AVX: 32-byte Vector256<T> (Vector<T> is 16-byte)
7878 // AVX2: 32-byte Vector<T> and Vector256<T>
7879 unsigned int maxSIMDStructBytes()
7881 #if defined(FEATURE_HW_INTRINSICS) && defined(_TARGET_XARCH_)
7882 if (compSupports(InstructionSet_AVX))
7884 return YMM_REGSIZE_BYTES;
7888 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7889 return XMM_REGSIZE_BYTES;
7892 return getSIMDVectorRegisterByteLength();
7895 unsigned int minSIMDStructBytes()
7897 return emitTypeSize(TYP_SIMD8);
7900 // Returns the codegen type for a given SIMD size.
7901 var_types getSIMDTypeForSize(unsigned size)
7903 var_types simdType = TYP_UNDEF;
7906 simdType = TYP_SIMD8;
7908 else if (size == 12)
7910 simdType = TYP_SIMD12;
7912 else if (size == 16)
7914 simdType = TYP_SIMD16;
7916 else if (size == 32)
7918 simdType = TYP_SIMD32;
7922 noway_assert(!"Unexpected size for SIMD type");
7927 unsigned getSIMDInitTempVarNum()
7929 if (lvaSIMDInitTempVarNum == BAD_VAR_NUM)
7931 lvaSIMDInitTempVarNum = lvaGrabTempWithImplicitUse(false DEBUGARG("SIMDInitTempVar"));
7932 lvaTable[lvaSIMDInitTempVarNum].lvType = getSIMDVectorType();
7934 return lvaSIMDInitTempVarNum;
7937 #else // !FEATURE_SIMD
7938 bool isOpaqueSIMDLclVar(LclVarDsc* varDsc)
7942 #endif // FEATURE_SIMD
7945 //------------------------------------------------------------------------
7946 // largestEnregisterableStruct: The size in bytes of the largest struct that can be enregistered.
7948 // Notes: It is not guaranteed that the struct of this size or smaller WILL be a
7949 // candidate for enregistration.
7951 unsigned largestEnregisterableStructSize()
7954 unsigned vectorRegSize = getSIMDVectorRegisterByteLength();
7955 if (vectorRegSize > TARGET_POINTER_SIZE)
7957 return vectorRegSize;
7960 #endif // FEATURE_SIMD
7962 return TARGET_POINTER_SIZE;
7967 // These routines need not be enclosed under FEATURE_SIMD since lvIsSIMDType()
7968 // is defined for both FEATURE_SIMD and !FEATURE_SIMD apropriately. The use
7969 // of this routines also avoids the need of #ifdef FEATURE_SIMD specific code.
7971 // Is this var is of type simd struct?
7972 bool lclVarIsSIMDType(unsigned varNum)
7974 LclVarDsc* varDsc = lvaTable + varNum;
7975 return varDsc->lvIsSIMDType();
7978 // Is this Local node a SIMD local?
7979 bool lclVarIsSIMDType(GenTreeLclVarCommon* lclVarTree)
7981 return lclVarIsSIMDType(lclVarTree->gtLclNum);
7984 // Returns true if the TYP_SIMD locals on stack are aligned at their
7985 // preferred byte boundary specified by getSIMDTypeAlignment().
7987 // As per the Intel manual, the preferred alignment for AVX vectors is 32-bytes. On Amd64,
7988 // RSP/EBP is aligned at 16-bytes, therefore to align SIMD types at 32-bytes we need even
7989 // RSP/EBP to be 32-byte aligned. It is not clear whether additional stack space used in
7990 // aligning stack is worth the benefit and for now will use 16-byte alignment for AVX
7991 // 256-bit vectors with unaligned load/stores to/from memory. On x86, the stack frame
7992 // is aligned to 4 bytes. We need to extend existing support for double (8-byte) alignment
7993 // to 16 or 32 byte alignment for frames with local SIMD vars, if that is determined to be
7996 bool isSIMDTypeLocalAligned(unsigned varNum)
7998 #if defined(FEATURE_SIMD) && ALIGN_SIMD_TYPES
7999 if (lclVarIsSIMDType(varNum) && lvaTable[varNum].lvType != TYP_BYREF)
8002 int off = lvaFrameAddress(varNum, &ebpBased);
8003 // TODO-Cleanup: Can't this use the lvExactSize on the varDsc?
8004 int alignment = getSIMDTypeAlignment(lvaTable[varNum].lvType);
8005 bool isAligned = (alignment <= STACK_ALIGN) && ((off % alignment) == 0);
8008 #endif // FEATURE_SIMD
8013 bool compSupports(InstructionSet isa) const
8015 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
8016 return (opts.compSupportsISA & (1ULL << isa)) != 0;
8022 bool canUseVexEncoding() const
8024 #ifdef _TARGET_XARCH_
8025 return compSupports(InstructionSet_AVX);
8032 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8033 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8037 XX Generic info about the compilation and the method being compiled. XX
8038 XX It is responsible for driving the other phases. XX
8039 XX It is also responsible for all the memory management. XX
8041 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8042 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8046 Compiler* InlineeCompiler; // The Compiler instance for the inlinee
8048 InlineResult* compInlineResult; // The result of importing the inlinee method.
8050 bool compDoAggressiveInlining; // If true, mark every method as CORINFO_FLG_FORCEINLINE
8051 bool compJmpOpUsed; // Does the method do a JMP
8052 bool compLongUsed; // Does the method use TYP_LONG
8053 bool compFloatingPointUsed; // Does the method use TYP_FLOAT or TYP_DOUBLE
8054 bool compTailCallUsed; // Does the method do a tailcall
8055 bool compLocallocUsed; // Does the method use localloc.
8056 bool compLocallocOptimized; // Does the method have an optimized localloc
8057 bool compQmarkUsed; // Does the method use GT_QMARK/GT_COLON
8058 bool compQmarkRationalized; // Is it allowed to use a GT_QMARK/GT_COLON node.
8059 bool compUnsafeCastUsed; // Does the method use LDIND/STIND to cast between scalar/refernce types
8061 // NOTE: These values are only reliable after
8062 // the importing is completely finished.
8065 // State information - which phases have completed?
8066 // These are kept together for easy discoverability
8068 bool bRangeAllowStress;
8069 bool compCodeGenDone;
8070 int64_t compNumStatementLinksTraversed; // # of links traversed while doing debug checks
8071 bool fgNormalizeEHDone; // Has the flowgraph EH normalization phase been done?
8072 size_t compSizeEstimate; // The estimated size of the method as per `gtSetEvalOrder`.
8073 size_t compCycleEstimate; // The estimated cycle count of the method as per `gtSetEvalOrder`
8076 bool fgLocalVarLivenessDone; // Note that this one is used outside of debug.
8077 bool fgLocalVarLivenessChanged;
8079 bool compRationalIRForm;
8081 bool compUsesThrowHelper; // There is a call to a THOROW_HELPER for the compiled method.
8083 bool compGeneratingProlog;
8084 bool compGeneratingEpilog;
8085 bool compNeedsGSSecurityCookie; // There is an unsafe buffer (or localloc) on the stack.
8086 // Insert cookie on frame and code to check the cookie, like VC++ -GS.
8087 bool compGSReorderStackLayout; // There is an unsafe buffer on the stack, reorder locals and make local
8088 // copies of susceptible parameters to avoid buffer overrun attacks through locals/params
8089 bool getNeedsGSSecurityCookie() const
8091 return compNeedsGSSecurityCookie;
8093 void setNeedsGSSecurityCookie()
8095 compNeedsGSSecurityCookie = true;
8098 FrameLayoutState lvaDoneFrameLayout; // The highest frame layout state that we've completed. During
8099 // frame layout calculations, this is the level we are currently
8102 //---------------------------- JITing options -----------------------------
8115 JitFlags* jitFlags; // all flags passed from the EE
8116 unsigned compFlags; // method attributes
8118 codeOptimize compCodeOpt; // what type of code optimizations
8123 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
8124 uint64_t compSupportsISA;
8125 void setSupportedISA(InstructionSet isa)
8127 compSupportsISA |= 1ULL << isa;
8131 // optimize maximally and/or favor speed over size?
8133 #define DEFAULT_MIN_OPTS_CODE_SIZE 60000
8134 #define DEFAULT_MIN_OPTS_INSTR_COUNT 20000
8135 #define DEFAULT_MIN_OPTS_BB_COUNT 2000
8136 #define DEFAULT_MIN_OPTS_LV_NUM_COUNT 2000
8137 #define DEFAULT_MIN_OPTS_LV_REF_COUNT 8000
8139 // Maximun number of locals before turning off the inlining
8140 #define MAX_LV_NUM_COUNT_FOR_INLINING 512
8143 unsigned instrCount;
8144 unsigned lvRefCount;
8145 bool compMinOptsIsSet;
8147 bool compMinOptsIsUsed;
8151 assert(compMinOptsIsSet);
8152 compMinOptsIsUsed = true;
8157 return compMinOptsIsSet;
8166 return compMinOptsIsSet;
8170 bool OptimizationDisabled()
8172 return MinOpts() || compDbgCode;
8174 bool OptimizationEnabled()
8176 return !OptimizationDisabled();
8179 void SetMinOpts(bool val)
8181 assert(!compMinOptsIsUsed);
8182 assert(!compMinOptsIsSet || (compMinOpts == val));
8184 compMinOptsIsSet = true;
8187 // true if the CLFLG_* for an optimization is set.
8188 bool OptEnabled(unsigned optFlag)
8190 return !!(compFlags & optFlag);
8193 #ifdef FEATURE_READYTORUN_COMPILER
8196 return jitFlags->IsSet(JitFlags::JIT_FLAG_READYTORUN);
8205 // true if we should use the PINVOKE_{BEGIN,END} helpers instead of generating
8206 // PInvoke transitions inline (e.g. when targeting CoreRT).
8207 bool ShouldUsePInvokeHelpers()
8209 return jitFlags->IsSet(JitFlags::JIT_FLAG_USE_PINVOKE_HELPERS);
8212 // true if we should use insert the REVERSE_PINVOKE_{ENTER,EXIT} helpers in the method
8214 bool IsReversePInvoke()
8216 return jitFlags->IsSet(JitFlags::JIT_FLAG_REVERSE_PINVOKE);
8219 // true if we must generate code compatible with JIT32 quirks
8220 bool IsJit32Compat()
8222 #if defined(_TARGET_X86_)
8223 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
8229 // true if we must generate code compatible with Jit64 quirks
8230 bool IsJit64Compat()
8232 #if defined(_TARGET_AMD64_)
8233 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
8234 #elif !defined(FEATURE_CORECLR)
8241 bool compScopeInfo; // Generate the LocalVar info ?
8242 bool compDbgCode; // Generate debugger-friendly code?
8243 bool compDbgInfo; // Gather debugging info?
8246 #ifdef PROFILING_SUPPORTED
8247 bool compNoPInvokeInlineCB;
8249 static const bool compNoPInvokeInlineCB;
8253 bool compGcChecks; // Check arguments and return values to ensure they are sane
8256 #if defined(DEBUG) && defined(_TARGET_XARCH_)
8258 bool compStackCheckOnRet; // Check stack pointer on return to ensure it is correct.
8260 #endif // defined(DEBUG) && defined(_TARGET_XARCH_)
8262 #if defined(DEBUG) && defined(_TARGET_X86_)
8264 bool compStackCheckOnCall; // Check stack pointer after call to ensure it is correct. Only for x86.
8266 #endif // defined(DEBUG) && defined(_TARGET_X86_)
8268 bool compNeedSecurityCheck; // This flag really means where or not a security object needs
8269 // to be allocated on the stack.
8270 // It will be set to true in the following cases:
8271 // 1. When the method being compiled has a declarative security
8272 // (i.e. when CORINFO_FLG_NOSECURITYWRAP is reset for the current method).
8273 // This is also the case when we inject a prolog and epilog in the method.
8275 // 2. When the method being compiled has imperative security (i.e. the method
8276 // calls into another method that has CORINFO_FLG_SECURITYCHECK flag set).
8278 // 3. When opts.compDbgEnC is true. (See also Compiler::compCompile).
8280 // When this flag is set, jit will allocate a gc-reference local variable (lvaSecurityObject),
8281 // which gets reported as a GC root to stackwalker.
8282 // (See also ICodeManager::GetAddrOfSecurityObject.)
8284 bool compReloc; // Generate relocs for pointers in code, true for all ngen/prejit codegen
8287 #if defined(_TARGET_XARCH_)
8288 bool compEnablePCRelAddr; // Whether absolute addr be encoded as PC-rel offset by RyuJIT where possible
8292 #ifdef UNIX_AMD64_ABI
8293 // This flag is indicating if there is a need to align the frame.
8294 // On AMD64-Windows, if there are calls, 4 slots for the outgoing ars are allocated, except for
8295 // FastTailCall. This slots makes the frame size non-zero, so alignment logic will be called.
8296 // On AMD64-Unix, there are no such slots. There is a possibility to have calls in the method with frame size of
8297 // 0. The frame alignment logic won't kick in. This flags takes care of the AMD64-Unix case by remembering that
8298 // there are calls and making sure the frame alignment logic is executed.
8299 bool compNeedToAlignFrame;
8300 #endif // UNIX_AMD64_ABI
8302 bool compProcedureSplitting; // Separate cold code from hot code
8304 bool genFPorder; // Preserve FP order (operations are non-commutative)
8305 bool genFPopt; // Can we do frame-pointer-omission optimization?
8306 bool altJit; // True if we are an altjit and are compiling this method
8309 bool optRepeat; // Repeat optimizer phases k times
8313 bool compProcedureSplittingEH; // Separate cold code from hot code for functions with EH
8314 bool dspCode; // Display native code generated
8315 bool dspEHTable; // Display the EH table reported to the VM
8316 bool dspDebugInfo; // Display the Debug info reported to the VM
8317 bool dspInstrs; // Display the IL instructions intermixed with the native code output
8318 bool dspEmit; // Display emitter output
8319 bool dspLines; // Display source-code lines intermixed with native code output
8320 bool dmpHex; // Display raw bytes in hex of native code output
8321 bool varNames; // Display variables names in native code output
8322 bool disAsm; // Display native code as it is generated
8323 bool disAsmSpilled; // Display native code when any register spilling occurs
8324 bool disDiffable; // Makes the Disassembly code 'diff-able'
8325 bool disAsm2; // Display native code after it is generated using external disassembler
8326 bool dspOrder; // Display names of each of the methods that we ngen/jit
8327 bool dspUnwind; // Display the unwind info output
8328 bool dspDiffable; // Makes the Jit Dump 'diff-able' (currently uses same COMPlus_* flag as disDiffable)
8329 bool compLongAddress; // Force using large pseudo instructions for long address
8330 // (IF_LARGEJMP/IF_LARGEADR/IF_LARGLDC)
8331 bool dspGCtbls; // Display the GC tables
8335 bool doLateDisasm; // Run the late disassembler
8336 #endif // LATE_DISASM
8338 #if DUMP_GC_TABLES && !defined(DEBUG) && defined(JIT32_GCENCODER)
8339 // Only the JIT32_GCENCODER implements GC dumping in non-DEBUG code.
8340 #pragma message("NOTE: this non-debug build has GC ptr table dumping always enabled!")
8341 static const bool dspGCtbls = true;
8344 #ifdef PROFILING_SUPPORTED
8345 // Whether to emit Enter/Leave/TailCall hooks using a dummy stub (DummyProfilerELTStub()).
8346 // This option helps make the JIT behave as if it is running under a profiler.
8347 bool compJitELTHookEnabled;
8348 #endif // PROFILING_SUPPORTED
8350 #if FEATURE_TAILCALL_OPT
8351 // Whether opportunistic or implicit tail call optimization is enabled.
8352 bool compTailCallOpt;
8353 // Whether optimization of transforming a recursive tail call into a loop is enabled.
8354 bool compTailCallLoopOpt;
8357 #if defined(_TARGET_ARM64_)
8358 // Decision about whether to save FP/LR registers with callee-saved registers (see
8359 // COMPlus_JitSaveFpLrWithCalleSavedRegisters).
8360 int compJitSaveFpLrWithCalleeSavedRegisters;
8361 #endif // defined(_TARGET_ARM64_)
8364 static const bool compUseSoftFP = true;
8365 #else // !ARM_SOFTFP
8366 static const bool compUseSoftFP = false;
8369 GCPollType compGCPollType;
8373 static bool s_pAltJitExcludeAssembliesListInitialized;
8374 static AssemblyNamesList2* s_pAltJitExcludeAssembliesList;
8378 static bool s_pJitDisasmIncludeAssembliesListInitialized;
8379 static AssemblyNamesList2* s_pJitDisasmIncludeAssembliesList;
8381 static bool s_pJitFunctionFileInitialized;
8382 static MethodSet* s_pJitMethodSet;
8386 // silence warning of cast to greater size. It is easier to silence than construct code the compiler is happy with, and
8387 // it is safe in this case
8388 #pragma warning(push)
8389 #pragma warning(disable : 4312)
8391 template <typename T>
8394 return (p == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : p);
8397 template <typename T>
8400 return (o == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : o);
8402 #pragma warning(pop)
8404 static int dspTreeID(GenTree* tree)
8406 return tree->gtTreeID;
8408 static void printTreeID(GenTree* tree)
8410 if (tree == nullptr)
8416 printf("[%06d]", dspTreeID(tree));
8423 #define STRESS_MODES \
8427 /* "Variations" stress areas which we try to mix up with each other. */ \
8428 /* These should not be exhaustively used as they might */ \
8429 /* hide/trivialize other areas */ \
8432 STRESS_MODE(DBL_ALN) \
8433 STRESS_MODE(LCL_FLDS) \
8434 STRESS_MODE(UNROLL_LOOPS) \
8435 STRESS_MODE(MAKE_CSE) \
8436 STRESS_MODE(LEGACY_INLINE) \
8437 STRESS_MODE(CLONE_EXPR) \
8438 STRESS_MODE(USE_FCOMI) \
8439 STRESS_MODE(USE_CMOV) \
8441 STRESS_MODE(BB_PROFILE) \
8442 STRESS_MODE(OPT_BOOLS_GC) \
8443 STRESS_MODE(REMORPH_TREES) \
8444 STRESS_MODE(64RSLT_MUL) \
8445 STRESS_MODE(DO_WHILE_LOOPS) \
8446 STRESS_MODE(MIN_OPTS) \
8447 STRESS_MODE(REVERSE_FLAG) /* Will set GTF_REVERSE_OPS whenever we can */ \
8448 STRESS_MODE(REVERSE_COMMA) /* Will reverse commas created with gtNewCommaNode */ \
8449 STRESS_MODE(TAILCALL) /* Will make the call as a tailcall whenever legal */ \
8450 STRESS_MODE(CATCH_ARG) /* Will spill catch arg */ \
8451 STRESS_MODE(UNSAFE_BUFFER_CHECKS) \
8452 STRESS_MODE(NULL_OBJECT_CHECK) \
8453 STRESS_MODE(PINVOKE_RESTORE_ESP) \
8454 STRESS_MODE(RANDOM_INLINE) \
8455 STRESS_MODE(SWITCH_CMP_BR_EXPANSION) \
8456 STRESS_MODE(GENERIC_VARN) \
8458 /* After COUNT_VARN, stress level 2 does all of these all the time */ \
8460 STRESS_MODE(COUNT_VARN) \
8462 /* "Check" stress areas that can be exhaustively used if we */ \
8463 /* dont care about performance at all */ \
8465 STRESS_MODE(FORCE_INLINE) /* Treat every method as AggressiveInlining */ \
8466 STRESS_MODE(CHK_FLOW_UPDATE) \
8467 STRESS_MODE(EMITTER) \
8468 STRESS_MODE(CHK_REIMPORT) \
8469 STRESS_MODE(FLATFP) \
8470 STRESS_MODE(GENERIC_CHECK) \
8475 #define STRESS_MODE(mode) STRESS_##mode,
8482 static const LPCWSTR s_compStressModeNames[STRESS_COUNT + 1];
8483 BYTE compActiveStressModes[STRESS_COUNT];
8486 #define MAX_STRESS_WEIGHT 100
8488 bool compStressCompile(compStressArea stressArea, unsigned weightPercentage);
8492 bool compInlineStress()
8494 return compStressCompile(STRESS_LEGACY_INLINE, 50);
8497 bool compRandomInlineStress()
8499 return compStressCompile(STRESS_RANDOM_INLINE, 50);
8504 bool compTailCallStress()
8507 return (JitConfig.TailcallStress() != 0 || compStressCompile(STRESS_TAILCALL, 5));
8513 codeOptimize compCodeOpt()
8516 // Switching between size & speed has measurable throughput impact
8517 // (3.5% on NGen mscorlib when measured). It used to be enabled for
8518 // DEBUG, but should generate identical code between CHK & RET builds,
8519 // so that's not acceptable.
8520 // TODO-Throughput: Figure out what to do about size vs. speed & throughput.
8521 // Investigate the cause of the throughput regression.
8523 return opts.compCodeOpt;
8525 return BLENDED_CODE;
8529 //--------------------- Info about the procedure --------------------------
8533 COMP_HANDLE compCompHnd;
8534 CORINFO_MODULE_HANDLE compScopeHnd;
8535 CORINFO_CLASS_HANDLE compClassHnd;
8536 CORINFO_METHOD_HANDLE compMethodHnd;
8537 CORINFO_METHOD_INFO* compMethodInfo;
8539 BOOL hasCircularClassConstraints;
8540 BOOL hasCircularMethodConstraints;
8542 #if defined(DEBUG) || defined(LATE_DISASM)
8543 const char* compMethodName;
8544 const char* compClassName;
8545 const char* compFullName;
8546 #endif // defined(DEBUG) || defined(LATE_DISASM)
8548 #if defined(DEBUG) || defined(INLINE_DATA)
8549 // Method hash is logcally const, but computed
8551 mutable unsigned compMethodHashPrivate;
8552 unsigned compMethodHash() const;
8553 #endif // defined(DEBUG) || defined(INLINE_DATA)
8555 #ifdef PSEUDORANDOM_NOP_INSERTION
8556 // things for pseudorandom nop insertion
8557 unsigned compChecksum;
8561 // The following holds the FLG_xxxx flags for the method we're compiling.
8564 // The following holds the class attributes for the method we're compiling.
8565 unsigned compClassAttr;
8567 const BYTE* compCode;
8568 IL_OFFSET compILCodeSize; // The IL code size
8569 IL_OFFSET compILImportSize; // Estimated amount of IL actually imported
8570 UNATIVE_OFFSET compNativeCodeSize; // The native code size, after instructions are issued. This
8571 // is less than (compTotalHotCodeSize + compTotalColdCodeSize) only if:
8572 // (1) the code is not hot/cold split, and we issued less code than we expected, or
8573 // (2) the code is hot/cold split, and we issued less code than we expected
8574 // in the cold section (the hot section will always be padded out to compTotalHotCodeSize).
8576 bool compIsStatic : 1; // Is the method static (no 'this' pointer)?
8577 bool compIsVarArgs : 1; // Does the method have varargs parameters?
8578 bool compIsContextful : 1; // contextful method
8579 bool compInitMem : 1; // Is the CORINFO_OPT_INIT_LOCALS bit set in the method info options?
8580 bool compUnwrapContextful : 1; // JIT should unwrap proxies when possible
8581 bool compProfilerCallback : 1; // JIT inserted a profiler Enter callback
8582 bool compPublishStubParam : 1; // EAX captured in prolog will be available through an instrinsic
8583 bool compRetBuffDefStack : 1; // The ret buff argument definitely points into the stack.
8585 var_types compRetType; // Return type of the method as declared in IL
8586 var_types compRetNativeType; // Normalized return type as per target arch ABI
8587 unsigned compILargsCount; // Number of arguments (incl. implicit but not hidden)
8588 unsigned compArgsCount; // Number of arguments (incl. implicit and hidden)
8590 #if FEATURE_FASTTAILCALL
8591 size_t compArgStackSize; // Incoming argument stack size in bytes
8592 #endif // FEATURE_FASTTAILCALL
8594 unsigned compRetBuffArg; // position of hidden return param var (0, 1) (BAD_VAR_NUM means not present);
8595 int compTypeCtxtArg; // position of hidden param for type context for generic code (CORINFO_CALLCONV_PARAMTYPE)
8596 unsigned compThisArg; // position of implicit this pointer param (not to be confused with lvaArg0Var)
8597 unsigned compILlocalsCount; // Number of vars : args + locals (incl. implicit but not hidden)
8598 unsigned compLocalsCount; // Number of vars : args + locals (incl. implicit and hidden)
8599 unsigned compMaxStack;
8600 UNATIVE_OFFSET compTotalHotCodeSize; // Total number of bytes of Hot Code in the method
8601 UNATIVE_OFFSET compTotalColdCodeSize; // Total number of bytes of Cold Code in the method
8603 unsigned compCallUnmanaged; // count of unmanaged calls
8604 unsigned compLvFrameListRoot; // lclNum for the Frame root
8605 unsigned compXcptnsCount; // Number of exception-handling clauses read in the method's IL.
8606 // You should generally use compHndBBtabCount instead: it is the
8607 // current number of EH clauses (after additions like synchronized
8608 // methods and funclets, and removals like unreachable code deletion).
8610 bool compMatchedVM; // true if the VM is "matched": either the JIT is a cross-compiler
8611 // and the VM expects that, or the JIT is a "self-host" compiler
8612 // (e.g., x86 hosted targeting x86) and the VM expects that.
8614 /* The following holds IL scope information about local variables.
8617 unsigned compVarScopesCount;
8618 VarScopeDsc* compVarScopes;
8620 /* The following holds information about instr offsets for
8621 * which we need to report IP-mappings
8624 IL_OFFSET* compStmtOffsets; // sorted
8625 unsigned compStmtOffsetsCount;
8626 ICorDebugInfo::BoundaryTypes compStmtOffsetsImplicit;
8628 #define CPU_X86 0x0100 // The generic X86 CPU
8629 #define CPU_X86_PENTIUM_4 0x0110
8631 #define CPU_X64 0x0200 // The generic x64 CPU
8632 #define CPU_AMD_X64 0x0210 // AMD x64 CPU
8633 #define CPU_INTEL_X64 0x0240 // Intel x64 CPU
8635 #define CPU_ARM 0x0300 // The generic ARM CPU
8636 #define CPU_ARM64 0x0400 // The generic ARM64 CPU
8638 unsigned genCPU; // What CPU are we running on
8641 // Returns true if the method being compiled returns a non-void and non-struct value.
8642 // Note that lvaInitTypeRef() normalizes compRetNativeType for struct returns in a
8643 // single register as per target arch ABI (e.g on Amd64 Windows structs of size 1, 2,
8644 // 4 or 8 gets normalized to TYP_BYTE/TYP_SHORT/TYP_INT/TYP_LONG; On Arm HFA structs).
8645 // Methods returning such structs are considered to return non-struct return value and
8646 // this method returns true in that case.
8647 bool compMethodReturnsNativeScalarType()
8649 return (info.compRetType != TYP_VOID) && !varTypeIsStruct(info.compRetNativeType);
8652 // Returns true if the method being compiled returns RetBuf addr as its return value
8653 bool compMethodReturnsRetBufAddr()
8655 // There are cases where implicit RetBuf argument should be explicitly returned in a register.
8656 // In such cases the return type is changed to TYP_BYREF and appropriate IR is generated.
8658 // 1. Profiler Leave calllback expects the address of retbuf as return value for
8659 // methods with hidden RetBuf argument. impReturnInstruction() when profiler
8660 // callbacks are needed creates GT_RETURN(TYP_BYREF, op1 = Addr of RetBuf) for
8661 // methods with hidden RetBufArg.
8663 // 2. As per the System V ABI, the address of RetBuf needs to be returned by
8664 // methods with hidden RetBufArg in RAX. In such case GT_RETURN is of TYP_BYREF,
8665 // returning the address of RetBuf.
8667 // 3. Windows 64-bit native calling convention also requires the address of RetBuff
8668 // to be returned in RAX.
8669 CLANG_FORMAT_COMMENT_ANCHOR;
8671 #ifdef _TARGET_AMD64_
8672 return (info.compRetBuffArg != BAD_VAR_NUM);
8673 #else // !_TARGET_AMD64_
8674 return (compIsProfilerHookNeeded()) && (info.compRetBuffArg != BAD_VAR_NUM);
8675 #endif // !_TARGET_AMD64_
8678 // Returns true if the method returns a value in more than one return register
8679 // TODO-ARM-Bug: Deal with multi-register genReturnLocaled structs?
8680 // TODO-ARM64: Does this apply for ARM64 too?
8681 bool compMethodReturnsMultiRegRetType()
8683 #if FEATURE_MULTIREG_RET
8684 #if defined(_TARGET_X86_)
8685 // On x86 only 64-bit longs are returned in multiple registers
8686 return varTypeIsLong(info.compRetNativeType);
8687 #else // targets: X64-UNIX, ARM64 or ARM32
8688 // On all other targets that support multireg return values:
8689 // Methods returning a struct in multiple registers have a return value of TYP_STRUCT.
8690 // Such method's compRetNativeType is TYP_STRUCT without a hidden RetBufArg
8691 return varTypeIsStruct(info.compRetNativeType) && (info.compRetBuffArg == BAD_VAR_NUM);
8692 #endif // TARGET_XXX
8694 #else // not FEATURE_MULTIREG_RET
8696 // For this architecture there are no multireg returns
8699 #endif // FEATURE_MULTIREG_RET
8702 #if FEATURE_MULTIREG_ARGS
8703 // Given a GenTree node of TYP_STRUCT that represents a pass by value argument
8704 // return the gcPtr layout for the pointers sized fields
8705 void getStructGcPtrsFromOp(GenTree* op, BYTE* gcPtrsOut);
8706 #endif // FEATURE_MULTIREG_ARGS
8708 // Returns true if the method being compiled returns a value
8709 bool compMethodHasRetVal()
8711 return compMethodReturnsNativeScalarType() || compMethodReturnsRetBufAddr() ||
8712 compMethodReturnsMultiRegRetType();
8717 void compDispLocalVars();
8721 //-------------------------- Global Compiler Data ------------------------------------
8724 static unsigned s_compMethodsCount; // to produce unique label names
8725 unsigned compGenTreeID;
8726 unsigned compBasicBlockID;
8729 BasicBlock* compCurBB; // the current basic block in process
8730 GenTree* compCurStmt; // the current statement in process
8732 unsigned compCurStmtNum; // to give all statements an increasing StmtNum when printing dumps
8735 // The following is used to create the 'method JIT info' block.
8736 size_t compInfoBlkSize;
8737 BYTE* compInfoBlkAddr;
8739 EHblkDsc* compHndBBtab; // array of EH data
8740 unsigned compHndBBtabCount; // element count of used elements in EH data array
8741 unsigned compHndBBtabAllocCount; // element count of allocated elements in EH data array
8743 #if defined(_TARGET_X86_)
8745 //-------------------------------------------------------------------------
8746 // Tracking of region covered by the monitor in synchronized methods
8747 void* syncStartEmitCookie; // the emitter cookie for first instruction after the call to MON_ENTER
8748 void* syncEndEmitCookie; // the emitter cookie for first instruction after the call to MON_EXIT
8750 #endif // !_TARGET_X86_
8752 Phases previousCompletedPhase; // the most recently completed phase
8754 //-------------------------------------------------------------------------
8755 // The following keeps track of how many bytes of local frame space we've
8756 // grabbed so far in the current function, and how many argument bytes we
8757 // need to pop when we return.
8760 unsigned compLclFrameSize; // secObject+lclBlk+locals+temps
8762 // Count of callee-saved regs we pushed in the prolog.
8763 // Does not include EBP for isFramePointerUsed() and double-aligned frames.
8764 // In case of Amd64 this doesn't include float regs saved on stack.
8765 unsigned compCalleeRegsPushed;
8767 #if defined(_TARGET_XARCH_)
8768 // Mask of callee saved float regs on stack.
8769 regMaskTP compCalleeFPRegsSavedMask;
8771 #ifdef _TARGET_AMD64_
8772 // Quirk for VS debug-launch scenario to work:
8773 // Bytes of padding between save-reg area and locals.
8774 #define VSQUIRK_STACK_PAD (2 * REGSIZE_BYTES)
8775 unsigned compVSQuirkStackPaddingNeeded;
8776 bool compQuirkForPPPflag;
8779 unsigned compArgSize; // total size of arguments in bytes (including register args (lvIsRegArg))
8781 unsigned compMapILargNum(unsigned ILargNum); // map accounting for hidden args
8782 unsigned compMapILvarNum(unsigned ILvarNum); // map accounting for hidden args
8783 unsigned compMap2ILvarNum(unsigned varNum); // map accounting for hidden args
8785 //-------------------------------------------------------------------------
8787 static void compStartup(); // One-time initialization
8788 static void compShutdown(); // One-time finalization
8790 void compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo);
8793 static void compDisplayStaticSizes(FILE* fout);
8795 //------------ Some utility functions --------------
8797 void* compGetHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
8798 void** ppIndirection); /* OUT */
8800 // Several JIT/EE interface functions return a CorInfoType, and also return a
8801 // class handle as an out parameter if the type is a value class. Returns the
8802 // size of the type these describe.
8803 unsigned compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd);
8806 // Components used by the compiler may write unit test suites, and
8807 // have them run within this method. They will be run only once per process, and only
8808 // in debug. (Perhaps should be under the control of a COMPlus_ flag.)
8809 // These should fail by asserting.
8810 void compDoComponentUnitTestsOnce();
8813 int compCompile(CORINFO_METHOD_HANDLE methodHnd,
8814 CORINFO_MODULE_HANDLE classPtr,
8815 COMP_HANDLE compHnd,
8816 CORINFO_METHOD_INFO* methodInfo,
8817 void** methodCodePtr,
8818 ULONG* methodCodeSize,
8819 JitFlags* compileFlags);
8820 void compCompileFinish();
8821 int compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
8822 COMP_HANDLE compHnd,
8823 CORINFO_METHOD_INFO* methodInfo,
8824 void** methodCodePtr,
8825 ULONG* methodCodeSize,
8826 JitFlags* compileFlags,
8827 CorInfoInstantiationVerification instVerInfo);
8829 ArenaAllocator* compGetArenaAllocator();
8831 #if MEASURE_MEM_ALLOC
8832 static bool s_dspMemStats; // Display per-phase memory statistics for every function
8833 #endif // MEASURE_MEM_ALLOC
8835 #if LOOP_HOIST_STATS
8836 unsigned m_loopsConsidered;
8837 bool m_curLoopHasHoistedExpression;
8838 unsigned m_loopsWithHoistedExpressions;
8839 unsigned m_totalHoistedExpressions;
8841 void AddLoopHoistStats();
8842 void PrintPerMethodLoopHoistStats();
8844 static CritSecObject s_loopHoistStatsLock; // This lock protects the data structures below.
8845 static unsigned s_loopsConsidered;
8846 static unsigned s_loopsWithHoistedExpressions;
8847 static unsigned s_totalHoistedExpressions;
8849 static void PrintAggregateLoopHoistStats(FILE* f);
8850 #endif // LOOP_HOIST_STATS
8852 bool compIsForImportOnly();
8853 bool compIsForInlining();
8854 bool compDonotInline();
8857 unsigned char compGetJitDefaultFill(); // Get the default fill char value
8858 // we randomize this value when JitStress is enabled
8860 const char* compLocalVarName(unsigned varNum, unsigned offs);
8861 VarName compVarName(regNumber reg, bool isFloatReg = false);
8862 const char* compRegVarName(regNumber reg, bool displayVar = false, bool isFloatReg = false);
8863 const char* compRegNameForSize(regNumber reg, size_t size);
8864 const char* compFPregVarName(unsigned fpReg, bool displayVar = false);
8865 void compDspSrcLinesByNativeIP(UNATIVE_OFFSET curIP);
8866 void compDspSrcLinesByLineNum(unsigned line, bool seek = false);
8869 //-------------------------------------------------------------------------
8871 struct VarScopeListNode
8874 VarScopeListNode* next;
8875 static VarScopeListNode* Create(VarScopeDsc* value, CompAllocator alloc)
8877 VarScopeListNode* node = new (alloc) VarScopeListNode;
8879 node->next = nullptr;
8884 struct VarScopeMapInfo
8886 VarScopeListNode* head;
8887 VarScopeListNode* tail;
8888 static VarScopeMapInfo* Create(VarScopeListNode* node, CompAllocator alloc)
8890 VarScopeMapInfo* info = new (alloc) VarScopeMapInfo;
8897 // Max value of scope count for which we would use linear search; for larger values we would use hashtable lookup.
8898 static const unsigned MAX_LINEAR_FIND_LCL_SCOPELIST = 32;
8900 typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, VarScopeMapInfo*> VarNumToScopeDscMap;
8902 // Map to keep variables' scope indexed by varNum containing it's scope dscs at the index.
8903 VarNumToScopeDscMap* compVarScopeMap;
8905 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned lifeBeg, unsigned lifeEnd);
8907 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned offs);
8909 VarScopeDsc* compFindLocalVarLinear(unsigned varNum, unsigned offs);
8911 void compInitVarScopeMap();
8913 VarScopeDsc** compEnterScopeList; // List has the offsets where variables
8914 // enter scope, sorted by instr offset
8915 unsigned compNextEnterScope;
8917 VarScopeDsc** compExitScopeList; // List has the offsets where variables
8918 // go out of scope, sorted by instr offset
8919 unsigned compNextExitScope;
8921 void compInitScopeLists();
8923 void compResetScopeLists();
8925 VarScopeDsc* compGetNextEnterScope(unsigned offs, bool scan = false);
8927 VarScopeDsc* compGetNextExitScope(unsigned offs, bool scan = false);
8929 void compProcessScopesUntil(unsigned offset,
8931 void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*),
8932 void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*));
8935 void compDispScopeLists();
8938 bool compIsProfilerHookNeeded();
8940 //-------------------------------------------------------------------------
8941 /* Statistical Data Gathering */
8943 void compJitStats(); // call this function and enable
8944 // various ifdef's below for statistical data
8947 void compCallArgStats();
8948 static void compDispCallArgStats(FILE* fout);
8951 //-------------------------------------------------------------------------
8958 ArenaAllocator* compArenaAllocator;
8961 void compFunctionTraceStart();
8962 void compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, bool isNYI);
8965 size_t compMaxUncheckedOffsetForNullObject;
8967 void compInitOptions(JitFlags* compileFlags);
8969 void compSetProcessor();
8970 void compInitDebuggingInfo();
8971 void compSetOptimizationLevel();
8972 #ifdef _TARGET_ARMARCH_
8973 bool compRsvdRegCheck(FrameLayoutState curState);
8975 void compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags);
8977 // Clear annotations produced during optimizations; to be used between iterations when repeating opts.
8978 void ResetOptAnnotations();
8980 // Regenerate loop descriptors; to be used between iterations when repeating opts.
8981 void RecomputeLoopInfo();
8983 #ifdef PROFILING_SUPPORTED
8984 // Data required for generating profiler Enter/Leave/TailCall hooks
8986 bool compProfilerHookNeeded; // Whether profiler Enter/Leave/TailCall hook needs to be generated for the method
8987 void* compProfilerMethHnd; // Profiler handle of the method being compiled. Passed as param to ELT callbacks
8988 bool compProfilerMethHndIndirected; // Whether compProfilerHandle is pointer to the handle or is an actual handle
8991 #ifdef _TARGET_AMD64_
8992 bool compQuirkForPPP(); // Check if this method should be Quirked for the PPP issue
8995 // Assumes called as part of process shutdown; does any compiler-specific work associated with that.
8996 static void ProcessShutdownWork(ICorStaticInfo* statInfo);
8998 CompAllocator getAllocator(CompMemKind cmk = CMK_Generic)
9000 return CompAllocator(compArenaAllocator, cmk);
9003 CompAllocator getAllocatorGC()
9005 return getAllocator(CMK_GC);
9008 CompAllocator getAllocatorLoopHoist()
9010 return getAllocator(CMK_LoopHoist);
9014 CompAllocator getAllocatorDebugOnly()
9016 return getAllocator(CMK_DebugOnly);
9021 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9022 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9026 XX Checks for type compatibility and merges types XX
9028 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9029 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9033 // Set to TRUE if verification cannot be skipped for this method
9034 // If we detect unverifiable code, we will lazily check
9035 // canSkipMethodVerification() to see if verification is REALLY needed.
9036 BOOL tiVerificationNeeded;
9038 // It it initially TRUE, and it gets set to FALSE if we run into unverifiable code
9039 // Note that this is valid only if tiVerificationNeeded was ever TRUE.
9040 BOOL tiIsVerifiableCode;
9042 // Set to TRUE if runtime callout is needed for this method
9043 BOOL tiRuntimeCalloutNeeded;
9045 // Set to TRUE if security prolog/epilog callout is needed for this method
9046 // Note: This flag is different than compNeedSecurityCheck.
9047 // compNeedSecurityCheck means whether or not a security object needs
9048 // to be allocated on the stack, which is currently true for EnC as well.
9049 // tiSecurityCalloutNeeded means whether or not security callouts need
9050 // to be inserted in the jitted code.
9051 BOOL tiSecurityCalloutNeeded;
9053 // Returns TRUE if child is equal to or a subtype of parent for merge purposes
9054 // This support is necessary to suport attributes that are not described in
9055 // for example, signatures. For example, the permanent home byref (byref that
9056 // points to the gc heap), isn't a property of method signatures, therefore,
9057 // it is safe to have mismatches here (that tiCompatibleWith will not flag),
9058 // but when deciding if we need to reimport a block, we need to take these
9060 BOOL tiMergeCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
9062 // Returns TRUE if child is equal to or a subtype of parent.
9063 // normalisedForStack indicates that both types are normalised for the stack
9064 BOOL tiCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
9066 // Merges pDest and pSrc. Returns FALSE if merge is undefined.
9067 // *pDest is modified to represent the merged type. Sets "*changed" to true
9068 // if this changes "*pDest".
9069 BOOL tiMergeToCommonParent(typeInfo* pDest, const typeInfo* pSrc, bool* changed) const;
9072 // <BUGNUM> VSW 471305
9073 // IJW allows assigning REF to BYREF. The following allows us to temporarily
9074 // bypass the assert check in gcMarkRegSetGCref and gcMarkRegSetByref
9075 // We use a "short" as we need to push/pop this scope.
9077 short compRegSetCheckLevel;
9081 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9082 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9084 XX IL verification stuff XX
9087 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9088 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9092 // The following is used to track liveness of local variables, initialization
9093 // of valueclass constructors, and type safe use of IL instructions.
9095 // dynamic state info needed for verification
9096 EntryState verCurrentState;
9098 // this ptr of object type .ctors are considered intited only after
9099 // the base class ctor is called, or an alternate ctor is called.
9100 // An uninited this ptr can be used to access fields, but cannot
9101 // be used to call a member function.
9102 BOOL verTrackObjCtorInitState;
9104 void verInitBBEntryState(BasicBlock* block, EntryState* currentState);
9106 // Requires that "tis" is not TIS_Bottom -- it's a definite init/uninit state.
9107 void verSetThisInit(BasicBlock* block, ThisInitState tis);
9108 void verInitCurrentState();
9109 void verResetCurrentState(BasicBlock* block, EntryState* currentState);
9111 // Merges the current verification state into the entry state of "block", return FALSE if that merge fails,
9112 // TRUE if it succeeds. Further sets "*changed" to true if this changes the entry state of "block".
9113 BOOL verMergeEntryStates(BasicBlock* block, bool* changed);
9115 void verConvertBBToThrowVerificationException(BasicBlock* block DEBUGARG(bool logMsg));
9116 void verHandleVerificationFailure(BasicBlock* block DEBUGARG(bool logMsg));
9117 typeInfo verMakeTypeInfo(CORINFO_CLASS_HANDLE clsHnd,
9118 bool bashStructToRef = false); // converts from jit type representation to typeInfo
9119 typeInfo verMakeTypeInfo(CorInfoType ciType,
9120 CORINFO_CLASS_HANDLE clsHnd); // converts from jit type representation to typeInfo
9121 BOOL verIsSDArray(typeInfo ti);
9122 typeInfo verGetArrayElemType(typeInfo ti);
9124 typeInfo verParseArgSigToTypeInfo(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args);
9125 BOOL verNeedsVerification();
9126 BOOL verIsByRefLike(const typeInfo& ti);
9127 BOOL verIsSafeToReturnByRef(const typeInfo& ti);
9129 // generic type variables range over types that satisfy IsBoxable
9130 BOOL verIsBoxable(const typeInfo& ti);
9132 void DECLSPEC_NORETURN verRaiseVerifyException(INDEBUG(const char* reason) DEBUGARG(const char* file)
9133 DEBUGARG(unsigned line));
9134 void verRaiseVerifyExceptionIfNeeded(INDEBUG(const char* reason) DEBUGARG(const char* file)
9135 DEBUGARG(unsigned line));
9136 bool verCheckTailCallConstraint(OPCODE opcode,
9137 CORINFO_RESOLVED_TOKEN* pResolvedToken,
9138 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call
9139 // on a type parameter?
9140 bool speculative // If true, won't throw if verificatoin fails. Instead it will
9141 // return false to the caller.
9142 // If false, it will throw.
9144 bool verIsBoxedValueType(typeInfo ti);
9146 void verVerifyCall(OPCODE opcode,
9147 CORINFO_RESOLVED_TOKEN* pResolvedToken,
9148 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
9150 bool readonlyCall, // is this a "readonly." call?
9151 const BYTE* delegateCreateStart,
9152 const BYTE* codeAddr,
9153 CORINFO_CALL_INFO* callInfo DEBUGARG(const char* methodName));
9155 BOOL verCheckDelegateCreation(const BYTE* delegateCreateStart, const BYTE* codeAddr, mdMemberRef& targetMemberRef);
9157 typeInfo verVerifySTIND(const typeInfo& ptr, const typeInfo& value, const typeInfo& instrType);
9158 typeInfo verVerifyLDIND(const typeInfo& ptr, const typeInfo& instrType);
9159 void verVerifyField(CORINFO_RESOLVED_TOKEN* pResolvedToken,
9160 const CORINFO_FIELD_INFO& fieldInfo,
9161 const typeInfo* tiThis,
9163 BOOL allowPlainStructAsThis = FALSE);
9164 void verVerifyCond(const typeInfo& tiOp1, const typeInfo& tiOp2, unsigned opcode);
9165 void verVerifyThisPtrInitialised();
9166 BOOL verIsCallToInitThisPtr(CORINFO_CLASS_HANDLE context, CORINFO_CLASS_HANDLE target);
9170 // One line log function. Default level is 0. Increasing it gives you
9171 // more log information
9173 // levels are currently unused: #define JITDUMP(level,...) ();
9174 void JitLogEE(unsigned level, const char* fmt, ...);
9176 bool compDebugBreak;
9178 bool compJitHaltMethod();
9183 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9184 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9186 XX GS Security checks for unsafe buffers XX
9188 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9189 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9192 struct ShadowParamVarInfo
9194 FixedBitVect* assignGroup; // the closure set of variables whose values depend on each other
9195 unsigned shadowCopy; // Lcl var num, valid only if not set to NO_SHADOW_COPY
9197 static bool mayNeedShadowCopy(LclVarDsc* varDsc)
9199 #if defined(_TARGET_AMD64_)
9200 // GS cookie logic to create shadow slots, create trees to copy reg args to shadow
9201 // slots and update all trees to refer to shadow slots is done immediately after
9202 // fgMorph(). Lsra could potentially mark a param as DoNotEnregister after JIT determines
9203 // not to shadow a parameter. Also, LSRA could potentially spill a param which is passed
9204 // in register. Therefore, conservatively all params may need a shadow copy. Note that
9205 // GS cookie logic further checks whether the param is a ptr or an unsafe buffer before
9206 // creating a shadow slot even though this routine returns true.
9208 // TODO-AMD64-CQ: Revisit this conservative approach as it could create more shadow slots than
9209 // required. There are two cases under which a reg arg could potentially be used from its
9211 // a) LSRA marks it as DoNotEnregister (see LinearScan::identifyCandidates())
9212 // b) LSRA spills it
9214 // Possible solution to address case (a)
9215 // - The conditions under which LSRA marks a varDsc as DoNotEnregister could be checked
9216 // in this routine. Note that live out of exception handler is something we may not be
9217 // able to do it here since GS cookie logic is invoked ahead of liveness computation.
9218 // Therefore, for methods with exception handling and need GS cookie check we might have
9219 // to take conservative approach.
9221 // Possible solution to address case (b)
9222 // - Whenver a parameter passed in an argument register needs to be spilled by LSRA, we
9223 // create a new spill temp if the method needs GS cookie check.
9224 return varDsc->lvIsParam;
9225 #else // !defined(_TARGET_AMD64_)
9226 return varDsc->lvIsParam && !varDsc->lvIsRegArg;
9233 printf("assignGroup [%p]; shadowCopy: [%d];\n", assignGroup, shadowCopy);
9238 GSCookie* gsGlobalSecurityCookieAddr; // Address of global cookie for unsafe buffer checks
9239 GSCookie gsGlobalSecurityCookieVal; // Value of global cookie if addr is NULL
9240 ShadowParamVarInfo* gsShadowVarInfo; // Table used by shadow param analysis code
9242 void gsGSChecksInitCookie(); // Grabs cookie variable
9243 void gsCopyShadowParams(); // Identify vulnerable params and create dhadow copies
9244 bool gsFindVulnerableParams(); // Shadow param analysis code
9245 void gsParamsToShadows(); // Insert copy code and replave param uses by shadow
9247 static fgWalkPreFn gsMarkPtrsAndAssignGroups; // Shadow param analysis tree-walk
9248 static fgWalkPreFn gsReplaceShadowParams; // Shadow param replacement tree-walk
9250 #define DEFAULT_MAX_INLINE_SIZE 100 // Methods with > DEFAULT_MAX_INLINE_SIZE IL bytes will never be inlined.
9251 // This can be overwritten by setting complus_JITInlineSize env variable.
9253 #define DEFAULT_MAX_INLINE_DEPTH 20 // Methods at more than this level deep will not be inlined
9255 #define DEFAULT_MAX_LOCALLOC_TO_LOCAL_SIZE 32 // fixed locallocs of this size or smaller will convert to local buffers
9258 #ifdef FEATURE_JIT_METHOD_PERF
9259 JitTimer* pCompJitTimer; // Timer data structure (by phases) for current compilation.
9260 static CompTimeSummaryInfo s_compJitTimerSummary; // Summary of the Timer information for the whole run.
9262 static LPCWSTR JitTimeLogCsv(); // Retrieve the file name for CSV from ConfigDWORD.
9263 static LPCWSTR compJitTimeLogFilename; // If a log file for JIT time is desired, filename to write it to.
9265 inline void EndPhase(Phases phase); // Indicate the end of the given phase.
9267 #if MEASURE_CLRAPI_CALLS
9268 // Thin wrappers that call into JitTimer (if present).
9269 inline void CLRApiCallEnter(unsigned apix);
9270 inline void CLRApiCallLeave(unsigned apix);
9273 inline void CLR_API_Enter(API_ICorJitInfo_Names ename);
9274 inline void CLR_API_Leave(API_ICorJitInfo_Names ename);
9279 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9280 // These variables are associated with maintaining SQM data about compile time.
9281 unsigned __int64 m_compCyclesAtEndOfInlining; // The thread-virtualized cycle count at the end of the inlining phase
9282 // in the current compilation.
9283 unsigned __int64 m_compCycles; // Net cycle count for current compilation
9284 DWORD m_compTickCountAtEndOfInlining; // The result of GetTickCount() (# ms since some epoch marker) at the end of
9285 // the inlining phase in the current compilation.
9286 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9288 // Records the SQM-relevant (cycles and tick count). Should be called after inlining is complete.
9289 // (We do this after inlining because this marks the last point at which the JIT is likely to cause
9290 // type-loading and class initialization).
9291 void RecordStateAtEndOfInlining();
9292 // Assumes being called at the end of compilation. Update the SQM state.
9293 void RecordStateAtEndOfCompilation();
9295 #ifdef FEATURE_CLRSQM
9296 // Does anything SQM related necessary at process shutdown time.
9297 static void ProcessShutdownSQMWork(ICorStaticInfo* statInfo);
9298 #endif // FEATURE_CLRSQM
9301 #if FUNC_INFO_LOGGING
9302 static LPCWSTR compJitFuncInfoFilename; // If a log file for per-function information is required, this is the
9303 // filename to write it to.
9304 static FILE* compJitFuncInfoFile; // And this is the actual FILE* to write to.
9305 #endif // FUNC_INFO_LOGGING
9307 Compiler* prevCompiler; // Previous compiler on stack for TLS Compiler* linked list for reentrant compilers.
9309 // Is the compilation in a full trust context?
9310 bool compIsFullTrust();
9313 void RecordNowayAssert(const char* filename, unsigned line, const char* condStr);
9314 #endif // MEASURE_NOWAY
9316 #ifndef FEATURE_TRACELOGGING
9317 // Should we actually fire the noway assert body and the exception handler?
9318 bool compShouldThrowOnNoway();
9319 #else // FEATURE_TRACELOGGING
9320 // Should we actually fire the noway assert body and the exception handler?
9321 bool compShouldThrowOnNoway(const char* filename, unsigned line);
9323 // Telemetry instance to use per method compilation.
9324 JitTelemetry compJitTelemetry;
9326 // Get common parameters that have to be logged with most telemetry data.
9327 void compGetTelemetryDefaults(const char** assemblyName,
9328 const char** scopeName,
9329 const char** methodName,
9330 unsigned* methodHash);
9331 #endif // !FEATURE_TRACELOGGING
9335 NodeToTestDataMap* m_nodeTestData;
9337 static const unsigned FIRST_LOOP_HOIST_CSE_CLASS = 1000;
9338 unsigned m_loopHoistCSEClass; // LoopHoist test annotations turn into CSE requirements; we
9339 // label them with CSE Class #'s starting at FIRST_LOOP_HOIST_CSE_CLASS.
9340 // Current kept in this.
9342 NodeToTestDataMap* GetNodeTestData()
9344 Compiler* compRoot = impInlineRoot();
9345 if (compRoot->m_nodeTestData == nullptr)
9347 compRoot->m_nodeTestData = new (getAllocatorDebugOnly()) NodeToTestDataMap(getAllocatorDebugOnly());
9349 return compRoot->m_nodeTestData;
9352 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, int> NodeToIntMap;
9354 // Returns the set (i.e., the domain of the result map) of nodes that are keys in m_nodeTestData, and
9355 // currently occur in the AST graph.
9356 NodeToIntMap* FindReachableNodesInNodeTestData();
9358 // Node "from" is being eliminated, and being replaced by node "to". If "from" had any associated
9359 // test data, associate that data with "to".
9360 void TransferTestDataToNode(GenTree* from, GenTree* to);
9362 // Requires that "to" is a clone of "from". If any nodes in the "from" tree
9363 // have annotations, attach similar annotations to the corresponding nodes in "to".
9364 void CopyTestDataToCloneTree(GenTree* from, GenTree* to);
9366 // These are the methods that test that the various conditions implied by the
9367 // test attributes are satisfied.
9368 void JitTestCheckSSA(); // SSA builder tests.
9369 void JitTestCheckVN(); // Value numbering tests.
9372 // The "FieldSeqStore", for canonicalizing field sequences. See the definition of FieldSeqStore for
9374 FieldSeqStore* m_fieldSeqStore;
9376 FieldSeqStore* GetFieldSeqStore()
9378 Compiler* compRoot = impInlineRoot();
9379 if (compRoot->m_fieldSeqStore == nullptr)
9381 // Create a CompAllocator that labels sub-structure with CMK_FieldSeqStore, and use that for allocation.
9382 CompAllocator ialloc(getAllocator(CMK_FieldSeqStore));
9383 compRoot->m_fieldSeqStore = new (ialloc) FieldSeqStore(ialloc);
9385 return compRoot->m_fieldSeqStore;
9388 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, FieldSeqNode*> NodeToFieldSeqMap;
9390 // Some nodes of "TYP_BYREF" or "TYP_I_IMPL" actually represent the address of a field within a struct, but since
9391 // the offset of the field is zero, there's no "GT_ADD" node. We normally attach a field sequence to the constant
9392 // that is added, but what do we do when that constant is zero, and is thus not present? We use this mechanism to
9393 // attach the field sequence directly to the address node.
9394 NodeToFieldSeqMap* m_zeroOffsetFieldMap;
9396 NodeToFieldSeqMap* GetZeroOffsetFieldMap()
9398 // Don't need to worry about inlining here
9399 if (m_zeroOffsetFieldMap == nullptr)
9401 // Create a CompAllocator that labels sub-structure with CMK_ZeroOffsetFieldMap, and use that for
9403 CompAllocator ialloc(getAllocator(CMK_ZeroOffsetFieldMap));
9404 m_zeroOffsetFieldMap = new (ialloc) NodeToFieldSeqMap(ialloc);
9406 return m_zeroOffsetFieldMap;
9409 // Requires that "op1" is a node of type "TYP_BYREF" or "TYP_I_IMPL". We are dereferencing this with the fields in
9410 // "fieldSeq", whose offsets are required all to be zero. Ensures that any field sequence annotation currently on
9411 // "op1" or its components is augmented by appending "fieldSeq". In practice, if "op1" is a GT_LCL_FLD, it has
9412 // a field sequence as a member; otherwise, it may be the addition of an a byref and a constant, where the const
9413 // has a field sequence -- in this case "fieldSeq" is appended to that of the constant; otherwise, we
9414 // record the the field sequence using the ZeroOffsetFieldMap described above.
9416 // One exception above is that "op1" is a node of type "TYP_REF" where "op1" is a GT_LCL_VAR.
9417 // This happens when System.Object vtable pointer is a regular field at offset 0 in System.Private.CoreLib in
9418 // CoreRT. Such case is handled same as the default case.
9419 void fgAddFieldSeqForZeroOffset(GenTree* op1, FieldSeqNode* fieldSeq);
9421 typedef JitHashTable<const GenTree*, JitPtrKeyFuncs<GenTree>, ArrayInfo> NodeToArrayInfoMap;
9422 NodeToArrayInfoMap* m_arrayInfoMap;
9424 NodeToArrayInfoMap* GetArrayInfoMap()
9426 Compiler* compRoot = impInlineRoot();
9427 if (compRoot->m_arrayInfoMap == nullptr)
9429 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9430 CompAllocator ialloc(getAllocator(CMK_ArrayInfoMap));
9431 compRoot->m_arrayInfoMap = new (ialloc) NodeToArrayInfoMap(ialloc);
9433 return compRoot->m_arrayInfoMap;
9436 //-----------------------------------------------------------------------------------------------------------------
9437 // Compiler::TryGetArrayInfo:
9438 // Given an indirection node, checks to see whether or not that indirection represents an array access, and
9439 // if so returns information about the array.
9442 // indir - The `GT_IND` node.
9443 // arrayInfo (out) - Information about the accessed array if this function returns true. Undefined otherwise.
9446 // True if the `GT_IND` node represents an array access; false otherwise.
9447 bool TryGetArrayInfo(GenTreeIndir* indir, ArrayInfo* arrayInfo)
9449 if ((indir->gtFlags & GTF_IND_ARR_INDEX) == 0)
9454 if (indir->gtOp1->OperIs(GT_INDEX_ADDR))
9456 GenTreeIndexAddr* const indexAddr = indir->gtOp1->AsIndexAddr();
9457 *arrayInfo = ArrayInfo(indexAddr->gtElemType, indexAddr->gtElemSize, indexAddr->gtElemOffset,
9458 indexAddr->gtStructElemClass);
9462 bool found = GetArrayInfoMap()->Lookup(indir, arrayInfo);
9467 NodeToUnsignedMap* m_memorySsaMap[MemoryKindCount];
9469 // In some cases, we want to assign intermediate SSA #'s to memory states, and know what nodes create those memory
9470 // states. (We do this for try blocks, where, if the try block doesn't do a call that loses track of the memory
9471 // state, all the possible memory states are possible initial states of the corresponding catch block(s).)
9472 NodeToUnsignedMap* GetMemorySsaMap(MemoryKind memoryKind)
9474 if (memoryKind == GcHeap && byrefStatesMatchGcHeapStates)
9476 // Use the same map for GCHeap and ByrefExposed when their states match.
9477 memoryKind = ByrefExposed;
9480 assert(memoryKind < MemoryKindCount);
9481 Compiler* compRoot = impInlineRoot();
9482 if (compRoot->m_memorySsaMap[memoryKind] == nullptr)
9484 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9485 CompAllocator ialloc(getAllocator(CMK_ArrayInfoMap));
9486 compRoot->m_memorySsaMap[memoryKind] = new (ialloc) NodeToUnsignedMap(ialloc);
9488 return compRoot->m_memorySsaMap[memoryKind];
9491 // The Refany type is the only struct type whose structure is implicitly assumed by IL. We need its fields.
9492 CORINFO_CLASS_HANDLE m_refAnyClass;
9493 CORINFO_FIELD_HANDLE GetRefanyDataField()
9495 if (m_refAnyClass == nullptr)
9497 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9499 return info.compCompHnd->getFieldInClass(m_refAnyClass, 0);
9501 CORINFO_FIELD_HANDLE GetRefanyTypeField()
9503 if (m_refAnyClass == nullptr)
9505 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9507 return info.compCompHnd->getFieldInClass(m_refAnyClass, 1);
9511 static BitSetSupport::BitSetOpCounter m_varsetOpCounter;
9513 #if ALLVARSET_COUNTOPS
9514 static BitSetSupport::BitSetOpCounter m_allvarsetOpCounter;
9517 static HelperCallProperties s_helperCallProperties;
9519 #ifdef UNIX_AMD64_ABI
9520 static var_types GetTypeFromClassificationAndSizes(SystemVClassificationType classType, int size);
9521 static var_types GetEightByteType(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9524 static void GetStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9527 unsigned __int8* offset0,
9528 unsigned __int8* offset1);
9530 void GetStructTypeOffset(CORINFO_CLASS_HANDLE typeHnd,
9533 unsigned __int8* offset0,
9534 unsigned __int8* offset1);
9536 #endif // defined(UNIX_AMD64_ABI)
9538 void fgMorphMultiregStructArgs(GenTreeCall* call);
9539 GenTree* fgMorphMultiregStructArg(GenTree* arg, fgArgTabEntry* fgEntryPtr);
9541 bool killGCRefs(GenTree* tree);
9543 }; // end of class Compiler
9545 //---------------------------------------------------------------------------------------------------------------------
9546 // GenTreeVisitor: a flexible tree walker implemented using the curiosly-recurring-template pattern.
9548 // This class implements a configurable walker for IR trees. There are five configuration options (defaults values are
9549 // shown in parentheses):
9551 // - ComputeStack (false): when true, the walker will push each node onto the `m_ancestors` stack. "Ancestors" is a bit
9552 // of a misnomer, as the first entry will always be the current node.
9554 // - DoPreOrder (false): when true, the walker will invoke `TVisitor::PreOrderVisit` with the current node as an
9555 // argument before visiting the node's operands.
9557 // - DoPostOrder (false): when true, the walker will invoke `TVisitor::PostOrderVisit` with the current node as an
9558 // argument after visiting the node's operands.
9560 // - DoLclVarsOnly (false): when true, the walker will only invoke `TVisitor::PreOrderVisit` for lclVar nodes.
9561 // `DoPreOrder` must be true if this option is true.
9563 // - UseExecutionOrder (false): when true, then walker will visit a node's operands in execution order (e.g. if a
9564 // binary operator has the `GTF_REVERSE_OPS` flag set, the second operand will be
9565 // visited before the first).
9567 // At least one of `DoPreOrder` and `DoPostOrder` must be specified.
9569 // A simple pre-order visitor might look something like the following:
9571 // class CountingVisitor final : public GenTreeVisitor<CountingVisitor>
9576 // DoPreOrder = true
9579 // unsigned m_count;
9581 // CountingVisitor(Compiler* compiler)
9582 // : GenTreeVisitor<CountingVisitor>(compiler), m_count(0)
9586 // Compiler::fgWalkResult PreOrderVisit(GenTree* node)
9592 // This visitor would then be used like so:
9594 // CountingVisitor countingVisitor(compiler);
9595 // countingVisitor.WalkTree(root);
9597 template <typename TVisitor>
9598 class GenTreeVisitor
9601 typedef Compiler::fgWalkResult fgWalkResult;
9605 ComputeStack = false,
9607 DoPostOrder = false,
9608 DoLclVarsOnly = false,
9609 UseExecutionOrder = false,
9612 Compiler* m_compiler;
9613 ArrayStack<GenTree*> m_ancestors;
9615 GenTreeVisitor(Compiler* compiler) : m_compiler(compiler), m_ancestors(compiler->getAllocator(CMK_ArrayStack))
9617 assert(compiler != nullptr);
9619 static_assert_no_msg(TVisitor::DoPreOrder || TVisitor::DoPostOrder);
9620 static_assert_no_msg(!TVisitor::DoLclVarsOnly || TVisitor::DoPreOrder);
9623 fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
9625 return fgWalkResult::WALK_CONTINUE;
9628 fgWalkResult PostOrderVisit(GenTree** use, GenTree* user)
9630 return fgWalkResult::WALK_CONTINUE;
9634 fgWalkResult WalkTree(GenTree** use, GenTree* user)
9636 assert(use != nullptr);
9638 GenTree* node = *use;
9640 if (TVisitor::ComputeStack)
9642 m_ancestors.Push(node);
9645 fgWalkResult result = fgWalkResult::WALK_CONTINUE;
9646 if (TVisitor::DoPreOrder && !TVisitor::DoLclVarsOnly)
9648 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9649 if (result == fgWalkResult::WALK_ABORT)
9655 if ((node == nullptr) || (result == fgWalkResult::WALK_SKIP_SUBTREES))
9661 switch (node->OperGet())
9666 case GT_LCL_VAR_ADDR:
9667 case GT_LCL_FLD_ADDR:
9668 if (TVisitor::DoLclVarsOnly)
9670 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9671 if (result == fgWalkResult::WALK_ABORT)
9687 case GT_MEMORYBARRIER:
9692 case GT_START_NONGC:
9693 case GT_START_PREEMPTGC:
9695 #if !FEATURE_EH_FUNCLETS
9697 #endif // !FEATURE_EH_FUNCLETS
9701 case GT_CLS_VAR_ADDR:
9705 case GT_PINVOKE_PROLOG:
9706 case GT_PINVOKE_EPILOG:
9710 // Lclvar unary operators
9711 case GT_STORE_LCL_VAR:
9712 case GT_STORE_LCL_FLD:
9713 if (TVisitor::DoLclVarsOnly)
9715 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9716 if (result == fgWalkResult::WALK_ABORT)
9723 // Standard unary operators
9752 case GT_RUNTIMELOOKUP:
9754 GenTreeUnOp* const unOp = node->AsUnOp();
9755 if (unOp->gtOp1 != nullptr)
9757 result = WalkTree(&unOp->gtOp1, unOp);
9758 if (result == fgWalkResult::WALK_ABORT)
9769 GenTreeCmpXchg* const cmpXchg = node->AsCmpXchg();
9771 result = WalkTree(&cmpXchg->gtOpLocation, cmpXchg);
9772 if (result == fgWalkResult::WALK_ABORT)
9776 result = WalkTree(&cmpXchg->gtOpValue, cmpXchg);
9777 if (result == fgWalkResult::WALK_ABORT)
9781 result = WalkTree(&cmpXchg->gtOpComparand, cmpXchg);
9782 if (result == fgWalkResult::WALK_ABORT)
9789 case GT_ARR_BOUNDS_CHECK:
9792 #endif // FEATURE_SIMD
9793 #ifdef FEATURE_HW_INTRINSICS
9794 case GT_HW_INTRINSIC_CHK:
9795 #endif // FEATURE_HW_INTRINSICS
9797 GenTreeBoundsChk* const boundsChk = node->AsBoundsChk();
9799 result = WalkTree(&boundsChk->gtIndex, boundsChk);
9800 if (result == fgWalkResult::WALK_ABORT)
9804 result = WalkTree(&boundsChk->gtArrLen, boundsChk);
9805 if (result == fgWalkResult::WALK_ABORT)
9814 GenTreeField* const field = node->AsField();
9816 if (field->gtFldObj != nullptr)
9818 result = WalkTree(&field->gtFldObj, field);
9819 if (result == fgWalkResult::WALK_ABORT)
9829 GenTreeArrElem* const arrElem = node->AsArrElem();
9831 result = WalkTree(&arrElem->gtArrObj, arrElem);
9832 if (result == fgWalkResult::WALK_ABORT)
9837 const unsigned rank = arrElem->gtArrRank;
9838 for (unsigned dim = 0; dim < rank; dim++)
9840 result = WalkTree(&arrElem->gtArrInds[dim], arrElem);
9841 if (result == fgWalkResult::WALK_ABORT)
9851 GenTreeArrOffs* const arrOffs = node->AsArrOffs();
9853 result = WalkTree(&arrOffs->gtOffset, arrOffs);
9854 if (result == fgWalkResult::WALK_ABORT)
9858 result = WalkTree(&arrOffs->gtIndex, arrOffs);
9859 if (result == fgWalkResult::WALK_ABORT)
9863 result = WalkTree(&arrOffs->gtArrObj, arrOffs);
9864 if (result == fgWalkResult::WALK_ABORT)
9873 GenTreeDynBlk* const dynBlock = node->AsDynBlk();
9875 GenTree** op1Use = &dynBlock->gtOp1;
9876 GenTree** op2Use = &dynBlock->gtDynamicSize;
9878 if (TVisitor::UseExecutionOrder && dynBlock->gtEvalSizeFirst)
9880 std::swap(op1Use, op2Use);
9883 result = WalkTree(op1Use, dynBlock);
9884 if (result == fgWalkResult::WALK_ABORT)
9888 result = WalkTree(op2Use, dynBlock);
9889 if (result == fgWalkResult::WALK_ABORT)
9896 case GT_STORE_DYN_BLK:
9898 GenTreeDynBlk* const dynBlock = node->AsDynBlk();
9900 GenTree** op1Use = &dynBlock->gtOp1;
9901 GenTree** op2Use = &dynBlock->gtOp2;
9902 GenTree** op3Use = &dynBlock->gtDynamicSize;
9904 if (TVisitor::UseExecutionOrder)
9906 if (dynBlock->IsReverseOp())
9908 std::swap(op1Use, op2Use);
9910 if (dynBlock->gtEvalSizeFirst)
9912 std::swap(op3Use, op2Use);
9913 std::swap(op2Use, op1Use);
9917 result = WalkTree(op1Use, dynBlock);
9918 if (result == fgWalkResult::WALK_ABORT)
9922 result = WalkTree(op2Use, dynBlock);
9923 if (result == fgWalkResult::WALK_ABORT)
9927 result = WalkTree(op3Use, dynBlock);
9928 if (result == fgWalkResult::WALK_ABORT)
9937 GenTreeCall* const call = node->AsCall();
9939 if (call->gtCallObjp != nullptr)
9941 result = WalkTree(&call->gtCallObjp, call);
9942 if (result == fgWalkResult::WALK_ABORT)
9948 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
9950 result = WalkTree(args->pCurrent(), call);
9951 if (result == fgWalkResult::WALK_ABORT)
9957 for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
9959 result = WalkTree(args->pCurrent(), call);
9960 if (result == fgWalkResult::WALK_ABORT)
9966 if (call->gtCallType == CT_INDIRECT)
9968 if (call->gtCallCookie != nullptr)
9970 result = WalkTree(&call->gtCallCookie, call);
9971 if (result == fgWalkResult::WALK_ABORT)
9977 result = WalkTree(&call->gtCallAddr, call);
9978 if (result == fgWalkResult::WALK_ABORT)
9984 if (call->gtControlExpr != nullptr)
9986 result = WalkTree(&call->gtControlExpr, call);
9987 if (result == fgWalkResult::WALK_ABORT)
9999 assert(node->OperIsBinary());
10001 GenTreeOp* const op = node->AsOp();
10003 GenTree** op1Use = &op->gtOp1;
10004 GenTree** op2Use = &op->gtOp2;
10006 if (TVisitor::UseExecutionOrder && node->IsReverseOp())
10008 std::swap(op1Use, op2Use);
10011 if (*op1Use != nullptr)
10013 result = WalkTree(op1Use, op);
10014 if (result == fgWalkResult::WALK_ABORT)
10020 if (*op2Use != nullptr)
10022 result = WalkTree(op2Use, op);
10023 if (result == fgWalkResult::WALK_ABORT)
10033 // Finally, visit the current node
10034 if (TVisitor::DoPostOrder)
10036 result = reinterpret_cast<TVisitor*>(this)->PostOrderVisit(use, user);
10039 if (TVisitor::ComputeStack)
10048 template <bool computeStack, bool doPreOrder, bool doPostOrder, bool doLclVarsOnly, bool useExecutionOrder>
10049 class GenericTreeWalker final
10050 : public GenTreeVisitor<GenericTreeWalker<computeStack, doPreOrder, doPostOrder, doLclVarsOnly, useExecutionOrder>>
10055 ComputeStack = computeStack,
10056 DoPreOrder = doPreOrder,
10057 DoPostOrder = doPostOrder,
10058 DoLclVarsOnly = doLclVarsOnly,
10059 UseExecutionOrder = useExecutionOrder,
10063 Compiler::fgWalkData* m_walkData;
10066 GenericTreeWalker(Compiler::fgWalkData* walkData)
10067 : GenTreeVisitor<GenericTreeWalker<computeStack, doPreOrder, doPostOrder, doLclVarsOnly, useExecutionOrder>>(
10068 walkData->compiler)
10069 , m_walkData(walkData)
10071 assert(walkData != nullptr);
10075 walkData->parentStack = &this->m_ancestors;
10079 Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
10081 m_walkData->parent = user;
10082 return m_walkData->wtprVisitorFn(use, m_walkData);
10085 Compiler::fgWalkResult PostOrderVisit(GenTree** use, GenTree* user)
10087 m_walkData->parent = user;
10088 return m_walkData->wtpoVisitorFn(use, m_walkData);
10093 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10094 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10096 XX Miscellaneous Compiler stuff XX
10098 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10099 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10102 // Values used to mark the types a stack slot is used for
10104 const unsigned TYPE_REF_INT = 0x01; // slot used as a 32-bit int
10105 const unsigned TYPE_REF_LNG = 0x02; // slot used as a 64-bit long
10106 const unsigned TYPE_REF_FLT = 0x04; // slot used as a 32-bit float
10107 const unsigned TYPE_REF_DBL = 0x08; // slot used as a 64-bit float
10108 const unsigned TYPE_REF_PTR = 0x10; // slot used as a 32-bit pointer
10109 const unsigned TYPE_REF_BYR = 0x20; // slot used as a byref pointer
10110 const unsigned TYPE_REF_STC = 0x40; // slot used as a struct
10111 const unsigned TYPE_REF_TYPEMASK = 0x7F; // bits that represent the type
10113 // const unsigned TYPE_REF_ADDR_TAKEN = 0x80; // slots address was taken
10115 /*****************************************************************************
10117 * Variables to keep track of total code amounts.
10122 extern size_t grossVMsize;
10123 extern size_t grossNCsize;
10124 extern size_t totalNCsize;
10126 extern unsigned genMethodICnt;
10127 extern unsigned genMethodNCnt;
10128 extern size_t gcHeaderISize;
10129 extern size_t gcPtrMapISize;
10130 extern size_t gcHeaderNSize;
10131 extern size_t gcPtrMapNSize;
10133 #endif // DISPLAY_SIZES
10135 /*****************************************************************************
10137 * Variables to keep track of basic block counts (more data on 1 BB methods)
10140 #if COUNT_BASIC_BLOCKS
10141 extern Histogram bbCntTable;
10142 extern Histogram bbOneBBSizeTable;
10145 /*****************************************************************************
10147 * Used by optFindNaturalLoops to gather statistical information such as
10148 * - total number of natural loops
10149 * - number of loops with 1, 2, ... exit conditions
10150 * - number of loops that have an iterator (for like)
10151 * - number of loops that have a constant iterator
10156 extern unsigned totalLoopMethods; // counts the total number of methods that have natural loops
10157 extern unsigned maxLoopsPerMethod; // counts the maximum number of loops a method has
10158 extern unsigned totalLoopOverflows; // # of methods that identified more loops than we can represent
10159 extern unsigned totalLoopCount; // counts the total number of natural loops
10160 extern unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
10161 extern unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
10162 extern unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
10163 extern unsigned simpleTestLoopCount; // counts the # of loops with an iterator and a simple loop condition (iter <
10165 extern unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
10166 extern bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
10167 extern unsigned loopsThisMethod; // counts the number of loops in the current method
10168 extern bool loopOverflowThisMethod; // True if we exceeded the max # of loops in the method.
10169 extern Histogram loopCountTable; // Histogram of loop counts
10170 extern Histogram loopExitCountTable; // Histogram of loop exit counts
10172 #endif // COUNT_LOOPS
10174 /*****************************************************************************
10175 * variables to keep track of how many iterations we go in a dataflow pass
10180 extern unsigned CSEiterCount; // counts the # of iteration for the CSE dataflow
10181 extern unsigned CFiterCount; // counts the # of iteration for the Const Folding dataflow
10183 #endif // DATAFLOW_ITER
10185 #if MEASURE_BLOCK_SIZE
10186 extern size_t genFlowNodeSize;
10187 extern size_t genFlowNodeCnt;
10188 #endif // MEASURE_BLOCK_SIZE
10190 #if MEASURE_NODE_SIZE
10191 struct NodeSizeStats
10195 genTreeNodeCnt = 0;
10196 genTreeNodeSize = 0;
10197 genTreeNodeActualSize = 0;
10200 // Count of tree nodes allocated.
10201 unsigned __int64 genTreeNodeCnt;
10203 // The size we allocate.
10204 unsigned __int64 genTreeNodeSize;
10206 // The actual size of the node. Note that the actual size will likely be smaller
10207 // than the allocated size, but we sometimes use SetOper()/ChangeOper() to change
10208 // a smaller node to a larger one. TODO-Cleanup: add stats on
10209 // SetOper()/ChangeOper() usage to quantify this.
10210 unsigned __int64 genTreeNodeActualSize;
10212 extern NodeSizeStats genNodeSizeStats; // Total node size stats
10213 extern NodeSizeStats genNodeSizeStatsPerFunc; // Per-function node size stats
10214 extern Histogram genTreeNcntHist;
10215 extern Histogram genTreeNsizHist;
10216 #endif // MEASURE_NODE_SIZE
10218 /*****************************************************************************
10219 * Count fatal errors (including noway_asserts).
10223 extern unsigned fatal_badCode;
10224 extern unsigned fatal_noWay;
10225 extern unsigned fatal_NOMEM;
10226 extern unsigned fatal_noWayAssertBody;
10228 extern unsigned fatal_noWayAssertBodyArgs;
10230 extern unsigned fatal_NYI;
10231 #endif // MEASURE_FATAL
10233 /*****************************************************************************
10237 #ifdef _TARGET_XARCH_
10239 const instruction INS_SHIFT_LEFT_LOGICAL = INS_shl;
10240 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_shr;
10241 const instruction INS_SHIFT_RIGHT_ARITHM = INS_sar;
10243 const instruction INS_AND = INS_and;
10244 const instruction INS_OR = INS_or;
10245 const instruction INS_XOR = INS_xor;
10246 const instruction INS_NEG = INS_neg;
10247 const instruction INS_TEST = INS_test;
10248 const instruction INS_MUL = INS_imul;
10249 const instruction INS_SIGNED_DIVIDE = INS_idiv;
10250 const instruction INS_UNSIGNED_DIVIDE = INS_div;
10251 const instruction INS_BREAKPOINT = INS_int3;
10252 const instruction INS_ADDC = INS_adc;
10253 const instruction INS_SUBC = INS_sbb;
10254 const instruction INS_NOT = INS_not;
10256 #endif // _TARGET_XARCH_
10258 #ifdef _TARGET_ARM_
10260 const instruction INS_SHIFT_LEFT_LOGICAL = INS_lsl;
10261 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_lsr;
10262 const instruction INS_SHIFT_RIGHT_ARITHM = INS_asr;
10264 const instruction INS_AND = INS_and;
10265 const instruction INS_OR = INS_orr;
10266 const instruction INS_XOR = INS_eor;
10267 const instruction INS_NEG = INS_rsb;
10268 const instruction INS_TEST = INS_tst;
10269 const instruction INS_MUL = INS_mul;
10270 const instruction INS_MULADD = INS_mla;
10271 const instruction INS_SIGNED_DIVIDE = INS_sdiv;
10272 const instruction INS_UNSIGNED_DIVIDE = INS_udiv;
10273 const instruction INS_BREAKPOINT = INS_bkpt;
10274 const instruction INS_ADDC = INS_adc;
10275 const instruction INS_SUBC = INS_sbc;
10276 const instruction INS_NOT = INS_mvn;
10278 const instruction INS_ABS = INS_vabs;
10279 const instruction INS_SQRT = INS_vsqrt;
10281 #endif // _TARGET_ARM_
10283 #ifdef _TARGET_ARM64_
10285 const instruction INS_MULADD = INS_madd;
10286 const instruction INS_BREAKPOINT = INS_bkpt;
10288 const instruction INS_ABS = INS_fabs;
10289 const instruction INS_SQRT = INS_fsqrt;
10291 #endif // _TARGET_ARM64_
10293 /*****************************************************************************/
10295 extern const BYTE genTypeSizes[];
10296 extern const BYTE genTypeAlignments[];
10297 extern const BYTE genTypeStSzs[];
10298 extern const BYTE genActualTypes[];
10300 /*****************************************************************************/
10302 // VERY_LARGE_FRAME_SIZE_REG_MASK is the set of registers we need to use for
10303 // the probing loop generated for very large stack frames (see `getVeryLargeFrameSize`).
10305 #ifdef _TARGET_ARM_
10306 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R4 | RBM_R5 | RBM_R6)
10307 #elif defined(_TARGET_ARM64_)
10308 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R9 | RBM_R10 | RBM_R11)
10311 /*****************************************************************************/
10313 extern BasicBlock dummyBB;
10315 /*****************************************************************************/
10316 /*****************************************************************************/
10318 // foreach_treenode_execution_order: An iterator that iterates through all the tree
10319 // nodes of a statement in execution order.
10320 // __stmt: a GT_STMT type GenTree*
10321 // __node: a GenTree*, already declared, that gets updated with each node in the statement, in execution order
10323 #define foreach_treenode_execution_order(__node, __stmt) \
10324 for ((__node) = (__stmt)->gtStmt.gtStmtList; (__node); (__node) = (__node)->gtNext)
10326 // foreach_block: An iterator over all blocks in the function.
10327 // __compiler: the Compiler* object
10328 // __block : a BasicBlock*, already declared, that gets updated each iteration.
10330 #define foreach_block(__compiler, __block) \
10331 for ((__block) = (__compiler)->fgFirstBB; (__block); (__block) = (__block)->bbNext)
10333 /*****************************************************************************/
10334 /*****************************************************************************/
10338 void dumpConvertedVarSet(Compiler* comp, VARSET_VALARG_TP vars);
10340 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10341 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10343 XX Debugging helpers XX
10345 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10346 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10349 /*****************************************************************************/
10350 /* The following functions are intended to be called from the debugger, to dump
10351 * various data structures. The can be used in the debugger Watch or Quick Watch
10352 * windows. They are designed to be short to type and take as few arguments as
10353 * possible. The 'c' versions take a Compiler*, whereas the 'd' versions use the TlsCompiler.
10354 * See the function definition comment for more details.
10357 void cBlock(Compiler* comp, BasicBlock* block);
10358 void cBlocks(Compiler* comp);
10359 void cBlocksV(Compiler* comp);
10360 void cTree(Compiler* comp, GenTree* tree);
10361 void cTrees(Compiler* comp);
10362 void cEH(Compiler* comp);
10363 void cVar(Compiler* comp, unsigned lclNum);
10364 void cVarDsc(Compiler* comp, LclVarDsc* varDsc);
10365 void cVars(Compiler* comp);
10366 void cVarsFinal(Compiler* comp);
10367 void cBlockPreds(Compiler* comp, BasicBlock* block);
10368 void cReach(Compiler* comp);
10369 void cDoms(Compiler* comp);
10370 void cLiveness(Compiler* comp);
10371 void cCVarSet(Compiler* comp, VARSET_VALARG_TP vars);
10373 void cFuncIR(Compiler* comp);
10374 void cBlockIR(Compiler* comp, BasicBlock* block);
10375 void cLoopIR(Compiler* comp, Compiler::LoopDsc* loop);
10376 void cTreeIR(Compiler* comp, GenTree* tree);
10377 int cTreeTypeIR(Compiler* comp, GenTree* tree);
10378 int cTreeKindsIR(Compiler* comp, GenTree* tree);
10379 int cTreeFlagsIR(Compiler* comp, GenTree* tree);
10380 int cOperandIR(Compiler* comp, GenTree* operand);
10381 int cLeafIR(Compiler* comp, GenTree* tree);
10382 int cIndirIR(Compiler* comp, GenTree* tree);
10383 int cListIR(Compiler* comp, GenTree* list);
10384 int cSsaNumIR(Compiler* comp, GenTree* tree);
10385 int cValNumIR(Compiler* comp, GenTree* tree);
10386 int cDependsIR(Compiler* comp, GenTree* comma, bool* first);
10388 void dBlock(BasicBlock* block);
10391 void dTree(GenTree* tree);
10394 void dVar(unsigned lclNum);
10395 void dVarDsc(LclVarDsc* varDsc);
10398 void dBlockPreds(BasicBlock* block);
10402 void dCVarSet(VARSET_VALARG_TP vars);
10404 void dRegMask(regMaskTP mask);
10407 void dBlockIR(BasicBlock* block);
10408 void dTreeIR(GenTree* tree);
10409 void dLoopIR(Compiler::LoopDsc* loop);
10410 void dLoopNumIR(unsigned loopNum);
10411 int dTabStopIR(int curr, int tabstop);
10412 int dTreeTypeIR(GenTree* tree);
10413 int dTreeKindsIR(GenTree* tree);
10414 int dTreeFlagsIR(GenTree* tree);
10415 int dOperandIR(GenTree* operand);
10416 int dLeafIR(GenTree* tree);
10417 int dIndirIR(GenTree* tree);
10418 int dListIR(GenTree* list);
10419 int dSsaNumIR(GenTree* tree);
10420 int dValNumIR(GenTree* tree);
10421 int dDependsIR(GenTree* comma);
10424 GenTree* dFindTree(GenTree* tree, unsigned id);
10425 GenTree* dFindTree(unsigned id);
10426 GenTreeStmt* dFindStmt(unsigned id);
10427 BasicBlock* dFindBlock(unsigned bbNum);
10431 #include "compiler.hpp" // All the shared inline functions
10433 /*****************************************************************************/
10434 #endif //_COMPILER_H_
10435 /*****************************************************************************/