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 bool needsTemps; // one or more arguments must be copied to a temp by EvalArgsToTemps
1636 fgArgTabEntry** argTable; // variable sized array of per argument descrption: (i.e. argTable[argTableSize])
1639 void AddArg(fgArgTabEntry* curArgTabEntry);
1642 fgArgInfo(Compiler* comp, GenTreeCall* call, unsigned argCount);
1643 fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall);
1645 fgArgTabEntry* AddRegArg(unsigned argNum,
1652 bool isVararg = false);
1654 #ifdef UNIX_AMD64_ABI
1655 fgArgTabEntry* AddRegArg(unsigned argNum,
1661 const bool isStruct,
1662 const bool isVararg,
1663 const regNumber otherRegNum,
1664 const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* const structDescPtr = nullptr);
1665 #endif // UNIX_AMD64_ABI
1667 fgArgTabEntry* AddStkArg(unsigned argNum,
1673 bool isVararg = false);
1675 void RemorphReset();
1676 void UpdateRegArg(fgArgTabEntry* argEntry, GenTree* node, bool reMorphing);
1677 void UpdateStkArg(fgArgTabEntry* argEntry, GenTree* node, bool reMorphing);
1679 void SplitArg(unsigned argNum, unsigned numRegs, unsigned numSlots);
1681 void EvalToTmp(fgArgTabEntry* curArgTabEntry, unsigned tmpNum, GenTree* newNode);
1683 void ArgsComplete();
1687 void EvalArgsToTemps();
1693 fgArgTabEntry** ArgTable()
1697 unsigned GetNextSlotNum()
1711 return hasStackArgs;
1713 bool AreArgsComplete() const
1715 return argsComplete;
1717 #if FEATURE_FIXED_OUT_ARGS
1718 unsigned GetOutArgSize() const
1722 void SetOutArgSize(unsigned newVal)
1724 outArgSize = newVal;
1726 #endif // FEATURE_FIXED_OUT_ARGS
1728 #if defined(UNIX_X86_ABI)
1729 void ComputeStackAlignment(unsigned curStackLevelInBytes)
1731 padStkAlign = AlignmentPad(curStackLevelInBytes, STACK_ALIGN);
1734 unsigned GetStkAlign()
1739 void SetStkSizeBytes(unsigned newStkSizeBytes)
1741 stkSizeBytes = newStkSizeBytes;
1744 unsigned GetStkSizeBytes() const
1746 return stkSizeBytes;
1749 bool IsStkAlignmentDone() const
1751 return alignmentDone;
1754 void SetStkAlignmentDone()
1756 alignmentDone = true;
1758 #endif // defined(UNIX_X86_ABI)
1760 // Get the fgArgTabEntry for the arg at position argNum.
1761 fgArgTabEntry* GetArgEntry(unsigned argNum, bool reMorphing = true)
1763 fgArgTabEntry* curArgTabEntry = nullptr;
1767 // The arg table has not yet been sorted.
1768 curArgTabEntry = argTable[argNum];
1769 assert(curArgTabEntry->argNum == argNum);
1770 return curArgTabEntry;
1773 for (unsigned i = 0; i < argCount; i++)
1775 curArgTabEntry = argTable[i];
1776 if (curArgTabEntry->argNum == argNum)
1778 return curArgTabEntry;
1781 noway_assert(!"GetArgEntry: argNum not found");
1785 // Get the node for the arg at position argIndex.
1786 // Caller must ensure that this index is a valid arg index.
1787 GenTree* GetArgNode(unsigned argIndex)
1789 return GetArgEntry(argIndex)->node;
1792 void Dump(Compiler* compiler);
1796 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1797 // We have the ability to mark source expressions with "Test Labels."
1798 // These drive assertions within the JIT, or internal JIT testing. For example, we could label expressions
1799 // that should be CSE defs, and other expressions that should uses of those defs, with a shared label.
1801 enum TestLabel // This must be kept identical to System.Runtime.CompilerServices.JitTestLabel.TestLabel.
1804 TL_VN, // Defines a "VN equivalence class". (For full VN, including exceptions thrown).
1805 TL_VNNorm, // Like above, but uses the non-exceptional value of the expression.
1806 TL_CSE_Def, // This must be identified in the JIT as a CSE def
1807 TL_CSE_Use, // This must be identified in the JIT as a CSE use
1808 TL_LoopHoist, // Expression must (or must not) be hoisted out of the loop.
1811 struct TestLabelAndNum
1816 TestLabelAndNum() : m_tl(TestLabel(0)), m_num(0)
1821 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, TestLabelAndNum> NodeToTestDataMap;
1823 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1827 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1828 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1830 XX The big guy. The sections are currently organized as : XX
1832 XX o GenTree and BasicBlock XX
1844 XX o PrologScopeInfo XX
1845 XX o CodeGenerator XX
1850 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1851 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1854 struct HWIntrinsicInfo;
1858 friend class emitter;
1859 friend class UnwindInfo;
1860 friend class UnwindFragmentInfo;
1861 friend class UnwindEpilogInfo;
1862 friend class JitTimer;
1863 friend class LinearScan;
1864 friend class fgArgInfo;
1865 friend class Rationalizer;
1867 friend class Lowering;
1868 friend class CSE_DataFlow;
1869 friend class CSE_Heuristic;
1870 friend class CodeGenInterface;
1871 friend class CodeGen;
1872 friend class LclVarDsc;
1873 friend class TempDsc;
1875 friend class ObjectAllocator;
1876 friend class LocalAddressVisitor;
1877 friend struct GenTree;
1879 #ifdef FEATURE_HW_INTRINSICS
1880 friend struct HWIntrinsicInfo;
1881 #endif // FEATURE_HW_INTRINSICS
1883 #ifndef _TARGET_64BIT_
1884 friend class DecomposeLongs;
1885 #endif // !_TARGET_64BIT_
1888 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1889 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1891 XX Misc structs definitions XX
1893 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1894 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1898 hashBvGlobalData hbvGlobalData; // Used by the hashBv bitvector package.
1917 bool dumpIRDataflow;
1918 bool dumpIRBlockHeaders;
1920 LPCWSTR dumpIRPhase;
1921 LPCWSTR dumpIRFormat;
1923 bool shouldUseVerboseTrees();
1924 bool asciiTrees; // If true, dump trees using only ASCII characters
1925 bool shouldDumpASCIITrees();
1926 bool verboseSsa; // If true, produce especially verbose dump output in SSA construction.
1927 bool shouldUseVerboseSsa();
1928 bool treesBeforeAfterMorph; // If true, print trees before/after morphing (paired by an intra-compilation id:
1929 int morphNum; // This counts the the trees that have been morphed, allowing us to label each uniquely.
1931 const char* VarNameToStr(VarName name)
1936 DWORD expensiveDebugCheckLevel;
1939 #if FEATURE_MULTIREG_RET
1940 GenTree* impAssignMultiRegTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass);
1941 #endif // FEATURE_MULTIREG_RET
1943 GenTree* impAssignSmallStructTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass);
1946 bool isSingleFloat32Struct(CORINFO_CLASS_HANDLE hClass);
1947 #endif // ARM_SOFTFP
1949 //-------------------------------------------------------------------------
1950 // Functions to handle homogeneous floating-point aggregates (HFAs) in ARM.
1951 // HFAs are one to four element structs where each element is the same
1952 // type, either all float or all double. They are treated specially
1953 // in the ARM Procedure Call Standard, specifically, they are passed in
1954 // floating-point registers instead of the general purpose registers.
1957 bool IsHfa(CORINFO_CLASS_HANDLE hClass);
1958 bool IsHfa(GenTree* tree);
1960 var_types GetHfaType(GenTree* tree);
1961 unsigned GetHfaCount(GenTree* tree);
1963 var_types GetHfaType(CORINFO_CLASS_HANDLE hClass);
1964 unsigned GetHfaCount(CORINFO_CLASS_HANDLE hClass);
1966 bool IsMultiRegReturnedType(CORINFO_CLASS_HANDLE hClass);
1968 //-------------------------------------------------------------------------
1969 // The following is used for validating format of EH table
1973 typedef struct EHNodeDsc* pEHNodeDsc;
1975 EHNodeDsc* ehnTree; // root of the tree comprising the EHnodes.
1976 EHNodeDsc* ehnNext; // root of the tree comprising the EHnodes.
1989 EHBlockType ehnBlockType; // kind of EH block
1990 IL_OFFSET ehnStartOffset; // IL offset of start of the EH block
1991 IL_OFFSET ehnEndOffset; // IL offset past end of the EH block. (TODO: looks like verInsertEhNode() sets this to
1992 // the last IL offset, not "one past the last one", i.e., the range Start to End is
1994 pEHNodeDsc ehnNext; // next (non-nested) block in sequential order
1995 pEHNodeDsc ehnChild; // leftmost nested block
1997 pEHNodeDsc ehnTryNode; // for filters and handlers, the corresponding try node
1998 pEHNodeDsc ehnHandlerNode; // for a try node, the corresponding handler node
2000 pEHNodeDsc ehnFilterNode; // if this is a try node and has a filter, otherwise 0
2001 pEHNodeDsc ehnEquivalent; // if blockType=tryNode, start offset and end offset is same,
2003 void ehnSetTryNodeType()
2005 ehnBlockType = TryNode;
2007 void ehnSetFilterNodeType()
2009 ehnBlockType = FilterNode;
2011 void ehnSetHandlerNodeType()
2013 ehnBlockType = HandlerNode;
2015 void ehnSetFinallyNodeType()
2017 ehnBlockType = FinallyNode;
2019 void ehnSetFaultNodeType()
2021 ehnBlockType = FaultNode;
2024 BOOL ehnIsTryBlock()
2026 return ehnBlockType == TryNode;
2028 BOOL ehnIsFilterBlock()
2030 return ehnBlockType == FilterNode;
2032 BOOL ehnIsHandlerBlock()
2034 return ehnBlockType == HandlerNode;
2036 BOOL ehnIsFinallyBlock()
2038 return ehnBlockType == FinallyNode;
2040 BOOL ehnIsFaultBlock()
2042 return ehnBlockType == FaultNode;
2045 // returns true if there is any overlap between the two nodes
2046 static BOOL ehnIsOverlap(pEHNodeDsc node1, pEHNodeDsc node2)
2048 if (node1->ehnStartOffset < node2->ehnStartOffset)
2050 return (node1->ehnEndOffset >= node2->ehnStartOffset);
2054 return (node1->ehnStartOffset <= node2->ehnEndOffset);
2058 // fails with BADCODE if inner is not completely nested inside outer
2059 static BOOL ehnIsNested(pEHNodeDsc inner, pEHNodeDsc outer)
2061 return ((inner->ehnStartOffset >= outer->ehnStartOffset) && (inner->ehnEndOffset <= outer->ehnEndOffset));
2065 //-------------------------------------------------------------------------
2066 // Exception handling functions
2069 #if !FEATURE_EH_FUNCLETS
2071 bool ehNeedsShadowSPslots()
2073 return (info.compXcptnsCount || opts.compDbgEnC);
2076 // 0 for methods with no EH
2077 // 1 for methods with non-nested EH, or where only the try blocks are nested
2078 // 2 for a method with a catch within a catch
2080 unsigned ehMaxHndNestingCount;
2082 #endif // !FEATURE_EH_FUNCLETS
2084 static bool jitIsBetween(unsigned value, unsigned start, unsigned end);
2085 static bool jitIsBetweenInclusive(unsigned value, unsigned start, unsigned end);
2087 bool bbInCatchHandlerILRange(BasicBlock* blk);
2088 bool bbInFilterILRange(BasicBlock* blk);
2089 bool bbInTryRegions(unsigned regionIndex, BasicBlock* blk);
2090 bool bbInExnFlowRegions(unsigned regionIndex, BasicBlock* blk);
2091 bool bbInHandlerRegions(unsigned regionIndex, BasicBlock* blk);
2092 bool bbInCatchHandlerRegions(BasicBlock* tryBlk, BasicBlock* hndBlk);
2093 unsigned short bbFindInnermostCommonTryRegion(BasicBlock* bbOne, BasicBlock* bbTwo);
2095 unsigned short bbFindInnermostTryRegionContainingHandlerRegion(unsigned handlerIndex);
2096 unsigned short bbFindInnermostHandlerRegionContainingTryRegion(unsigned tryIndex);
2098 // Returns true if "block" is the start of a try region.
2099 bool bbIsTryBeg(BasicBlock* block);
2101 // Returns true if "block" is the start of a handler or filter region.
2102 bool bbIsHandlerBeg(BasicBlock* block);
2104 // Returns true iff "block" is where control flows if an exception is raised in the
2105 // try region, and sets "*regionIndex" to the index of the try for the handler.
2106 // Differs from "IsHandlerBeg" in the case of filters, where this is true for the first
2107 // block of the filter, but not for the filter's handler.
2108 bool bbIsExFlowBlock(BasicBlock* block, unsigned* regionIndex);
2110 bool ehHasCallableHandlers();
2112 // Return the EH descriptor for the given region index.
2113 EHblkDsc* ehGetDsc(unsigned regionIndex);
2115 // Return the EH index given a region descriptor.
2116 unsigned ehGetIndex(EHblkDsc* ehDsc);
2118 // Return the EH descriptor index of the enclosing try, for the given region index.
2119 unsigned ehGetEnclosingTryIndex(unsigned regionIndex);
2121 // Return the EH descriptor index of the enclosing handler, for the given region index.
2122 unsigned ehGetEnclosingHndIndex(unsigned regionIndex);
2124 // Return the EH descriptor for the most nested 'try' region this BasicBlock is a member of (or nullptr if this
2125 // block is not in a 'try' region).
2126 EHblkDsc* ehGetBlockTryDsc(BasicBlock* block);
2128 // Return the EH descriptor for the most nested filter or handler region this BasicBlock is a member of (or nullptr
2129 // if this block is not in a filter or handler region).
2130 EHblkDsc* ehGetBlockHndDsc(BasicBlock* block);
2132 // Return the EH descriptor for the most nested region that may handle exceptions raised in this BasicBlock (or
2133 // nullptr if this block's exceptions propagate to caller).
2134 EHblkDsc* ehGetBlockExnFlowDsc(BasicBlock* block);
2136 EHblkDsc* ehIsBlockTryLast(BasicBlock* block);
2137 EHblkDsc* ehIsBlockHndLast(BasicBlock* block);
2138 bool ehIsBlockEHLast(BasicBlock* block);
2140 bool ehBlockHasExnFlowDsc(BasicBlock* block);
2142 // Return the region index of the most nested EH region this block is in.
2143 unsigned ehGetMostNestedRegionIndex(BasicBlock* block, bool* inTryRegion);
2145 // Find the true enclosing try index, ignoring 'mutual protect' try. Uses IL ranges to check.
2146 unsigned ehTrueEnclosingTryIndexIL(unsigned regionIndex);
2148 // Return the index of the most nested enclosing region for a particular EH region. Returns NO_ENCLOSING_INDEX
2149 // if there is no enclosing region. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion'
2150 // is set to 'true' if the enclosing region is a 'try', or 'false' if the enclosing region is a handler.
2151 // (It can never be a filter.)
2152 unsigned ehGetEnclosingRegionIndex(unsigned regionIndex, bool* inTryRegion);
2154 // A block has been deleted. Update the EH table appropriately.
2155 void ehUpdateForDeletedBlock(BasicBlock* block);
2157 // Determine whether a block can be deleted while preserving the EH normalization rules.
2158 bool ehCanDeleteEmptyBlock(BasicBlock* block);
2160 // Update the 'last' pointers in the EH table to reflect new or deleted blocks in an EH region.
2161 void ehUpdateLastBlocks(BasicBlock* oldLast, BasicBlock* newLast);
2163 // For a finally handler, find the region index that the BBJ_CALLFINALLY lives in that calls the handler,
2164 // or NO_ENCLOSING_INDEX if the BBJ_CALLFINALLY lives in the main function body. Normally, the index
2165 // is the same index as the handler (and the BBJ_CALLFINALLY lives in the 'try' region), but for AMD64 the
2166 // BBJ_CALLFINALLY lives in the enclosing try or handler region, whichever is more nested, or the main function
2167 // body. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion' is set to 'true' if the
2168 // BBJ_CALLFINALLY lives in the returned index's 'try' region, or 'false' if lives in the handler region. (It never
2169 // lives in a filter.)
2170 unsigned ehGetCallFinallyRegionIndex(unsigned finallyIndex, bool* inTryRegion);
2172 // Find the range of basic blocks in which all BBJ_CALLFINALLY will be found that target the 'finallyIndex' region's
2173 // handler. Set begBlk to the first block, and endBlk to the block after the last block of the range
2174 // (nullptr if the last block is the last block in the program).
2175 // Precondition: 'finallyIndex' is the EH region of a try/finally clause.
2176 void ehGetCallFinallyBlockRange(unsigned finallyIndex, BasicBlock** begBlk, BasicBlock** endBlk);
2179 // Given a BBJ_CALLFINALLY block and the EH region index of the finally it is calling, return
2180 // 'true' if the BBJ_CALLFINALLY is in the correct EH region.
2181 bool ehCallFinallyInCorrectRegion(BasicBlock* blockCallFinally, unsigned finallyIndex);
2184 #if FEATURE_EH_FUNCLETS
2185 // Do we need a PSPSym in the main function? For codegen purposes, we only need one
2186 // if there is a filter that protects a region with a nested EH clause (such as a
2187 // try/catch nested in the 'try' body of a try/filter/filter-handler). See
2188 // genFuncletProlog() for more details. However, the VM seems to use it for more
2189 // purposes, maybe including debugging. Until we are sure otherwise, always create
2190 // a PSPSym for functions with any EH.
2191 bool ehNeedsPSPSym() const
2195 #else // _TARGET_X86_
2196 return compHndBBtabCount > 0;
2197 #endif // _TARGET_X86_
2200 bool ehAnyFunclets(); // Are there any funclets in this function?
2201 unsigned ehFuncletCount(); // Return the count of funclets in the function
2203 unsigned bbThrowIndex(BasicBlock* blk); // Get the index to use as the cache key for sharing throw blocks
2204 #else // !FEATURE_EH_FUNCLETS
2205 bool ehAnyFunclets()
2209 unsigned ehFuncletCount()
2214 unsigned bbThrowIndex(BasicBlock* blk)
2216 return blk->bbTryIndex;
2217 } // Get the index to use as the cache key for sharing throw blocks
2218 #endif // !FEATURE_EH_FUNCLETS
2220 // Returns a flowList representing the "EH predecessors" of "blk". These are the normal predecessors of
2221 // "blk", plus one special case: if "blk" is the first block of a handler, considers the predecessor(s) of the first
2222 // first block of the corresponding try region to be "EH predecessors". (If there is a single such predecessor,
2223 // for example, we want to consider that the immediate dominator of the catch clause start block, so it's
2224 // convenient to also consider it a predecessor.)
2225 flowList* BlockPredsWithEH(BasicBlock* blk);
2227 // This table is useful for memoization of the method above.
2228 typedef JitHashTable<BasicBlock*, JitPtrKeyFuncs<BasicBlock>, flowList*> BlockToFlowListMap;
2229 BlockToFlowListMap* m_blockToEHPreds;
2230 BlockToFlowListMap* GetBlockToEHPreds()
2232 if (m_blockToEHPreds == nullptr)
2234 m_blockToEHPreds = new (getAllocator()) BlockToFlowListMap(getAllocator());
2236 return m_blockToEHPreds;
2239 void* ehEmitCookie(BasicBlock* block);
2240 UNATIVE_OFFSET ehCodeOffset(BasicBlock* block);
2242 EHblkDsc* ehInitHndRange(BasicBlock* src, IL_OFFSET* hndBeg, IL_OFFSET* hndEnd, bool* inFilter);
2244 EHblkDsc* ehInitTryRange(BasicBlock* src, IL_OFFSET* tryBeg, IL_OFFSET* tryEnd);
2246 EHblkDsc* ehInitHndBlockRange(BasicBlock* blk, BasicBlock** hndBeg, BasicBlock** hndLast, bool* inFilter);
2248 EHblkDsc* ehInitTryBlockRange(BasicBlock* blk, BasicBlock** tryBeg, BasicBlock** tryLast);
2250 void fgSetTryEnd(EHblkDsc* handlerTab, BasicBlock* newTryLast);
2252 void fgSetHndEnd(EHblkDsc* handlerTab, BasicBlock* newHndLast);
2254 void fgSkipRmvdBlocks(EHblkDsc* handlerTab);
2256 void fgAllocEHTable();
2258 void fgRemoveEHTableEntry(unsigned XTnum);
2260 #if FEATURE_EH_FUNCLETS
2262 EHblkDsc* fgAddEHTableEntry(unsigned XTnum);
2264 #endif // FEATURE_EH_FUNCLETS
2268 #endif // !FEATURE_EH
2270 void fgSortEHTable();
2272 // Causes the EH table to obey some well-formedness conditions, by inserting
2273 // empty BB's when necessary:
2274 // * No block is both the first block of a handler and the first block of a try.
2275 // * No block is the first block of multiple 'try' regions.
2276 // * No block is the last block of multiple EH regions.
2277 void fgNormalizeEH();
2278 bool fgNormalizeEHCase1();
2279 bool fgNormalizeEHCase2();
2280 bool fgNormalizeEHCase3();
2283 void dispIncomingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
2284 void dispOutgoingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
2285 void fgVerifyHandlerTab();
2286 void fgDispHandlerTab();
2289 bool fgNeedToSortEHTable;
2291 void verInitEHTree(unsigned numEHClauses);
2292 void verInsertEhNode(CORINFO_EH_CLAUSE* clause, EHblkDsc* handlerTab);
2293 void verInsertEhNodeInTree(EHNodeDsc** ppRoot, EHNodeDsc* node);
2294 void verInsertEhNodeParent(EHNodeDsc** ppRoot, EHNodeDsc* node);
2295 void verCheckNestingLevel(EHNodeDsc* initRoot);
2298 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2299 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2301 XX GenTree and BasicBlock XX
2303 XX Functions to allocate and display the GenTrees and BasicBlocks XX
2305 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2306 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2309 // Functions to create nodes
2310 GenTreeStmt* gtNewStmt(GenTree* expr = nullptr, IL_OFFSETX offset = BAD_IL_OFFSET);
2313 GenTree* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, bool doSimplifications = TRUE);
2315 // For binary opers.
2316 GenTree* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2);
2318 GenTree* gtNewQmarkNode(var_types type, GenTree* cond, GenTree* colon);
2320 GenTree* gtNewLargeOperNode(genTreeOps oper,
2321 var_types type = TYP_I_IMPL,
2322 GenTree* op1 = nullptr,
2323 GenTree* op2 = nullptr);
2325 GenTreeIntCon* gtNewIconNode(ssize_t value, var_types type = TYP_INT);
2327 GenTree* gtNewPhysRegNode(regNumber reg, var_types type);
2329 GenTree* gtNewJmpTableNode();
2331 GenTree* gtNewIndOfIconHandleNode(var_types indType, size_t value, unsigned iconFlags, bool isInvariant);
2333 GenTree* gtNewIconHandleNode(size_t value, unsigned flags, FieldSeqNode* fields = nullptr);
2335 unsigned gtTokenToIconFlags(unsigned token);
2337 GenTree* gtNewIconEmbHndNode(void* value, void* pValue, unsigned flags, void* compileTimeHandle);
2339 GenTree* gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd);
2340 GenTree* gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd);
2341 GenTree* gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd);
2342 GenTree* gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd);
2344 GenTree* gtNewStringLiteralNode(InfoAccessType iat, void* pValue);
2346 GenTree* gtNewLconNode(__int64 value);
2348 GenTree* gtNewDconNode(double value, var_types type = TYP_DOUBLE);
2350 GenTree* gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle);
2352 GenTree* gtNewZeroConNode(var_types type);
2354 GenTree* gtNewOneConNode(var_types type);
2357 GenTree* gtNewSIMDVectorZero(var_types simdType, var_types baseType, unsigned size);
2358 GenTree* gtNewSIMDVectorOne(var_types simdType, var_types baseType, unsigned size);
2361 GenTree* gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, unsigned size, bool isVolatile, bool isCopyBlock);
2363 GenTree* gtNewPutArgReg(var_types type, GenTree* arg, regNumber argReg);
2365 GenTree* gtNewBitCastNode(var_types type, GenTree* arg);
2368 void gtBlockOpInit(GenTree* result, GenTree* dst, GenTree* srcOrFillVal, bool isVolatile);
2371 GenTree* gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr);
2372 void gtSetObjGcInfo(GenTreeObj* objNode);
2373 GenTree* gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTree* addr);
2374 GenTree* gtNewBlockVal(GenTree* addr, unsigned size);
2376 GenTree* gtNewCpObjNode(GenTree* dst, GenTree* src, CORINFO_CLASS_HANDLE structHnd, bool isVolatile);
2378 GenTreeArgList* gtNewListNode(GenTree* op1, GenTreeArgList* op2);
2380 GenTreeCall* gtNewCallNode(gtCallTypes callType,
2381 CORINFO_METHOD_HANDLE handle,
2383 GenTreeArgList* args,
2384 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2386 GenTreeCall* gtNewIndCallNode(GenTree* addr,
2388 GenTreeArgList* args,
2389 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2391 GenTreeCall* gtNewHelperCallNode(unsigned helper, var_types type, GenTreeArgList* args = nullptr);
2393 GenTree* gtNewLclvNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));
2394 GenTree* gtNewLclLNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));
2397 GenTreeSIMD* gtNewSIMDNode(
2398 var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
2399 GenTreeSIMD* gtNewSIMDNode(
2400 var_types type, GenTree* op1, GenTree* op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
2401 void SetOpLclRelatedToSIMDIntrinsic(GenTree* op);
2404 #ifdef FEATURE_HW_INTRINSICS
2405 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2406 NamedIntrinsic hwIntrinsicID,
2409 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
2410 var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
2411 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
2412 var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
2413 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2417 NamedIntrinsic hwIntrinsicID,
2420 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2425 NamedIntrinsic hwIntrinsicID,
2428 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID);
2429 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type,
2432 NamedIntrinsic hwIntrinsicID);
2433 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(
2434 var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID);
2435 GenTree* gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd);
2436 CORINFO_CLASS_HANDLE gtGetStructHandleForHWSIMD(var_types simdType, var_types simdBaseType);
2437 #endif // FEATURE_HW_INTRINSICS
2439 GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset);
2440 GenTree* gtNewInlineCandidateReturnExpr(GenTree* inlineCandidate, var_types type);
2442 GenTree* gtNewFieldRef(var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj = nullptr, DWORD offset = 0);
2444 GenTree* gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree* indexOp);
2446 GenTreeArrLen* gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset);
2448 GenTree* gtNewIndir(var_types typ, GenTree* addr);
2450 GenTreeArgList* gtNewArgList(GenTree* op);
2451 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2);
2452 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2, GenTree* op3);
2453 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2, GenTree* op3, GenTree* op4);
2455 static fgArgTabEntry* gtArgEntryByArgNum(GenTreeCall* call, unsigned argNum);
2456 static fgArgTabEntry* gtArgEntryByNode(GenTreeCall* call, GenTree* node);
2457 fgArgTabEntry* gtArgEntryByLateArgIndex(GenTreeCall* call, unsigned lateArgInx);
2458 static GenTree* gtArgNodeByLateArgInx(GenTreeCall* call, unsigned lateArgInx);
2459 bool gtArgIsThisPtr(fgArgTabEntry* argEntry);
2461 GenTree* gtNewAssignNode(GenTree* dst, GenTree* src);
2463 GenTree* gtNewTempAssign(unsigned tmp,
2465 GenTree** pAfterStmt = nullptr,
2466 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
2467 BasicBlock* block = nullptr);
2469 GenTree* gtNewRefCOMfield(GenTree* objPtr,
2470 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2471 CORINFO_ACCESS_FLAGS access,
2472 CORINFO_FIELD_INFO* pFieldInfo,
2474 CORINFO_CLASS_HANDLE structType,
2477 GenTree* gtNewNothingNode();
2479 GenTree* gtNewArgPlaceHolderNode(var_types type, CORINFO_CLASS_HANDLE clsHnd);
2481 GenTree* gtUnusedValNode(GenTree* expr);
2483 GenTreeCast* gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
2485 GenTreeCast* gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
2487 GenTreeAllocObj* gtNewAllocObjNode(
2488 unsigned int helper, bool helperHasSideEffects, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTree* op1);
2490 GenTreeAllocObj* gtNewAllocObjNode(CORINFO_RESOLVED_TOKEN* pResolvedToken, BOOL useParent);
2492 GenTree* gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* lookupTree);
2494 //------------------------------------------------------------------------
2495 // Other GenTree functions
2497 GenTree* gtClone(GenTree* tree, bool complexOK = false);
2499 // If `tree` is a lclVar with lclNum `varNum`, return an IntCns with value `varVal`; otherwise,
2500 // create a copy of `tree`, adding specified flags, replacing uses of lclVar `deepVarNum` with
2501 // IntCnses with value `deepVarVal`.
2502 GenTree* gtCloneExpr(
2503 GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal);
2505 // Create a copy of `tree`, optionally adding specifed flags, and optionally mapping uses of local
2506 // `varNum` to int constants with value `varVal`.
2507 GenTree* gtCloneExpr(GenTree* tree, unsigned addFlags = 0, unsigned varNum = BAD_VAR_NUM, int varVal = 0)
2509 return gtCloneExpr(tree, addFlags, varNum, varVal, varNum, varVal);
2512 // Internal helper for cloning a call
2513 GenTreeCall* gtCloneExprCallHelper(GenTreeCall* call,
2514 unsigned addFlags = 0,
2515 unsigned deepVarNum = BAD_VAR_NUM,
2516 int deepVarVal = 0);
2518 // Create copy of an inline or guarded devirtualization candidate tree.
2519 GenTreeCall* gtCloneCandidateCall(GenTreeCall* call);
2521 GenTree* gtReplaceTree(GenTree* stmt, GenTree* tree, GenTree* replacementTree);
2523 void gtUpdateSideEffects(GenTree* stmt, GenTree* tree);
2525 void gtUpdateTreeAncestorsSideEffects(GenTree* tree);
2527 void gtUpdateStmtSideEffects(GenTree* stmt);
2529 void gtUpdateNodeSideEffects(GenTree* tree);
2531 void gtUpdateNodeOperSideEffects(GenTree* tree);
2533 // Returns "true" iff the complexity (not formally defined, but first interpretation
2534 // is #of nodes in subtree) of "tree" is greater than "limit".
2535 // (This is somewhat redundant with the "gtCostEx/gtCostSz" fields, but can be used
2536 // before they have been set.)
2537 bool gtComplexityExceeds(GenTree** tree, unsigned limit);
2539 bool gtCompareTree(GenTree* op1, GenTree* op2);
2541 GenTree* gtReverseCond(GenTree* tree);
2543 bool gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly);
2545 bool gtHasLocalsWithAddrOp(GenTree* tree);
2547 unsigned gtSetListOrder(GenTree* list, bool regs, bool isListCallArgs);
2549 void gtWalkOp(GenTree** op1, GenTree** op2, GenTree* base, bool constOnly);
2552 unsigned gtHashValue(GenTree* tree);
2554 GenTree* gtWalkOpEffectiveVal(GenTree* op);
2557 void gtPrepareCost(GenTree* tree);
2558 bool gtIsLikelyRegVar(GenTree* tree);
2560 // Returns true iff the secondNode can be swapped with firstNode.
2561 bool gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode);
2563 // Given an address expression, compute its costs and addressing mode opportunities,
2564 // and mark addressing mode candidates as GTF_DONT_CSE.
2565 // TODO-Throughput - Consider actually instantiating these early, to avoid
2566 // having to re-run the algorithm that looks for them (might also improve CQ).
2567 bool gtMarkAddrMode(GenTree* addr, int* costEx, int* costSz, var_types type);
2569 unsigned gtSetEvalOrder(GenTree* tree);
2571 void gtSetStmtInfo(GenTree* stmt);
2573 // Returns "true" iff "node" has any of the side effects in "flags".
2574 bool gtNodeHasSideEffects(GenTree* node, unsigned flags);
2576 // Returns "true" iff "tree" or its (transitive) children have any of the side effects in "flags".
2577 bool gtTreeHasSideEffects(GenTree* tree, unsigned flags);
2579 // Appends 'expr' in front of 'list'
2580 // 'list' will typically start off as 'nullptr'
2581 // when 'list' is non-null a GT_COMMA node is used to insert 'expr'
2582 GenTree* gtBuildCommaList(GenTree* list, GenTree* expr);
2584 void gtExtractSideEffList(GenTree* expr,
2586 unsigned flags = GTF_SIDE_EFFECT,
2587 bool ignoreRoot = false);
2589 GenTree* gtGetThisArg(GenTreeCall* call);
2591 // Static fields of struct types (and sometimes the types that those are reduced to) are represented by having the
2592 // static field contain an object pointer to the boxed struct. This simplifies the GC implementation...but
2593 // complicates the JIT somewhat. This predicate returns "true" iff a node with type "fieldNodeType", representing
2594 // the given "fldHnd", is such an object pointer.
2595 bool gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd);
2597 // Return true if call is a recursive call; return false otherwise.
2598 // Note when inlining, this looks for calls back to the root method.
2599 bool gtIsRecursiveCall(GenTreeCall* call)
2601 return gtIsRecursiveCall(call->gtCallMethHnd);
2604 bool gtIsRecursiveCall(CORINFO_METHOD_HANDLE callMethodHandle)
2606 return (callMethodHandle == impInlineRoot()->info.compMethodHnd);
2609 //-------------------------------------------------------------------------
2611 GenTree* gtFoldExpr(GenTree* tree);
2614 // TODO-Amd64-Unix: Remove this when the clang optimizer is fixed and/or the method implementation is
2615 // refactored in a simpler code. This is a workaround for a bug in the clang-3.5 optimizer. The issue is that in
2616 // release build the optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner case
2617 // of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div operation instead of 64 bit) - see
2618 // the implementation of the method in gentree.cpp. For the case of lval1 and lval2 equal to MIN_LONG
2619 // (0x8000000000000000) this results in raising a SIGFPE. The method implementation is rather complex. Disable
2620 // optimizations for now.
2621 __attribute__((optnone))
2623 gtFoldExprConst(GenTree* tree);
2624 GenTree* gtFoldExprSpecial(GenTree* tree);
2625 GenTree* gtFoldExprCompare(GenTree* tree);
2626 GenTree* gtCreateHandleCompare(genTreeOps oper,
2629 CorInfoInlineTypeCheck typeCheckInliningResult);
2630 GenTree* gtFoldExprCall(GenTreeCall* call);
2631 GenTree* gtFoldTypeCompare(GenTree* tree);
2632 GenTree* gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2);
2634 // Options to control behavior of gtTryRemoveBoxUpstreamEffects
2635 enum BoxRemovalOptions
2637 BR_REMOVE_AND_NARROW, // remove effects, minimize remaining work, return possibly narrowed source tree
2638 BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE, // remove effects and minimize remaining work, return type handle tree
2639 BR_REMOVE_BUT_NOT_NARROW, // remove effects, return original source tree
2640 BR_DONT_REMOVE, // check if removal is possible, return copy source tree
2641 BR_DONT_REMOVE_WANT_TYPE_HANDLE, // check if removal is possible, return type handle tree
2642 BR_MAKE_LOCAL_COPY // revise box to copy to temp local and return local's address
2645 GenTree* gtTryRemoveBoxUpstreamEffects(GenTree* tree, BoxRemovalOptions options = BR_REMOVE_AND_NARROW);
2646 GenTree* gtOptimizeEnumHasFlag(GenTree* thisOp, GenTree* flagOp);
2648 //-------------------------------------------------------------------------
2649 // Get the handle, if any.
2650 CORINFO_CLASS_HANDLE gtGetStructHandleIfPresent(GenTree* tree);
2651 // Get the handle, and assert if not found.
2652 CORINFO_CLASS_HANDLE gtGetStructHandle(GenTree* tree);
2653 // Get the handle for a ref type.
2654 CORINFO_CLASS_HANDLE gtGetClassHandle(GenTree* tree, bool* pIsExact, bool* pIsNonNull);
2655 // Get the class handle for an helper call
2656 CORINFO_CLASS_HANDLE gtGetHelperCallClassHandle(GenTreeCall* call, bool* pIsExact, bool* pIsNonNull);
2657 // Get the element handle for an array of ref type.
2658 CORINFO_CLASS_HANDLE gtGetArrayElementClassHandle(GenTree* array);
2659 // Get a class handle from a helper call argument
2660 CORINFO_CLASS_HANDLE gtGetHelperArgClassHandle(GenTree* array,
2661 unsigned* runtimeLookupCount = nullptr,
2662 GenTree** handleTree = nullptr);
2663 // Get the class handle for a field
2664 CORINFO_CLASS_HANDLE gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull);
2665 // Check if this tree is a gc static base helper call
2666 bool gtIsStaticGCBaseHelperCall(GenTree* tree);
2668 //-------------------------------------------------------------------------
2669 // Functions to display the trees
2672 void gtDispNode(GenTree* tree, IndentStack* indentStack, __in_z const char* msg, bool isLIR);
2674 void gtDispVN(GenTree* tree);
2675 void gtDispConst(GenTree* tree);
2676 void gtDispLeaf(GenTree* tree, IndentStack* indentStack);
2677 void gtDispNodeName(GenTree* tree);
2678 void gtDispRegVal(GenTree* tree);
2690 void gtDispChild(GenTree* child,
2691 IndentStack* indentStack,
2693 __in_opt const char* msg = nullptr,
2694 bool topOnly = false);
2695 void gtDispTree(GenTree* tree,
2696 IndentStack* indentStack = nullptr,
2697 __in_opt const char* msg = nullptr,
2698 bool topOnly = false,
2699 bool isLIR = false);
2700 void gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut);
2701 int gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining);
2702 char* gtGetLclVarName(unsigned lclNum);
2703 void gtDispLclVar(unsigned varNum, bool padForBiggestDisp = true);
2704 void gtDispTreeList(GenTree* tree, IndentStack* indentStack = nullptr);
2705 void gtGetArgMsg(GenTreeCall* call, GenTree* arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength);
2706 void gtGetLateArgMsg(GenTreeCall* call, GenTree* arg, int argNum, int listCount, char* bufp, unsigned bufLength);
2707 void gtDispArgList(GenTreeCall* call, IndentStack* indentStack);
2708 void gtDispFieldSeq(FieldSeqNode* pfsn);
2710 void gtDispRange(LIR::ReadOnlyRange const& range);
2712 void gtDispTreeRange(LIR::Range& containingRange, GenTree* tree);
2714 void gtDispLIRNode(GenTree* node, const char* prefixMsg = nullptr);
2726 typedef fgWalkResult(fgWalkPreFn)(GenTree** pTree, fgWalkData* data);
2727 typedef fgWalkResult(fgWalkPostFn)(GenTree** pTree, fgWalkData* data);
2730 static fgWalkPreFn gtAssertColonCond;
2732 static fgWalkPreFn gtMarkColonCond;
2733 static fgWalkPreFn gtClearColonCond;
2735 GenTree** gtFindLink(GenTree* stmt, GenTree* node);
2736 bool gtHasCatchArg(GenTree* tree);
2738 typedef ArrayStack<GenTree*> GenTreeStack;
2740 static bool gtHasCallOnStack(GenTreeStack* parentStack);
2742 //=========================================================================
2743 // BasicBlock functions
2745 // This is a debug flag we will use to assert when creating block during codegen
2746 // as this interferes with procedure splitting. If you know what you're doing, set
2747 // it to true before creating the block. (DEBUG only)
2748 bool fgSafeBasicBlockCreation;
2751 BasicBlock* bbNewBasicBlock(BBjumpKinds jumpKind);
2754 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2755 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2759 XX The variables to be used by the code generator. XX
2761 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2762 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2766 // For both PROMOTION_TYPE_NONE and PROMOTION_TYPE_DEPENDENT the struct will
2767 // be placed in the stack frame and it's fields must be laid out sequentially.
2769 // For PROMOTION_TYPE_INDEPENDENT each of the struct's fields is replaced by
2770 // a local variable that can be enregistered or placed in the stack frame.
2771 // The fields do not need to be laid out sequentially
2773 enum lvaPromotionType
2775 PROMOTION_TYPE_NONE, // The struct local is not promoted
2776 PROMOTION_TYPE_INDEPENDENT, // The struct local is promoted,
2777 // and its field locals are independent of its parent struct local.
2778 PROMOTION_TYPE_DEPENDENT // The struct local is promoted,
2779 // but its field locals depend on its parent struct local.
2782 static int __cdecl RefCntCmp(const void* op1, const void* op2);
2783 static int __cdecl WtdRefCntCmp(const void* op1, const void* op2);
2785 /*****************************************************************************/
2787 enum FrameLayoutState
2790 INITIAL_FRAME_LAYOUT,
2791 PRE_REGALLOC_FRAME_LAYOUT,
2792 REGALLOC_FRAME_LAYOUT,
2793 TENTATIVE_FRAME_LAYOUT,
2798 RefCountState lvaRefCountState; // Current local ref count state
2800 bool lvaLocalVarRefCounted() const
2802 return lvaRefCountState == RCS_NORMAL;
2805 bool lvaTrackedFixed; // true: We cannot add new 'tracked' variable
2806 unsigned lvaCount; // total number of locals
2808 unsigned lvaRefCount; // total number of references to locals
2809 LclVarDsc* lvaTable; // variable descriptor table
2810 unsigned lvaTableCnt; // lvaTable size (>= lvaCount)
2812 LclVarDsc** lvaRefSorted; // table sorted by refcount
2814 unsigned short lvaTrackedCount; // actual # of locals being tracked
2815 unsigned lvaTrackedCountInSizeTUnits; // min # of size_t's sufficient to hold a bit for all the locals being tracked
2818 VARSET_TP lvaTrackedVars; // set of tracked variables
2820 #ifndef _TARGET_64BIT_
2821 VARSET_TP lvaLongVars; // set of long (64-bit) variables
2823 VARSET_TP lvaFloatVars; // set of floating-point (32-bit and 64-bit) variables
2825 unsigned lvaCurEpoch; // VarSets are relative to a specific set of tracked var indices.
2826 // It that changes, this changes. VarSets from different epochs
2827 // cannot be meaningfully combined.
2829 unsigned GetCurLVEpoch()
2834 // reverse map of tracked number to var number
2835 unsigned* lvaTrackedToVarNum;
2839 // # of procs compiled a with double-aligned stack
2840 static unsigned s_lvaDoubleAlignedProcsCount;
2844 // Getters and setters for address-exposed and do-not-enregister local var properties.
2845 bool lvaVarAddrExposed(unsigned varNum);
2846 void lvaSetVarAddrExposed(unsigned varNum);
2847 bool lvaVarDoNotEnregister(unsigned varNum);
2849 // Reasons why we can't enregister. Some of these correspond to debug properties of local vars.
2850 enum DoNotEnregisterReason
2855 DNER_VMNeedsStackAddr,
2856 DNER_LiveInOutOfHandler,
2857 DNER_LiveAcrossUnmanagedCall,
2858 DNER_BlockOp, // Is read or written via a block operation that explicitly takes the address.
2859 DNER_IsStructArg, // Is a struct passed as an argument in a way that requires a stack location.
2860 DNER_DepField, // It is a field of a dependently promoted struct
2861 DNER_NoRegVars, // opts.compFlags & CLFLG_REGVAR is not set
2862 DNER_MinOptsGC, // It is a GC Ref and we are compiling MinOpts
2863 #if !defined(_TARGET_64BIT_)
2864 DNER_LongParamField, // It is a decomposed field of a long parameter.
2866 #ifdef JIT32_GCENCODER
2871 void lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregisterReason reason));
2873 unsigned lvaVarargsHandleArg;
2875 unsigned lvaVarargsBaseOfStkArgs; // Pointer (computed based on incoming varargs handle) to the start of the stack
2877 #endif // _TARGET_X86_
2879 unsigned lvaInlinedPInvokeFrameVar; // variable representing the InlinedCallFrame
2880 unsigned lvaReversePInvokeFrameVar; // variable representing the reverse PInvoke frame
2881 #if FEATURE_FIXED_OUT_ARGS
2882 unsigned lvaPInvokeFrameRegSaveVar; // variable representing the RegSave for PInvoke inlining.
2884 unsigned lvaMonAcquired; // boolean variable introduced into in synchronized methods
2885 // that tracks whether the lock has been taken
2887 unsigned lvaArg0Var; // The lclNum of arg0. Normally this will be info.compThisArg.
2888 // However, if there is a "ldarga 0" or "starg 0" in the IL,
2889 // we will redirect all "ldarg(a) 0" and "starg 0" to this temp.
2891 unsigned lvaInlineeReturnSpillTemp; // The temp to spill the non-VOID return expression
2892 // in case there are multiple BBJ_RETURN blocks in the inlinee
2893 // or if the inlinee has GC ref locals.
2895 #if FEATURE_FIXED_OUT_ARGS
2896 unsigned lvaOutgoingArgSpaceVar; // dummy TYP_LCLBLK var for fixed outgoing argument space
2897 PhasedVar<unsigned> lvaOutgoingArgSpaceSize; // size of fixed outgoing argument space
2898 #endif // FEATURE_FIXED_OUT_ARGS
2901 // On architectures whose ABIs allow structs to be passed in registers, struct promotion will sometimes
2902 // require us to "rematerialize" a struct from it's separate constituent field variables. Packing several sub-word
2903 // field variables into an argument register is a hard problem. It's easier to reserve a word of memory into which
2904 // such field can be copied, after which the assembled memory word can be read into the register. We will allocate
2905 // this variable to be this scratch word whenever struct promotion occurs.
2906 unsigned lvaPromotedStructAssemblyScratchVar;
2907 #endif // _TARGET_ARM_
2909 #if defined(DEBUG) && defined(_TARGET_XARCH_)
2911 unsigned lvaReturnSpCheck; // Stores SP to confirm it is not corrupted on return.
2913 #endif // defined(DEBUG) && defined(_TARGET_XARCH_)
2915 #if defined(DEBUG) && defined(_TARGET_X86_)
2917 unsigned lvaCallSpCheck; // Stores SP to confirm it is not corrupted after every call.
2919 #endif // defined(DEBUG) && defined(_TARGET_X86_)
2921 unsigned lvaGenericsContextUseCount;
2923 bool lvaKeepAliveAndReportThis(); // Synchronized instance method of a reference type, or
2924 // CORINFO_GENERICS_CTXT_FROM_THIS?
2925 bool lvaReportParamTypeArg(); // Exceptions and CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG?
2927 //-------------------------------------------------------------------------
2928 // All these frame offsets are inter-related and must be kept in sync
2930 #if !FEATURE_EH_FUNCLETS
2931 // This is used for the callable handlers
2932 unsigned lvaShadowSPslotsVar; // TYP_BLK variable for all the shadow SP slots
2933 #endif // FEATURE_EH_FUNCLETS
2935 int lvaCachedGenericContextArgOffs;
2936 int lvaCachedGenericContextArgOffset(); // For CORINFO_CALLCONV_PARAMTYPE and if generic context is passed as
2939 #ifdef JIT32_GCENCODER
2941 unsigned lvaLocAllocSPvar; // variable which stores the value of ESP after the the last alloca/localloc
2943 #endif // JIT32_GCENCODER
2945 unsigned lvaNewObjArrayArgs; // variable with arguments for new MD array helper
2947 // TODO-Review: Prior to reg predict we reserve 24 bytes for Spill temps.
2948 // after the reg predict we will use a computed maxTmpSize
2949 // which is based upon the number of spill temps predicted by reg predict
2950 // All this is necessary because if we under-estimate the size of the spill
2951 // temps we could fail when encoding instructions that reference stack offsets for ARM.
2953 // Pre codegen max spill temp size.
2954 static const unsigned MAX_SPILL_TEMP_SIZE = 24;
2956 //-------------------------------------------------------------------------
2958 unsigned lvaGetMaxSpillTempSize();
2960 bool lvaIsPreSpilled(unsigned lclNum, regMaskTP preSpillMask);
2961 #endif // _TARGET_ARM_
2962 void lvaAssignFrameOffsets(FrameLayoutState curState);
2963 void lvaFixVirtualFrameOffsets();
2964 void lvaUpdateArgsWithInitialReg();
2965 void lvaAssignVirtualFrameOffsetsToArgs();
2966 #ifdef UNIX_AMD64_ABI
2967 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs, int* callerArgOffset);
2968 #else // !UNIX_AMD64_ABI
2969 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs);
2970 #endif // !UNIX_AMD64_ABI
2971 void lvaAssignVirtualFrameOffsetsToLocals();
2972 int lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, int stkOffs);
2973 #ifdef _TARGET_AMD64_
2974 // Returns true if compCalleeRegsPushed (including RBP if used as frame pointer) is even.
2975 bool lvaIsCalleeSavedIntRegCountEven();
2977 void lvaAlignFrame();
2978 void lvaAssignFrameOffsetsToPromotedStructs();
2979 int lvaAllocateTemps(int stkOffs, bool mustDoubleAlign);
2982 void lvaDumpRegLocation(unsigned lclNum);
2983 void lvaDumpFrameLocation(unsigned lclNum);
2984 void lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t refCntWtdWidth = 6);
2985 void lvaTableDump(FrameLayoutState curState = NO_FRAME_LAYOUT); // NO_FRAME_LAYOUT means use the current frame
2986 // layout state defined by lvaDoneFrameLayout
2989 // Limit frames size to 1GB. The maximum is 2GB in theory - make it intentionally smaller
2990 // to avoid bugs from borderline cases.
2991 #define MAX_FrameSize 0x3FFFFFFF
2992 void lvaIncrementFrameSize(unsigned size);
2994 unsigned lvaFrameSize(FrameLayoutState curState);
2996 // Returns the caller-SP-relative offset for the SP/FP relative offset determined by FP based.
2997 int lvaToCallerSPRelativeOffset(int offs, bool isFpBased) const;
2999 // Returns the caller-SP-relative offset for the local variable "varNum."
3000 int lvaGetCallerSPRelativeOffset(unsigned varNum);
3002 // Returns the SP-relative offset for the local variable "varNum". Illegal to ask this for functions with localloc.
3003 int lvaGetSPRelativeOffset(unsigned varNum);
3005 int lvaToInitialSPRelativeOffset(unsigned offset, bool isFpBased);
3006 int lvaGetInitialSPRelativeOffset(unsigned varNum);
3008 //------------------------ For splitting types ----------------------------
3010 void lvaInitTypeRef();
3012 void lvaInitArgs(InitVarDscInfo* varDscInfo);
3013 void lvaInitThisPtr(InitVarDscInfo* varDscInfo);
3014 void lvaInitRetBuffArg(InitVarDscInfo* varDscInfo);
3015 void lvaInitUserArgs(InitVarDscInfo* varDscInfo);
3016 void lvaInitGenericsCtxt(InitVarDscInfo* varDscInfo);
3017 void lvaInitVarArgsHandle(InitVarDscInfo* varDscInfo);
3019 void lvaInitVarDsc(LclVarDsc* varDsc,
3021 CorInfoType corInfoType,
3022 CORINFO_CLASS_HANDLE typeHnd,
3023 CORINFO_ARG_LIST_HANDLE varList,
3024 CORINFO_SIG_INFO* varSig);
3026 static unsigned lvaTypeRefMask(var_types type);
3028 var_types lvaGetActualType(unsigned lclNum);
3029 var_types lvaGetRealType(unsigned lclNum);
3031 //-------------------------------------------------------------------------
3035 LclVarDsc* lvaGetDesc(unsigned lclNum)
3037 assert(lclNum < lvaCount);
3038 return &lvaTable[lclNum];
3041 LclVarDsc* lvaGetDesc(GenTreeLclVarCommon* lclVar)
3043 assert(lclVar->GetLclNum() < lvaCount);
3044 return &lvaTable[lclVar->GetLclNum()];
3047 unsigned lvaLclSize(unsigned varNum);
3048 unsigned lvaLclExactSize(unsigned varNum);
3050 bool lvaHaveManyLocals() const;
3052 unsigned lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason));
3053 unsigned lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason));
3054 unsigned lvaGrabTempWithImplicitUse(bool shortLifetime DEBUGARG(const char* reason));
3057 void lvaSortByRefCount();
3058 void lvaDumpRefCounts();
3060 void lvaMarkLocalVars(); // Local variable ref-counting
3061 void lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers);
3062 void lvaMarkLocalVars(BasicBlock* block, bool isRecompute);
3064 void lvaAllocOutgoingArgSpaceVar(); // Set up lvaOutgoingArgSpaceVar
3066 VARSET_VALRET_TP lvaStmtLclMask(GenTree* stmt);
3069 struct lvaStressLclFldArgs
3071 Compiler* m_pCompiler;
3075 static fgWalkPreFn lvaStressLclFldCB;
3076 void lvaStressLclFld();
3078 void lvaDispVarSet(VARSET_VALARG_TP set, VARSET_VALARG_TP allVars);
3079 void lvaDispVarSet(VARSET_VALARG_TP set);
3084 int lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset, bool isFloatUsage);
3086 int lvaFrameAddress(int varNum, bool* pFPbased);
3089 bool lvaIsParameter(unsigned varNum);
3090 bool lvaIsRegArgument(unsigned varNum);
3091 BOOL lvaIsOriginalThisArg(unsigned varNum); // Is this varNum the original this argument?
3092 BOOL lvaIsOriginalThisReadOnly(); // return TRUE if there is no place in the code
3093 // that writes to arg0
3095 // Struct parameters that are passed by reference are marked as both lvIsParam and lvIsTemp
3096 // (this is an overload of lvIsTemp because there are no temp parameters).
3097 // For x64 this is 3, 5, 6, 7, >8 byte structs that are passed by reference.
3098 // For ARM64, this is structs larger than 16 bytes that are passed by reference.
3099 bool lvaIsImplicitByRefLocal(unsigned varNum)
3101 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
3102 LclVarDsc* varDsc = &(lvaTable[varNum]);
3103 if (varDsc->lvIsParam && varDsc->lvIsTemp)
3105 assert(varTypeIsStruct(varDsc) || (varDsc->lvType == TYP_BYREF));
3108 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
3112 // Returns true if this local var is a multireg struct
3113 bool lvaIsMultiregStruct(LclVarDsc* varDsc, bool isVararg);
3115 // If the local is a TYP_STRUCT, get/set a class handle describing it
3116 CORINFO_CLASS_HANDLE lvaGetStruct(unsigned varNum);
3117 void lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool unsafeValueClsCheck, bool setTypeInfo = true);
3118 void lvaSetStructUsedAsVarArg(unsigned varNum);
3120 // If the local is TYP_REF, set or update the associated class information.
3121 void lvaSetClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
3122 void lvaSetClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
3123 void lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
3124 void lvaUpdateClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
3126 #define MAX_NumOfFieldsInPromotableStruct 4 // Maximum number of fields in promotable struct
3128 // Info about struct type fields.
3129 struct lvaStructFieldInfo
3131 CORINFO_FIELD_HANDLE fldHnd;
3132 unsigned char fldOffset;
3133 unsigned char fldOrdinal;
3136 CORINFO_CLASS_HANDLE fldTypeHnd;
3138 lvaStructFieldInfo()
3139 : fldHnd(nullptr), fldOffset(0), fldOrdinal(0), fldType(TYP_UNDEF), fldSize(0), fldTypeHnd(nullptr)
3144 // Info about a struct type, instances of which may be candidates for promotion.
3145 struct lvaStructPromotionInfo
3147 CORINFO_CLASS_HANDLE typeHnd;
3152 unsigned char fieldCnt;
3153 lvaStructFieldInfo fields[MAX_NumOfFieldsInPromotableStruct];
3155 lvaStructPromotionInfo(CORINFO_CLASS_HANDLE typeHnd = nullptr)
3158 , containsHoles(false)
3159 , customLayout(false)
3160 , fieldsSorted(false)
3166 static int __cdecl lvaFieldOffsetCmp(const void* field1, const void* field2);
3168 // This class is responsible for checking validity and profitability of struct promotion.
3169 // If it is both legal and profitable, then TryPromoteStructVar promotes the struct and initializes
3170 // nessesary information for fgMorphStructField to use.
3171 class StructPromotionHelper
3174 StructPromotionHelper(Compiler* compiler);
3176 bool CanPromoteStructType(CORINFO_CLASS_HANDLE typeHnd);
3177 bool TryPromoteStructVar(unsigned lclNum);
3180 void CheckRetypedAsScalar(CORINFO_FIELD_HANDLE fieldHnd, var_types requestedType);
3184 bool GetRequiresScratchVar();
3185 #endif // _TARGET_ARM_
3188 bool CanPromoteStructVar(unsigned lclNum);
3189 bool ShouldPromoteStructVar(unsigned lclNum);
3190 void PromoteStructVar(unsigned lclNum);
3191 void SortStructFields();
3193 lvaStructFieldInfo GetFieldInfo(CORINFO_FIELD_HANDLE fieldHnd, BYTE ordinal);
3194 bool TryPromoteStructField(lvaStructFieldInfo& outerFieldInfo);
3198 lvaStructPromotionInfo structPromotionInfo;
3201 bool requiresScratchVar;
3202 #endif // _TARGET_ARM_
3205 typedef JitHashTable<CORINFO_FIELD_HANDLE, JitPtrKeyFuncs<CORINFO_FIELD_STRUCT_>, var_types>
3206 RetypedAsScalarFieldsMap;
3207 RetypedAsScalarFieldsMap retypedFieldsMap;
3211 StructPromotionHelper* structPromotionHelper;
3213 #if !defined(_TARGET_64BIT_)
3214 void lvaPromoteLongVars();
3215 #endif // !defined(_TARGET_64BIT_)
3216 unsigned lvaGetFieldLocal(const LclVarDsc* varDsc, unsigned int fldOffset);
3217 lvaPromotionType lvaGetPromotionType(const LclVarDsc* varDsc);
3218 lvaPromotionType lvaGetPromotionType(unsigned varNum);
3219 lvaPromotionType lvaGetParentPromotionType(const LclVarDsc* varDsc);
3220 lvaPromotionType lvaGetParentPromotionType(unsigned varNum);
3221 bool lvaIsFieldOfDependentlyPromotedStruct(const LclVarDsc* varDsc);
3222 bool lvaIsGCTracked(const LclVarDsc* varDsc);
3224 #if defined(FEATURE_SIMD)
3225 bool lvaMapSimd12ToSimd16(const LclVarDsc* varDsc)
3227 assert(varDsc->lvType == TYP_SIMD12);
3228 assert(varDsc->lvExactSize == 12);
3230 #if defined(_TARGET_64BIT_)
3231 assert(varDsc->lvSize() == 16);
3232 #endif // defined(_TARGET_64BIT_)
3234 // We make local variable SIMD12 types 16 bytes instead of just 12. lvSize()
3235 // already does this calculation. However, we also need to prevent mapping types if the var is a
3236 // dependently promoted struct field, which must remain its exact size within its parent struct.
3237 // However, we don't know this until late, so we may have already pretended the field is bigger
3239 if ((varDsc->lvSize() == 16) && !lvaIsFieldOfDependentlyPromotedStruct(varDsc))
3248 #endif // defined(FEATURE_SIMD)
3250 BYTE* lvaGetGcLayout(unsigned varNum);
3251 bool lvaTypeIsGC(unsigned varNum);
3252 unsigned lvaGSSecurityCookie; // LclVar number
3253 bool lvaTempsHaveLargerOffsetThanVars();
3255 // Returns "true" iff local variable "lclNum" is in SSA form.
3256 bool lvaInSsa(unsigned lclNum)
3258 assert(lclNum < lvaCount);
3259 return lvaTable[lclNum].lvInSsa;
3262 unsigned lvaSecurityObject; // variable representing the security object on the stack
3263 unsigned lvaStubArgumentVar; // variable representing the secret stub argument coming in EAX
3265 #if FEATURE_EH_FUNCLETS
3266 unsigned lvaPSPSym; // variable representing the PSPSym
3269 InlineInfo* impInlineInfo;
3270 InlineStrategy* m_inlineStrategy;
3272 // The Compiler* that is the root of the inlining tree of which "this" is a member.
3273 Compiler* impInlineRoot();
3275 #if defined(DEBUG) || defined(INLINE_DATA)
3276 unsigned __int64 getInlineCycleCount()
3278 return m_compCycles;
3280 #endif // defined(DEBUG) || defined(INLINE_DATA)
3282 bool fgNoStructPromotion; // Set to TRUE to turn off struct promotion for this method.
3283 bool fgNoStructParamPromotion; // Set to TRUE to turn off struct promotion for parameters this method.
3285 //=========================================================================
3287 //=========================================================================
3290 //---------------- Local variable ref-counting ----------------------------
3292 void lvaMarkLclRefs(GenTree* tree, BasicBlock* block, GenTreeStmt* stmt, bool isRecompute);
3293 bool IsDominatedByExceptionalEntry(BasicBlock* block);
3294 void SetVolatileHint(LclVarDsc* varDsc);
3296 // Keeps the mapping from SSA #'s to VN's for the implicit memory variables.
3297 SsaDefArray<SsaMemDef> lvMemoryPerSsaData;
3300 // Returns the address of the per-Ssa data for memory at the given ssaNum (which is required
3301 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
3302 // not an SSA variable).
3303 SsaMemDef* GetMemoryPerSsaData(unsigned ssaNum)
3305 return lvMemoryPerSsaData.GetSsaDef(ssaNum);
3309 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3310 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3314 XX Imports the given method and converts it to semantic trees XX
3316 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3317 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3323 void impImport(BasicBlock* method);
3325 CORINFO_CLASS_HANDLE impGetRefAnyClass();
3326 CORINFO_CLASS_HANDLE impGetRuntimeArgumentHandle();
3327 CORINFO_CLASS_HANDLE impGetTypeHandleClass();
3328 CORINFO_CLASS_HANDLE impGetStringClass();
3329 CORINFO_CLASS_HANDLE impGetObjectClass();
3331 // Returns underlying type of handles returned by ldtoken instruction
3332 var_types GetRuntimeHandleUnderlyingType()
3334 // RuntimeTypeHandle is backed by raw pointer on CoreRT and by object reference on other runtimes
3335 return IsTargetAbi(CORINFO_CORERT_ABI) ? TYP_I_IMPL : TYP_REF;
3338 void impDevirtualizeCall(GenTreeCall* call,
3339 CORINFO_METHOD_HANDLE* method,
3340 unsigned* methodFlags,
3341 CORINFO_CONTEXT_HANDLE* contextHandle,
3342 CORINFO_CONTEXT_HANDLE* exactContextHandle,
3343 bool isLateDevirtualization,
3344 bool isExplicitTailCall);
3346 //=========================================================================
3348 //=========================================================================
3351 //-------------------- Stack manipulation ---------------------------------
3353 unsigned impStkSize; // Size of the full stack
3355 #define SMALL_STACK_SIZE 16 // number of elements in impSmallStack
3357 struct SavedStack // used to save/restore stack contents.
3359 unsigned ssDepth; // number of values on stack
3360 StackEntry* ssTrees; // saved tree values
3363 bool impIsPrimitive(CorInfoType type);
3364 bool impILConsumesAddr(const BYTE* codeAddr, CORINFO_METHOD_HANDLE fncHandle, CORINFO_MODULE_HANDLE scpHandle);
3366 void impResolveToken(const BYTE* addr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CorInfoTokenKind kind);
3368 void impPushOnStack(GenTree* tree, typeInfo ti);
3369 void impPushNullObjRefOnStack();
3370 StackEntry impPopStack();
3371 StackEntry& impStackTop(unsigned n = 0);
3372 unsigned impStackHeight();
3374 void impSaveStackState(SavedStack* savePtr, bool copy);
3375 void impRestoreStackState(SavedStack* savePtr);
3377 GenTree* impImportLdvirtftn(GenTree* thisPtr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3379 void impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken);
3381 void impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3383 bool impCanPInvokeInline();
3384 bool impCanPInvokeInlineCallSite(BasicBlock* block);
3385 void impCheckForPInvokeCall(
3386 GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block);
3387 GenTreeCall* impImportIndirectCall(CORINFO_SIG_INFO* sig, IL_OFFSETX ilOffset = BAD_IL_OFFSET);
3388 void impPopArgsForUnmanagedCall(GenTree* call, CORINFO_SIG_INFO* sig);
3390 void impInsertHelperCall(CORINFO_HELPER_DESC* helperCall);
3391 void impHandleAccessAllowed(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
3392 void impHandleAccessAllowedInternal(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
3394 var_types impImportCall(OPCODE opcode,
3395 CORINFO_RESOLVED_TOKEN* pResolvedToken,
3396 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call on a
3398 GenTree* newobjThis,
3400 CORINFO_CALL_INFO* callInfo,
3401 IL_OFFSET rawILOffset);
3403 CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(CORINFO_METHOD_HANDLE specialIntrinsicHandle);
3405 bool impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo);
3407 GenTree* impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HANDLE retClsHnd);
3409 GenTree* impFixupStructReturnType(GenTree* op, CORINFO_CLASS_HANDLE retClsHnd);
3412 var_types impImportJitTestLabelMark(int numArgs);
3415 GenTree* impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken);
3417 GenTree* impImportStaticReadOnlyField(void* fldAddr, var_types lclTyp);
3419 GenTree* impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3420 CORINFO_ACCESS_FLAGS access,
3421 CORINFO_FIELD_INFO* pFieldInfo,
3424 static void impBashVarAddrsToI(GenTree* tree1, GenTree* tree2 = nullptr);
3426 GenTree* impImplicitIorI4Cast(GenTree* tree, var_types dstTyp);
3428 GenTree* impImplicitR4orR8Cast(GenTree* tree, var_types dstTyp);
3430 void impImportLeave(BasicBlock* block);
3431 void impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr);
3432 GenTree* impIntrinsic(GenTree* newobjThis,
3433 CORINFO_CLASS_HANDLE clsHnd,
3434 CORINFO_METHOD_HANDLE method,
3435 CORINFO_SIG_INFO* sig,
3436 unsigned methodFlags,
3440 CORINFO_RESOLVED_TOKEN* pContstrainedResolvedToken,
3441 CORINFO_THIS_TRANSFORM constraintCallThisTransform,
3442 CorInfoIntrinsics* pIntrinsicID,
3443 bool* isSpecialIntrinsic = nullptr);
3444 GenTree* impMathIntrinsic(CORINFO_METHOD_HANDLE method,
3445 CORINFO_SIG_INFO* sig,
3447 CorInfoIntrinsics intrinsicID,
3449 NamedIntrinsic lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method);
3451 #ifdef FEATURE_HW_INTRINSICS
3452 GenTree* impHWIntrinsic(NamedIntrinsic intrinsic,
3453 CORINFO_METHOD_HANDLE method,
3454 CORINFO_SIG_INFO* sig,
3456 GenTree* impUnsupportedHWIntrinsic(unsigned helper,
3457 CORINFO_METHOD_HANDLE method,
3458 CORINFO_SIG_INFO* sig,
3462 bool compSupportsHWIntrinsic(InstructionSet isa);
3464 #ifdef _TARGET_XARCH_
3465 GenTree* impBaseIntrinsic(NamedIntrinsic intrinsic,
3466 CORINFO_METHOD_HANDLE method,
3467 CORINFO_SIG_INFO* sig,
3469 GenTree* impSSEIntrinsic(NamedIntrinsic intrinsic,
3470 CORINFO_METHOD_HANDLE method,
3471 CORINFO_SIG_INFO* sig,
3473 GenTree* impSSE2Intrinsic(NamedIntrinsic intrinsic,
3474 CORINFO_METHOD_HANDLE method,
3475 CORINFO_SIG_INFO* sig,
3477 GenTree* impSSE42Intrinsic(NamedIntrinsic intrinsic,
3478 CORINFO_METHOD_HANDLE method,
3479 CORINFO_SIG_INFO* sig,
3481 GenTree* impAvxOrAvx2Intrinsic(NamedIntrinsic intrinsic,
3482 CORINFO_METHOD_HANDLE method,
3483 CORINFO_SIG_INFO* sig,
3485 GenTree* impAESIntrinsic(NamedIntrinsic intrinsic,
3486 CORINFO_METHOD_HANDLE method,
3487 CORINFO_SIG_INFO* sig,
3489 GenTree* impBMI1OrBMI2Intrinsic(NamedIntrinsic intrinsic,
3490 CORINFO_METHOD_HANDLE method,
3491 CORINFO_SIG_INFO* sig,
3493 GenTree* impFMAIntrinsic(NamedIntrinsic intrinsic,
3494 CORINFO_METHOD_HANDLE method,
3495 CORINFO_SIG_INFO* sig,
3497 GenTree* impLZCNTIntrinsic(NamedIntrinsic intrinsic,
3498 CORINFO_METHOD_HANDLE method,
3499 CORINFO_SIG_INFO* sig,
3501 GenTree* impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic,
3502 CORINFO_METHOD_HANDLE method,
3503 CORINFO_SIG_INFO* sig,
3505 GenTree* impPOPCNTIntrinsic(NamedIntrinsic intrinsic,
3506 CORINFO_METHOD_HANDLE method,
3507 CORINFO_SIG_INFO* sig,
3511 GenTree* getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE argClass);
3512 GenTree* impNonConstFallback(NamedIntrinsic intrinsic, var_types simdType, var_types baseType);
3513 GenTree* addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* lastOp, bool mustExpand);
3514 #endif // _TARGET_XARCH_
3515 #ifdef _TARGET_ARM64_
3516 InstructionSet lookupHWIntrinsicISA(const char* className);
3517 NamedIntrinsic lookupHWIntrinsic(const char* className, const char* methodName);
3518 GenTree* addRangeCheckIfNeeded(GenTree* lastOp, unsigned int max, bool mustExpand);
3519 #endif // _TARGET_ARM64_
3520 #endif // FEATURE_HW_INTRINSICS
3521 GenTree* impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
3522 CORINFO_SIG_INFO* sig,
3525 CorInfoIntrinsics intrinsicID);
3526 GenTree* impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig);
3528 GenTree* impMethodPointer(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3530 GenTree* impTransformThis(GenTree* thisPtr,
3531 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
3532 CORINFO_THIS_TRANSFORM transform);
3534 //----------------- Manipulating the trees and stmts ----------------------
3536 GenTree* impTreeList; // Trees for the BB being imported
3537 GenTree* impTreeLast; // The last tree for the current BB
3542 CHECK_SPILL_ALL = -1,
3543 CHECK_SPILL_NONE = -2
3546 void impBeginTreeList();
3547 void impEndTreeList(BasicBlock* block, GenTree* firstStmt, GenTree* lastStmt);
3548 void impEndTreeList(BasicBlock* block);
3549 void impAppendStmtCheck(GenTree* stmt, unsigned chkLevel);
3550 void impAppendStmt(GenTree* stmt, unsigned chkLevel);
3551 void impInsertStmtBefore(GenTree* stmt, GenTree* stmtBefore);
3552 GenTree* impAppendTree(GenTree* tree, unsigned chkLevel, IL_OFFSETX offset);
3553 void impInsertTreeBefore(GenTree* tree, IL_OFFSETX offset, GenTree* stmtBefore);
3554 void impAssignTempGen(unsigned tmp,
3557 GenTree** pAfterStmt = nullptr,
3558 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3559 BasicBlock* block = nullptr);
3560 void impAssignTempGen(unsigned tmpNum,
3562 CORINFO_CLASS_HANDLE structHnd,
3564 GenTree** pAfterStmt = nullptr,
3565 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3566 BasicBlock* block = nullptr);
3567 GenTree* impCloneExpr(GenTree* tree,
3569 CORINFO_CLASS_HANDLE structHnd,
3571 GenTree** pAfterStmt DEBUGARG(const char* reason));
3572 GenTree* impAssignStruct(GenTree* dest,
3574 CORINFO_CLASS_HANDLE structHnd,
3576 GenTree** pAfterStmt = nullptr,
3577 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3578 BasicBlock* block = nullptr);
3579 GenTree* impAssignStructPtr(GenTree* dest,
3581 CORINFO_CLASS_HANDLE structHnd,
3583 GenTree** pAfterStmt = nullptr,
3584 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3585 BasicBlock* block = nullptr);
3587 GenTree* impGetStructAddr(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, unsigned curLevel, bool willDeref);
3589 var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd,
3590 BYTE* gcLayout = nullptr,
3591 unsigned* numGCVars = nullptr,
3592 var_types* simdBaseType = nullptr);
3594 GenTree* impNormStructVal(GenTree* structVal,
3595 CORINFO_CLASS_HANDLE structHnd,
3597 bool forceNormalization = false);
3599 GenTree* impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3600 BOOL* pRuntimeLookup = nullptr,
3601 BOOL mustRestoreHandle = FALSE,
3602 BOOL importParent = FALSE);
3604 GenTree* impParentClassTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3605 BOOL* pRuntimeLookup = nullptr,
3606 BOOL mustRestoreHandle = FALSE)
3608 return impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, TRUE);
3611 GenTree* impLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3612 CORINFO_LOOKUP* pLookup,
3614 void* compileTimeHandle);
3616 GenTree* getRuntimeContextTree(CORINFO_RUNTIME_LOOKUP_KIND kind);
3618 GenTree* impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3619 CORINFO_LOOKUP* pLookup,
3620 void* compileTimeHandle);
3622 GenTree* impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP* pLookup, unsigned flags, void* compileTimeHandle);
3624 GenTreeCall* impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3625 CorInfoHelpFunc helper,
3627 GenTreeArgList* arg = nullptr,
3628 CORINFO_LOOKUP_KIND* pGenericLookupKind = nullptr);
3630 GenTree* impCastClassOrIsInstToTree(GenTree* op1,
3632 CORINFO_RESOLVED_TOKEN* pResolvedToken,
3635 GenTree* impOptimizeCastClassOrIsInst(GenTree* op1, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isCastClass);
3637 bool VarTypeIsMultiByteAndCanEnreg(
3638 var_types type, CORINFO_CLASS_HANDLE typeClass, unsigned* typeSize, bool forReturn, bool isVarArg);
3640 bool IsIntrinsicImplementedByUserCall(CorInfoIntrinsics intrinsicId);
3641 bool IsTargetIntrinsic(CorInfoIntrinsics intrinsicId);
3642 bool IsMathIntrinsic(CorInfoIntrinsics intrinsicId);
3643 bool IsMathIntrinsic(GenTree* tree);
3646 //----------------- Importing the method ----------------------------------
3648 CORINFO_CONTEXT_HANDLE impTokenLookupContextHandle; // The context used for looking up tokens.
3651 unsigned impCurOpcOffs;
3652 const char* impCurOpcName;
3653 bool impNestedStackSpill;
3655 // For displaying instrs with generated native code (-n:B)
3656 GenTree* impLastILoffsStmt; // oldest stmt added for which we did not gtStmtLastILoffs
3657 void impNoteLastILoffs();
3660 /* IL offset of the stmt currently being imported. It gets set to
3661 BAD_IL_OFFSET after it has been set in the appended trees. Then it gets
3662 updated at IL offsets for which we have to report mapping info.
3663 It also includes flag bits, so use jitGetILoffs()
3664 to get the actual IL offset value.
3667 IL_OFFSETX impCurStmtOffs;
3668 void impCurStmtOffsSet(IL_OFFSET offs);
3670 void impNoteBranchOffs();
3672 unsigned impInitBlockLineInfo();
3674 GenTree* impCheckForNullPointer(GenTree* obj);
3675 bool impIsThis(GenTree* obj);
3676 bool impIsLDFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3677 bool impIsDUP_LDVIRTFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3678 bool impIsAnySTLOC(OPCODE opcode)
3680 return ((opcode == CEE_STLOC) || (opcode == CEE_STLOC_S) ||
3681 ((opcode >= CEE_STLOC_0) && (opcode <= CEE_STLOC_3)));
3684 GenTreeArgList* impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenTreeArgList* prefixTree = nullptr);
3686 GenTreeArgList* impPopRevList(unsigned count, CORINFO_SIG_INFO* sig, unsigned skipReverseCount = 0);
3689 * Get current IL offset with stack-empty info incoporated
3691 IL_OFFSETX impCurILOffset(IL_OFFSET offs, bool callInstruction = false);
3693 //---------------- Spilling the importer stack ----------------------------
3695 // The maximum number of bytes of IL processed without clean stack state.
3696 // It allows to limit the maximum tree size and depth.
3697 static const unsigned MAX_TREE_SIZE = 200;
3698 bool impCanSpillNow(OPCODE prevOpcode);
3704 SavedStack pdSavedStack;
3705 ThisInitState pdThisPtrInit;
3708 PendingDsc* impPendingList; // list of BBs currently waiting to be imported.
3709 PendingDsc* impPendingFree; // Freed up dscs that can be reused
3711 // We keep a byte-per-block map (dynamically extended) in the top-level Compiler object of a compilation.
3712 JitExpandArray<BYTE> impPendingBlockMembers;
3714 // Return the byte for "b" (allocating/extending impPendingBlockMembers if necessary.)
3715 // Operates on the map in the top-level ancestor.
3716 BYTE impGetPendingBlockMember(BasicBlock* blk)
3718 return impInlineRoot()->impPendingBlockMembers.Get(blk->bbInd());
3721 // Set the byte for "b" to "val" (allocating/extending impPendingBlockMembers if necessary.)
3722 // Operates on the map in the top-level ancestor.
3723 void impSetPendingBlockMember(BasicBlock* blk, BYTE val)
3725 impInlineRoot()->impPendingBlockMembers.Set(blk->bbInd(), val);
3728 bool impCanReimport;
3730 bool impSpillStackEntry(unsigned level,
3734 bool bAssertOnRecursion,
3739 void impSpillStackEnsure(bool spillLeaves = false);
3740 void impEvalSideEffects();
3741 void impSpillSpecialSideEff();
3742 void impSpillSideEffects(bool spillGlobEffects, unsigned chkLevel DEBUGARG(const char* reason));
3743 void impSpillValueClasses();
3744 void impSpillEvalStack();
3745 static fgWalkPreFn impFindValueClasses;
3746 void impSpillLclRefs(ssize_t lclNum);
3748 BasicBlock* impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_HANDLE clsHnd, bool isSingleBlockFilter);
3750 void impImportBlockCode(BasicBlock* block);
3752 void impReimportMarkBlock(BasicBlock* block);
3753 void impReimportMarkSuccessors(BasicBlock* block);
3755 void impVerifyEHBlock(BasicBlock* block, bool isTryStart);
3757 void impImportBlockPending(BasicBlock* block);
3759 // Similar to impImportBlockPending, but assumes that block has already been imported once and is being
3760 // reimported for some reason. It specifically does *not* look at verCurrentState to set the EntryState
3761 // for the block, but instead, just re-uses the block's existing EntryState.
3762 void impReimportBlockPending(BasicBlock* block);
3764 var_types impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTree** pOp1, GenTree** pOp2);
3766 void impImportBlock(BasicBlock* block);
3768 // Assumes that "block" is a basic block that completes with a non-empty stack. We will assign the values
3769 // on the stack to local variables (the "spill temp" variables). The successor blocks will assume that
3770 // its incoming stack contents are in those locals. This requires "block" and its successors to agree on
3771 // the variables that will be used -- and for all the predecessors of those successors, and the
3772 // successors of those predecessors, etc. Call such a set of blocks closed under alternating
3773 // successor/predecessor edges a "spill clique." A block is a "predecessor" or "successor" member of the
3774 // clique (or, conceivably, both). Each block has a specified sequence of incoming and outgoing spill
3775 // temps. If "block" already has its outgoing spill temps assigned (they are always a contiguous series
3776 // of local variable numbers, so we represent them with the base local variable number), returns that.
3777 // Otherwise, picks a set of spill temps, and propagates this choice to all blocks in the spill clique of
3778 // which "block" is a member (asserting, in debug mode, that no block in this clique had its spill temps
3779 // chosen already. More precisely, that the incoming or outgoing spill temps are not chosen, depending
3780 // on which kind of member of the clique the block is).
3781 unsigned impGetSpillTmpBase(BasicBlock* block);
3783 // Assumes that "block" is a basic block that completes with a non-empty stack. We have previously
3784 // assigned the values on the stack to local variables (the "spill temp" variables). The successor blocks
3785 // will assume that its incoming stack contents are in those locals. This requires "block" and its
3786 // successors to agree on the variables and their types that will be used. The CLI spec allows implicit
3787 // conversions between 'int' and 'native int' or 'float' and 'double' stack types. So one predecessor can
3788 // push an int and another can push a native int. For 64-bit we have chosen to implement this by typing
3789 // the "spill temp" as native int, and then importing (or re-importing as needed) so that all the
3790 // predecessors in the "spill clique" push a native int (sign-extending if needed), and all the
3791 // successors receive a native int. Similarly float and double are unified to double.
3792 // This routine is called after a type-mismatch is detected, and it will walk the spill clique to mark
3793 // blocks for re-importation as appropriate (both successors, so they get the right incoming type, and
3794 // predecessors, so they insert an upcast if needed).
3795 void impReimportSpillClique(BasicBlock* block);
3797 // When we compute a "spill clique" (see above) these byte-maps are allocated to have a byte per basic
3798 // block, and represent the predecessor and successor members of the clique currently being computed.
3799 // *** Access to these will need to be locked in a parallel compiler.
3800 JitExpandArray<BYTE> impSpillCliquePredMembers;
3801 JitExpandArray<BYTE> impSpillCliqueSuccMembers;
3809 // Abstract class for receiving a callback while walking a spill clique
3810 class SpillCliqueWalker
3813 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk) = 0;
3816 // This class is used for setting the bbStkTempsIn and bbStkTempsOut on the blocks within a spill clique
3817 class SetSpillTempsBase : public SpillCliqueWalker
3822 SetSpillTempsBase(unsigned baseTmp) : m_baseTmp(baseTmp)
3825 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3828 // This class is used for implementing impReimportSpillClique part on each block within the spill clique
3829 class ReimportSpillClique : public SpillCliqueWalker
3834 ReimportSpillClique(Compiler* pComp) : m_pComp(pComp)
3837 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3840 // This is the heart of the algorithm for walking spill cliques. It invokes callback->Visit for each
3841 // predecessor or successor within the spill clique
3842 void impWalkSpillCliqueFromPred(BasicBlock* pred, SpillCliqueWalker* callback);
3844 // For a BasicBlock that has already been imported, the EntryState has an array of GenTrees for the
3845 // incoming locals. This walks that list an resets the types of the GenTrees to match the types of
3846 // the VarDscs. They get out of sync when we have int/native int issues (see impReimportSpillClique).
3847 void impRetypeEntryStateTemps(BasicBlock* blk);
3849 BYTE impSpillCliqueGetMember(SpillCliqueDir predOrSucc, BasicBlock* blk);
3850 void impSpillCliqueSetMember(SpillCliqueDir predOrSucc, BasicBlock* blk, BYTE val);
3852 void impPushVar(GenTree* op, typeInfo tiRetVal);
3853 void impLoadVar(unsigned lclNum, IL_OFFSET offset, typeInfo tiRetVal);
3854 void impLoadVar(unsigned lclNum, IL_OFFSET offset)
3856 impLoadVar(lclNum, offset, lvaTable[lclNum].lvVerTypeInfo);
3858 void impLoadArg(unsigned ilArgNum, IL_OFFSET offset);
3859 void impLoadLoc(unsigned ilLclNum, IL_OFFSET offset);
3860 bool impReturnInstruction(BasicBlock* block, int prefixFlags, OPCODE& opcode);
3863 void impMarkLclDstNotPromotable(unsigned tmpNum, GenTree* op, CORINFO_CLASS_HANDLE hClass);
3866 // A free list of linked list nodes used to represent to-do stacks of basic blocks.
3867 struct BlockListNode
3870 BlockListNode* m_next;
3871 BlockListNode(BasicBlock* blk, BlockListNode* next = nullptr) : m_blk(blk), m_next(next)
3874 void* operator new(size_t sz, Compiler* comp);
3876 BlockListNode* impBlockListNodeFreeList;
3878 void FreeBlockListNode(BlockListNode* node);
3880 bool impIsValueType(typeInfo* pTypeInfo);
3881 var_types mangleVarArgsType(var_types type);
3884 regNumber getCallArgIntRegister(regNumber floatReg);
3885 regNumber getCallArgFloatRegister(regNumber intReg);
3886 #endif // FEATURE_VARARG
3889 static unsigned jitTotalMethodCompiled;
3893 static LONG jitNestingLevel;
3896 static BOOL impIsAddressInLocal(GenTree* tree, GenTree** lclVarTreeOut);
3898 void impMakeDiscretionaryInlineObservations(InlineInfo* pInlineInfo, InlineResult* inlineResult);
3900 // STATIC inlining decision based on the IL code.
3901 void impCanInlineIL(CORINFO_METHOD_HANDLE fncHandle,
3902 CORINFO_METHOD_INFO* methInfo,
3904 InlineResult* inlineResult);
3906 void impCheckCanInline(GenTreeCall* call,
3907 CORINFO_METHOD_HANDLE fncHandle,
3909 CORINFO_CONTEXT_HANDLE exactContextHnd,
3910 InlineCandidateInfo** ppInlineCandidateInfo,
3911 InlineResult* inlineResult);
3913 void impInlineRecordArgInfo(InlineInfo* pInlineInfo,
3916 InlineResult* inlineResult);
3918 void impInlineInitVars(InlineInfo* pInlineInfo);
3920 unsigned impInlineFetchLocal(unsigned lclNum DEBUGARG(const char* reason));
3922 GenTree* impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, InlLclVarInfo* lclTypeInfo);
3924 BOOL impInlineIsThis(GenTree* tree, InlArgInfo* inlArgInfo);
3926 BOOL impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTree* additionalTreesToBeEvaluatedBefore,
3927 GenTree* variableBeingDereferenced,
3928 InlArgInfo* inlArgInfo);
3930 void impMarkInlineCandidate(GenTree* call,
3931 CORINFO_CONTEXT_HANDLE exactContextHnd,
3932 bool exactContextNeedsRuntimeLookup,
3933 CORINFO_CALL_INFO* callInfo);
3935 void impMarkInlineCandidateHelper(GenTreeCall* call,
3936 CORINFO_CONTEXT_HANDLE exactContextHnd,
3937 bool exactContextNeedsRuntimeLookup,
3938 CORINFO_CALL_INFO* callInfo);
3940 bool impTailCallRetTypeCompatible(var_types callerRetType,
3941 CORINFO_CLASS_HANDLE callerRetTypeClass,
3942 var_types calleeRetType,
3943 CORINFO_CLASS_HANDLE calleeRetTypeClass);
3945 bool impIsTailCallILPattern(bool tailPrefixed,
3947 const BYTE* codeAddrOfNextOpcode,
3948 const BYTE* codeEnd,
3950 bool* IsCallPopRet = nullptr);
3952 bool impIsImplicitTailCallCandidate(
3953 OPCODE curOpcode, const BYTE* codeAddrOfNextOpcode, const BYTE* codeEnd, int prefixFlags, bool isRecursive);
3955 CORINFO_RESOLVED_TOKEN* impAllocateToken(CORINFO_RESOLVED_TOKEN token);
3958 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3959 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3963 XX Info about the basic-blocks, their contents and the flow analysis XX
3965 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3966 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3970 BasicBlock* fgFirstBB; // Beginning of the basic block list
3971 BasicBlock* fgLastBB; // End of the basic block list
3972 BasicBlock* fgFirstColdBlock; // First block to be placed in the cold section
3973 #if FEATURE_EH_FUNCLETS
3974 BasicBlock* fgFirstFuncletBB; // First block of outlined funclets (to allow block insertion before the funclets)
3976 BasicBlock* fgFirstBBScratch; // Block inserted for initialization stuff. Is nullptr if no such block has been
3978 BasicBlockList* fgReturnBlocks; // list of BBJ_RETURN blocks
3979 unsigned fgEdgeCount; // # of control flow edges between the BBs
3980 unsigned fgBBcount; // # of BBs in the method
3982 unsigned fgBBcountAtCodegen; // # of BBs in the method at the start of codegen
3984 unsigned fgBBNumMax; // The max bbNum that has been assigned to basic blocks
3985 unsigned fgDomBBcount; // # of BBs for which we have dominator and reachability information
3986 BasicBlock** fgBBInvPostOrder; // The flow graph stored in an array sorted in topological order, needed to compute
3987 // dominance. Indexed by block number. Size: fgBBNumMax + 1.
3989 // After the dominance tree is computed, we cache a DFS preorder number and DFS postorder number to compute
3990 // dominance queries in O(1). fgDomTreePreOrder and fgDomTreePostOrder are arrays giving the block's preorder and
3991 // postorder number, respectively. The arrays are indexed by basic block number. (Note that blocks are numbered
3992 // starting from one. Thus, we always waste element zero. This makes debugging easier and makes the code less likely
3993 // to suffer from bugs stemming from forgetting to add or subtract one from the block number to form an array
3994 // index). The arrays are of size fgBBNumMax + 1.
3995 unsigned* fgDomTreePreOrder;
3996 unsigned* fgDomTreePostOrder;
3998 bool fgBBVarSetsInited;
4000 // Allocate array like T* a = new T[fgBBNumMax + 1];
4001 // Using helper so we don't keep forgetting +1.
4002 template <typename T>
4003 T* fgAllocateTypeForEachBlk(CompMemKind cmk = CMK_Unknown)
4005 return getAllocator(cmk).allocate<T>(fgBBNumMax + 1);
4008 // BlockSets are relative to a specific set of BasicBlock numbers. If that changes
4009 // (if the blocks are renumbered), this changes. BlockSets from different epochs
4010 // cannot be meaningfully combined. Note that new blocks can be created with higher
4011 // block numbers without changing the basic block epoch. These blocks *cannot*
4012 // participate in a block set until the blocks are all renumbered, causing the epoch
4013 // to change. This is useful if continuing to use previous block sets is valuable.
4014 // If the epoch is zero, then it is uninitialized, and block sets can't be used.
4015 unsigned fgCurBBEpoch;
4017 unsigned GetCurBasicBlockEpoch()
4019 return fgCurBBEpoch;
4022 // The number of basic blocks in the current epoch. When the blocks are renumbered,
4023 // this is fgBBcount. As blocks are added, fgBBcount increases, fgCurBBEpochSize remains
4024 // the same, until a new BasicBlock epoch is created, such as when the blocks are all renumbered.
4025 unsigned fgCurBBEpochSize;
4027 // The number of "size_t" elements required to hold a bitset large enough for fgCurBBEpochSize
4028 // bits. This is precomputed to avoid doing math every time BasicBlockBitSetTraits::GetArrSize() is called.
4029 unsigned fgBBSetCountInSizeTUnits;
4031 void NewBasicBlockEpoch()
4033 INDEBUG(unsigned oldEpochArrSize = fgBBSetCountInSizeTUnits);
4035 // We have a new epoch. Compute and cache the size needed for new BlockSets.
4037 fgCurBBEpochSize = fgBBNumMax + 1;
4038 fgBBSetCountInSizeTUnits =
4039 roundUp(fgCurBBEpochSize, (unsigned)(sizeof(size_t) * 8)) / unsigned(sizeof(size_t) * 8);
4042 // All BlockSet objects are now invalid!
4043 fgReachabilitySetsValid = false; // the bbReach sets are now invalid!
4044 fgEnterBlksSetValid = false; // the fgEnterBlks set is now invalid!
4048 unsigned epochArrSize = BasicBlockBitSetTraits::GetArrSize(this, sizeof(size_t));
4049 printf("\nNew BlockSet epoch %d, # of blocks (including unused BB00): %u, bitset array size: %u (%s)",
4050 fgCurBBEpoch, fgCurBBEpochSize, epochArrSize, (epochArrSize <= 1) ? "short" : "long");
4051 if ((fgCurBBEpoch != 1) && ((oldEpochArrSize <= 1) != (epochArrSize <= 1)))
4053 // If we're not just establishing the first epoch, and the epoch array size has changed such that we're
4054 // going to change our bitset representation from short (just a size_t bitset) to long (a pointer to an
4055 // array of size_t bitsets), then print that out.
4056 printf("; NOTE: BlockSet size was previously %s!", (oldEpochArrSize <= 1) ? "short" : "long");
4063 void EnsureBasicBlockEpoch()
4065 if (fgCurBBEpochSize != fgBBNumMax + 1)
4067 NewBasicBlockEpoch();
4071 BasicBlock* fgNewBasicBlock(BBjumpKinds jumpKind);
4072 void fgEnsureFirstBBisScratch();
4073 bool fgFirstBBisScratch();
4074 bool fgBBisScratch(BasicBlock* block);
4076 void fgExtendEHRegionBefore(BasicBlock* block);
4077 void fgExtendEHRegionAfter(BasicBlock* block);
4079 BasicBlock* fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
4081 BasicBlock* fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
4083 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
4086 BasicBlock* nearBlk,
4087 bool putInFilter = false,
4088 bool runRarely = false,
4089 bool insertAtEnd = false);
4091 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
4093 bool runRarely = false,
4094 bool insertAtEnd = false);
4096 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind);
4098 BasicBlock* fgNewBBinRegionWorker(BBjumpKinds jumpKind,
4099 BasicBlock* afterBlk,
4100 unsigned xcptnIndex,
4101 bool putInTryRegion);
4103 void fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk);
4104 void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk);
4105 void fgUnlinkBlock(BasicBlock* block);
4107 unsigned fgMeasureIR();
4109 bool fgModified; // True if the flow graph has been modified recently
4110 bool fgComputePredsDone; // Have we computed the bbPreds list
4111 bool fgCheapPredsValid; // Is the bbCheapPreds list valid?
4112 bool fgDomsComputed; // Have we computed the dominator sets?
4113 bool fgOptimizedFinally; // Did we optimize any try-finallys?
4115 bool fgHasSwitch; // any BBJ_SWITCH jumps?
4117 BlockSet fgEnterBlks; // Set of blocks which have a special transfer of control; the "entry" blocks plus EH handler
4121 bool fgReachabilitySetsValid; // Are the bbReach sets valid?
4122 bool fgEnterBlksSetValid; // Is the fgEnterBlks set valid?
4125 bool fgRemoveRestOfBlock; // true if we know that we will throw
4126 bool fgStmtRemoved; // true if we remove statements -> need new DFA
4128 // There are two modes for ordering of the trees.
4129 // - In FGOrderTree, the dominant ordering is the tree order, and the nodes contained in
4130 // each tree and sub-tree are contiguous, and can be traversed (in gtNext/gtPrev order)
4131 // by traversing the tree according to the order of the operands.
4132 // - In FGOrderLinear, the dominant ordering is the linear order.
4139 FlowGraphOrder fgOrder;
4141 // The following are boolean flags that keep track of the state of internal data structures
4143 bool fgStmtListThreaded; // true if the node list is now threaded
4144 bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
4145 bool fgEdgeWeightsComputed; // true after we have called fgComputeEdgeWeights
4146 bool fgHaveValidEdgeWeights; // true if we were successful in computing all of the edge weights
4147 bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
4148 bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
4149 bool fgNeedsUpdateFlowGraph; // true if we need to run fgUpdateFlowGraph
4150 BasicBlock::weight_t fgCalledCount; // count of the number of times this method was called
4151 // This is derived from the profile data
4152 // or is BB_UNITY_WEIGHT when we don't have profile data
4154 #if FEATURE_EH_FUNCLETS
4155 bool fgFuncletsCreated; // true if the funclet creation phase has been run
4156 #endif // FEATURE_EH_FUNCLETS
4158 bool fgGlobalMorph; // indicates if we are during the global morphing phase
4159 // since fgMorphTree can be called from several places
4161 bool impBoxTempInUse; // the temp below is valid and available
4162 unsigned impBoxTemp; // a temporary that is used for boxing
4165 bool jitFallbackCompile; // Are we doing a fallback compile? That is, have we executed a NO_WAY assert,
4166 // and we are trying to compile again in a "safer", minopts mode?
4170 unsigned impInlinedCodeSize;
4173 //-------------------------------------------------------------------------
4179 void fgTransformIndirectCalls();
4183 void fgRemoveEmptyTry();
4185 void fgRemoveEmptyFinally();
4187 void fgMergeFinallyChains();
4189 void fgCloneFinally();
4191 void fgCleanupContinuation(BasicBlock* continuation);
4193 void fgUpdateFinallyTargetFlags();
4195 void fgClearAllFinallyTargetBits();
4197 void fgAddFinallyTargetFlags();
4199 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
4200 // Sometimes we need to defer updating the BBF_FINALLY_TARGET bit. fgNeedToAddFinallyTargetBits signals
4201 // when this is necessary.
4202 bool fgNeedToAddFinallyTargetBits;
4203 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
4205 bool fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block,
4206 BasicBlock* handler,
4207 BlockToBlockMap& continuationMap);
4209 GenTree* fgGetCritSectOfStaticMethod();
4211 #if FEATURE_EH_FUNCLETS
4213 void fgAddSyncMethodEnterExit();
4215 GenTree* fgCreateMonitorTree(unsigned lvaMonitorBool, unsigned lvaThisVar, BasicBlock* block, bool enter);
4217 void fgConvertSyncReturnToLeave(BasicBlock* block);
4219 #endif // FEATURE_EH_FUNCLETS
4221 void fgAddReversePInvokeEnterExit();
4223 bool fgMoreThanOneReturnBlock();
4225 // The number of separate return points in the method.
4226 unsigned fgReturnCount;
4228 void fgAddInternal();
4230 bool fgFoldConditional(BasicBlock* block);
4232 void fgMorphStmts(BasicBlock* block, bool* lnot, bool* loadw);
4233 void fgMorphBlocks();
4235 bool fgMorphBlockStmt(BasicBlock* block, GenTreeStmt* stmt DEBUGARG(const char* msg));
4237 void fgSetOptions();
4240 static fgWalkPreFn fgAssertNoQmark;
4241 void fgPreExpandQmarkChecks(GenTree* expr);
4242 void fgPostExpandQmarkChecks();
4243 static void fgCheckQmarkAllowedForm(GenTree* tree);
4246 IL_OFFSET fgFindBlockILOffset(BasicBlock* block);
4248 BasicBlock* fgSplitBlockAtBeginning(BasicBlock* curr);
4249 BasicBlock* fgSplitBlockAtEnd(BasicBlock* curr);
4250 BasicBlock* fgSplitBlockAfterStatement(BasicBlock* curr, GenTree* stmt);
4251 BasicBlock* fgSplitBlockAfterNode(BasicBlock* curr, GenTree* node); // for LIR
4252 BasicBlock* fgSplitEdge(BasicBlock* curr, BasicBlock* succ);
4254 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, BasicBlock* block, IL_OFFSETX offs);
4255 GenTreeStmt* fgNewStmtFromTree(GenTree* tree);
4256 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, BasicBlock* block);
4257 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, IL_OFFSETX offs);
4259 GenTree* fgGetTopLevelQmark(GenTree* expr, GenTree** ppDst = nullptr);
4260 void fgExpandQmarkForCastInstOf(BasicBlock* block, GenTree* stmt);
4261 void fgExpandQmarkStmt(BasicBlock* block, GenTree* expr);
4262 void fgExpandQmarkNodes();
4266 // Do "simple lowering." This functionality is (conceptually) part of "general"
4267 // lowering that is distributed between fgMorph and the lowering phase of LSRA.
4268 void fgSimpleLowering();
4270 GenTree* fgInitThisClass();
4272 GenTreeCall* fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper);
4274 GenTreeCall* fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls);
4276 bool backendRequiresLocalVarLifetimes()
4278 return !opts.MinOpts() || m_pLinearScan->willEnregisterLocalVars();
4281 void fgLocalVarLiveness();
4283 void fgLocalVarLivenessInit();
4285 void fgPerNodeLocalVarLiveness(GenTree* node);
4286 void fgPerBlockLocalVarLiveness();
4288 VARSET_VALRET_TP fgGetHandlerLiveVars(BasicBlock* block);
4290 void fgLiveVarAnalysis(bool updateInternalOnly = false);
4292 void fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call);
4294 void fgComputeLifeTrackedLocalUse(VARSET_TP& life, LclVarDsc& varDsc, GenTreeLclVarCommon* node);
4295 bool fgComputeLifeTrackedLocalDef(VARSET_TP& life,
4296 VARSET_VALARG_TP keepAliveVars,
4298 GenTreeLclVarCommon* node);
4299 void fgComputeLifeUntrackedLocal(VARSET_TP& life,
4300 VARSET_VALARG_TP keepAliveVars,
4302 GenTreeLclVarCommon* lclVarNode);
4303 bool fgComputeLifeLocal(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTree* lclVarNode);
4305 void fgComputeLife(VARSET_TP& life,
4308 VARSET_VALARG_TP volatileVars,
4309 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
4311 void fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALARG_TP volatileVars);
4313 bool fgRemoveDeadStore(GenTree** pTree,
4315 VARSET_VALARG_TP life,
4317 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
4319 // For updating liveset during traversal AFTER fgComputeLife has completed
4320 VARSET_VALRET_TP fgGetVarBits(GenTree* tree);
4321 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tree);
4323 // Returns the set of live variables after endTree,
4324 // assuming that liveSet is the set of live variables BEFORE tree.
4325 // Requires that fgComputeLife has completed, and that tree is in the same
4326 // statement as endTree, and that it comes before endTree in execution order
4328 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tree, GenTree* endTree)
4330 VARSET_TP newLiveSet(VarSetOps::MakeCopy(this, liveSet));
4331 while (tree != nullptr && tree != endTree->gtNext)
4333 VarSetOps::AssignNoCopy(this, newLiveSet, fgUpdateLiveSet(newLiveSet, tree));
4334 tree = tree->gtNext;
4336 assert(tree == endTree->gtNext);
4340 void fgInterBlockLocalVarLiveness();
4342 // The presence of a partial definition presents some difficulties for SSA: this is both a use of some SSA name
4343 // 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
4344 // whether to treat that as the use or def. It chooses the "use", and thus the old SSA name. This map allows us
4345 // to record/recover the "def" SSA number, given the lcl var node for "x" in such a tree.
4346 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, unsigned> NodeToUnsignedMap;
4347 NodeToUnsignedMap* m_opAsgnVarDefSsaNums;
4348 NodeToUnsignedMap* GetOpAsgnVarDefSsaNums()
4350 if (m_opAsgnVarDefSsaNums == nullptr)
4352 m_opAsgnVarDefSsaNums = new (getAllocator()) NodeToUnsignedMap(getAllocator());
4354 return m_opAsgnVarDefSsaNums;
4357 // Requires value numbering phase to have completed. Returns the value number ("gtVN") of the
4358 // "tree," EXCEPT in the case of GTF_VAR_USEASG, because the tree node's gtVN member is the
4359 // "use" VN. Performs a lookup into the map of (use asg tree -> def VN.) to return the "def's"
4361 inline ValueNum GetUseAsgDefVNOrTreeVN(GenTree* tree);
4363 // Requires that "lcl" has the GTF_VAR_DEF flag set. Returns the SSA number of "lcl".
4364 // Except: assumes that lcl is a def, and if it is
4365 // a partial def (GTF_VAR_USEASG), looks up and returns the SSA number for the "def",
4366 // rather than the "use" SSA number recorded in the tree "lcl".
4367 inline unsigned GetSsaNumForLocalVarDef(GenTree* lcl);
4369 // Performs SSA conversion.
4372 // Reset any data structures to the state expected by "fgSsaBuild", so it can be run again.
4373 void fgResetForSsa();
4375 unsigned fgSsaPassesCompleted; // Number of times fgSsaBuild has been run.
4377 // Returns "true" if a struct temp of the given type requires needs zero init in this block
4378 inline bool fgStructTempNeedsExplicitZeroInit(LclVarDsc* varDsc, BasicBlock* block);
4380 // The value numbers for this compilation.
4381 ValueNumStore* vnStore;
4384 ValueNumStore* GetValueNumStore()
4389 // Do value numbering (assign a value number to each
4391 void fgValueNumber();
4393 // Computes new GcHeap VN via the assignment H[elemTypeEq][arrVN][inx][fldSeq] = rhsVN.
4394 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
4395 // The 'indType' is the indirection type of the lhs of the assignment and will typically
4396 // match the element type of the array or fldSeq. When this type doesn't match
4397 // or if the fldSeq is 'NotAField' we invalidate the array contents H[elemTypeEq][arrVN]
4399 ValueNum fgValueNumberArrIndexAssign(CORINFO_CLASS_HANDLE elemTypeEq,
4402 FieldSeqNode* fldSeq,
4406 // Requires that "tree" is a GT_IND marked as an array index, and that its address argument
4407 // has been parsed to yield the other input arguments. If evaluation of the address
4408 // can raise exceptions, those should be captured in the exception set "excVN."
4409 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
4410 // Marks "tree" with the VN for H[elemTypeEq][arrVN][inx][fldSeq] (for the liberal VN; a new unique
4411 // VN for the conservative VN.) Also marks the tree's argument as the address of an array element.
4412 // The type tree->TypeGet() will typically match the element type of the array or fldSeq.
4413 // When this type doesn't match or if the fldSeq is 'NotAField' we return a new unique VN
4415 ValueNum fgValueNumberArrIndexVal(GenTree* tree,
4416 CORINFO_CLASS_HANDLE elemTypeEq,
4420 FieldSeqNode* fldSeq);
4422 // Requires "funcApp" to be a VNF_PtrToArrElem, and "addrXvn" to represent the exception set thrown
4423 // by evaluating the array index expression "tree". Returns the value number resulting from
4424 // dereferencing the array in the current GcHeap state. If "tree" is non-null, it must be the
4425 // "GT_IND" that does the dereference, and it is given the returned value number.
4426 ValueNum fgValueNumberArrIndexVal(GenTree* tree, struct VNFuncApp* funcApp, ValueNum addrXvn);
4428 // Compute the value number for a byref-exposed load of the given type via the given pointerVN.
4429 ValueNum fgValueNumberByrefExposedLoad(var_types type, ValueNum pointerVN);
4431 unsigned fgVNPassesCompleted; // Number of times fgValueNumber has been run.
4433 // Utility functions for fgValueNumber.
4435 // Perform value-numbering for the trees in "blk".
4436 void fgValueNumberBlock(BasicBlock* blk);
4438 // Requires that "entryBlock" is the entry block of loop "loopNum", and that "loopNum" is the
4439 // innermost loop of which "entryBlock" is the entry. Returns the value number that should be
4440 // assumed for the memoryKind at the start "entryBlk".
4441 ValueNum fgMemoryVNForLoopSideEffects(MemoryKind memoryKind, BasicBlock* entryBlock, unsigned loopNum);
4443 // Called when an operation (performed by "tree", described by "msg") may cause the GcHeap to be mutated.
4444 // As GcHeap is a subset of ByrefExposed, this will also annotate the ByrefExposed mutation.
4445 void fgMutateGcHeap(GenTree* tree DEBUGARG(const char* msg));
4447 // Called when an operation (performed by "tree", described by "msg") may cause an address-exposed local to be
4449 void fgMutateAddressExposedLocal(GenTree* tree DEBUGARG(const char* msg));
4451 // For a GC heap store at curTree, record the new curMemoryVN's and update curTree's MemorySsaMap.
4452 // As GcHeap is a subset of ByrefExposed, this will also record the ByrefExposed store.
4453 void recordGcHeapStore(GenTree* curTree, ValueNum gcHeapVN DEBUGARG(const char* msg));
4455 // For a store to an address-exposed local at curTree, record the new curMemoryVN and update curTree's MemorySsaMap.
4456 void recordAddressExposedLocalStore(GenTree* curTree, ValueNum memoryVN DEBUGARG(const char* msg));
4458 // Tree caused an update in the current memory VN. If "tree" has an associated heap SSA #, record that
4459 // value in that SSA #.
4460 void fgValueNumberRecordMemorySsa(MemoryKind memoryKind, GenTree* tree);
4462 // The input 'tree' is a leaf node that is a constant
4463 // Assign the proper value number to the tree
4464 void fgValueNumberTreeConst(GenTree* tree);
4466 // Assumes that all inputs to "tree" have had value numbers assigned; assigns a VN to tree.
4467 // (With some exceptions: the VN of the lhs of an assignment is assigned as part of the
4469 void fgValueNumberTree(GenTree* tree);
4471 // Does value-numbering for a block assignment.
4472 void fgValueNumberBlockAssignment(GenTree* tree);
4474 // Does value-numbering for a cast tree.
4475 void fgValueNumberCastTree(GenTree* tree);
4477 // Does value-numbering for an intrinsic tree.
4478 void fgValueNumberIntrinsic(GenTree* tree);
4480 // Does value-numbering for a call. We interpret some helper calls.
4481 void fgValueNumberCall(GenTreeCall* call);
4483 // The VN of some nodes in "args" may have changed -- reassign VNs to the arg list nodes.
4484 void fgUpdateArgListVNs(GenTreeArgList* args);
4486 // Does value-numbering for a helper "call" that has a VN function symbol "vnf".
4487 void fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc);
4489 // Requires "helpCall" to be a helper call. Assigns it a value number;
4490 // we understand the semantics of some of the calls. Returns "true" if
4491 // the call may modify the heap (we assume arbitrary memory side effects if so).
4492 bool fgValueNumberHelperCall(GenTreeCall* helpCall);
4494 // Requires that "helpFunc" is one of the pure Jit Helper methods.
4495 // Returns the corresponding VNFunc to use for value numbering
4496 VNFunc fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc);
4498 // Adds the exception set for the current tree node which has a memory indirection operation
4499 void fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree* baseAddr);
4501 // Adds the exception sets for the current tree node which is performing a division or modulus operation
4502 void fgValueNumberAddExceptionSetForDivision(GenTree* tree);
4504 // Adds the exception set for the current tree node which is performing a overflow checking operation
4505 void fgValueNumberAddExceptionSetForOverflow(GenTree* tree);
4507 // Adds the exception set for the current tree node which is performing a ckfinite operation
4508 void fgValueNumberAddExceptionSetForCkFinite(GenTree* tree);
4510 // Adds the exception sets for the current tree node
4511 void fgValueNumberAddExceptionSet(GenTree* tree);
4513 // These are the current value number for the memory implicit variables while
4514 // doing value numbering. These are the value numbers under the "liberal" interpretation
4515 // of memory values; the "conservative" interpretation needs no VN, since every access of
4516 // memory yields an unknown value.
4517 ValueNum fgCurMemoryVN[MemoryKindCount];
4519 // Return a "pseudo"-class handle for an array element type. If "elemType" is TYP_STRUCT,
4520 // requires "elemStructType" to be non-null (and to have a low-order zero). Otherwise, low order bit
4521 // is 1, and the rest is an encoding of "elemTyp".
4522 static CORINFO_CLASS_HANDLE EncodeElemType(var_types elemTyp, CORINFO_CLASS_HANDLE elemStructType)
4524 if (elemStructType != nullptr)
4526 assert(varTypeIsStruct(elemTyp) || elemTyp == TYP_REF || elemTyp == TYP_BYREF ||
4527 varTypeIsIntegral(elemTyp));
4528 assert((size_t(elemStructType) & 0x1) == 0x0); // Make sure the encoding below is valid.
4529 return elemStructType;
4533 assert(elemTyp != TYP_STRUCT);
4534 elemTyp = varTypeUnsignedToSigned(elemTyp);
4535 return CORINFO_CLASS_HANDLE(size_t(elemTyp) << 1 | 0x1);
4538 // If "clsHnd" is the result of an "EncodePrim" call, returns true and sets "*pPrimType" to the
4539 // var_types it represents. Otherwise, returns TYP_STRUCT (on the assumption that "clsHnd" is
4540 // the struct type of the element).
4541 static var_types DecodeElemType(CORINFO_CLASS_HANDLE clsHnd)
4543 size_t clsHndVal = size_t(clsHnd);
4544 if (clsHndVal & 0x1)
4546 return var_types(clsHndVal >> 1);
4554 // Convert a BYTE which represents the VM's CorInfoGCtype to the JIT's var_types
4555 var_types getJitGCType(BYTE gcType);
4557 enum structPassingKind
4559 SPK_Unknown, // Invalid value, never returned
4560 SPK_PrimitiveType, // The struct is passed/returned using a primitive type.
4561 SPK_EnclosingType, // Like SPK_Primitive type, but used for return types that
4562 // require a primitive type temp that is larger than the struct size.
4563 // Currently used for structs of size 3, 5, 6, or 7 bytes.
4564 SPK_ByValue, // The struct is passed/returned by value (using the ABI rules)
4565 // for ARM64 and UNIX_X64 in multiple registers. (when all of the
4566 // parameters registers are used, then the stack will be used)
4567 // for X86 passed on the stack, for ARM32 passed in registers
4568 // or the stack or split between registers and the stack.
4569 SPK_ByValueAsHfa, // The struct is passed/returned as an HFA in multiple registers.
4571 }; // The struct is passed/returned by reference to a copy/buffer.
4573 // Get the "primitive" type that is is used when we are given a struct of size 'structSize'.
4574 // For pointer sized structs the 'clsHnd' is used to determine if the struct contains GC ref.
4575 // A "primitive" type is one of the scalar types: byte, short, int, long, ref, float, double
4576 // If we can't or shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
4578 // isVarArg is passed for use on Windows Arm64 to change the decision returned regarding
4581 var_types getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS_HANDLE clsHnd, bool isVarArg);
4583 // Get the type that is used to pass values of the given struct type.
4584 // isVarArg is passed for use on Windows Arm64 to change the decision returned regarding
4587 var_types getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4588 structPassingKind* wbPassStruct,
4590 unsigned structSize);
4592 // Get the type that is used to return values of the given struct type.
4593 // If the size is unknown, pass 0 and it will be determined from 'clsHnd'.
4594 var_types getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4595 structPassingKind* wbPassStruct = nullptr,
4596 unsigned structSize = 0);
4599 // Print a representation of "vnp" or "vn" on standard output.
4600 // If "level" is non-zero, we also print out a partial expansion of the value.
4601 void vnpPrint(ValueNumPair vnp, unsigned level);
4602 void vnPrint(ValueNum vn, unsigned level);
4605 bool fgDominate(BasicBlock* b1, BasicBlock* b2); // Return true if b1 dominates b2
4607 // Dominator computation member functions
4608 // Not exposed outside Compiler
4610 bool fgReachable(BasicBlock* b1, BasicBlock* b2); // Returns true if block b1 can reach block b2
4612 void fgComputeDoms(); // Computes the immediate dominators for each basic block in the
4613 // flow graph. We first assume the fields bbIDom on each
4614 // basic block are invalid. This computation is needed later
4615 // by fgBuildDomTree to build the dominance tree structure.
4616 // Based on: A Simple, Fast Dominance Algorithm
4617 // by Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
4619 void fgCompDominatedByExceptionalEntryBlocks();
4621 BlockSet_ValRet_T fgGetDominatorSet(BasicBlock* block); // Returns a set of blocks that dominate the given block.
4622 // Note: this is relatively slow compared to calling fgDominate(),
4623 // especially if dealing with a single block versus block check.
4625 void fgComputeReachabilitySets(); // Compute bbReach sets. (Also sets BBF_GC_SAFE_POINT flag on blocks.)
4627 void fgComputeEnterBlocksSet(); // Compute the set of entry blocks, 'fgEnterBlks'.
4629 bool fgRemoveUnreachableBlocks(); // Remove blocks determined to be unreachable by the bbReach sets.
4631 void fgComputeReachability(); // Perform flow graph node reachability analysis.
4633 BasicBlock* fgIntersectDom(BasicBlock* a, BasicBlock* b); // Intersect two immediate dominator sets.
4635 void fgDfsInvPostOrder(); // In order to compute dominance using fgIntersectDom, the flow graph nodes must be
4636 // processed in topological sort, this function takes care of that.
4638 void fgDfsInvPostOrderHelper(BasicBlock* block, BlockSet& visited, unsigned* count);
4640 BlockSet_ValRet_T fgDomFindStartNodes(); // Computes which basic blocks don't have incoming edges in the flow graph.
4641 // Returns this as a set.
4643 BlockSet_ValRet_T fgDomTreeEntryNodes(BasicBlockList** domTree); // Computes which nodes in the dominance forest are
4644 // root nodes. Returns this as a set.
4647 void fgDispDomTree(BasicBlockList** domTree); // Helper that prints out the Dominator Tree in debug builds.
4650 void fgBuildDomTree(); // Once we compute all the immediate dominator sets for each node in the flow graph
4651 // (performed by fgComputeDoms), this procedure builds the dominance tree represented
4654 // In order to speed up the queries of the form 'Does A dominates B', we can perform a DFS preorder and postorder
4655 // traversal of the dominance tree and the dominance query will become A dominates B iif preOrder(A) <= preOrder(B)
4656 // && postOrder(A) >= postOrder(B) making the computation O(1).
4657 void fgTraverseDomTree(unsigned bbNum, BasicBlockList** domTree, unsigned* preNum, unsigned* postNum);
4659 // When the flow graph changes, we need to update the block numbers, predecessor lists, reachability sets, and
4661 void fgUpdateChangedFlowGraph();
4664 // Compute the predecessors of the blocks in the control flow graph.
4665 void fgComputePreds();
4667 // Remove all predecessor information.
4668 void fgRemovePreds();
4670 // Compute the cheap flow graph predecessors lists. This is used in some early phases
4671 // before the full predecessors lists are computed.
4672 void fgComputeCheapPreds();
4675 void fgAddCheapPred(BasicBlock* block, BasicBlock* blockPred);
4677 void fgRemoveCheapPred(BasicBlock* block, BasicBlock* blockPred);
4687 // Initialize the per-block variable sets (used for liveness analysis).
4688 void fgInitBlockVarSets();
4690 // true if we've gone through and created GC Poll calls.
4691 bool fgGCPollsCreated;
4692 void fgMarkGCPollBlocks();
4693 void fgCreateGCPolls();
4694 bool fgCreateGCPoll(GCPollType pollType, BasicBlock* block);
4696 // Requires that "block" is a block that returns from
4697 // a finally. Returns the number of successors (jump targets of
4698 // of blocks in the covered "try" that did a "LEAVE".)
4699 unsigned fgNSuccsOfFinallyRet(BasicBlock* block);
4701 // Requires that "block" is a block that returns (in the sense of BBJ_EHFINALLYRET) from
4702 // a finally. Returns its "i"th successor (jump targets of
4703 // of blocks in the covered "try" that did a "LEAVE".)
4704 // Requires that "i" < fgNSuccsOfFinallyRet(block).
4705 BasicBlock* fgSuccOfFinallyRet(BasicBlock* block, unsigned i);
4708 // Factor out common portions of the impls of the methods above.
4709 void fgSuccOfFinallyRetWork(BasicBlock* block, unsigned i, BasicBlock** bres, unsigned* nres);
4712 // For many purposes, it is desirable to be able to enumerate the *distinct* targets of a switch statement,
4713 // skipping duplicate targets. (E.g., in flow analyses that are only interested in the set of possible targets.)
4714 // SwitchUniqueSuccSet contains the non-duplicated switch targets.
4715 // (Code that modifies the jump table of a switch has an obligation to call Compiler::UpdateSwitchTableTarget,
4716 // which in turn will call the "UpdateTarget" method of this type if a SwitchUniqueSuccSet has already
4717 // been computed for the switch block. If a switch block is deleted or is transformed into a non-switch,
4718 // we leave the entry associated with the block, but it will no longer be accessed.)
4719 struct SwitchUniqueSuccSet
4721 unsigned numDistinctSuccs; // Number of distinct targets of the switch.
4722 BasicBlock** nonDuplicates; // Array of "numDistinctSuccs", containing all the distinct switch target
4725 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4726 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4727 // remove it from "this", and ensure that "to" is a member. Use "alloc" to do any required allocation.
4728 void UpdateTarget(CompAllocator alloc, BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4731 typedef JitHashTable<BasicBlock*, JitPtrKeyFuncs<BasicBlock>, SwitchUniqueSuccSet> BlockToSwitchDescMap;
4734 // Maps BasicBlock*'s that end in switch statements to SwitchUniqueSuccSets that allow
4735 // iteration over only the distinct successors.
4736 BlockToSwitchDescMap* m_switchDescMap;
4739 BlockToSwitchDescMap* GetSwitchDescMap(bool createIfNull = true)
4741 if ((m_switchDescMap == nullptr) && createIfNull)
4743 m_switchDescMap = new (getAllocator()) BlockToSwitchDescMap(getAllocator());
4745 return m_switchDescMap;
4748 // Invalidate the map of unique switch block successors. For example, since the hash key of the map
4749 // depends on block numbers, we must invalidate the map when the blocks are renumbered, to ensure that
4750 // we don't accidentally look up and return the wrong switch data.
4751 void InvalidateUniqueSwitchSuccMap()
4753 m_switchDescMap = nullptr;
4756 // Requires "switchBlock" to be a block that ends in a switch. Returns
4757 // the corresponding SwitchUniqueSuccSet.
4758 SwitchUniqueSuccSet GetDescriptorForSwitch(BasicBlock* switchBlk);
4760 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4761 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4762 // remove it from "this", and ensure that "to" is a member.
4763 void UpdateSwitchTableTarget(BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4765 // Remove the "SwitchUniqueSuccSet" of "switchBlk" in the BlockToSwitchDescMap.
4766 void fgInvalidateSwitchDescMapEntry(BasicBlock* switchBlk);
4768 BasicBlock* fgFirstBlockOfHandler(BasicBlock* block);
4770 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred);
4772 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred, flowList*** ptrToPred);
4774 flowList* fgSpliceOutPred(BasicBlock* block, BasicBlock* blockPred);
4776 flowList* fgRemoveRefPred(BasicBlock* block, BasicBlock* blockPred);
4778 flowList* fgRemoveAllRefPreds(BasicBlock* block, BasicBlock* blockPred);
4780 flowList* fgRemoveAllRefPreds(BasicBlock* block, flowList** ptrToPred);
4782 void fgRemoveBlockAsPred(BasicBlock* block);
4784 void fgChangeSwitchBlock(BasicBlock* oldSwitchBlock, BasicBlock* newSwitchBlock);
4786 void fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* newTarget, BasicBlock* oldTarget);
4788 void fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, BasicBlock* oldTarget);
4790 void fgReplacePred(BasicBlock* block, BasicBlock* oldPred, BasicBlock* newPred);
4792 flowList* fgAddRefPred(BasicBlock* block,
4793 BasicBlock* blockPred,
4794 flowList* oldEdge = nullptr,
4795 bool initializingPreds = false); // Only set to 'true' when we are computing preds in
4798 void fgFindBasicBlocks();
4800 bool fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt);
4802 bool fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionIndex, bool putInTryRegion);
4804 BasicBlock* fgFindInsertPoint(unsigned regionIndex,
4805 bool putInTryRegion,
4806 BasicBlock* startBlk,
4808 BasicBlock* nearBlk,
4809 BasicBlock* jumpBlk,
4812 unsigned fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNesting = nullptr);
4814 void fgRemoveEmptyBlocks();
4816 void fgRemoveStmt(BasicBlock* block, GenTree* stmt);
4818 bool fgCheckRemoveStmt(BasicBlock* block, GenTree* stmt);
4820 void fgCreateLoopPreHeader(unsigned lnum);
4822 void fgUnreachableBlock(BasicBlock* block);
4824 void fgRemoveConditionalJump(BasicBlock* block);
4826 BasicBlock* fgLastBBInMainFunction();
4828 BasicBlock* fgEndBBAfterMainFunction();
4830 void fgUnlinkRange(BasicBlock* bBeg, BasicBlock* bEnd);
4832 void fgRemoveBlock(BasicBlock* block, bool unreachable);
4834 bool fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4836 void fgCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4838 void fgUpdateLoopsAfterCompacting(BasicBlock* block, BasicBlock* bNext);
4840 BasicBlock* fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst);
4842 bool fgRenumberBlocks();
4844 bool fgExpandRarelyRunBlocks();
4846 bool fgEhAllowsMoveBlock(BasicBlock* bBefore, BasicBlock* bAfter);
4848 void fgMoveBlocksAfter(BasicBlock* bStart, BasicBlock* bEnd, BasicBlock* insertAfterBlk);
4850 enum FG_RELOCATE_TYPE
4852 FG_RELOCATE_TRY, // relocate the 'try' region
4853 FG_RELOCATE_HANDLER // relocate the handler region (including the filter if necessary)
4855 BasicBlock* fgRelocateEHRange(unsigned regionIndex, FG_RELOCATE_TYPE relocateType);
4857 #if FEATURE_EH_FUNCLETS
4858 #if defined(_TARGET_ARM_)
4859 void fgClearFinallyTargetBit(BasicBlock* block);
4860 #endif // defined(_TARGET_ARM_)
4861 bool fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block);
4862 bool fgAnyIntraHandlerPreds(BasicBlock* block);
4863 void fgInsertFuncletPrologBlock(BasicBlock* block);
4864 void fgCreateFuncletPrologBlocks();
4865 void fgCreateFunclets();
4866 #else // !FEATURE_EH_FUNCLETS
4867 bool fgRelocateEHRegions();
4868 #endif // !FEATURE_EH_FUNCLETS
4870 bool fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* target);
4872 bool fgBlockEndFavorsTailDuplication(BasicBlock* block);
4874 bool fgBlockIsGoodTailDuplicationCandidate(BasicBlock* block);
4876 bool fgOptimizeEmptyBlock(BasicBlock* block);
4878 bool fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBlock* bDest);
4880 bool fgOptimizeBranch(BasicBlock* bJump);
4882 bool fgOptimizeSwitchBranches(BasicBlock* block);
4884 bool fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev);
4886 bool fgOptimizeSwitchJumps();
4888 void fgPrintEdgeWeights();
4890 void fgComputeBlockAndEdgeWeights();
4891 BasicBlock::weight_t fgComputeMissingBlockWeights();
4892 void fgComputeCalledCount(BasicBlock::weight_t returnWeight);
4893 void fgComputeEdgeWeights();
4895 void fgReorderBlocks();
4897 void fgDetermineFirstColdBlock();
4899 bool fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc = nullptr);
4901 bool fgUpdateFlowGraph(bool doTailDup = false);
4903 void fgFindOperOrder();
4905 // method that returns if you should split here
4906 typedef bool(fgSplitPredicate)(GenTree* tree, GenTree* parent, fgWalkData* data);
4908 void fgSetBlockOrder();
4910 void fgRemoveReturnBlock(BasicBlock* block);
4912 /* Helper code that has been factored out */
4913 inline void fgConvertBBToThrowBB(BasicBlock* block);
4915 bool fgCastNeeded(GenTree* tree, var_types toType);
4916 GenTree* fgDoNormalizeOnStore(GenTree* tree);
4917 GenTree* fgMakeTmpArgNode(fgArgTabEntry* curArgTabEntry);
4919 // The following check for loops that don't execute calls
4920 bool fgLoopCallMarked;
4922 void fgLoopCallTest(BasicBlock* srcBB, BasicBlock* dstBB);
4923 void fgLoopCallMark();
4925 void fgMarkLoopHead(BasicBlock* block);
4927 unsigned fgGetCodeEstimate(BasicBlock* block);
4930 const char* fgProcessEscapes(const char* nameIn, escapeMapping_t* map);
4931 FILE* fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, LPCWSTR type);
4932 bool fgDumpFlowGraph(Phases phase);
4934 #endif // DUMP_FLOWGRAPHS
4939 void fgDispBBLiveness(BasicBlock* block);
4940 void fgDispBBLiveness();
4941 void fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth = 0);
4942 void fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, bool dumpTrees);
4943 void fgDispBasicBlocks(bool dumpTrees = false);
4944 void fgDumpStmtTree(GenTree* stmt, unsigned bbNum);
4945 void fgDumpBlock(BasicBlock* block);
4946 void fgDumpTrees(BasicBlock* firstBlock, BasicBlock* lastBlock);
4948 static fgWalkPreFn fgStress64RsltMulCB;
4949 void fgStress64RsltMul();
4950 void fgDebugCheckUpdate();
4951 void fgDebugCheckBBlist(bool checkBBNum = false, bool checkBBRefs = true);
4952 void fgDebugCheckBlockLinks();
4953 void fgDebugCheckLinks(bool morphTrees = false);
4954 void fgDebugCheckStmtsList(BasicBlock* block, bool morphTrees);
4955 void fgDebugCheckNodeLinks(BasicBlock* block, GenTree* stmt);
4956 void fgDebugCheckNodesUniqueness();
4958 void fgDebugCheckFlags(GenTree* tree);
4959 void fgDebugCheckFlagsHelper(GenTree* tree, unsigned treeFlags, unsigned chkFlags);
4960 void fgDebugCheckTryFinallyExits();
4963 static GenTree* fgGetFirstNode(GenTree* tree);
4965 //--------------------- Walking the trees in the IR -----------------------
4970 fgWalkPreFn* wtprVisitorFn;
4971 fgWalkPostFn* wtpoVisitorFn;
4972 void* pCallbackData; // user-provided data
4973 bool wtprLclsOnly; // whether to only visit lclvar nodes
4974 GenTree* parent; // parent of current node, provided to callback
4975 GenTreeStack* parentStack; // stack of parent nodes, if asked for
4977 bool printModified; // callback can use this
4981 fgWalkResult fgWalkTreePre(GenTree** pTree,
4982 fgWalkPreFn* visitor,
4983 void* pCallBackData = nullptr,
4984 bool lclVarsOnly = false,
4985 bool computeStack = false);
4987 fgWalkResult fgWalkTree(GenTree** pTree,
4988 fgWalkPreFn* preVisitor,
4989 fgWalkPostFn* postVisitor,
4990 void* pCallBackData = nullptr);
4992 void fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData);
4996 fgWalkResult fgWalkTreePost(GenTree** pTree,
4997 fgWalkPostFn* visitor,
4998 void* pCallBackData = nullptr,
4999 bool computeStack = false);
5001 // An fgWalkPreFn that looks for expressions that have inline throws in
5002 // minopts mode. Basically it looks for tress with gtOverflowEx() or
5003 // GTF_IND_RNGCHK. It returns WALK_ABORT if one is found. It
5004 // returns WALK_SKIP_SUBTREES if GTF_EXCEPT is not set (assumes flags
5005 // properly propagated to parent trees). It returns WALK_CONTINUE
5007 static fgWalkResult fgChkThrowCB(GenTree** pTree, Compiler::fgWalkData* data);
5008 static fgWalkResult fgChkLocAllocCB(GenTree** pTree, Compiler::fgWalkData* data);
5009 static fgWalkResult fgChkQmarkCB(GenTree** pTree, Compiler::fgWalkData* data);
5011 /**************************************************************************
5013 *************************************************************************/
5016 friend class SsaBuilder;
5017 friend struct ValueNumberState;
5019 //--------------------- Detect the basic blocks ---------------------------
5021 BasicBlock** fgBBs; // Table of pointers to the BBs
5023 void fgInitBBLookup();
5024 BasicBlock* fgLookupBB(unsigned addr);
5026 void fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, FixedBitVect* jumpTarget);
5028 void fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock);
5030 void fgLinkBasicBlocks();
5032 unsigned fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, FixedBitVect* jumpTarget);
5034 void fgCheckBasicBlockControlFlow();
5036 void fgControlFlowPermitted(BasicBlock* blkSrc,
5037 BasicBlock* blkDest,
5038 BOOL IsLeave = false /* is the src a leave block */);
5040 bool fgFlowToFirstBlockOfInnerTry(BasicBlock* blkSrc, BasicBlock* blkDest, bool sibling);
5042 void fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, bool isInlining);
5044 void fgAdjustForAddressExposedOrWrittenThis();
5046 bool fgProfileData_ILSizeMismatch;
5047 ICorJitInfo::ProfileBuffer* fgProfileBuffer;
5048 ULONG fgProfileBufferCount;
5049 ULONG fgNumProfileRuns;
5051 unsigned fgStressBBProf()
5054 unsigned result = JitConfig.JitStressBBProf();
5057 if (compStressCompile(STRESS_BB_PROFILE, 15))
5068 bool fgHaveProfileData();
5069 bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weight);
5070 void fgInstrumentMethod();
5073 // fgIsUsingProfileWeights - returns true if we have real profile data for this method
5074 // or if we have some fake profile data for the stress mode
5075 bool fgIsUsingProfileWeights()
5077 return (fgHaveProfileData() || fgStressBBProf());
5080 // fgProfileRunsCount - returns total number of scenario runs for the profile data
5081 // or BB_UNITY_WEIGHT when we aren't using profile data.
5082 unsigned fgProfileRunsCount()
5084 return fgIsUsingProfileWeights() ? fgNumProfileRuns : BB_UNITY_WEIGHT;
5087 //-------- Insert a statement at the start or end of a basic block --------
5091 static bool fgBlockContainsStatementBounded(BasicBlock* block, GenTree* stmt, bool answerOnBoundExceeded = true);
5095 GenTreeStmt* fgInsertStmtAtEnd(BasicBlock* block, GenTree* node);
5097 public: // Used by linear scan register allocation
5098 GenTreeStmt* fgInsertStmtNearEnd(BasicBlock* block, GenTree* node);
5101 GenTree* fgInsertStmtAtBeg(BasicBlock* block, GenTree* stmt);
5102 GenTree* fgInsertStmtAfter(BasicBlock* block, GenTree* insertionPoint, GenTree* stmt);
5104 public: // Used by linear scan register allocation
5105 GenTree* fgInsertStmtBefore(BasicBlock* block, GenTree* insertionPoint, GenTree* stmt);
5108 GenTree* fgInsertStmtListAfter(BasicBlock* block, GenTree* stmtAfter, GenTree* stmtList);
5110 // Create a new temporary variable to hold the result of *ppTree,
5111 // and transform the graph accordingly.
5112 GenTree* fgInsertCommaFormTemp(GenTree** ppTree, CORINFO_CLASS_HANDLE structType = nullptr);
5113 GenTree* fgMakeMultiUse(GenTree** ppTree);
5116 // Recognize a bitwise rotation pattern and convert into a GT_ROL or a GT_ROR node.
5117 GenTree* fgRecognizeAndMorphBitwiseRotation(GenTree* tree);
5118 bool fgOperIsBitwiseRotationRoot(genTreeOps oper);
5120 //-------- Determine the order in which the trees will be evaluated -------
5122 unsigned fgTreeSeqNum;
5123 GenTree* fgTreeSeqLst;
5124 GenTree* fgTreeSeqBeg;
5126 GenTree* fgSetTreeSeq(GenTree* tree, GenTree* prev = nullptr, bool isLIR = false);
5127 void fgSetTreeSeqHelper(GenTree* tree, bool isLIR);
5128 void fgSetTreeSeqFinish(GenTree* tree, bool isLIR);
5129 void fgSetStmtSeq(GenTree* tree);
5130 void fgSetBlockOrder(BasicBlock* block);
5132 //------------------------- Morphing --------------------------------------
5134 unsigned fgPtrArgCntMax;
5137 //------------------------------------------------------------------------
5138 // fgGetPtrArgCntMax: Return the maximum number of pointer-sized stack arguments that calls inside this method
5139 // can push on the stack. This value is calculated during morph.
5142 // Returns fgPtrArgCntMax, that is a private field.
5144 unsigned fgGetPtrArgCntMax() const
5146 return fgPtrArgCntMax;
5149 //------------------------------------------------------------------------
5150 // fgSetPtrArgCntMax: Set the maximum number of pointer-sized stack arguments that calls inside this method
5151 // can push on the stack. This function is used during StackLevelSetter to fix incorrect morph calculations.
5153 void fgSetPtrArgCntMax(unsigned argCntMax)
5155 fgPtrArgCntMax = argCntMax;
5158 bool compCanEncodePtrArgCntMax();
5161 hashBv* fgOutgoingArgTemps;
5162 hashBv* fgCurrentlyInUseArgTemps;
5164 void fgSetRngChkTarget(GenTree* tree, bool delay = true);
5166 BasicBlock* fgSetRngChkTargetInner(SpecialCodeKind kind, bool delay);
5169 void fgMoveOpsLeft(GenTree* tree);
5172 bool fgIsCommaThrow(GenTree* tree, bool forFolding = false);
5174 bool fgIsThrow(GenTree* tree);
5176 bool fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2);
5177 bool fgIsBlockCold(BasicBlock* block);
5179 GenTree* fgMorphCastIntoHelper(GenTree* tree, int helper, GenTree* oper);
5181 GenTree* fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeArgList* args, bool morphArgs = true);
5183 GenTree* fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType, unsigned lclOffs);
5185 // A "MorphAddrContext" carries information from the surrounding context. If we are evaluating a byref address,
5186 // it is useful to know whether the address will be immediately dereferenced, or whether the address value will
5187 // be used, perhaps by passing it as an argument to a called method. This affects how null checking is done:
5188 // for sufficiently small offsets, we can rely on OS page protection to implicitly null-check addresses that we
5189 // know will be dereferenced. To know that reliance on implicit null checking is sound, we must further know that
5190 // all offsets between the top-level indirection and the bottom are constant, and that their sum is sufficiently
5191 // small; hence the other fields of MorphAddrContext.
5192 enum MorphAddrContextKind
5197 struct MorphAddrContext
5199 MorphAddrContextKind m_kind;
5200 bool m_allConstantOffsets; // Valid only for "m_kind == MACK_Ind". True iff all offsets between
5201 // top-level indirection and here have been constants.
5202 size_t m_totalOffset; // Valid only for "m_kind == MACK_Ind", and if "m_allConstantOffsets" is true.
5203 // In that case, is the sum of those constant offsets.
5205 MorphAddrContext(MorphAddrContextKind kind) : m_kind(kind), m_allConstantOffsets(true), m_totalOffset(0)
5210 // A MACK_CopyBlock context is immutable, so we can just make one of these and share it.
5211 static MorphAddrContext s_CopyBlockMAC;
5214 GenTree* getSIMDStructFromField(GenTree* tree,
5215 var_types* baseTypeOut,
5217 unsigned* simdSizeOut,
5218 bool ignoreUsedInSIMDIntrinsic = false);
5219 GenTree* fgMorphFieldAssignToSIMDIntrinsicSet(GenTree* tree);
5220 GenTree* fgMorphFieldToSIMDIntrinsicGet(GenTree* tree);
5221 bool fgMorphCombineSIMDFieldAssignments(BasicBlock* block, GenTree* stmt);
5222 void impMarkContiguousSIMDFieldAssignments(GenTree* stmt);
5224 // fgPreviousCandidateSIMDFieldAsgStmt is only used for tracking previous simd field assignment
5225 // in function: Complier::impMarkContiguousSIMDFieldAssignments.
5226 GenTree* fgPreviousCandidateSIMDFieldAsgStmt;
5228 #endif // FEATURE_SIMD
5229 GenTree* fgMorphArrayIndex(GenTree* tree);
5230 GenTree* fgMorphCast(GenTree* tree);
5231 GenTree* fgUnwrapProxy(GenTree* objRef);
5232 GenTreeFieldList* fgMorphLclArgToFieldlist(GenTreeLclVarCommon* lcl);
5233 void fgInitArgInfo(GenTreeCall* call);
5234 GenTreeCall* fgMorphArgs(GenTreeCall* call);
5235 GenTreeArgList* fgMorphArgList(GenTreeArgList* args, MorphAddrContext* mac);
5237 void fgMakeOutgoingStructArgCopy(GenTreeCall* call,
5240 CORINFO_CLASS_HANDLE copyBlkClass);
5242 void fgFixupStructReturn(GenTree* call);
5243 GenTree* fgMorphLocalVar(GenTree* tree, bool forceRemorph);
5246 bool fgAddrCouldBeNull(GenTree* addr);
5249 GenTree* fgMorphField(GenTree* tree, MorphAddrContext* mac);
5250 bool fgCanFastTailCall(GenTreeCall* call);
5251 bool fgCheckStmtAfterTailCall();
5252 void fgMorphTailCall(GenTreeCall* call, void* pfnCopyArgs);
5253 GenTree* fgGetStubAddrArg(GenTreeCall* call);
5254 void fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCall* recursiveTailCall);
5255 GenTree* fgAssignRecursiveCallArgToCallerParam(GenTree* arg,
5256 fgArgTabEntry* argTabEntry,
5258 IL_OFFSETX callILOffset,
5259 GenTree* tmpAssignmentInsertionPoint,
5260 GenTree* paramAssignmentInsertionPoint);
5261 static int fgEstimateCallStackSize(GenTreeCall* call);
5262 GenTree* fgMorphCall(GenTreeCall* call);
5263 void fgMorphCallInline(GenTreeCall* call, InlineResult* result);
5264 void fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result);
5266 void fgNoteNonInlineCandidate(GenTreeStmt* stmt, GenTreeCall* call);
5267 static fgWalkPreFn fgFindNonInlineCandidate;
5269 GenTree* fgOptimizeDelegateConstructor(GenTreeCall* call,
5270 CORINFO_CONTEXT_HANDLE* ExactContextHnd,
5271 CORINFO_RESOLVED_TOKEN* ldftnToken);
5272 GenTree* fgMorphLeaf(GenTree* tree);
5273 void fgAssignSetVarDef(GenTree* tree);
5274 GenTree* fgMorphOneAsgBlockOp(GenTree* tree);
5275 GenTree* fgMorphInitBlock(GenTree* tree);
5276 GenTree* fgMorphPromoteLocalInitBlock(GenTreeLclVar* destLclNode, GenTree* initVal, unsigned blockSize);
5277 GenTree* fgMorphBlkToInd(GenTreeBlk* tree, var_types type);
5278 GenTree* fgMorphGetStructAddr(GenTree** pTree, CORINFO_CLASS_HANDLE clsHnd, bool isRValue = false);
5279 GenTree* fgMorphBlkNode(GenTree* tree, bool isDest);
5280 GenTree* fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigned blockWidth, bool isDest);
5281 void fgMorphUnsafeBlk(GenTreeObj* obj);
5282 GenTree* fgMorphCopyBlock(GenTree* tree);
5283 GenTree* fgMorphForRegisterFP(GenTree* tree);
5284 GenTree* fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac = nullptr);
5285 GenTree* fgMorphModToSubMulDiv(GenTreeOp* tree);
5286 GenTree* fgMorphSmpOpOptional(GenTreeOp* tree);
5287 GenTree* fgMorphRecognizeBoxNullable(GenTree* compare);
5289 GenTree* fgMorphToEmulatedFP(GenTree* tree);
5290 GenTree* fgMorphConst(GenTree* tree);
5293 GenTree* fgMorphTree(GenTree* tree, MorphAddrContext* mac = nullptr);
5296 #if LOCAL_ASSERTION_PROP
5297 void fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTree* tree));
5298 void fgKillDependentAssertions(unsigned lclNum DEBUGARG(GenTree* tree));
5300 void fgMorphTreeDone(GenTree* tree, GenTree* oldTree = nullptr DEBUGARG(int morphNum = 0));
5302 GenTreeStmt* fgMorphStmt;
5304 unsigned fgGetBigOffsetMorphingTemp(var_types type); // We cache one temp per type to be
5305 // used when morphing big offset.
5307 //----------------------- Liveness analysis -------------------------------
5309 VARSET_TP fgCurUseSet; // vars used by block (before an assignment)
5310 VARSET_TP fgCurDefSet; // vars assigned by block (before a use)
5312 MemoryKindSet fgCurMemoryUse; // True iff the current basic block uses memory.
5313 MemoryKindSet fgCurMemoryDef; // True iff the current basic block modifies memory.
5314 MemoryKindSet fgCurMemoryHavoc; // True if the current basic block is known to set memory to a "havoc" value.
5316 bool byrefStatesMatchGcHeapStates; // True iff GcHeap and ByrefExposed memory have all the same def points.
5318 void fgMarkUseDef(GenTreeLclVarCommon* tree);
5320 void fgBeginScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
5321 void fgEndScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
5323 void fgMarkInScope(BasicBlock* block, VARSET_VALARG_TP inScope);
5324 void fgUnmarkInScope(BasicBlock* block, VARSET_VALARG_TP unmarkScope);
5326 void fgExtendDbgScopes();
5327 void fgExtendDbgLifetimes();
5330 void fgDispDebugScopes();
5333 //-------------------------------------------------------------------------
5335 // The following keeps track of any code we've added for things like array
5336 // range checking or explicit calls to enable GC, and so on.
5341 AddCodeDsc* acdNext;
5342 BasicBlock* acdDstBlk; // block to which we jump
5344 SpecialCodeKind acdKind; // what kind of a special block is this?
5345 #if !FEATURE_FIXED_OUT_ARGS
5346 bool acdStkLvlInit; // has acdStkLvl value been already set?
5348 #endif // !FEATURE_FIXED_OUT_ARGS
5352 static unsigned acdHelper(SpecialCodeKind codeKind);
5354 AddCodeDsc* fgAddCodeList;
5356 bool fgRngChkThrowAdded;
5357 AddCodeDsc* fgExcptnTargetCache[SCK_COUNT];
5359 BasicBlock* fgRngChkTarget(BasicBlock* block, SpecialCodeKind kind);
5361 BasicBlock* fgAddCodeRef(BasicBlock* srcBlk, unsigned refData, SpecialCodeKind kind);
5364 AddCodeDsc* fgFindExcptnTarget(SpecialCodeKind kind, unsigned refData);
5366 bool fgUseThrowHelperBlocks();
5368 AddCodeDsc* fgGetAdditionalCodeDescriptors()
5370 return fgAddCodeList;
5374 bool fgIsCodeAdded();
5376 bool fgIsThrowHlpBlk(BasicBlock* block);
5378 #if !FEATURE_FIXED_OUT_ARGS
5379 unsigned fgThrowHlpBlkStkLevel(BasicBlock* block);
5380 #endif // !FEATURE_FIXED_OUT_ARGS
5382 unsigned fgBigOffsetMorphingTemps[TYP_COUNT];
5384 unsigned fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo);
5385 void fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* result);
5386 void fgInsertInlineeBlocks(InlineInfo* pInlineInfo);
5387 GenTree* fgInlinePrependStatements(InlineInfo* inlineInfo);
5388 void fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, GenTree* stmt);
5390 #if FEATURE_MULTIREG_RET
5391 GenTree* fgGetStructAsStructPtr(GenTree* tree);
5392 GenTree* fgAssignStructInlineeToVar(GenTree* child, CORINFO_CLASS_HANDLE retClsHnd);
5393 void fgAttachStructInlineeToAsg(GenTree* tree, GenTree* child, CORINFO_CLASS_HANDLE retClsHnd);
5394 #endif // FEATURE_MULTIREG_RET
5396 static fgWalkPreFn fgUpdateInlineReturnExpressionPlaceHolder;
5397 static fgWalkPostFn fgLateDevirtualization;
5400 static fgWalkPreFn fgDebugCheckInlineCandidates;
5402 void CheckNoTransformableIndirectCallsRemain();
5403 static fgWalkPreFn fgDebugCheckForTransformableIndirectCalls;
5406 void fgPromoteStructs();
5407 void fgMorphStructField(GenTree* tree, GenTree* parent);
5408 void fgMorphLocalField(GenTree* tree, GenTree* parent);
5410 // Identify which parameters are implicit byrefs, and flag their LclVarDscs.
5411 void fgMarkImplicitByRefArgs();
5413 // Change implicit byrefs' types from struct to pointer, and for any that were
5414 // promoted, create new promoted struct temps.
5415 void fgRetypeImplicitByRefArgs();
5417 // Rewrite appearances of implicit byrefs (manifest the implied additional level of indirection).
5418 bool fgMorphImplicitByRefArgs(GenTree* tree);
5419 GenTree* fgMorphImplicitByRefArgs(GenTree* tree, bool isAddr);
5421 // Clear up annotations for any struct promotion temps created for implicit byrefs.
5422 void fgMarkDemotedImplicitByRefArgs();
5424 void fgMarkAddressExposedLocals();
5426 static fgWalkPreFn fgUpdateSideEffectsPre;
5427 static fgWalkPostFn fgUpdateSideEffectsPost;
5429 // The given local variable, required to be a struct variable, is being assigned via
5430 // a "lclField", to make it masquerade as an integral type in the ABI. Make sure that
5431 // the variable is not enregistered, and is therefore not promoted independently.
5432 void fgLclFldAssign(unsigned lclNum);
5434 static fgWalkPreFn gtHasLocalsWithAddrOpCB;
5436 enum TypeProducerKind
5438 TPK_Unknown = 0, // May not be a RuntimeType
5439 TPK_Handle = 1, // RuntimeType via handle
5440 TPK_GetType = 2, // RuntimeType via Object.get_Type()
5441 TPK_Null = 3, // Tree value is null
5442 TPK_Other = 4 // RuntimeType via other means
5445 TypeProducerKind gtGetTypeProducerKind(GenTree* tree);
5446 bool gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call);
5447 bool gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper = nullptr);
5448 bool gtIsActiveCSE_Candidate(GenTree* tree);
5451 bool fgPrintInlinedMethods;
5454 bool fgIsBigOffset(size_t offset);
5456 bool fgNeedReturnSpillTemp();
5459 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5460 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5464 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5465 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5471 void optRemoveRangeCheck(GenTree* tree, GenTree* stmt);
5472 bool optIsRangeCheckRemovable(GenTree* tree);
5475 static fgWalkPreFn optValidRangeCheckIndex;
5477 /**************************************************************************
5479 *************************************************************************/
5482 // Do hoisting for all loops.
5483 void optHoistLoopCode();
5485 // To represent sets of VN's that have already been hoisted in outer loops.
5486 typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, bool> VNToBoolMap;
5487 typedef VNToBoolMap VNSet;
5489 struct LoopHoistContext
5492 // The set of variables hoisted in the current loop (or nullptr if there are none).
5493 VNSet* m_pHoistedInCurLoop;
5496 // Value numbers of expressions that have been hoisted in parent loops in the loop nest.
5497 VNSet m_hoistedInParentLoops;
5498 // Value numbers of expressions that have been hoisted in the current (or most recent) loop in the nest.
5499 // Previous decisions on loop-invariance of value numbers in the current loop.
5500 VNToBoolMap m_curLoopVnInvariantCache;
5502 VNSet* GetHoistedInCurLoop(Compiler* comp)
5504 if (m_pHoistedInCurLoop == nullptr)
5506 m_pHoistedInCurLoop = new (comp->getAllocatorLoopHoist()) VNSet(comp->getAllocatorLoopHoist());
5508 return m_pHoistedInCurLoop;
5511 VNSet* ExtractHoistedInCurLoop()
5513 VNSet* res = m_pHoistedInCurLoop;
5514 m_pHoistedInCurLoop = nullptr;
5518 LoopHoistContext(Compiler* comp)
5519 : m_pHoistedInCurLoop(nullptr)
5520 , m_hoistedInParentLoops(comp->getAllocatorLoopHoist())
5521 , m_curLoopVnInvariantCache(comp->getAllocatorLoopHoist())
5526 // Do hoisting for loop "lnum" (an index into the optLoopTable), and all loops nested within it.
5527 // Tracks the expressions that have been hoisted by containing loops by temporary recording their
5528 // value numbers in "m_hoistedInParentLoops". This set is not modified by the call.
5529 void optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);
5531 // Do hoisting for a particular loop ("lnum" is an index into the optLoopTable.)
5532 // Assumes that expressions have been hoisted in containing loops if their value numbers are in
5533 // "m_hoistedInParentLoops".
5535 void optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt);
5537 // Hoist all expressions in "blk" that are invariant in loop "lnum" (an index into the optLoopTable)
5538 // outside of that loop. Exempt expressions whose value number is in "m_hoistedInParentLoops"; add VN's of hoisted
5539 // expressions to "hoistInLoop".
5540 void optHoistLoopExprsForBlock(BasicBlock* blk, unsigned lnum, LoopHoistContext* hoistCtxt);
5542 // Return true if the tree looks profitable to hoist out of loop 'lnum'.
5543 bool optIsProfitableToHoistableTree(GenTree* tree, unsigned lnum);
5545 // Hoist all proper sub-expressions of "tree" (which occurs in "stmt", which occurs in "blk")
5546 // that are invariant in loop "lnum" (an index into the optLoopTable)
5547 // outside of that loop. Exempt expressions whose value number is in "hoistedInParents"; add VN's of hoisted
5548 // expressions to "hoistInLoop".
5549 // Returns "true" iff "tree" is loop-invariant (wrt "lnum").
5550 // Assumes that the value of "*firstBlockAndBeforeSideEffect" indicates that we're in the first block, and before
5551 // any possible globally visible side effects. Assume is called in evaluation order, and updates this.
5552 bool optHoistLoopExprsForTree(GenTree* tree,
5554 LoopHoistContext* hoistCtxt,
5555 bool* firstBlockAndBeforeSideEffect,
5557 bool* pCctorDependent);
5559 // Performs the hoisting 'tree' into the PreHeader for loop 'lnum'
5560 void optHoistCandidate(GenTree* tree, unsigned lnum, LoopHoistContext* hoistCtxt);
5562 // Returns true iff the ValueNum "vn" represents a value that is loop-invariant in "lnum".
5563 // Constants and init values are always loop invariant.
5564 // VNPhi's connect VN's to the SSA definition, so we can know if the SSA def occurs in the loop.
5565 bool optVNIsLoopInvariant(ValueNum vn, unsigned lnum, VNToBoolMap* recordedVNs);
5567 // Returns "true" iff "tree" is valid at the head of loop "lnum", in the context of the hoist substitution
5568 // "subst". If "tree" is a local SSA var, it is valid if its SSA definition occurs outside of the loop, or
5569 // if it is in the domain of "subst" (meaning that it's definition has been previously hoisted, with a "standin"
5570 // local.) If tree is a constant, it is valid. Otherwise, if it is an operator, it is valid iff its children are.
5571 bool optTreeIsValidAtLoopHead(GenTree* tree, unsigned lnum);
5573 // If "blk" is the entry block of a natural loop, returns true and sets "*pLnum" to the index of the loop
5574 // in the loop table.
5575 bool optBlockIsLoopEntry(BasicBlock* blk, unsigned* pLnum);
5577 // Records the set of "side effects" of all loops: fields (object instance and static)
5578 // written to, and SZ-array element type equivalence classes updated.
5579 void optComputeLoopSideEffects();
5582 // Requires "lnum" to be the index of an outermost loop in the loop table. Traverses the body of that loop,
5583 // including all nested loops, and records the set of "side effects" of the loop: fields (object instance and
5584 // static) written to, and SZ-array element type equivalence classes updated.
5585 void optComputeLoopNestSideEffects(unsigned lnum);
5587 // Add the side effects of "blk" (which is required to be within a loop) to all loops of which it is a part.
5588 void optComputeLoopSideEffectsOfBlock(BasicBlock* blk);
5590 // Hoist the expression "expr" out of loop "lnum".
5591 void optPerformHoistExpr(GenTree* expr, unsigned lnum);
5594 void optOptimizeBools();
5597 GenTree* optIsBoolCond(GenTree* condBranch, GenTree** compPtr, bool* boolPtr);
5599 void optOptimizeBoolsGcStress(BasicBlock* condBlock);
5602 void optOptimizeLayout(); // Optimize the BasicBlock layout of the method
5604 void optOptimizeLoops(); // for "while-do" loops duplicates simple loop conditions and transforms
5605 // the loop into a "do-while" loop
5606 // Also finds all natural loops and records them in the loop table
5608 // Optionally clone loops in the loop table.
5609 void optCloneLoops();
5611 // Clone loop "loopInd" in the loop table.
5612 void optCloneLoop(unsigned loopInd, LoopCloneContext* context);
5614 // Ensure that loop "loopInd" has a unique head block. (If the existing entry has
5615 // non-loop predecessors other than the head entry, create a new, empty block that goes (only) to the entry,
5616 // and redirects the preds of the entry to this new block.) Sets the weight of the newly created block to
5618 void optEnsureUniqueHead(unsigned loopInd, unsigned ambientWeight);
5620 void optUnrollLoops(); // Unrolls loops (needs to have cost info)
5623 // This enumeration describes what is killed by a call.
5627 CALLINT_NONE, // no interference (most helpers)
5628 CALLINT_REF_INDIRS, // kills GC ref indirections (SETFIELD OBJ)
5629 CALLINT_SCL_INDIRS, // kills non GC ref indirections (SETFIELD non-OBJ)
5630 CALLINT_ALL_INDIRS, // kills both GC ref and non GC ref indirections (SETFIELD STRUCT)
5631 CALLINT_ALL, // kills everything (normal method call)
5635 // A "LoopDsc" describes a ("natural") loop. We (currently) require the body of a loop to be a contiguous (in
5636 // bbNext order) sequence of basic blocks. (At times, we may require the blocks in a loop to be "properly numbered"
5637 // in bbNext order; we use comparisons on the bbNum to decide order.)
5638 // The blocks that define the body are
5639 // first <= top <= entry <= bottom .
5640 // The "head" of the loop is a block outside the loop that has "entry" as a successor. We only support loops with a
5641 // single 'head' block. The meanings of these blocks are given in the definitions below. Also see the picture at
5642 // Compiler::optFindNaturalLoops().
5645 BasicBlock* lpHead; // HEAD of the loop (not part of the looping of the loop) -- has ENTRY as a successor.
5646 BasicBlock* lpFirst; // FIRST block (in bbNext order) reachable within this loop. (May be part of a nested
5647 // loop, but not the outer loop.)
5648 BasicBlock* lpTop; // loop TOP (the back edge from lpBottom reaches here) (in most cases FIRST and TOP are the
5650 BasicBlock* lpEntry; // the ENTRY in the loop (in most cases TOP or BOTTOM)
5651 BasicBlock* lpBottom; // loop BOTTOM (from here we have a back edge to the TOP)
5652 BasicBlock* lpExit; // if a single exit loop this is the EXIT (in most cases BOTTOM)
5654 callInterf lpAsgCall; // "callInterf" for calls in the loop
5655 ALLVARSET_TP lpAsgVars; // set of vars assigned within the loop (all vars, not just tracked)
5656 varRefKinds lpAsgInds : 8; // set of inds modified within the loop
5658 unsigned short lpFlags; // Mask of the LPFLG_* constants
5660 unsigned char lpExitCnt; // number of exits from the loop
5662 unsigned char lpParent; // The index of the most-nested loop that completely contains this one,
5663 // or else BasicBlock::NOT_IN_LOOP if no such loop exists.
5664 unsigned char lpChild; // The index of a nested loop, or else BasicBlock::NOT_IN_LOOP if no child exists.
5665 // (Actually, an "immediately" nested loop --
5666 // no other child of this loop is a parent of lpChild.)
5667 unsigned char lpSibling; // The index of another loop that is an immediate child of lpParent,
5668 // or else BasicBlock::NOT_IN_LOOP. One can enumerate all the children of a loop
5669 // by following "lpChild" then "lpSibling" links.
5671 #define LPFLG_DO_WHILE 0x0001 // it's a do-while loop (i.e ENTRY is at the TOP)
5672 #define LPFLG_ONE_EXIT 0x0002 // the loop has only one exit
5674 #define LPFLG_ITER 0x0004 // for (i = icon or lclVar; test_condition(); i++)
5675 #define LPFLG_HOISTABLE 0x0008 // the loop is in a form that is suitable for hoisting expressions
5676 #define LPFLG_CONST 0x0010 // for (i=icon;i<icon;i++){ ... } - constant loop
5678 #define LPFLG_VAR_INIT 0x0020 // iterator is initialized with a local var (var # found in lpVarInit)
5679 #define LPFLG_CONST_INIT 0x0040 // iterator is initialized with a constant (found in lpConstInit)
5681 #define LPFLG_VAR_LIMIT 0x0100 // iterator is compared with a local var (var # found in lpVarLimit)
5682 #define LPFLG_CONST_LIMIT 0x0200 // iterator is compared with a constant (found in lpConstLimit)
5683 #define LPFLG_ARRLEN_LIMIT 0x0400 // iterator is compared with a.len or a[i].len (found in lpArrLenLimit)
5684 #define LPFLG_SIMD_LIMIT 0x0080 // iterator is compared with Vector<T>.Count (found in lpConstLimit)
5686 #define LPFLG_HAS_PREHEAD 0x0800 // lpHead is known to be a preHead for this loop
5687 #define LPFLG_REMOVED 0x1000 // has been removed from the loop table (unrolled or optimized away)
5688 #define LPFLG_DONT_UNROLL 0x2000 // do not unroll this loop
5690 #define LPFLG_ASGVARS_YES 0x4000 // "lpAsgVars" has been computed
5691 #define LPFLG_ASGVARS_INC 0x8000 // "lpAsgVars" is incomplete -- vars beyond those representable in an AllVarSet
5692 // type are assigned to.
5694 bool lpLoopHasMemoryHavoc[MemoryKindCount]; // The loop contains an operation that we assume has arbitrary
5695 // memory side effects. If this is set, the fields below
5696 // may not be accurate (since they become irrelevant.)
5697 bool lpContainsCall; // True if executing the loop body *may* execute a call
5699 VARSET_TP lpVarInOut; // The set of variables that are IN or OUT during the execution of this loop
5700 VARSET_TP lpVarUseDef; // The set of variables that are USE or DEF during the execution of this loop
5702 int lpHoistedExprCount; // The register count for the non-FP expressions from inside this loop that have been
5704 int lpLoopVarCount; // The register count for the non-FP LclVars that are read/written inside this loop
5705 int lpVarInOutCount; // The register count for the non-FP LclVars that are alive inside or accross this loop
5707 int lpHoistedFPExprCount; // The register count for the FP expressions from inside this loop that have been
5709 int lpLoopVarFPCount; // The register count for the FP LclVars that are read/written inside this loop
5710 int lpVarInOutFPCount; // The register count for the FP LclVars that are alive inside or accross this loop
5712 typedef JitHashTable<CORINFO_FIELD_HANDLE, JitPtrKeyFuncs<struct CORINFO_FIELD_STRUCT_>, bool> FieldHandleSet;
5713 FieldHandleSet* lpFieldsModified; // This has entries (mappings to "true") for all static field and object
5714 // instance fields modified
5717 typedef JitHashTable<CORINFO_CLASS_HANDLE, JitPtrKeyFuncs<struct CORINFO_CLASS_STRUCT_>, bool> ClassHandleSet;
5718 ClassHandleSet* lpArrayElemTypesModified; // Bits set indicate the set of sz array element types such that
5719 // arrays of that type are modified
5722 // Adds the variable liveness information for 'blk' to 'this' LoopDsc
5723 void AddVariableLiveness(Compiler* comp, BasicBlock* blk);
5725 inline void AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd);
5726 // This doesn't *always* take a class handle -- it can also take primitive types, encoded as class handles
5727 // (shifted left, with a low-order bit set to distinguish.)
5728 // Use the {Encode/Decode}ElemType methods to construct/destruct these.
5729 inline void AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd);
5731 /* The following values are set only for iterator loops, i.e. has the flag LPFLG_ITER set */
5733 GenTree* lpIterTree; // The "i = i <op> const" tree
5734 unsigned lpIterVar(); // iterator variable #
5735 int lpIterConst(); // the constant with which the iterator is incremented
5736 genTreeOps lpIterOper(); // the type of the operation on the iterator (ASG_ADD, ASG_SUB, etc.)
5737 void VERIFY_lpIterTree();
5739 var_types lpIterOperType(); // For overflow instructions
5742 int lpConstInit; // initial constant value of iterator : Valid if LPFLG_CONST_INIT
5743 unsigned lpVarInit; // initial local var number to which we initialize the iterator : Valid if
5747 /* The following is for LPFLG_ITER loops only (i.e. the loop condition is "i RELOP const or var" */
5749 GenTree* lpTestTree; // pointer to the node containing the loop test
5750 genTreeOps lpTestOper(); // the type of the comparison between the iterator and the limit (GT_LE, GT_GE, etc.)
5751 void VERIFY_lpTestTree();
5753 bool lpIsReversed(); // true if the iterator node is the second operand in the loop condition
5754 GenTree* lpIterator(); // the iterator node in the loop test
5755 GenTree* lpLimit(); // the limit node in the loop test
5757 int lpConstLimit(); // limit constant value of iterator - loop condition is "i RELOP const" : Valid if
5758 // LPFLG_CONST_LIMIT
5759 unsigned lpVarLimit(); // the lclVar # in the loop condition ( "i RELOP lclVar" ) : Valid if
5761 bool lpArrLenLimit(Compiler* comp, ArrIndex* index); // The array length in the loop condition ( "i RELOP
5762 // arr.len" or "i RELOP arr[i][j].len" ) : Valid if
5763 // LPFLG_ARRLEN_LIMIT
5765 // Returns "true" iff "*this" contains the blk.
5766 bool lpContains(BasicBlock* blk)
5768 return lpFirst->bbNum <= blk->bbNum && blk->bbNum <= lpBottom->bbNum;
5770 // Returns "true" iff "*this" (properly) contains the range [first, bottom] (allowing firsts
5771 // to be equal, but requiring bottoms to be different.)
5772 bool lpContains(BasicBlock* first, BasicBlock* bottom)
5774 return lpFirst->bbNum <= first->bbNum && bottom->bbNum < lpBottom->bbNum;
5777 // Returns "true" iff "*this" (properly) contains "lp2" (allowing firsts to be equal, but requiring
5778 // bottoms to be different.)
5779 bool lpContains(const LoopDsc& lp2)
5781 return lpContains(lp2.lpFirst, lp2.lpBottom);
5784 // Returns "true" iff "*this" is (properly) contained by the range [first, bottom]
5785 // (allowing firsts to be equal, but requiring bottoms to be different.)
5786 bool lpContainedBy(BasicBlock* first, BasicBlock* bottom)
5788 return first->bbNum <= lpFirst->bbNum && lpBottom->bbNum < bottom->bbNum;
5791 // Returns "true" iff "*this" is (properly) contained by "lp2"
5792 // (allowing firsts to be equal, but requiring bottoms to be different.)
5793 bool lpContainedBy(const LoopDsc& lp2)
5795 return lpContains(lp2.lpFirst, lp2.lpBottom);
5798 // Returns "true" iff "*this" is disjoint from the range [top, bottom].
5799 bool lpDisjoint(BasicBlock* first, BasicBlock* bottom)
5801 return bottom->bbNum < lpFirst->bbNum || lpBottom->bbNum < first->bbNum;
5803 // Returns "true" iff "*this" is disjoint from "lp2".
5804 bool lpDisjoint(const LoopDsc& lp2)
5806 return lpDisjoint(lp2.lpFirst, lp2.lpBottom);
5808 // Returns "true" iff the loop is well-formed (see code for defn).
5811 return lpFirst->bbNum <= lpTop->bbNum && lpTop->bbNum <= lpEntry->bbNum &&
5812 lpEntry->bbNum <= lpBottom->bbNum &&
5813 (lpHead->bbNum < lpTop->bbNum || lpHead->bbNum > lpBottom->bbNum);
5818 bool fgMightHaveLoop(); // returns true if there are any backedges
5819 bool fgHasLoops; // True if this method has any loops, set in fgComputeReachability
5822 LoopDsc* optLoopTable; // loop descriptor table
5823 unsigned char optLoopCount; // number of tracked loops
5825 bool optRecordLoop(BasicBlock* head,
5831 unsigned char exitCnt);
5834 unsigned optCallCount; // number of calls made in the method
5835 unsigned optIndirectCallCount; // number of virtual, interface and indirect calls made in the method
5836 unsigned optNativeCallCount; // number of Pinvoke/Native calls made in the method
5837 unsigned optLoopsCloned; // number of loops cloned in the current method.
5840 unsigned optFindLoopNumberFromBeginBlock(BasicBlock* begBlk);
5841 void optPrintLoopInfo(unsigned loopNum,
5843 BasicBlock* lpFirst,
5845 BasicBlock* lpEntry,
5846 BasicBlock* lpBottom,
5847 unsigned char lpExitCnt,
5849 unsigned parentLoop = BasicBlock::NOT_IN_LOOP);
5850 void optPrintLoopInfo(unsigned lnum);
5851 void optPrintLoopRecording(unsigned lnum);
5853 void optCheckPreds();
5856 void optSetBlockWeights();
5858 void optMarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk, bool excludeEndBlk);
5860 void optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk);
5862 void optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmarkLoop = false);
5864 bool optIsLoopTestEvalIntoTemp(GenTree* test, GenTree** newTest);
5865 unsigned optIsLoopIncrTree(GenTree* incr);
5866 bool optCheckIterInLoopTest(unsigned loopInd, GenTree* test, BasicBlock* from, BasicBlock* to, unsigned iterVar);
5867 bool optComputeIterInfo(GenTree* incr, BasicBlock* from, BasicBlock* to, unsigned* pIterVar);
5868 bool optPopulateInitInfo(unsigned loopInd, GenTree* init, unsigned iterVar);
5869 bool optExtractInitTestIncr(
5870 BasicBlock* head, BasicBlock* bottom, BasicBlock* exit, GenTree** ppInit, GenTree** ppTest, GenTree** ppIncr);
5872 void optFindNaturalLoops();
5874 // Ensures that all the loops in the loop nest rooted at "loopInd" (an index into the loop table) are 'canonical' --
5875 // each loop has a unique "top." Returns "true" iff the flowgraph has been modified.
5876 bool optCanonicalizeLoopNest(unsigned char loopInd);
5878 // Ensures that the loop "loopInd" (an index into the loop table) is 'canonical' -- it has a unique "top,"
5879 // unshared with any other loop. Returns "true" iff the flowgraph has been modified
5880 bool optCanonicalizeLoop(unsigned char loopInd);
5882 // Requires "l1" to be a valid loop table index, and not "BasicBlock::NOT_IN_LOOP". Requires "l2" to be
5883 // a valid loop table index, or else "BasicBlock::NOT_IN_LOOP". Returns true
5884 // iff "l2" is not NOT_IN_LOOP, and "l1" contains "l2".
5885 bool optLoopContains(unsigned l1, unsigned l2);
5887 // Requires "loopInd" to be a valid index into the loop table.
5888 // Updates the loop table by changing loop "loopInd", whose head is required
5889 // to be "from", to be "to". Also performs this transformation for any
5890 // loop nested in "loopInd" that shares the same head as "loopInd".
5891 void optUpdateLoopHead(unsigned loopInd, BasicBlock* from, BasicBlock* to);
5893 // Updates the successors of "blk": if "blk2" is a successor of "blk", and there is a mapping for "blk2->blk3" in
5894 // "redirectMap", change "blk" so that "blk3" is this successor. Note that the predecessor lists are not updated.
5895 void optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap);
5897 // Marks the containsCall information to "lnum" and any parent loops.
5898 void AddContainsCallAllContainingLoops(unsigned lnum);
5899 // Adds the variable liveness information from 'blk' to "lnum" and any parent loops.
5900 void AddVariableLivenessAllContainingLoops(unsigned lnum, BasicBlock* blk);
5901 // Adds "fldHnd" to the set of modified fields of "lnum" and any parent loops.
5902 void AddModifiedFieldAllContainingLoops(unsigned lnum, CORINFO_FIELD_HANDLE fldHnd);
5903 // Adds "elemType" to the set of modified array element types of "lnum" and any parent loops.
5904 void AddModifiedElemTypeAllContainingLoops(unsigned lnum, CORINFO_CLASS_HANDLE elemType);
5906 // Requires that "from" and "to" have the same "bbJumpKind" (perhaps because "to" is a clone
5907 // of "from".) Copies the jump destination from "from" to "to".
5908 void optCopyBlkDest(BasicBlock* from, BasicBlock* to);
5910 // The depth of the loop described by "lnum" (an index into the loop table.) (0 == top level)
5911 unsigned optLoopDepth(unsigned lnum)
5913 unsigned par = optLoopTable[lnum].lpParent;
5914 if (par == BasicBlock::NOT_IN_LOOP)
5920 return 1 + optLoopDepth(par);
5924 void fgOptWhileLoop(BasicBlock* block);
5926 bool optComputeLoopRep(int constInit,
5929 genTreeOps iterOper,
5931 genTreeOps testOper,
5934 unsigned* iterCount);
5937 static fgWalkPreFn optIsVarAssgCB;
5940 bool optIsVarAssigned(BasicBlock* beg, BasicBlock* end, GenTree* skip, unsigned var);
5942 bool optIsVarAssgLoop(unsigned lnum, unsigned var);
5944 int optIsSetAssgLoop(unsigned lnum, ALLVARSET_VALARG_TP vars, varRefKinds inds = VR_NONE);
5946 bool optNarrowTree(GenTree* tree, var_types srct, var_types dstt, ValueNumPair vnpNarrow, bool doit);
5948 /**************************************************************************
5949 * Optimization conditions
5950 *************************************************************************/
5952 bool optFastCodeOrBlendedLoop(BasicBlock::weight_t bbWeight);
5953 bool optPentium4(void);
5954 bool optAvoidIncDec(BasicBlock::weight_t bbWeight);
5955 bool optAvoidIntMult(void);
5960 // The following is the upper limit on how many expressions we'll keep track
5961 // of for the CSE analysis.
5963 static const unsigned MAX_CSE_CNT = EXPSET_SZ;
5965 static const int MIN_CSE_COST = 2;
5967 // Keeps tracked cse indices
5968 BitVecTraits* cseTraits;
5971 /* Generic list of nodes - used by the CSE logic */
5981 treeStmtLst* tslNext;
5982 GenTree* tslTree; // tree node
5983 GenTree* tslStmt; // statement containing the tree
5984 BasicBlock* tslBlock; // block containing the statement
5987 // The following logic keeps track of expressions via a simple hash table.
5991 CSEdsc* csdNextInBucket; // used by the hash table
5993 unsigned csdHashKey; // the orginal hashkey
5995 unsigned csdIndex; // 1..optCSECandidateCount
5996 char csdLiveAcrossCall; // 0 or 1
5998 unsigned short csdDefCount; // definition count
5999 unsigned short csdUseCount; // use count (excluding the implicit uses at defs)
6001 unsigned csdDefWtCnt; // weighted def count
6002 unsigned csdUseWtCnt; // weighted use count (excluding the implicit uses at defs)
6004 GenTree* csdTree; // treenode containing the 1st occurance
6005 GenTree* csdStmt; // stmt containing the 1st occurance
6006 BasicBlock* csdBlock; // block containing the 1st occurance
6008 treeStmtLst* csdTreeList; // list of matching tree nodes: head
6009 treeStmtLst* csdTreeLast; // list of matching tree nodes: tail
6011 ValueNum defExcSetPromise; // The exception set that is now required for all defs of this CSE.
6012 // This will be set to NoVN if we decide to abandon this CSE
6014 ValueNum defExcSetCurrent; // The set of exceptions we currently can use for CSE uses.
6016 ValueNum defConservNormVN; // if all def occurrences share the same conservative normal value
6017 // number, this will reflect it; otherwise, NoVN.
6020 static const size_t s_optCSEhashSize;
6021 CSEdsc** optCSEhash;
6024 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, GenTree*> NodeToNodeMap;
6026 NodeToNodeMap* optCseCheckedBoundMap; // Maps bound nodes to ancestor compares that should be
6027 // re-numbered with the bound to improve range check elimination
6029 // Given a compare, look for a cse candidate checked bound feeding it and add a map entry if found.
6030 void optCseUpdateCheckedBoundMap(GenTree* compare);
6034 CSEdsc* optCSEfindDsc(unsigned index);
6035 bool optUnmarkCSE(GenTree* tree);
6037 // user defined callback data for the tree walk function optCSE_MaskHelper()
6038 struct optCSE_MaskData
6040 EXPSET_TP CSE_defMask;
6041 EXPSET_TP CSE_useMask;
6044 // Treewalk helper for optCSE_DefMask and optCSE_UseMask
6045 static fgWalkPreFn optCSE_MaskHelper;
6047 // This function walks all the node for an given tree
6048 // and return the mask of CSE definitions and uses for the tree
6050 void optCSE_GetMaskData(GenTree* tree, optCSE_MaskData* pMaskData);
6052 // Given a binary tree node return true if it is safe to swap the order of evaluation for op1 and op2.
6053 bool optCSE_canSwap(GenTree* firstNode, GenTree* secondNode);
6054 bool optCSE_canSwap(GenTree* tree);
6056 static int __cdecl optCSEcostCmpEx(const void* op1, const void* op2);
6057 static int __cdecl optCSEcostCmpSz(const void* op1, const void* op2);
6059 void optCleanupCSEs();
6062 void optEnsureClearCSEInfo();
6065 #endif // FEATURE_ANYCSE
6067 #if FEATURE_VALNUM_CSE
6068 /**************************************************************************
6069 * Value Number based CSEs
6070 *************************************************************************/
6073 void optOptimizeValnumCSEs();
6076 void optValnumCSE_Init();
6077 unsigned optValnumCSE_Index(GenTree* tree, GenTree* stmt);
6078 unsigned optValnumCSE_Locate();
6079 void optValnumCSE_InitDataFlow();
6080 void optValnumCSE_DataFlow();
6081 void optValnumCSE_Availablity();
6082 void optValnumCSE_Heuristic();
6084 #endif // FEATURE_VALNUM_CSE
6087 bool optDoCSE; // True when we have found a duplicate CSE tree
6088 bool optValnumCSE_phase; // True when we are executing the optValnumCSE_phase
6089 unsigned optCSECandidateTotal; // Grand total of CSE candidates for both Lexical and ValNum
6090 unsigned optCSECandidateCount; // Count of CSE's candidates, reset for Lexical and ValNum CSE's
6091 unsigned optCSEstart; // The first local variable number that is a CSE
6092 unsigned optCSEcount; // The total count of CSE's introduced.
6093 unsigned optCSEweight; // The weight of the current block when we are
6094 // scanning for CSE expressions
6096 bool optIsCSEcandidate(GenTree* tree);
6098 // lclNumIsTrueCSE returns true if the LclVar was introduced by the CSE phase of the compiler
6100 bool lclNumIsTrueCSE(unsigned lclNum) const
6102 return ((optCSEcount > 0) && (lclNum >= optCSEstart) && (lclNum < optCSEstart + optCSEcount));
6105 // lclNumIsCSE returns true if the LclVar should be treated like a CSE with regards to constant prop.
6107 bool lclNumIsCSE(unsigned lclNum) const
6109 return lvaTable[lclNum].lvIsCSE;
6113 bool optConfigDisableCSE();
6114 bool optConfigDisableCSE2();
6116 void optOptimizeCSEs();
6118 #endif // FEATURE_ANYCSE
6126 unsigned ivaVar; // Variable we are interested in, or -1
6127 ALLVARSET_TP ivaMaskVal; // Set of variables assigned to. This is a set of all vars, not tracked vars.
6128 bool ivaMaskIncomplete; // Variables not representable in ivaMaskVal were assigned to.
6129 varRefKinds ivaMaskInd; // What kind of indirect assignments are there?
6130 callInterf ivaMaskCall; // What kind of calls are there?
6133 static callInterf optCallInterf(GenTreeCall* call);
6136 // VN based copy propagation.
6137 typedef ArrayStack<GenTree*> GenTreePtrStack;
6138 typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, GenTreePtrStack*> LclNumToGenTreePtrStack;
6140 // Kill set to track variables with intervening definitions.
6141 VARSET_TP optCopyPropKillSet;
6143 // Copy propagation functions.
6144 void optCopyProp(BasicBlock* block, GenTree* stmt, GenTree* tree, LclNumToGenTreePtrStack* curSsaName);
6145 void optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
6146 void optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
6147 bool optIsSsaLocal(GenTree* tree);
6148 int optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2);
6149 void optVnCopyProp();
6150 INDEBUG(void optDumpCopyPropStack(LclNumToGenTreePtrStack* curSsaName));
6152 /**************************************************************************
6153 * Early value propagation
6154 *************************************************************************/
6160 SSAName(unsigned lvNum, unsigned ssaNum) : m_lvNum(lvNum), m_ssaNum(ssaNum)
6164 static unsigned GetHashCode(SSAName ssaNm)
6166 return (ssaNm.m_lvNum << 16) | (ssaNm.m_ssaNum);
6169 static bool Equals(SSAName ssaNm1, SSAName ssaNm2)
6171 return (ssaNm1.m_lvNum == ssaNm2.m_lvNum) && (ssaNm1.m_ssaNum == ssaNm2.m_ssaNum);
6175 #define OMF_HAS_NEWARRAY 0x00000001 // Method contains 'new' of an array
6176 #define OMF_HAS_NEWOBJ 0x00000002 // Method contains 'new' of an object type.
6177 #define OMF_HAS_ARRAYREF 0x00000004 // Method contains array element loads or stores.
6178 #define OMF_HAS_VTABLEREF 0x00000008 // Method contains method table reference.
6179 #define OMF_HAS_NULLCHECK 0x00000010 // Method contains null check.
6180 #define OMF_HAS_FATPOINTER 0x00000020 // Method contains call, that needs fat pointer transformation.
6181 #define OMF_HAS_OBJSTACKALLOC 0x00000040 // Method contains an object allocated on the stack.
6182 #define OMF_HAS_GUARDEDDEVIRT 0x00000080 // Method contains guarded devirtualization candidate
6184 bool doesMethodHaveFatPointer()
6186 return (optMethodFlags & OMF_HAS_FATPOINTER) != 0;
6189 void setMethodHasFatPointer()
6191 optMethodFlags |= OMF_HAS_FATPOINTER;
6194 void clearMethodHasFatPointer()
6196 optMethodFlags &= ~OMF_HAS_FATPOINTER;
6199 void addFatPointerCandidate(GenTreeCall* call);
6201 bool doesMethodHaveGuardedDevirtualization()
6203 return (optMethodFlags & OMF_HAS_GUARDEDDEVIRT) != 0;
6206 void setMethodHasGuardedDevirtualization()
6208 optMethodFlags |= OMF_HAS_GUARDEDDEVIRT;
6211 void clearMethodHasGuardedDevirtualization()
6213 optMethodFlags &= ~OMF_HAS_GUARDEDDEVIRT;
6216 void addGuardedDevirtualizationCandidate(GenTreeCall* call,
6217 CORINFO_METHOD_HANDLE methodHandle,
6218 CORINFO_CLASS_HANDLE classHandle,
6219 unsigned methodAttr,
6220 unsigned classAttr);
6222 unsigned optMethodFlags;
6224 // Recursion bound controls how far we can go backwards tracking for a SSA value.
6225 // No throughput diff was found with backward walk bound between 3-8.
6226 static const int optEarlyPropRecurBound = 5;
6228 enum class optPropKind
6236 bool gtIsVtableRef(GenTree* tree);
6237 GenTree* getArrayLengthFromAllocation(GenTree* tree);
6238 GenTree* getObjectHandleNodeFromAllocation(GenTree* tree);
6239 GenTree* optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropKind valueKind, int walkDepth);
6240 GenTree* optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind);
6241 GenTree* optEarlyPropRewriteTree(GenTree* tree);
6242 bool optDoEarlyPropForBlock(BasicBlock* block);
6243 bool optDoEarlyPropForFunc();
6244 void optEarlyProp();
6245 void optFoldNullCheck(GenTree* tree);
6246 bool optCanMoveNullCheckPastTree(GenTree* tree, bool isInsideTry);
6249 /**************************************************************************
6250 * Value/Assertion propagation
6251 *************************************************************************/
6253 // Data structures for assertion prop
6254 BitVecTraits* apTraits;
6257 enum optAssertionKind
6274 O1K_CONSTANT_LOOP_BND,
6295 optAssertionKind assertionKind;
6298 unsigned lclNum; // assigned to or property of this local var number
6306 struct AssertionDscOp1
6308 optOp1Kind kind; // a normal LclVar, or Exact-type or Subtype
6315 struct AssertionDscOp2
6317 optOp2Kind kind; // a const or copy assignment
6321 ssize_t iconVal; // integer
6322 unsigned iconFlags; // gtFlags
6324 struct Range // integer subrange
6338 bool IsCheckedBoundArithBound()
6340 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_BOUND_OPER_BND);
6342 bool IsCheckedBoundBound()
6344 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_BOUND_LOOP_BND);
6346 bool IsConstantBound()
6348 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) &&
6349 op1.kind == O1K_CONSTANT_LOOP_BND);
6351 bool IsBoundsCheckNoThrow()
6353 return ((assertionKind == OAK_NO_THROW) && (op1.kind == O1K_ARR_BND));
6356 bool IsCopyAssertion()
6358 return ((assertionKind == OAK_EQUAL) && (op1.kind == O1K_LCLVAR) && (op2.kind == O2K_LCLVAR_COPY));
6361 static bool SameKind(AssertionDsc* a1, AssertionDsc* a2)
6363 return a1->assertionKind == a2->assertionKind && a1->op1.kind == a2->op1.kind &&
6364 a1->op2.kind == a2->op2.kind;
6367 static bool ComplementaryKind(optAssertionKind kind, optAssertionKind kind2)
6369 if (kind == OAK_EQUAL)
6371 return kind2 == OAK_NOT_EQUAL;
6373 else if (kind == OAK_NOT_EQUAL)
6375 return kind2 == OAK_EQUAL;
6380 static ssize_t GetLowerBoundForIntegralType(var_types type)
6399 static ssize_t GetUpperBoundForIntegralType(var_types type)
6422 bool HasSameOp1(AssertionDsc* that, bool vnBased)
6424 if (op1.kind != that->op1.kind)
6428 else if (op1.kind == O1K_ARR_BND)
6431 return (op1.bnd.vnIdx == that->op1.bnd.vnIdx) && (op1.bnd.vnLen == that->op1.bnd.vnLen);
6435 return ((vnBased && (op1.vn == that->op1.vn)) ||
6436 (!vnBased && (op1.lcl.lclNum == that->op1.lcl.lclNum)));
6440 bool HasSameOp2(AssertionDsc* that, bool vnBased)
6442 if (op2.kind != that->op2.kind)
6448 case O2K_IND_CNS_INT:
6450 return ((op2.u1.iconVal == that->op2.u1.iconVal) && (op2.u1.iconFlags == that->op2.u1.iconFlags));
6452 case O2K_CONST_LONG:
6453 return (op2.lconVal == that->op2.lconVal);
6455 case O2K_CONST_DOUBLE:
6456 // exact match because of positive and negative zero.
6457 return (memcmp(&op2.dconVal, &that->op2.dconVal, sizeof(double)) == 0);
6459 case O2K_LCLVAR_COPY:
6461 return (op2.lcl.lclNum == that->op2.lcl.lclNum) &&
6462 (!vnBased || op2.lcl.ssaNum == that->op2.lcl.ssaNum);
6465 return ((op2.u2.loBound == that->op2.u2.loBound) && (op2.u2.hiBound == that->op2.u2.hiBound));
6468 // we will return false
6472 assert(!"Unexpected value for op2.kind in AssertionDsc.");
6478 bool Complementary(AssertionDsc* that, bool vnBased)
6480 return ComplementaryKind(assertionKind, that->assertionKind) && HasSameOp1(that, vnBased) &&
6481 HasSameOp2(that, vnBased);
6484 bool Equals(AssertionDsc* that, bool vnBased)
6486 if (assertionKind != that->assertionKind)
6490 else if (assertionKind == OAK_NO_THROW)
6492 assert(op2.kind == O2K_INVALID);
6493 return HasSameOp1(that, vnBased);
6497 return HasSameOp1(that, vnBased) && HasSameOp2(that, vnBased);
6503 static fgWalkPreFn optAddCopiesCallback;
6504 static fgWalkPreFn optVNAssertionPropCurStmtVisitor;
6505 unsigned optAddCopyLclNum;
6506 GenTree* optAddCopyAsgnNode;
6508 bool optLocalAssertionProp; // indicates that we are performing local assertion prop
6509 bool optAssertionPropagated; // set to true if we modified the trees
6510 bool optAssertionPropagatedCurrentStmt;
6512 GenTree* optAssertionPropCurrentTree;
6514 AssertionIndex* optComplementaryAssertionMap;
6515 JitExpandArray<ASSERT_TP>* optAssertionDep; // table that holds dependent assertions (assertions
6516 // using the value of a local var) for each local var
6517 AssertionDsc* optAssertionTabPrivate; // table that holds info about value assignments
6518 AssertionIndex optAssertionCount; // total number of assertions in the assertion table
6519 AssertionIndex optMaxAssertionCount;
6522 void optVnNonNullPropCurStmt(BasicBlock* block, GenTree* stmt, GenTree* tree);
6523 fgWalkResult optVNConstantPropCurStmt(BasicBlock* block, GenTree* stmt, GenTree* tree);
6524 GenTree* optVNConstantPropOnJTrue(BasicBlock* block, GenTree* stmt, GenTree* test);
6525 GenTree* optVNConstantPropOnTree(BasicBlock* block, GenTree* stmt, GenTree* tree);
6526 GenTree* optPrepareTreeForReplacement(GenTree* extractTree, GenTree* replaceTree);
6528 AssertionIndex GetAssertionCount()
6530 return optAssertionCount;
6532 ASSERT_TP* bbJtrueAssertionOut;
6533 typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, ASSERT_TP> ValueNumToAssertsMap;
6534 ValueNumToAssertsMap* optValueNumToAsserts;
6536 // Assertion prop helpers.
6537 ASSERT_TP& GetAssertionDep(unsigned lclNum);
6538 AssertionDsc* optGetAssertion(AssertionIndex assertIndex);
6539 void optAssertionInit(bool isLocalProp);
6540 void optAssertionTraitsInit(AssertionIndex assertionCount);
6541 #if LOCAL_ASSERTION_PROP
6542 void optAssertionReset(AssertionIndex limit);
6543 void optAssertionRemove(AssertionIndex index);
6546 // Assertion prop data flow functions.
6547 void optAssertionPropMain();
6548 GenTree* optVNAssertionPropCurStmt(BasicBlock* block, GenTree* stmt);
6549 bool optIsTreeKnownIntValue(bool vnBased, GenTree* tree, ssize_t* pConstant, unsigned* pIconFlags);
6550 ASSERT_TP* optInitAssertionDataflowFlags();
6551 ASSERT_TP* optComputeAssertionGen();
6553 // Assertion Gen functions.
6554 void optAssertionGen(GenTree* tree);
6555 AssertionIndex optAssertionGenPhiDefn(GenTree* tree);
6556 AssertionInfo optCreateJTrueBoundsAssertion(GenTree* tree);
6557 AssertionInfo optAssertionGenJtrue(GenTree* tree);
6558 AssertionIndex optCreateJtrueAssertions(GenTree* op1, GenTree* op2, Compiler::optAssertionKind assertionKind);
6559 AssertionIndex optFindComplementary(AssertionIndex assertionIndex);
6560 void optMapComplementary(AssertionIndex assertionIndex, AssertionIndex index);
6562 // Assertion creation functions.
6563 AssertionIndex optCreateAssertion(GenTree* op1, GenTree* op2, optAssertionKind assertionKind);
6564 AssertionIndex optCreateAssertion(GenTree* op1,
6566 optAssertionKind assertionKind,
6567 AssertionDsc* assertion);
6568 void optCreateComplementaryAssertion(AssertionIndex assertionIndex, GenTree* op1, GenTree* op2);
6570 bool optAssertionVnInvolvesNan(AssertionDsc* assertion);
6571 AssertionIndex optAddAssertion(AssertionDsc* assertion);
6572 void optAddVnAssertionMapping(ValueNum vn, AssertionIndex index);
6574 void optPrintVnAssertionMapping();
6576 ASSERT_TP optGetVnMappedAssertions(ValueNum vn);
6578 // Used for respective assertion propagations.
6579 AssertionIndex optAssertionIsSubrange(GenTree* tree, var_types toType, ASSERT_VALARG_TP assertions);
6580 AssertionIndex optAssertionIsSubtype(GenTree* tree, GenTree* methodTableArg, ASSERT_VALARG_TP assertions);
6581 AssertionIndex optAssertionIsNonNullInternal(GenTree* op, ASSERT_VALARG_TP assertions);
6582 bool optAssertionIsNonNull(GenTree* op,
6583 ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased) DEBUGARG(AssertionIndex* pIndex));
6585 // Used for Relop propagation.
6586 AssertionIndex optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP assertions, GenTree* op1, GenTree* op2);
6587 AssertionIndex optGlobalAssertionIsEqualOrNotEqualZero(ASSERT_VALARG_TP assertions, GenTree* op1);
6588 AssertionIndex optLocalAssertionIsEqualOrNotEqual(
6589 optOp1Kind op1Kind, unsigned lclNum, optOp2Kind op2Kind, ssize_t cnsVal, ASSERT_VALARG_TP assertions);
6591 // Assertion prop for lcl var functions.
6592 bool optAssertionProp_LclVarTypeCheck(GenTree* tree, LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc);
6593 GenTree* optCopyAssertionProp(AssertionDsc* curAssertion,
6595 GenTree* stmt DEBUGARG(AssertionIndex index));
6596 GenTree* optConstantAssertionProp(AssertionDsc* curAssertion,
6598 GenTree* stmt DEBUGARG(AssertionIndex index));
6600 // Assertion propagation functions.
6601 GenTree* optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6602 GenTree* optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6603 GenTree* optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6604 GenTree* optAssertionProp_Cast(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6605 GenTree* optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, GenTree* stmt);
6606 GenTree* optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6607 GenTree* optAssertionProp_Comma(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6608 GenTree* optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6609 GenTree* optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6610 GenTree* optAssertionPropLocal_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6611 GenTree* optAssertionProp_Update(GenTree* newTree, GenTree* tree, GenTree* stmt);
6612 GenTree* optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, GenTree* stmt);
6614 // Implied assertion functions.
6615 void optImpliedAssertions(AssertionIndex assertionIndex, ASSERT_TP& activeAssertions);
6616 void optImpliedByTypeOfAssertions(ASSERT_TP& activeAssertions);
6617 void optImpliedByCopyAssertion(AssertionDsc* copyAssertion, AssertionDsc* depAssertion, ASSERT_TP& result);
6618 void optImpliedByConstAssertion(AssertionDsc* curAssertion, ASSERT_TP& result);
6621 void optPrintAssertion(AssertionDsc* newAssertion, AssertionIndex assertionIndex = 0);
6622 void optDebugCheckAssertion(AssertionDsc* assertion);
6623 void optDebugCheckAssertions(AssertionIndex AssertionIndex);
6625 void optAddCopies();
6626 #endif // ASSERTION_PROP
6628 /**************************************************************************
6630 *************************************************************************/
6633 struct LoopCloneVisitorInfo
6635 LoopCloneContext* context;
6638 LoopCloneVisitorInfo(LoopCloneContext* context, unsigned loopNum, GenTree* stmt)
6639 : context(context), loopNum(loopNum), stmt(nullptr)
6644 bool optIsStackLocalInvariant(unsigned loopNum, unsigned lclNum);
6645 bool optExtractArrIndex(GenTree* tree, ArrIndex* result, unsigned lhsNum);
6646 bool optReconstructArrIndex(GenTree* tree, ArrIndex* result, unsigned lhsNum);
6647 bool optIdentifyLoopOptInfo(unsigned loopNum, LoopCloneContext* context);
6648 static fgWalkPreFn optCanOptimizeByLoopCloningVisitor;
6649 fgWalkResult optCanOptimizeByLoopCloning(GenTree* tree, LoopCloneVisitorInfo* info);
6650 void optObtainLoopCloningOpts(LoopCloneContext* context);
6651 bool optIsLoopClonable(unsigned loopInd);
6653 bool optCanCloneLoops();
6656 void optDebugLogLoopCloning(BasicBlock* block, GenTree* insertBefore);
6658 void optPerformStaticOptimizations(unsigned loopNum, LoopCloneContext* context DEBUGARG(bool fastPath));
6659 bool optComputeDerefConditions(unsigned loopNum, LoopCloneContext* context);
6660 bool optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext* context);
6661 BasicBlock* optInsertLoopChoiceConditions(LoopCloneContext* context,
6667 ssize_t optGetArrayRefScaleAndIndex(GenTree* mul, GenTree** pIndex DEBUGARG(bool bRngChk));
6669 bool optReachWithoutCall(BasicBlock* srcBB, BasicBlock* dstBB);
6672 bool optLoopsMarked;
6675 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6676 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6680 XX Does the register allocation and puts the remaining lclVars on the stack XX
6682 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6683 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6687 regNumber raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc);
6689 void raMarkStkVars();
6692 // Some things are used by both LSRA and regpredict allocators.
6694 FrameType rpFrameType;
6695 bool rpMustCreateEBPCalled; // Set to true after we have called rpMustCreateEBPFrame once
6697 bool rpMustCreateEBPFrame(INDEBUG(const char** wbReason));
6700 Lowering* m_pLowering; // Lowering; needed to Lower IR that's added or modified after Lowering.
6701 LinearScanInterface* m_pLinearScan; // Linear Scan allocator
6703 /* raIsVarargsStackArg is called by raMaskStkVars and by
6704 lvaSortByRefCount. It identifies the special case
6705 where a varargs function has a parameter passed on the
6706 stack, other than the special varargs handle. Such parameters
6707 require special treatment, because they cannot be tracked
6708 by the GC (their offsets in the stack are not known
6712 bool raIsVarargsStackArg(unsigned lclNum)
6716 LclVarDsc* varDsc = &lvaTable[lclNum];
6718 assert(varDsc->lvIsParam);
6720 return (info.compIsVarArgs && !varDsc->lvIsRegArg && (lclNum != lvaVarargsHandleArg));
6722 #else // _TARGET_X86_
6726 #endif // _TARGET_X86_
6730 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6731 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6735 XX Get to the class and method info from the Execution Engine given XX
6736 XX tokens for the class and method XX
6738 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6739 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6745 void eeGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6746 CORINFO_RESOLVED_TOKEN* pConstrainedToken,
6747 CORINFO_CALLINFO_FLAGS flags,
6748 CORINFO_CALL_INFO* pResult);
6749 inline CORINFO_CALLINFO_FLAGS addVerifyFlag(CORINFO_CALLINFO_FLAGS flags);
6751 void eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6752 CORINFO_ACCESS_FLAGS flags,
6753 CORINFO_FIELD_INFO* pResult);
6757 BOOL eeIsValueClass(CORINFO_CLASS_HANDLE clsHnd);
6759 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(TRACK_LSRA_STATS)
6761 bool IsSuperPMIException(unsigned code)
6763 // Copied from NDP\clr\src\ToolBox\SuperPMI\SuperPMI-Shared\ErrorHandling.h
6765 const unsigned EXCEPTIONCODE_DebugBreakorAV = 0xe0421000;
6766 const unsigned EXCEPTIONCODE_MC = 0xe0422000;
6767 const unsigned EXCEPTIONCODE_LWM = 0xe0423000;
6768 const unsigned EXCEPTIONCODE_SASM = 0xe0424000;
6769 const unsigned EXCEPTIONCODE_SSYM = 0xe0425000;
6770 const unsigned EXCEPTIONCODE_CALLUTILS = 0xe0426000;
6771 const unsigned EXCEPTIONCODE_TYPEUTILS = 0xe0427000;
6772 const unsigned EXCEPTIONCODE_ASSERT = 0xe0440000;
6776 case EXCEPTIONCODE_DebugBreakorAV:
6777 case EXCEPTIONCODE_MC:
6778 case EXCEPTIONCODE_LWM:
6779 case EXCEPTIONCODE_SASM:
6780 case EXCEPTIONCODE_SSYM:
6781 case EXCEPTIONCODE_CALLUTILS:
6782 case EXCEPTIONCODE_TYPEUTILS:
6783 case EXCEPTIONCODE_ASSERT:
6790 const char* eeGetMethodName(CORINFO_METHOD_HANDLE hnd, const char** className);
6791 const char* eeGetMethodFullName(CORINFO_METHOD_HANDLE hnd);
6793 bool eeIsNativeMethod(CORINFO_METHOD_HANDLE method);
6794 CORINFO_METHOD_HANDLE eeGetMethodHandleForNative(CORINFO_METHOD_HANDLE method);
6797 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6798 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig, bool* isPinned);
6799 unsigned eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6801 // VOM info, method sigs
6803 void eeGetSig(unsigned sigTok,
6804 CORINFO_MODULE_HANDLE scope,
6805 CORINFO_CONTEXT_HANDLE context,
6806 CORINFO_SIG_INFO* retSig);
6808 void eeGetCallSiteSig(unsigned sigTok,
6809 CORINFO_MODULE_HANDLE scope,
6810 CORINFO_CONTEXT_HANDLE context,
6811 CORINFO_SIG_INFO* retSig);
6813 void eeGetMethodSig(CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* retSig, CORINFO_CLASS_HANDLE owner = nullptr);
6815 // Method entry-points, instrs
6817 CORINFO_METHOD_HANDLE eeMarkNativeTarget(CORINFO_METHOD_HANDLE method);
6819 CORINFO_EE_INFO eeInfo;
6820 bool eeInfoInitialized;
6822 CORINFO_EE_INFO* eeGetEEInfo();
6824 // Gets the offset of a SDArray's first element
6825 unsigned eeGetArrayDataOffset(var_types type);
6826 // Gets the offset of a MDArray's first element
6827 unsigned eeGetMDArrayDataOffset(var_types type, unsigned rank);
6829 GenTree* eeGetPInvokeCookie(CORINFO_SIG_INFO* szMetaSig);
6831 // Returns the page size for the target machine as reported by the EE.
6832 target_size_t eeGetPageSize()
6834 return (target_size_t)eeGetEEInfo()->osPageSize;
6837 // Returns the frame size at which we will generate a loop to probe the stack.
6838 target_size_t getVeryLargeFrameSize()
6841 // The looping probe code is 40 bytes, whereas the straight-line probing for
6842 // the (0x2000..0x3000) case is 44, so use looping for anything 0x2000 bytes
6843 // or greater, to generate smaller code.
6844 return 2 * eeGetPageSize();
6846 return 3 * eeGetPageSize();
6850 //------------------------------------------------------------------------
6851 // VirtualStubParam: virtual stub dispatch extra parameter (slot address).
6853 // It represents Abi and target specific registers for the parameter.
6855 class VirtualStubParamInfo
6858 VirtualStubParamInfo(bool isCoreRTABI)
6860 #if defined(_TARGET_X86_)
6863 #elif defined(_TARGET_AMD64_)
6874 #elif defined(_TARGET_ARM_)
6885 #elif defined(_TARGET_ARM64_)
6889 #error Unsupported or unset target architecture
6893 regNumber GetReg() const
6898 _regMask_enum GetRegMask() const
6905 _regMask_enum regMask;
6908 VirtualStubParamInfo* virtualStubParamInfo;
6910 bool IsTargetAbi(CORINFO_RUNTIME_ABI abi)
6912 return eeGetEEInfo()->targetAbi == abi;
6915 bool generateCFIUnwindCodes()
6917 #if defined(_TARGET_UNIX_)
6918 return IsTargetAbi(CORINFO_CORERT_ABI);
6924 // Debugging support - Line number info
6926 void eeGetStmtOffsets();
6928 unsigned eeBoundariesCount;
6930 struct boundariesDsc
6932 UNATIVE_OFFSET nativeIP;
6934 unsigned sourceReason;
6935 } * eeBoundaries; // Boundaries to report to EE
6936 void eeSetLIcount(unsigned count);
6937 void eeSetLIinfo(unsigned which, UNATIVE_OFFSET offs, unsigned srcIP, bool stkEmpty, bool callInstruction);
6941 static void eeDispILOffs(IL_OFFSET offs);
6942 static void eeDispLineInfo(const boundariesDsc* line);
6943 void eeDispLineInfos();
6946 // Debugging support - Local var info
6950 unsigned eeVarsCount;
6952 struct VarResultInfo
6954 UNATIVE_OFFSET startOffset;
6955 UNATIVE_OFFSET endOffset;
6957 CodeGenInterface::siVarLoc loc;
6959 void eeSetLVcount(unsigned count);
6960 void eeSetLVinfo(unsigned which,
6961 UNATIVE_OFFSET startOffs,
6962 UNATIVE_OFFSET length,
6967 const CodeGenInterface::siVarLoc* loc);
6971 void eeDispVar(ICorDebugInfo::NativeVarInfo* var);
6972 void eeDispVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars);
6975 // ICorJitInfo wrappers
6977 void eeReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize);
6979 void eeAllocUnwindInfo(BYTE* pHotCode,
6985 CorJitFuncKind funcKind);
6987 void eeSetEHcount(unsigned cEH);
6989 void eeSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause);
6991 WORD eeGetRelocTypeHint(void* target);
6993 // ICorStaticInfo wrapper functions
6995 bool eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken);
6997 #if defined(UNIX_AMD64_ABI)
6999 static void dumpSystemVClassificationType(SystemVClassificationType ct);
7002 void eeGetSystemVAmd64PassStructInRegisterDescriptor(
7003 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
7004 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr);
7005 #endif // UNIX_AMD64_ABI
7007 template <typename ParamType>
7008 bool eeRunWithErrorTrap(void (*function)(ParamType*), ParamType* param)
7010 return eeRunWithErrorTrapImp(reinterpret_cast<void (*)(void*)>(function), reinterpret_cast<void*>(param));
7013 bool eeRunWithErrorTrapImp(void (*function)(void*), void* param);
7015 // Utility functions
7017 const char* eeGetFieldName(CORINFO_FIELD_HANDLE fieldHnd, const char** classNamePtr = nullptr);
7020 const wchar_t* eeGetCPString(size_t stringHandle);
7023 const char* eeGetClassName(CORINFO_CLASS_HANDLE clsHnd);
7025 static CORINFO_METHOD_HANDLE eeFindHelper(unsigned helper);
7026 static CorInfoHelpFunc eeGetHelperNum(CORINFO_METHOD_HANDLE method);
7028 static fgWalkPreFn CountSharedStaticHelper;
7029 static bool IsSharedStaticHelper(GenTree* tree);
7030 static bool IsTreeAlwaysHoistable(GenTree* tree);
7031 static bool IsGcSafePoint(GenTree* tree);
7033 static CORINFO_FIELD_HANDLE eeFindJitDataOffs(unsigned jitDataOffs);
7034 // returns true/false if 'field' is a Jit Data offset
7035 static bool eeIsJitDataOffs(CORINFO_FIELD_HANDLE field);
7036 // returns a number < 0 if 'field' is not a Jit Data offset, otherwise the data offset (limited to 2GB)
7037 static int eeGetJitDataOffs(CORINFO_FIELD_HANDLE field);
7039 /*****************************************************************************/
7042 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7043 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7047 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7048 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7052 CodeGenInterface* codeGen;
7054 // The following holds information about instr offsets in terms of generated code.
7058 IPmappingDsc* ipmdNext; // next line# record
7059 IL_OFFSETX ipmdILoffsx; // the instr offset
7060 emitLocation ipmdNativeLoc; // the emitter location of the native code corresponding to the IL offset
7061 bool ipmdIsLabel; // Can this code be a branch label?
7064 // Record the instr offset mapping to the generated code
7066 IPmappingDsc* genIPmappingList;
7067 IPmappingDsc* genIPmappingLast;
7069 // Managed RetVal - A side hash table meant to record the mapping from a
7070 // GT_CALL node to its IL offset. This info is used to emit sequence points
7071 // that can be used by debugger to determine the native offset at which the
7072 // managed RetVal will be available.
7074 // In fact we can store IL offset in a GT_CALL node. This was ruled out in
7075 // favor of a side table for two reasons: 1) We need IL offset for only those
7076 // GT_CALL nodes (created during importation) that correspond to an IL call and
7077 // whose return type is other than TYP_VOID. 2) GT_CALL node is a frequently used
7078 // structure and IL offset is needed only when generating debuggable code. Therefore
7079 // it is desirable to avoid memory size penalty in retail scenarios.
7080 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, IL_OFFSETX> CallSiteILOffsetTable;
7081 CallSiteILOffsetTable* genCallSite2ILOffsetMap;
7083 unsigned genReturnLocal; // Local number for the return value when applicable.
7084 BasicBlock* genReturnBB; // jumped to when not optimizing for speed.
7086 // The following properties are part of CodeGenContext. Getters are provided here for
7087 // convenience and backward compatibility, but the properties can only be set by invoking
7088 // the setter on CodeGenContext directly.
7090 __declspec(property(get = getEmitter)) emitter* genEmitter;
7091 emitter* getEmitter() const
7093 return codeGen->getEmitter();
7096 bool isFramePointerUsed() const
7098 return codeGen->isFramePointerUsed();
7101 __declspec(property(get = getInterruptible, put = setInterruptible)) bool genInterruptible;
7102 bool getInterruptible()
7104 return codeGen->genInterruptible;
7106 void setInterruptible(bool value)
7108 codeGen->setInterruptible(value);
7111 #ifdef _TARGET_ARMARCH_
7112 __declspec(property(get = getHasTailCalls, put = setHasTailCalls)) bool hasTailCalls;
7113 bool getHasTailCalls()
7115 return codeGen->hasTailCalls;
7117 void setHasTailCalls(bool value)
7119 codeGen->setHasTailCalls(value);
7121 #endif // _TARGET_ARMARCH_
7124 const bool genDoubleAlign()
7126 return codeGen->doDoubleAlign();
7128 DWORD getCanDoubleAlign();
7129 bool shouldDoubleAlign(unsigned refCntStk,
7131 unsigned refCntWtdReg,
7132 unsigned refCntStkParam,
7133 unsigned refCntWtdStkDbl);
7134 #endif // DOUBLE_ALIGN
7136 __declspec(property(get = getFullPtrRegMap, put = setFullPtrRegMap)) bool genFullPtrRegMap;
7137 bool getFullPtrRegMap()
7139 return codeGen->genFullPtrRegMap;
7141 void setFullPtrRegMap(bool value)
7143 codeGen->setFullPtrRegMap(value);
7146 // Things that MAY belong either in CodeGen or CodeGenContext
7148 #if FEATURE_EH_FUNCLETS
7149 FuncInfoDsc* compFuncInfos;
7150 unsigned short compCurrFuncIdx;
7151 unsigned short compFuncInfoCount;
7153 unsigned short compFuncCount()
7155 assert(fgFuncletsCreated);
7156 return compFuncInfoCount;
7159 #else // !FEATURE_EH_FUNCLETS
7161 // This is a no-op when there are no funclets!
7162 void genUpdateCurrentFunclet(BasicBlock* block)
7167 FuncInfoDsc compFuncInfoRoot;
7169 static const unsigned compCurrFuncIdx = 0;
7171 unsigned short compFuncCount()
7176 #endif // !FEATURE_EH_FUNCLETS
7178 FuncInfoDsc* funCurrentFunc();
7179 void funSetCurrentFunc(unsigned funcIdx);
7180 FuncInfoDsc* funGetFunc(unsigned funcIdx);
7181 unsigned int funGetFuncIdx(BasicBlock* block);
7185 VARSET_TP compCurLife; // current live variables
7186 GenTree* compCurLifeTree; // node after which compCurLife has been computed
7188 template <bool ForCodeGen>
7189 void compChangeLife(VARSET_VALARG_TP newLife);
7191 template <bool ForCodeGen>
7192 inline void compUpdateLife(VARSET_VALARG_TP newLife);
7194 // Gets a register mask that represent the kill set for a helper call since
7195 // not all JIT Helper calls follow the standard ABI on the target architecture.
7196 regMaskTP compHelperCallKillSet(CorInfoHelpFunc helper);
7199 // Requires that "varDsc" be a promoted struct local variable being passed as an argument, beginning at
7200 // "firstArgRegNum", which is assumed to have already been aligned to the register alignment restriction of the
7201 // struct type. Adds bits to "*pArgSkippedRegMask" for any argument registers *not* used in passing "varDsc" --
7202 // i.e., internal "holes" caused by internal alignment constraints. For example, if the struct contained an int and
7203 // a double, and we at R0 (on ARM), then R1 would be skipped, and the bit for R1 would be added to the mask.
7204 void fgAddSkippedRegsInPromotedStructArg(LclVarDsc* varDsc, unsigned firstArgRegNum, regMaskTP* pArgSkippedRegMask);
7205 #endif // _TARGET_ARM_
7207 // 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
7209 static GenTree* fgIsIndirOfAddrOfLocal(GenTree* tree);
7211 // This map is indexed by GT_OBJ nodes that are address of promoted struct variables, which
7212 // have been annotated with the GTF_VAR_DEATH flag. If such a node is *not* mapped in this
7213 // table, one may assume that all the (tracked) field vars die at this GT_OBJ. Otherwise,
7214 // the node maps to a pointer to a VARSET_TP, containing set bits for each of the tracked field
7215 // vars of the promoted struct local that go dead at the given node (the set bits are the bits
7216 // for the tracked var indices of the field vars, as in a live var set).
7218 // The map is allocated on demand so all map operations should use one of the following three
7221 NodeToVarsetPtrMap* m_promotedStructDeathVars;
7223 NodeToVarsetPtrMap* GetPromotedStructDeathVars()
7225 if (m_promotedStructDeathVars == nullptr)
7227 m_promotedStructDeathVars = new (getAllocator()) NodeToVarsetPtrMap(getAllocator());
7229 return m_promotedStructDeathVars;
7232 void ClearPromotedStructDeathVars()
7234 if (m_promotedStructDeathVars != nullptr)
7236 m_promotedStructDeathVars->RemoveAll();
7240 bool LookupPromotedStructDeathVars(GenTree* tree, VARSET_TP** bits)
7243 bool result = false;
7245 if (m_promotedStructDeathVars != nullptr)
7247 result = m_promotedStructDeathVars->Lookup(tree, bits);
7254 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7255 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7259 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7260 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7263 #if !defined(__GNUC__)
7264 #pragma region Unwind information
7269 // Infrastructure functions: start/stop/reserve/emit.
7272 void unwindBegProlog();
7273 void unwindEndProlog();
7274 void unwindBegEpilog();
7275 void unwindEndEpilog();
7276 void unwindReserve();
7277 void unwindEmit(void* pHotCode, void* pColdCode);
7280 // Specific unwind information functions: called by code generation to indicate a particular
7281 // prolog or epilog unwindable instruction has been generated.
7284 void unwindPush(regNumber reg);
7285 void unwindAllocStack(unsigned size);
7286 void unwindSetFrameReg(regNumber reg, unsigned offset);
7287 void unwindSaveReg(regNumber reg, unsigned offset);
7289 #if defined(_TARGET_ARM_)
7290 void unwindPushMaskInt(regMaskTP mask);
7291 void unwindPushMaskFloat(regMaskTP mask);
7292 void unwindPopMaskInt(regMaskTP mask);
7293 void unwindPopMaskFloat(regMaskTP mask);
7294 void unwindBranch16(); // The epilog terminates with a 16-bit branch (e.g., "bx lr")
7295 void unwindNop(unsigned codeSizeInBytes); // Generate unwind NOP code. 'codeSizeInBytes' is 2 or 4 bytes. Only
7296 // called via unwindPadding().
7297 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7298 // instruction and the current location.
7299 #endif // _TARGET_ARM_
7301 #if defined(_TARGET_ARM64_)
7303 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7304 // instruction and the current location.
7305 void unwindSaveReg(regNumber reg, int offset); // str reg, [sp, #offset]
7306 void unwindSaveRegPreindexed(regNumber reg, int offset); // str reg, [sp, #offset]!
7307 void unwindSaveRegPair(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]
7308 void unwindSaveRegPairPreindexed(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]!
7309 void unwindSaveNext(); // unwind code: save_next
7310 void unwindReturn(regNumber reg); // ret lr
7311 #endif // defined(_TARGET_ARM64_)
7314 // Private "helper" functions for the unwind implementation.
7318 #if FEATURE_EH_FUNCLETS
7319 void unwindGetFuncLocations(FuncInfoDsc* func,
7320 bool getHotSectionData,
7321 /* OUT */ emitLocation** ppStartLoc,
7322 /* OUT */ emitLocation** ppEndLoc);
7323 #endif // FEATURE_EH_FUNCLETS
7325 void unwindReserveFunc(FuncInfoDsc* func);
7326 void unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
7328 #if defined(_TARGET_AMD64_) || (defined(_TARGET_X86_) && FEATURE_EH_FUNCLETS)
7330 void unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode);
7331 void unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode);
7333 #endif // _TARGET_AMD64_ || (_TARGET_X86_ && FEATURE_EH_FUNCLETS)
7335 UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func);
7337 #if defined(_TARGET_AMD64_)
7339 void unwindBegPrologWindows();
7340 void unwindPushWindows(regNumber reg);
7341 void unwindAllocStackWindows(unsigned size);
7342 void unwindSetFrameRegWindows(regNumber reg, unsigned offset);
7343 void unwindSaveRegWindows(regNumber reg, unsigned offset);
7345 #ifdef UNIX_AMD64_ABI
7346 void unwindSaveRegCFI(regNumber reg, unsigned offset);
7347 #endif // UNIX_AMD64_ABI
7348 #elif defined(_TARGET_ARM_)
7350 void unwindPushPopMaskInt(regMaskTP mask, bool useOpsize16);
7351 void unwindPushPopMaskFloat(regMaskTP mask);
7353 #endif // _TARGET_ARM_
7355 #if defined(_TARGET_UNIX_)
7356 int mapRegNumToDwarfReg(regNumber reg);
7357 void createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR opcode, USHORT dwarfReg, INT offset = 0);
7358 void unwindPushPopCFI(regNumber reg);
7359 void unwindBegPrologCFI();
7360 void unwindPushPopMaskCFI(regMaskTP regMask, bool isFloat);
7361 void unwindAllocStackCFI(unsigned size);
7362 void unwindSetFrameRegCFI(regNumber reg, unsigned offset);
7363 void unwindEmitFuncCFI(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
7365 void DumpCfiInfo(bool isHotCode,
7366 UNATIVE_OFFSET startOffset,
7367 UNATIVE_OFFSET endOffset,
7369 const CFI_CODE* const pCfiCode);
7372 #endif // _TARGET_UNIX_
7374 #if !defined(__GNUC__)
7375 #pragma endregion // Note: region is NOT under !defined(__GNUC__)
7379 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7380 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7384 XX Info about SIMD types, methods and the SIMD assembly (i.e. the assembly XX
7385 XX that contains the distinguished, well-known SIMD type definitions). XX
7387 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7388 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7391 // Get highest available level for SIMD codegen
7392 SIMDLevel getSIMDSupportLevel()
7394 #if defined(_TARGET_XARCH_)
7395 if (compSupports(InstructionSet_AVX2))
7397 return SIMD_AVX2_Supported;
7400 if (compSupports(InstructionSet_SSE42))
7402 return SIMD_SSE4_Supported;
7406 return SIMD_SSE2_Supported;
7408 assert(!"Available instruction set(s) for SIMD codegen is not defined for target arch");
7410 return SIMD_Not_Supported;
7416 // Should we support SIMD intrinsics?
7419 // Have we identified any SIMD types?
7420 // This is currently used by struct promotion to avoid getting type information for a struct
7421 // field to see if it is a SIMD type, if we haven't seen any SIMD types or operations in
7423 bool _usesSIMDTypes;
7424 bool usesSIMDTypes()
7426 return _usesSIMDTypes;
7428 void setUsesSIMDTypes(bool value)
7430 _usesSIMDTypes = value;
7433 // This is a temp lclVar allocated on the stack as TYP_SIMD. It is used to implement intrinsics
7434 // that require indexed access to the individual fields of the vector, which is not well supported
7435 // by the hardware. It is allocated when/if such situations are encountered during Lowering.
7436 unsigned lvaSIMDInitTempVarNum;
7438 struct SIMDHandlesCache
7441 CORINFO_CLASS_HANDLE SIMDFloatHandle;
7442 CORINFO_CLASS_HANDLE SIMDDoubleHandle;
7443 CORINFO_CLASS_HANDLE SIMDIntHandle;
7444 CORINFO_CLASS_HANDLE SIMDUShortHandle;
7445 CORINFO_CLASS_HANDLE SIMDUByteHandle;
7446 CORINFO_CLASS_HANDLE SIMDShortHandle;
7447 CORINFO_CLASS_HANDLE SIMDByteHandle;
7448 CORINFO_CLASS_HANDLE SIMDLongHandle;
7449 CORINFO_CLASS_HANDLE SIMDUIntHandle;
7450 CORINFO_CLASS_HANDLE SIMDULongHandle;
7451 CORINFO_CLASS_HANDLE SIMDVector2Handle;
7452 CORINFO_CLASS_HANDLE SIMDVector3Handle;
7453 CORINFO_CLASS_HANDLE SIMDVector4Handle;
7454 CORINFO_CLASS_HANDLE SIMDVectorHandle;
7456 #ifdef FEATURE_HW_INTRINSICS
7457 #if defined(_TARGET_ARM64_)
7458 CORINFO_CLASS_HANDLE Vector64FloatHandle;
7459 CORINFO_CLASS_HANDLE Vector64IntHandle;
7460 CORINFO_CLASS_HANDLE Vector64UShortHandle;
7461 CORINFO_CLASS_HANDLE Vector64UByteHandle;
7462 CORINFO_CLASS_HANDLE Vector64ShortHandle;
7463 CORINFO_CLASS_HANDLE Vector64ByteHandle;
7464 CORINFO_CLASS_HANDLE Vector64UIntHandle;
7465 #endif // defined(_TARGET_ARM64_)
7466 CORINFO_CLASS_HANDLE Vector128FloatHandle;
7467 CORINFO_CLASS_HANDLE Vector128DoubleHandle;
7468 CORINFO_CLASS_HANDLE Vector128IntHandle;
7469 CORINFO_CLASS_HANDLE Vector128UShortHandle;
7470 CORINFO_CLASS_HANDLE Vector128UByteHandle;
7471 CORINFO_CLASS_HANDLE Vector128ShortHandle;
7472 CORINFO_CLASS_HANDLE Vector128ByteHandle;
7473 CORINFO_CLASS_HANDLE Vector128LongHandle;
7474 CORINFO_CLASS_HANDLE Vector128UIntHandle;
7475 CORINFO_CLASS_HANDLE Vector128ULongHandle;
7476 #if defined(_TARGET_XARCH_)
7477 CORINFO_CLASS_HANDLE Vector256FloatHandle;
7478 CORINFO_CLASS_HANDLE Vector256DoubleHandle;
7479 CORINFO_CLASS_HANDLE Vector256IntHandle;
7480 CORINFO_CLASS_HANDLE Vector256UShortHandle;
7481 CORINFO_CLASS_HANDLE Vector256UByteHandle;
7482 CORINFO_CLASS_HANDLE Vector256ShortHandle;
7483 CORINFO_CLASS_HANDLE Vector256ByteHandle;
7484 CORINFO_CLASS_HANDLE Vector256LongHandle;
7485 CORINFO_CLASS_HANDLE Vector256UIntHandle;
7486 CORINFO_CLASS_HANDLE Vector256ULongHandle;
7487 #endif // defined(_TARGET_XARCH_)
7488 #endif // FEATURE_HW_INTRINSICS
7492 memset(this, 0, sizeof(*this));
7496 SIMDHandlesCache* m_simdHandleCache;
7498 // Get an appropriate "zero" for the given type and class handle.
7499 GenTree* gtGetSIMDZero(var_types simdType, var_types baseType, CORINFO_CLASS_HANDLE simdHandle);
7501 // Get the handle for a SIMD type.
7502 CORINFO_CLASS_HANDLE gtGetStructHandleForSIMD(var_types simdType, var_types simdBaseType)
7504 if (m_simdHandleCache == nullptr)
7506 // This may happen if the JIT generates SIMD node on its own, without importing them.
7507 // Otherwise getBaseTypeAndSizeOfSIMDType should have created the cache.
7508 return NO_CLASS_HANDLE;
7511 if (simdBaseType == TYP_FLOAT)
7516 return m_simdHandleCache->SIMDVector2Handle;
7518 return m_simdHandleCache->SIMDVector3Handle;
7520 if ((getSIMDVectorType() == TYP_SIMD32) ||
7521 (m_simdHandleCache->SIMDVector4Handle != NO_CLASS_HANDLE))
7523 return m_simdHandleCache->SIMDVector4Handle;
7532 assert(emitTypeSize(simdType) <= maxSIMDStructBytes());
7533 switch (simdBaseType)
7536 return m_simdHandleCache->SIMDFloatHandle;
7538 return m_simdHandleCache->SIMDDoubleHandle;
7540 return m_simdHandleCache->SIMDIntHandle;
7542 return m_simdHandleCache->SIMDUShortHandle;
7544 return m_simdHandleCache->SIMDUByteHandle;
7546 return m_simdHandleCache->SIMDShortHandle;
7548 return m_simdHandleCache->SIMDByteHandle;
7550 return m_simdHandleCache->SIMDLongHandle;
7552 return m_simdHandleCache->SIMDUIntHandle;
7554 return m_simdHandleCache->SIMDULongHandle;
7556 assert(!"Didn't find a class handle for simdType");
7558 return NO_CLASS_HANDLE;
7561 // Returns true if this is a SIMD type that should be considered an opaque
7562 // vector type (i.e. do not analyze or promote its fields).
7563 // Note that all but the fixed vector types are opaque, even though they may
7564 // actually be declared as having fields.
7565 bool isOpaqueSIMDType(CORINFO_CLASS_HANDLE structHandle)
7567 return ((m_simdHandleCache != nullptr) && (structHandle != m_simdHandleCache->SIMDVector2Handle) &&
7568 (structHandle != m_simdHandleCache->SIMDVector3Handle) &&
7569 (structHandle != m_simdHandleCache->SIMDVector4Handle));
7572 // Returns true if the tree corresponds to a TYP_SIMD lcl var.
7573 // Note that both SIMD vector args and locals are mared as lvSIMDType = true, but
7574 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD or TYP_STRUCT.
7575 bool isSIMDTypeLocal(GenTree* tree)
7577 return tree->OperIsLocal() && lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7580 // Returns true if the lclVar is an opaque SIMD type.
7581 bool isOpaqueSIMDLclVar(LclVarDsc* varDsc)
7583 if (!varDsc->lvSIMDType)
7587 return isOpaqueSIMDType(varDsc->lvVerTypeInfo.GetClassHandle());
7590 // Returns true if the type of the tree is a byref of TYP_SIMD
7591 bool isAddrOfSIMDType(GenTree* tree)
7593 if (tree->TypeGet() == TYP_BYREF || tree->TypeGet() == TYP_I_IMPL)
7595 switch (tree->OperGet())
7598 return varTypeIsSIMD(tree->gtGetOp1());
7600 case GT_LCL_VAR_ADDR:
7601 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7604 return isSIMDTypeLocal(tree);
7611 static bool isRelOpSIMDIntrinsic(SIMDIntrinsicID intrinsicId)
7613 return (intrinsicId == SIMDIntrinsicEqual || intrinsicId == SIMDIntrinsicLessThan ||
7614 intrinsicId == SIMDIntrinsicLessThanOrEqual || intrinsicId == SIMDIntrinsicGreaterThan ||
7615 intrinsicId == SIMDIntrinsicGreaterThanOrEqual);
7618 // Returns base type of a TYP_SIMD local.
7619 // Returns TYP_UNKNOWN if the local is not TYP_SIMD.
7620 var_types getBaseTypeOfSIMDLocal(GenTree* tree)
7622 if (isSIMDTypeLocal(tree))
7624 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvBaseType;
7630 bool isSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7632 return info.compCompHnd->isInSIMDModule(clsHnd);
7635 bool isIntrinsicType(CORINFO_CLASS_HANDLE clsHnd)
7637 return (info.compCompHnd->getClassAttribs(clsHnd) & CORINFO_FLG_INTRINSIC_TYPE) != 0;
7640 const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName)
7642 return info.compCompHnd->getClassNameFromMetadata(cls, namespaceName);
7645 CORINFO_CLASS_HANDLE getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index)
7647 return info.compCompHnd->getTypeInstantiationArgument(cls, index);
7650 bool isSIMDClass(typeInfo* pTypeInfo)
7652 return pTypeInfo->IsStruct() && isSIMDClass(pTypeInfo->GetClassHandleForValueClass());
7655 bool isHWSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7657 #ifdef FEATURE_HW_INTRINSICS
7658 if (isIntrinsicType(clsHnd))
7660 const char* namespaceName = nullptr;
7661 (void)getClassNameFromMetadata(clsHnd, &namespaceName);
7662 return strcmp(namespaceName, "System.Runtime.Intrinsics") == 0;
7664 #endif // FEATURE_HW_INTRINSICS
7668 bool isHWSIMDClass(typeInfo* pTypeInfo)
7670 #ifdef FEATURE_HW_INTRINSICS
7671 return pTypeInfo->IsStruct() && isHWSIMDClass(pTypeInfo->GetClassHandleForValueClass());
7677 bool isSIMDorHWSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7679 return isSIMDClass(clsHnd) || isHWSIMDClass(clsHnd);
7682 bool isSIMDorHWSIMDClass(typeInfo* pTypeInfo)
7684 return isSIMDClass(pTypeInfo) || isHWSIMDClass(pTypeInfo);
7687 // Get the base (element) type and size in bytes for a SIMD type. Returns TYP_UNKNOWN
7688 // if it is not a SIMD type or is an unsupported base type.
7689 var_types getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes = nullptr);
7691 var_types getBaseTypeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7693 return getBaseTypeAndSizeOfSIMDType(typeHnd, nullptr);
7696 // Get SIMD Intrinsic info given the method handle.
7697 // Also sets typeHnd, argCount, baseType and sizeBytes out params.
7698 const SIMDIntrinsicInfo* getSIMDIntrinsicInfo(CORINFO_CLASS_HANDLE* typeHnd,
7699 CORINFO_METHOD_HANDLE methodHnd,
7700 CORINFO_SIG_INFO* sig,
7703 var_types* baseType,
7704 unsigned* sizeBytes);
7706 // Pops and returns GenTree node from importers type stack.
7707 // Normalizes TYP_STRUCT value in case of GT_CALL, GT_RET_EXPR and arg nodes.
7708 GenTree* impSIMDPopStack(var_types type, bool expectAddr = false, CORINFO_CLASS_HANDLE structType = nullptr);
7710 // Create a GT_SIMD tree for a Get property of SIMD vector with a fixed index.
7711 GenTreeSIMD* impSIMDGetFixed(var_types simdType, var_types baseType, unsigned simdSize, int index);
7713 // Creates a GT_SIMD tree for Select operation
7714 GenTree* impSIMDSelect(CORINFO_CLASS_HANDLE typeHnd,
7716 unsigned simdVectorSize,
7721 // Creates a GT_SIMD tree for Min/Max operation
7722 GenTree* impSIMDMinMax(SIMDIntrinsicID intrinsicId,
7723 CORINFO_CLASS_HANDLE typeHnd,
7725 unsigned simdVectorSize,
7729 // Transforms operands and returns the SIMD intrinsic to be applied on
7730 // transformed operands to obtain given relop result.
7731 SIMDIntrinsicID impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId,
7732 CORINFO_CLASS_HANDLE typeHnd,
7733 unsigned simdVectorSize,
7734 var_types* baseType,
7738 // Creates a GT_SIMD tree for Abs intrinsic.
7739 GenTree* impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType, unsigned simdVectorSize, GenTree* op1);
7741 #if defined(_TARGET_XARCH_)
7743 // Transforms operands and returns the SIMD intrinsic to be applied on
7744 // transformed operands to obtain == comparison result.
7745 SIMDIntrinsicID impSIMDLongRelOpEqual(CORINFO_CLASS_HANDLE typeHnd,
7746 unsigned simdVectorSize,
7750 // Transforms operands and returns the SIMD intrinsic to be applied on
7751 // transformed operands to obtain > comparison result.
7752 SIMDIntrinsicID impSIMDLongRelOpGreaterThan(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 impSIMDLongRelOpGreaterThanOrEqual(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 in case of int32
7766 // and small int base type vectors.
7767 SIMDIntrinsicID impSIMDIntegralRelOpGreaterThanOrEqual(
7768 CORINFO_CLASS_HANDLE typeHnd, unsigned simdVectorSize, var_types baseType, GenTree** op1, GenTree** op2);
7770 #endif // defined(_TARGET_XARCH_)
7772 void setLclRelatedToSIMDIntrinsic(GenTree* tree);
7773 bool areFieldsContiguous(GenTree* op1, GenTree* op2);
7774 bool areArrayElementsContiguous(GenTree* op1, GenTree* op2);
7775 bool areArgumentsContiguous(GenTree* op1, GenTree* op2);
7776 GenTree* createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize);
7778 // check methodHnd to see if it is a SIMD method that is expanded as an intrinsic in the JIT.
7779 GenTree* impSIMDIntrinsic(OPCODE opcode,
7780 GenTree* newobjThis,
7781 CORINFO_CLASS_HANDLE clsHnd,
7782 CORINFO_METHOD_HANDLE method,
7783 CORINFO_SIG_INFO* sig,
7784 unsigned methodFlags,
7787 GenTree* getOp1ForConstructor(OPCODE opcode, GenTree* newobjThis, CORINFO_CLASS_HANDLE clsHnd);
7789 // Whether SIMD vector occupies part of SIMD register.
7790 // SSE2: vector2f/3f are considered sub register SIMD types.
7791 // AVX: vector2f, 3f and 4f are all considered sub register SIMD types.
7792 bool isSubRegisterSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7794 unsigned sizeBytes = 0;
7795 var_types baseType = getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7796 return (baseType == TYP_FLOAT) && (sizeBytes < getSIMDVectorRegisterByteLength());
7799 bool isSubRegisterSIMDType(GenTreeSIMD* simdNode)
7801 return (simdNode->gtSIMDSize < getSIMDVectorRegisterByteLength());
7804 // Get the type for the hardware SIMD vector.
7805 // This is the maximum SIMD type supported for this target.
7806 var_types getSIMDVectorType()
7808 #if defined(_TARGET_XARCH_)
7809 if (getSIMDSupportLevel() == SIMD_AVX2_Supported)
7815 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7818 #elif defined(_TARGET_ARM64_)
7821 assert(!"getSIMDVectorType() unimplemented on target arch");
7826 // Get the size of the SIMD type in bytes
7827 int getSIMDTypeSizeInBytes(CORINFO_CLASS_HANDLE typeHnd)
7829 unsigned sizeBytes = 0;
7830 (void)getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7834 // Get the the number of elements of basetype of SIMD vector given by its size and baseType
7835 static int getSIMDVectorLength(unsigned simdSize, var_types baseType);
7837 // Get the the number of elements of basetype of SIMD vector given by its type handle
7838 int getSIMDVectorLength(CORINFO_CLASS_HANDLE typeHnd);
7840 // Get preferred alignment of SIMD type.
7841 int getSIMDTypeAlignment(var_types simdType);
7843 // Get the number of bytes in a System.Numeric.Vector<T> for the current compilation.
7844 // Note - cannot be used for System.Runtime.Intrinsic
7845 unsigned getSIMDVectorRegisterByteLength()
7847 #if defined(_TARGET_XARCH_)
7848 if (getSIMDSupportLevel() == SIMD_AVX2_Supported)
7850 return YMM_REGSIZE_BYTES;
7854 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7855 return XMM_REGSIZE_BYTES;
7857 #elif defined(_TARGET_ARM64_)
7858 return FP_REGSIZE_BYTES;
7860 assert(!"getSIMDVectorRegisterByteLength() unimplemented on target arch");
7865 // The minimum and maximum possible number of bytes in a SIMD vector.
7867 // maxSIMDStructBytes
7868 // The minimum SIMD size supported by System.Numeric.Vectors or System.Runtime.Intrinsic
7869 // SSE: 16-byte Vector<T> and Vector128<T>
7870 // AVX: 32-byte Vector256<T> (Vector<T> is 16-byte)
7871 // AVX2: 32-byte Vector<T> and Vector256<T>
7872 unsigned int maxSIMDStructBytes()
7874 #if defined(FEATURE_HW_INTRINSICS) && defined(_TARGET_XARCH_)
7875 if (compSupports(InstructionSet_AVX))
7877 return YMM_REGSIZE_BYTES;
7881 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7882 return XMM_REGSIZE_BYTES;
7885 return getSIMDVectorRegisterByteLength();
7888 unsigned int minSIMDStructBytes()
7890 return emitTypeSize(TYP_SIMD8);
7893 // Returns the codegen type for a given SIMD size.
7894 var_types getSIMDTypeForSize(unsigned size)
7896 var_types simdType = TYP_UNDEF;
7899 simdType = TYP_SIMD8;
7901 else if (size == 12)
7903 simdType = TYP_SIMD12;
7905 else if (size == 16)
7907 simdType = TYP_SIMD16;
7909 else if (size == 32)
7911 simdType = TYP_SIMD32;
7915 noway_assert(!"Unexpected size for SIMD type");
7920 unsigned getSIMDInitTempVarNum()
7922 if (lvaSIMDInitTempVarNum == BAD_VAR_NUM)
7924 lvaSIMDInitTempVarNum = lvaGrabTempWithImplicitUse(false DEBUGARG("SIMDInitTempVar"));
7925 lvaTable[lvaSIMDInitTempVarNum].lvType = getSIMDVectorType();
7927 return lvaSIMDInitTempVarNum;
7930 #else // !FEATURE_SIMD
7931 bool isOpaqueSIMDLclVar(LclVarDsc* varDsc)
7935 #endif // FEATURE_SIMD
7938 //------------------------------------------------------------------------
7939 // largestEnregisterableStruct: The size in bytes of the largest struct that can be enregistered.
7941 // Notes: It is not guaranteed that the struct of this size or smaller WILL be a
7942 // candidate for enregistration.
7944 unsigned largestEnregisterableStructSize()
7947 unsigned vectorRegSize = getSIMDVectorRegisterByteLength();
7948 if (vectorRegSize > TARGET_POINTER_SIZE)
7950 return vectorRegSize;
7953 #endif // FEATURE_SIMD
7955 return TARGET_POINTER_SIZE;
7960 // These routines need not be enclosed under FEATURE_SIMD since lvIsSIMDType()
7961 // is defined for both FEATURE_SIMD and !FEATURE_SIMD apropriately. The use
7962 // of this routines also avoids the need of #ifdef FEATURE_SIMD specific code.
7964 // Is this var is of type simd struct?
7965 bool lclVarIsSIMDType(unsigned varNum)
7967 LclVarDsc* varDsc = lvaTable + varNum;
7968 return varDsc->lvIsSIMDType();
7971 // Is this Local node a SIMD local?
7972 bool lclVarIsSIMDType(GenTreeLclVarCommon* lclVarTree)
7974 return lclVarIsSIMDType(lclVarTree->gtLclNum);
7977 // Returns true if the TYP_SIMD locals on stack are aligned at their
7978 // preferred byte boundary specified by getSIMDTypeAlignment().
7980 // As per the Intel manual, the preferred alignment for AVX vectors is 32-bytes. On Amd64,
7981 // RSP/EBP is aligned at 16-bytes, therefore to align SIMD types at 32-bytes we need even
7982 // RSP/EBP to be 32-byte aligned. It is not clear whether additional stack space used in
7983 // aligning stack is worth the benefit and for now will use 16-byte alignment for AVX
7984 // 256-bit vectors with unaligned load/stores to/from memory. On x86, the stack frame
7985 // is aligned to 4 bytes. We need to extend existing support for double (8-byte) alignment
7986 // to 16 or 32 byte alignment for frames with local SIMD vars, if that is determined to be
7989 bool isSIMDTypeLocalAligned(unsigned varNum)
7991 #if defined(FEATURE_SIMD) && ALIGN_SIMD_TYPES
7992 if (lclVarIsSIMDType(varNum) && lvaTable[varNum].lvType != TYP_BYREF)
7995 int off = lvaFrameAddress(varNum, &ebpBased);
7996 // TODO-Cleanup: Can't this use the lvExactSize on the varDsc?
7997 int alignment = getSIMDTypeAlignment(lvaTable[varNum].lvType);
7998 bool isAligned = (alignment <= STACK_ALIGN) && ((off % alignment) == 0);
8001 #endif // FEATURE_SIMD
8006 bool compSupports(InstructionSet isa) const
8008 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
8009 return (opts.compSupportsISA & (1ULL << isa)) != 0;
8015 bool canUseVexEncoding() const
8017 #ifdef _TARGET_XARCH_
8018 return compSupports(InstructionSet_AVX);
8025 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8026 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8030 XX Generic info about the compilation and the method being compiled. XX
8031 XX It is responsible for driving the other phases. XX
8032 XX It is also responsible for all the memory management. XX
8034 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8035 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8039 Compiler* InlineeCompiler; // The Compiler instance for the inlinee
8041 InlineResult* compInlineResult; // The result of importing the inlinee method.
8043 bool compDoAggressiveInlining; // If true, mark every method as CORINFO_FLG_FORCEINLINE
8044 bool compJmpOpUsed; // Does the method do a JMP
8045 bool compLongUsed; // Does the method use TYP_LONG
8046 bool compFloatingPointUsed; // Does the method use TYP_FLOAT or TYP_DOUBLE
8047 bool compTailCallUsed; // Does the method do a tailcall
8048 bool compLocallocUsed; // Does the method use localloc.
8049 bool compLocallocOptimized; // Does the method have an optimized localloc
8050 bool compQmarkUsed; // Does the method use GT_QMARK/GT_COLON
8051 bool compQmarkRationalized; // Is it allowed to use a GT_QMARK/GT_COLON node.
8052 bool compUnsafeCastUsed; // Does the method use LDIND/STIND to cast between scalar/refernce types
8054 // NOTE: These values are only reliable after
8055 // the importing is completely finished.
8058 // State information - which phases have completed?
8059 // These are kept together for easy discoverability
8061 bool bRangeAllowStress;
8062 bool compCodeGenDone;
8063 int64_t compNumStatementLinksTraversed; // # of links traversed while doing debug checks
8064 bool fgNormalizeEHDone; // Has the flowgraph EH normalization phase been done?
8065 size_t compSizeEstimate; // The estimated size of the method as per `gtSetEvalOrder`.
8066 size_t compCycleEstimate; // The estimated cycle count of the method as per `gtSetEvalOrder`
8069 bool fgLocalVarLivenessDone; // Note that this one is used outside of debug.
8070 bool fgLocalVarLivenessChanged;
8072 bool compRationalIRForm;
8074 bool compUsesThrowHelper; // There is a call to a THOROW_HELPER for the compiled method.
8076 bool compGeneratingProlog;
8077 bool compGeneratingEpilog;
8078 bool compNeedsGSSecurityCookie; // There is an unsafe buffer (or localloc) on the stack.
8079 // Insert cookie on frame and code to check the cookie, like VC++ -GS.
8080 bool compGSReorderStackLayout; // There is an unsafe buffer on the stack, reorder locals and make local
8081 // copies of susceptible parameters to avoid buffer overrun attacks through locals/params
8082 bool getNeedsGSSecurityCookie() const
8084 return compNeedsGSSecurityCookie;
8086 void setNeedsGSSecurityCookie()
8088 compNeedsGSSecurityCookie = true;
8091 FrameLayoutState lvaDoneFrameLayout; // The highest frame layout state that we've completed. During
8092 // frame layout calculations, this is the level we are currently
8095 //---------------------------- JITing options -----------------------------
8108 JitFlags* jitFlags; // all flags passed from the EE
8109 unsigned compFlags; // method attributes
8111 codeOptimize compCodeOpt; // what type of code optimizations
8116 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
8117 uint64_t compSupportsISA;
8118 void setSupportedISA(InstructionSet isa)
8120 compSupportsISA |= 1ULL << isa;
8124 // optimize maximally and/or favor speed over size?
8126 #define DEFAULT_MIN_OPTS_CODE_SIZE 60000
8127 #define DEFAULT_MIN_OPTS_INSTR_COUNT 20000
8128 #define DEFAULT_MIN_OPTS_BB_COUNT 2000
8129 #define DEFAULT_MIN_OPTS_LV_NUM_COUNT 2000
8130 #define DEFAULT_MIN_OPTS_LV_REF_COUNT 8000
8132 // Maximun number of locals before turning off the inlining
8133 #define MAX_LV_NUM_COUNT_FOR_INLINING 512
8136 unsigned instrCount;
8137 unsigned lvRefCount;
8138 bool compMinOptsIsSet;
8140 bool compMinOptsIsUsed;
8144 assert(compMinOptsIsSet);
8145 compMinOptsIsUsed = true;
8150 return compMinOptsIsSet;
8159 return compMinOptsIsSet;
8163 bool OptimizationDisabled()
8165 return MinOpts() || compDbgCode;
8167 bool OptimizationEnabled()
8169 return !OptimizationDisabled();
8172 void SetMinOpts(bool val)
8174 assert(!compMinOptsIsUsed);
8175 assert(!compMinOptsIsSet || (compMinOpts == val));
8177 compMinOptsIsSet = true;
8180 // true if the CLFLG_* for an optimization is set.
8181 bool OptEnabled(unsigned optFlag)
8183 return !!(compFlags & optFlag);
8186 #ifdef FEATURE_READYTORUN_COMPILER
8189 return jitFlags->IsSet(JitFlags::JIT_FLAG_READYTORUN);
8198 // true if we should use the PINVOKE_{BEGIN,END} helpers instead of generating
8199 // PInvoke transitions inline (e.g. when targeting CoreRT).
8200 bool ShouldUsePInvokeHelpers()
8202 return jitFlags->IsSet(JitFlags::JIT_FLAG_USE_PINVOKE_HELPERS);
8205 // true if we should use insert the REVERSE_PINVOKE_{ENTER,EXIT} helpers in the method
8207 bool IsReversePInvoke()
8209 return jitFlags->IsSet(JitFlags::JIT_FLAG_REVERSE_PINVOKE);
8212 // true if we must generate code compatible with JIT32 quirks
8213 bool IsJit32Compat()
8215 #if defined(_TARGET_X86_)
8216 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
8222 // true if we must generate code compatible with Jit64 quirks
8223 bool IsJit64Compat()
8225 #if defined(_TARGET_AMD64_)
8226 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
8227 #elif !defined(FEATURE_CORECLR)
8234 bool compScopeInfo; // Generate the LocalVar info ?
8235 bool compDbgCode; // Generate debugger-friendly code?
8236 bool compDbgInfo; // Gather debugging info?
8239 #ifdef PROFILING_SUPPORTED
8240 bool compNoPInvokeInlineCB;
8242 static const bool compNoPInvokeInlineCB;
8246 bool compGcChecks; // Check arguments and return values to ensure they are sane
8249 #if defined(DEBUG) && defined(_TARGET_XARCH_)
8251 bool compStackCheckOnRet; // Check stack pointer on return to ensure it is correct.
8253 #endif // defined(DEBUG) && defined(_TARGET_XARCH_)
8255 #if defined(DEBUG) && defined(_TARGET_X86_)
8257 bool compStackCheckOnCall; // Check stack pointer after call to ensure it is correct. Only for x86.
8259 #endif // defined(DEBUG) && defined(_TARGET_X86_)
8261 bool compNeedSecurityCheck; // This flag really means where or not a security object needs
8262 // to be allocated on the stack.
8263 // It will be set to true in the following cases:
8264 // 1. When the method being compiled has a declarative security
8265 // (i.e. when CORINFO_FLG_NOSECURITYWRAP is reset for the current method).
8266 // This is also the case when we inject a prolog and epilog in the method.
8268 // 2. When the method being compiled has imperative security (i.e. the method
8269 // calls into another method that has CORINFO_FLG_SECURITYCHECK flag set).
8271 // 3. When opts.compDbgEnC is true. (See also Compiler::compCompile).
8273 // When this flag is set, jit will allocate a gc-reference local variable (lvaSecurityObject),
8274 // which gets reported as a GC root to stackwalker.
8275 // (See also ICodeManager::GetAddrOfSecurityObject.)
8277 bool compReloc; // Generate relocs for pointers in code, true for all ngen/prejit codegen
8280 #if defined(_TARGET_XARCH_)
8281 bool compEnablePCRelAddr; // Whether absolute addr be encoded as PC-rel offset by RyuJIT where possible
8285 #ifdef UNIX_AMD64_ABI
8286 // This flag is indicating if there is a need to align the frame.
8287 // On AMD64-Windows, if there are calls, 4 slots for the outgoing ars are allocated, except for
8288 // FastTailCall. This slots makes the frame size non-zero, so alignment logic will be called.
8289 // On AMD64-Unix, there are no such slots. There is a possibility to have calls in the method with frame size of
8290 // 0. The frame alignment logic won't kick in. This flags takes care of the AMD64-Unix case by remembering that
8291 // there are calls and making sure the frame alignment logic is executed.
8292 bool compNeedToAlignFrame;
8293 #endif // UNIX_AMD64_ABI
8295 bool compProcedureSplitting; // Separate cold code from hot code
8297 bool genFPorder; // Preserve FP order (operations are non-commutative)
8298 bool genFPopt; // Can we do frame-pointer-omission optimization?
8299 bool altJit; // True if we are an altjit and are compiling this method
8302 bool optRepeat; // Repeat optimizer phases k times
8306 bool compProcedureSplittingEH; // Separate cold code from hot code for functions with EH
8307 bool dspCode; // Display native code generated
8308 bool dspEHTable; // Display the EH table reported to the VM
8309 bool dspDebugInfo; // Display the Debug info reported to the VM
8310 bool dspInstrs; // Display the IL instructions intermixed with the native code output
8311 bool dspEmit; // Display emitter output
8312 bool dspLines; // Display source-code lines intermixed with native code output
8313 bool dmpHex; // Display raw bytes in hex of native code output
8314 bool varNames; // Display variables names in native code output
8315 bool disAsm; // Display native code as it is generated
8316 bool disAsmSpilled; // Display native code when any register spilling occurs
8317 bool disDiffable; // Makes the Disassembly code 'diff-able'
8318 bool disAsm2; // Display native code after it is generated using external disassembler
8319 bool dspOrder; // Display names of each of the methods that we ngen/jit
8320 bool dspUnwind; // Display the unwind info output
8321 bool dspDiffable; // Makes the Jit Dump 'diff-able' (currently uses same COMPlus_* flag as disDiffable)
8322 bool compLongAddress; // Force using large pseudo instructions for long address
8323 // (IF_LARGEJMP/IF_LARGEADR/IF_LARGLDC)
8324 bool dspGCtbls; // Display the GC tables
8328 bool doLateDisasm; // Run the late disassembler
8329 #endif // LATE_DISASM
8331 #if DUMP_GC_TABLES && !defined(DEBUG) && defined(JIT32_GCENCODER)
8332 // Only the JIT32_GCENCODER implements GC dumping in non-DEBUG code.
8333 #pragma message("NOTE: this non-debug build has GC ptr table dumping always enabled!")
8334 static const bool dspGCtbls = true;
8337 #ifdef PROFILING_SUPPORTED
8338 // Whether to emit Enter/Leave/TailCall hooks using a dummy stub (DummyProfilerELTStub()).
8339 // This option helps make the JIT behave as if it is running under a profiler.
8340 bool compJitELTHookEnabled;
8341 #endif // PROFILING_SUPPORTED
8343 #if FEATURE_TAILCALL_OPT
8344 // Whether opportunistic or implicit tail call optimization is enabled.
8345 bool compTailCallOpt;
8346 // Whether optimization of transforming a recursive tail call into a loop is enabled.
8347 bool compTailCallLoopOpt;
8350 #if defined(_TARGET_ARM64_)
8351 // Decision about whether to save FP/LR registers with callee-saved registers (see
8352 // COMPlus_JitSaveFpLrWithCalleSavedRegisters).
8353 int compJitSaveFpLrWithCalleeSavedRegisters;
8354 #endif // defined(_TARGET_ARM64_)
8357 static const bool compUseSoftFP = true;
8358 #else // !ARM_SOFTFP
8359 static const bool compUseSoftFP = false;
8362 GCPollType compGCPollType;
8366 static bool s_pAltJitExcludeAssembliesListInitialized;
8367 static AssemblyNamesList2* s_pAltJitExcludeAssembliesList;
8371 static bool s_pJitDisasmIncludeAssembliesListInitialized;
8372 static AssemblyNamesList2* s_pJitDisasmIncludeAssembliesList;
8374 static bool s_pJitFunctionFileInitialized;
8375 static MethodSet* s_pJitMethodSet;
8379 // silence warning of cast to greater size. It is easier to silence than construct code the compiler is happy with, and
8380 // it is safe in this case
8381 #pragma warning(push)
8382 #pragma warning(disable : 4312)
8384 template <typename T>
8387 return (p == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : p);
8390 template <typename T>
8393 return (o == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : o);
8395 #pragma warning(pop)
8397 static int dspTreeID(GenTree* tree)
8399 return tree->gtTreeID;
8401 static void printTreeID(GenTree* tree)
8403 if (tree == nullptr)
8409 printf("[%06d]", dspTreeID(tree));
8416 #define STRESS_MODES \
8420 /* "Variations" stress areas which we try to mix up with each other. */ \
8421 /* These should not be exhaustively used as they might */ \
8422 /* hide/trivialize other areas */ \
8425 STRESS_MODE(DBL_ALN) \
8426 STRESS_MODE(LCL_FLDS) \
8427 STRESS_MODE(UNROLL_LOOPS) \
8428 STRESS_MODE(MAKE_CSE) \
8429 STRESS_MODE(LEGACY_INLINE) \
8430 STRESS_MODE(CLONE_EXPR) \
8431 STRESS_MODE(USE_FCOMI) \
8432 STRESS_MODE(USE_CMOV) \
8434 STRESS_MODE(BB_PROFILE) \
8435 STRESS_MODE(OPT_BOOLS_GC) \
8436 STRESS_MODE(REMORPH_TREES) \
8437 STRESS_MODE(64RSLT_MUL) \
8438 STRESS_MODE(DO_WHILE_LOOPS) \
8439 STRESS_MODE(MIN_OPTS) \
8440 STRESS_MODE(REVERSE_FLAG) /* Will set GTF_REVERSE_OPS whenever we can */ \
8441 STRESS_MODE(REVERSE_COMMA) /* Will reverse commas created with gtNewCommaNode */ \
8442 STRESS_MODE(TAILCALL) /* Will make the call as a tailcall whenever legal */ \
8443 STRESS_MODE(CATCH_ARG) /* Will spill catch arg */ \
8444 STRESS_MODE(UNSAFE_BUFFER_CHECKS) \
8445 STRESS_MODE(NULL_OBJECT_CHECK) \
8446 STRESS_MODE(PINVOKE_RESTORE_ESP) \
8447 STRESS_MODE(RANDOM_INLINE) \
8448 STRESS_MODE(SWITCH_CMP_BR_EXPANSION) \
8449 STRESS_MODE(GENERIC_VARN) \
8451 /* After COUNT_VARN, stress level 2 does all of these all the time */ \
8453 STRESS_MODE(COUNT_VARN) \
8455 /* "Check" stress areas that can be exhaustively used if we */ \
8456 /* dont care about performance at all */ \
8458 STRESS_MODE(FORCE_INLINE) /* Treat every method as AggressiveInlining */ \
8459 STRESS_MODE(CHK_FLOW_UPDATE) \
8460 STRESS_MODE(EMITTER) \
8461 STRESS_MODE(CHK_REIMPORT) \
8462 STRESS_MODE(FLATFP) \
8463 STRESS_MODE(GENERIC_CHECK) \
8468 #define STRESS_MODE(mode) STRESS_##mode,
8475 static const LPCWSTR s_compStressModeNames[STRESS_COUNT + 1];
8476 BYTE compActiveStressModes[STRESS_COUNT];
8479 #define MAX_STRESS_WEIGHT 100
8481 bool compStressCompile(compStressArea stressArea, unsigned weightPercentage);
8485 bool compInlineStress()
8487 return compStressCompile(STRESS_LEGACY_INLINE, 50);
8490 bool compRandomInlineStress()
8492 return compStressCompile(STRESS_RANDOM_INLINE, 50);
8497 bool compTailCallStress()
8500 return (JitConfig.TailcallStress() != 0 || compStressCompile(STRESS_TAILCALL, 5));
8506 codeOptimize compCodeOpt()
8509 // Switching between size & speed has measurable throughput impact
8510 // (3.5% on NGen mscorlib when measured). It used to be enabled for
8511 // DEBUG, but should generate identical code between CHK & RET builds,
8512 // so that's not acceptable.
8513 // TODO-Throughput: Figure out what to do about size vs. speed & throughput.
8514 // Investigate the cause of the throughput regression.
8516 return opts.compCodeOpt;
8518 return BLENDED_CODE;
8522 //--------------------- Info about the procedure --------------------------
8526 COMP_HANDLE compCompHnd;
8527 CORINFO_MODULE_HANDLE compScopeHnd;
8528 CORINFO_CLASS_HANDLE compClassHnd;
8529 CORINFO_METHOD_HANDLE compMethodHnd;
8530 CORINFO_METHOD_INFO* compMethodInfo;
8532 BOOL hasCircularClassConstraints;
8533 BOOL hasCircularMethodConstraints;
8535 #if defined(DEBUG) || defined(LATE_DISASM)
8536 const char* compMethodName;
8537 const char* compClassName;
8538 const char* compFullName;
8539 #endif // defined(DEBUG) || defined(LATE_DISASM)
8541 #if defined(DEBUG) || defined(INLINE_DATA)
8542 // Method hash is logcally const, but computed
8544 mutable unsigned compMethodHashPrivate;
8545 unsigned compMethodHash() const;
8546 #endif // defined(DEBUG) || defined(INLINE_DATA)
8548 #ifdef PSEUDORANDOM_NOP_INSERTION
8549 // things for pseudorandom nop insertion
8550 unsigned compChecksum;
8554 // The following holds the FLG_xxxx flags for the method we're compiling.
8557 // The following holds the class attributes for the method we're compiling.
8558 unsigned compClassAttr;
8560 const BYTE* compCode;
8561 IL_OFFSET compILCodeSize; // The IL code size
8562 IL_OFFSET compILImportSize; // Estimated amount of IL actually imported
8563 UNATIVE_OFFSET compNativeCodeSize; // The native code size, after instructions are issued. This
8564 // is less than (compTotalHotCodeSize + compTotalColdCodeSize) only if:
8565 // (1) the code is not hot/cold split, and we issued less code than we expected, or
8566 // (2) the code is hot/cold split, and we issued less code than we expected
8567 // in the cold section (the hot section will always be padded out to compTotalHotCodeSize).
8569 bool compIsStatic : 1; // Is the method static (no 'this' pointer)?
8570 bool compIsVarArgs : 1; // Does the method have varargs parameters?
8571 bool compIsContextful : 1; // contextful method
8572 bool compInitMem : 1; // Is the CORINFO_OPT_INIT_LOCALS bit set in the method info options?
8573 bool compUnwrapContextful : 1; // JIT should unwrap proxies when possible
8574 bool compProfilerCallback : 1; // JIT inserted a profiler Enter callback
8575 bool compPublishStubParam : 1; // EAX captured in prolog will be available through an instrinsic
8576 bool compRetBuffDefStack : 1; // The ret buff argument definitely points into the stack.
8578 var_types compRetType; // Return type of the method as declared in IL
8579 var_types compRetNativeType; // Normalized return type as per target arch ABI
8580 unsigned compILargsCount; // Number of arguments (incl. implicit but not hidden)
8581 unsigned compArgsCount; // Number of arguments (incl. implicit and hidden)
8583 #if FEATURE_FASTTAILCALL
8584 size_t compArgStackSize; // Incoming argument stack size in bytes
8585 bool compHasMultiSlotArgs; // Caller has >8 byte sized struct parameter
8586 #endif // FEATURE_FASTTAILCALL
8588 unsigned compRetBuffArg; // position of hidden return param var (0, 1) (BAD_VAR_NUM means not present);
8589 int compTypeCtxtArg; // position of hidden param for type context for generic code (CORINFO_CALLCONV_PARAMTYPE)
8590 unsigned compThisArg; // position of implicit this pointer param (not to be confused with lvaArg0Var)
8591 unsigned compILlocalsCount; // Number of vars : args + locals (incl. implicit but not hidden)
8592 unsigned compLocalsCount; // Number of vars : args + locals (incl. implicit and hidden)
8593 unsigned compMaxStack;
8594 UNATIVE_OFFSET compTotalHotCodeSize; // Total number of bytes of Hot Code in the method
8595 UNATIVE_OFFSET compTotalColdCodeSize; // Total number of bytes of Cold Code in the method
8597 unsigned compCallUnmanaged; // count of unmanaged calls
8598 unsigned compLvFrameListRoot; // lclNum for the Frame root
8599 unsigned compXcptnsCount; // Number of exception-handling clauses read in the method's IL.
8600 // You should generally use compHndBBtabCount instead: it is the
8601 // current number of EH clauses (after additions like synchronized
8602 // methods and funclets, and removals like unreachable code deletion).
8604 bool compMatchedVM; // true if the VM is "matched": either the JIT is a cross-compiler
8605 // and the VM expects that, or the JIT is a "self-host" compiler
8606 // (e.g., x86 hosted targeting x86) and the VM expects that.
8608 /* The following holds IL scope information about local variables.
8611 unsigned compVarScopesCount;
8612 VarScopeDsc* compVarScopes;
8614 /* The following holds information about instr offsets for
8615 * which we need to report IP-mappings
8618 IL_OFFSET* compStmtOffsets; // sorted
8619 unsigned compStmtOffsetsCount;
8620 ICorDebugInfo::BoundaryTypes compStmtOffsetsImplicit;
8622 #define CPU_X86 0x0100 // The generic X86 CPU
8623 #define CPU_X86_PENTIUM_4 0x0110
8625 #define CPU_X64 0x0200 // The generic x64 CPU
8626 #define CPU_AMD_X64 0x0210 // AMD x64 CPU
8627 #define CPU_INTEL_X64 0x0240 // Intel x64 CPU
8629 #define CPU_ARM 0x0300 // The generic ARM CPU
8630 #define CPU_ARM64 0x0400 // The generic ARM64 CPU
8632 unsigned genCPU; // What CPU are we running on
8635 // Returns true if the method being compiled returns a non-void and non-struct value.
8636 // Note that lvaInitTypeRef() normalizes compRetNativeType for struct returns in a
8637 // single register as per target arch ABI (e.g on Amd64 Windows structs of size 1, 2,
8638 // 4 or 8 gets normalized to TYP_BYTE/TYP_SHORT/TYP_INT/TYP_LONG; On Arm HFA structs).
8639 // Methods returning such structs are considered to return non-struct return value and
8640 // this method returns true in that case.
8641 bool compMethodReturnsNativeScalarType()
8643 return (info.compRetType != TYP_VOID) && !varTypeIsStruct(info.compRetNativeType);
8646 // Returns true if the method being compiled returns RetBuf addr as its return value
8647 bool compMethodReturnsRetBufAddr()
8649 // There are cases where implicit RetBuf argument should be explicitly returned in a register.
8650 // In such cases the return type is changed to TYP_BYREF and appropriate IR is generated.
8652 // 1. Profiler Leave calllback expects the address of retbuf as return value for
8653 // methods with hidden RetBuf argument. impReturnInstruction() when profiler
8654 // callbacks are needed creates GT_RETURN(TYP_BYREF, op1 = Addr of RetBuf) for
8655 // methods with hidden RetBufArg.
8657 // 2. As per the System V ABI, the address of RetBuf needs to be returned by
8658 // methods with hidden RetBufArg in RAX. In such case GT_RETURN is of TYP_BYREF,
8659 // returning the address of RetBuf.
8661 // 3. Windows 64-bit native calling convention also requires the address of RetBuff
8662 // to be returned in RAX.
8663 CLANG_FORMAT_COMMENT_ANCHOR;
8665 #ifdef _TARGET_AMD64_
8666 return (info.compRetBuffArg != BAD_VAR_NUM);
8667 #else // !_TARGET_AMD64_
8668 return (compIsProfilerHookNeeded()) && (info.compRetBuffArg != BAD_VAR_NUM);
8669 #endif // !_TARGET_AMD64_
8672 // Returns true if the method returns a value in more than one return register
8673 // TODO-ARM-Bug: Deal with multi-register genReturnLocaled structs?
8674 // TODO-ARM64: Does this apply for ARM64 too?
8675 bool compMethodReturnsMultiRegRetType()
8677 #if FEATURE_MULTIREG_RET
8678 #if defined(_TARGET_X86_)
8679 // On x86 only 64-bit longs are returned in multiple registers
8680 return varTypeIsLong(info.compRetNativeType);
8681 #else // targets: X64-UNIX, ARM64 or ARM32
8682 // On all other targets that support multireg return values:
8683 // Methods returning a struct in multiple registers have a return value of TYP_STRUCT.
8684 // Such method's compRetNativeType is TYP_STRUCT without a hidden RetBufArg
8685 return varTypeIsStruct(info.compRetNativeType) && (info.compRetBuffArg == BAD_VAR_NUM);
8686 #endif // TARGET_XXX
8688 #else // not FEATURE_MULTIREG_RET
8690 // For this architecture there are no multireg returns
8693 #endif // FEATURE_MULTIREG_RET
8696 #if FEATURE_MULTIREG_ARGS
8697 // Given a GenTree node of TYP_STRUCT that represents a pass by value argument
8698 // return the gcPtr layout for the pointers sized fields
8699 void getStructGcPtrsFromOp(GenTree* op, BYTE* gcPtrsOut);
8700 #endif // FEATURE_MULTIREG_ARGS
8702 // Returns true if the method being compiled returns a value
8703 bool compMethodHasRetVal()
8705 return compMethodReturnsNativeScalarType() || compMethodReturnsRetBufAddr() ||
8706 compMethodReturnsMultiRegRetType();
8711 void compDispLocalVars();
8715 //-------------------------- Global Compiler Data ------------------------------------
8718 static unsigned s_compMethodsCount; // to produce unique label names
8719 unsigned compGenTreeID;
8720 unsigned compBasicBlockID;
8723 BasicBlock* compCurBB; // the current basic block in process
8724 GenTree* compCurStmt; // the current statement in process
8726 unsigned compCurStmtNum; // to give all statements an increasing StmtNum when printing dumps
8729 // The following is used to create the 'method JIT info' block.
8730 size_t compInfoBlkSize;
8731 BYTE* compInfoBlkAddr;
8733 EHblkDsc* compHndBBtab; // array of EH data
8734 unsigned compHndBBtabCount; // element count of used elements in EH data array
8735 unsigned compHndBBtabAllocCount; // element count of allocated elements in EH data array
8737 #if defined(_TARGET_X86_)
8739 //-------------------------------------------------------------------------
8740 // Tracking of region covered by the monitor in synchronized methods
8741 void* syncStartEmitCookie; // the emitter cookie for first instruction after the call to MON_ENTER
8742 void* syncEndEmitCookie; // the emitter cookie for first instruction after the call to MON_EXIT
8744 #endif // !_TARGET_X86_
8746 Phases previousCompletedPhase; // the most recently completed phase
8748 //-------------------------------------------------------------------------
8749 // The following keeps track of how many bytes of local frame space we've
8750 // grabbed so far in the current function, and how many argument bytes we
8751 // need to pop when we return.
8754 unsigned compLclFrameSize; // secObject+lclBlk+locals+temps
8756 // Count of callee-saved regs we pushed in the prolog.
8757 // Does not include EBP for isFramePointerUsed() and double-aligned frames.
8758 // In case of Amd64 this doesn't include float regs saved on stack.
8759 unsigned compCalleeRegsPushed;
8761 #if defined(_TARGET_XARCH_)
8762 // Mask of callee saved float regs on stack.
8763 regMaskTP compCalleeFPRegsSavedMask;
8765 #ifdef _TARGET_AMD64_
8766 // Quirk for VS debug-launch scenario to work:
8767 // Bytes of padding between save-reg area and locals.
8768 #define VSQUIRK_STACK_PAD (2 * REGSIZE_BYTES)
8769 unsigned compVSQuirkStackPaddingNeeded;
8770 bool compQuirkForPPPflag;
8773 unsigned compArgSize; // total size of arguments in bytes (including register args (lvIsRegArg))
8775 unsigned compMapILargNum(unsigned ILargNum); // map accounting for hidden args
8776 unsigned compMapILvarNum(unsigned ILvarNum); // map accounting for hidden args
8777 unsigned compMap2ILvarNum(unsigned varNum) const; // map accounting for hidden args
8779 //-------------------------------------------------------------------------
8781 static void compStartup(); // One-time initialization
8782 static void compShutdown(); // One-time finalization
8784 void compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo);
8787 static void compDisplayStaticSizes(FILE* fout);
8789 //------------ Some utility functions --------------
8791 void* compGetHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
8792 void** ppIndirection); /* OUT */
8794 // Several JIT/EE interface functions return a CorInfoType, and also return a
8795 // class handle as an out parameter if the type is a value class. Returns the
8796 // size of the type these describe.
8797 unsigned compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd);
8800 // Components used by the compiler may write unit test suites, and
8801 // have them run within this method. They will be run only once per process, and only
8802 // in debug. (Perhaps should be under the control of a COMPlus_ flag.)
8803 // These should fail by asserting.
8804 void compDoComponentUnitTestsOnce();
8807 int compCompile(CORINFO_METHOD_HANDLE methodHnd,
8808 CORINFO_MODULE_HANDLE classPtr,
8809 COMP_HANDLE compHnd,
8810 CORINFO_METHOD_INFO* methodInfo,
8811 void** methodCodePtr,
8812 ULONG* methodCodeSize,
8813 JitFlags* compileFlags);
8814 void compCompileFinish();
8815 int compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
8816 COMP_HANDLE compHnd,
8817 CORINFO_METHOD_INFO* methodInfo,
8818 void** methodCodePtr,
8819 ULONG* methodCodeSize,
8820 JitFlags* compileFlags,
8821 CorInfoInstantiationVerification instVerInfo);
8823 ArenaAllocator* compGetArenaAllocator();
8825 #if MEASURE_MEM_ALLOC
8826 static bool s_dspMemStats; // Display per-phase memory statistics for every function
8827 #endif // MEASURE_MEM_ALLOC
8829 #if LOOP_HOIST_STATS
8830 unsigned m_loopsConsidered;
8831 bool m_curLoopHasHoistedExpression;
8832 unsigned m_loopsWithHoistedExpressions;
8833 unsigned m_totalHoistedExpressions;
8835 void AddLoopHoistStats();
8836 void PrintPerMethodLoopHoistStats();
8838 static CritSecObject s_loopHoistStatsLock; // This lock protects the data structures below.
8839 static unsigned s_loopsConsidered;
8840 static unsigned s_loopsWithHoistedExpressions;
8841 static unsigned s_totalHoistedExpressions;
8843 static void PrintAggregateLoopHoistStats(FILE* f);
8844 #endif // LOOP_HOIST_STATS
8846 bool compIsForImportOnly();
8847 bool compIsForInlining() const;
8848 bool compDonotInline();
8851 // Get the default fill char value we randomize this value when JitStress is enabled.
8852 static unsigned char compGetJitDefaultFill(Compiler* comp);
8854 const char* compLocalVarName(unsigned varNum, unsigned offs);
8855 VarName compVarName(regNumber reg, bool isFloatReg = false);
8856 const char* compRegVarName(regNumber reg, bool displayVar = false, bool isFloatReg = false);
8857 const char* compRegNameForSize(regNumber reg, size_t size);
8858 const char* compFPregVarName(unsigned fpReg, bool displayVar = false);
8859 void compDspSrcLinesByNativeIP(UNATIVE_OFFSET curIP);
8860 void compDspSrcLinesByLineNum(unsigned line, bool seek = false);
8863 //-------------------------------------------------------------------------
8865 struct VarScopeListNode
8868 VarScopeListNode* next;
8869 static VarScopeListNode* Create(VarScopeDsc* value, CompAllocator alloc)
8871 VarScopeListNode* node = new (alloc) VarScopeListNode;
8873 node->next = nullptr;
8878 struct VarScopeMapInfo
8880 VarScopeListNode* head;
8881 VarScopeListNode* tail;
8882 static VarScopeMapInfo* Create(VarScopeListNode* node, CompAllocator alloc)
8884 VarScopeMapInfo* info = new (alloc) VarScopeMapInfo;
8891 // Max value of scope count for which we would use linear search; for larger values we would use hashtable lookup.
8892 static const unsigned MAX_LINEAR_FIND_LCL_SCOPELIST = 32;
8894 typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, VarScopeMapInfo*> VarNumToScopeDscMap;
8896 // Map to keep variables' scope indexed by varNum containing it's scope dscs at the index.
8897 VarNumToScopeDscMap* compVarScopeMap;
8899 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned lifeBeg, unsigned lifeEnd);
8901 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned offs);
8903 VarScopeDsc* compFindLocalVarLinear(unsigned varNum, unsigned offs);
8905 void compInitVarScopeMap();
8907 VarScopeDsc** compEnterScopeList; // List has the offsets where variables
8908 // enter scope, sorted by instr offset
8909 unsigned compNextEnterScope;
8911 VarScopeDsc** compExitScopeList; // List has the offsets where variables
8912 // go out of scope, sorted by instr offset
8913 unsigned compNextExitScope;
8915 void compInitScopeLists();
8917 void compResetScopeLists();
8919 VarScopeDsc* compGetNextEnterScope(unsigned offs, bool scan = false);
8921 VarScopeDsc* compGetNextExitScope(unsigned offs, bool scan = false);
8923 void compProcessScopesUntil(unsigned offset,
8925 void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*),
8926 void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*));
8929 void compDispScopeLists();
8932 bool compIsProfilerHookNeeded();
8934 //-------------------------------------------------------------------------
8935 /* Statistical Data Gathering */
8937 void compJitStats(); // call this function and enable
8938 // various ifdef's below for statistical data
8941 void compCallArgStats();
8942 static void compDispCallArgStats(FILE* fout);
8945 //-------------------------------------------------------------------------
8952 ArenaAllocator* compArenaAllocator;
8955 void compFunctionTraceStart();
8956 void compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, bool isNYI);
8959 size_t compMaxUncheckedOffsetForNullObject;
8961 void compInitOptions(JitFlags* compileFlags);
8963 void compSetProcessor();
8964 void compInitDebuggingInfo();
8965 void compSetOptimizationLevel();
8966 #ifdef _TARGET_ARMARCH_
8967 bool compRsvdRegCheck(FrameLayoutState curState);
8969 void compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags);
8971 // Clear annotations produced during optimizations; to be used between iterations when repeating opts.
8972 void ResetOptAnnotations();
8974 // Regenerate loop descriptors; to be used between iterations when repeating opts.
8975 void RecomputeLoopInfo();
8977 #ifdef PROFILING_SUPPORTED
8978 // Data required for generating profiler Enter/Leave/TailCall hooks
8980 bool compProfilerHookNeeded; // Whether profiler Enter/Leave/TailCall hook needs to be generated for the method
8981 void* compProfilerMethHnd; // Profiler handle of the method being compiled. Passed as param to ELT callbacks
8982 bool compProfilerMethHndIndirected; // Whether compProfilerHandle is pointer to the handle or is an actual handle
8985 #ifdef _TARGET_AMD64_
8986 bool compQuirkForPPP(); // Check if this method should be Quirked for the PPP issue
8989 // Assumes called as part of process shutdown; does any compiler-specific work associated with that.
8990 static void ProcessShutdownWork(ICorStaticInfo* statInfo);
8992 CompAllocator getAllocator(CompMemKind cmk = CMK_Generic)
8994 return CompAllocator(compArenaAllocator, cmk);
8997 CompAllocator getAllocatorGC()
8999 return getAllocator(CMK_GC);
9002 CompAllocator getAllocatorLoopHoist()
9004 return getAllocator(CMK_LoopHoist);
9008 CompAllocator getAllocatorDebugOnly()
9010 return getAllocator(CMK_DebugOnly);
9015 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9016 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9020 XX Checks for type compatibility and merges types XX
9022 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9023 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9027 // Set to TRUE if verification cannot be skipped for this method
9028 // If we detect unverifiable code, we will lazily check
9029 // canSkipMethodVerification() to see if verification is REALLY needed.
9030 BOOL tiVerificationNeeded;
9032 // It it initially TRUE, and it gets set to FALSE if we run into unverifiable code
9033 // Note that this is valid only if tiVerificationNeeded was ever TRUE.
9034 BOOL tiIsVerifiableCode;
9036 // Set to TRUE if runtime callout is needed for this method
9037 BOOL tiRuntimeCalloutNeeded;
9039 // Set to TRUE if security prolog/epilog callout is needed for this method
9040 // Note: This flag is different than compNeedSecurityCheck.
9041 // compNeedSecurityCheck means whether or not a security object needs
9042 // to be allocated on the stack, which is currently true for EnC as well.
9043 // tiSecurityCalloutNeeded means whether or not security callouts need
9044 // to be inserted in the jitted code.
9045 BOOL tiSecurityCalloutNeeded;
9047 // Returns TRUE if child is equal to or a subtype of parent for merge purposes
9048 // This support is necessary to suport attributes that are not described in
9049 // for example, signatures. For example, the permanent home byref (byref that
9050 // points to the gc heap), isn't a property of method signatures, therefore,
9051 // it is safe to have mismatches here (that tiCompatibleWith will not flag),
9052 // but when deciding if we need to reimport a block, we need to take these
9054 BOOL tiMergeCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
9056 // Returns TRUE if child is equal to or a subtype of parent.
9057 // normalisedForStack indicates that both types are normalised for the stack
9058 BOOL tiCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
9060 // Merges pDest and pSrc. Returns FALSE if merge is undefined.
9061 // *pDest is modified to represent the merged type. Sets "*changed" to true
9062 // if this changes "*pDest".
9063 BOOL tiMergeToCommonParent(typeInfo* pDest, const typeInfo* pSrc, bool* changed) const;
9066 // <BUGNUM> VSW 471305
9067 // IJW allows assigning REF to BYREF. The following allows us to temporarily
9068 // bypass the assert check in gcMarkRegSetGCref and gcMarkRegSetByref
9069 // We use a "short" as we need to push/pop this scope.
9071 short compRegSetCheckLevel;
9075 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9076 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9078 XX IL verification stuff XX
9081 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9082 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9086 // The following is used to track liveness of local variables, initialization
9087 // of valueclass constructors, and type safe use of IL instructions.
9089 // dynamic state info needed for verification
9090 EntryState verCurrentState;
9092 // this ptr of object type .ctors are considered intited only after
9093 // the base class ctor is called, or an alternate ctor is called.
9094 // An uninited this ptr can be used to access fields, but cannot
9095 // be used to call a member function.
9096 BOOL verTrackObjCtorInitState;
9098 void verInitBBEntryState(BasicBlock* block, EntryState* currentState);
9100 // Requires that "tis" is not TIS_Bottom -- it's a definite init/uninit state.
9101 void verSetThisInit(BasicBlock* block, ThisInitState tis);
9102 void verInitCurrentState();
9103 void verResetCurrentState(BasicBlock* block, EntryState* currentState);
9105 // Merges the current verification state into the entry state of "block", return FALSE if that merge fails,
9106 // TRUE if it succeeds. Further sets "*changed" to true if this changes the entry state of "block".
9107 BOOL verMergeEntryStates(BasicBlock* block, bool* changed);
9109 void verConvertBBToThrowVerificationException(BasicBlock* block DEBUGARG(bool logMsg));
9110 void verHandleVerificationFailure(BasicBlock* block DEBUGARG(bool logMsg));
9111 typeInfo verMakeTypeInfo(CORINFO_CLASS_HANDLE clsHnd,
9112 bool bashStructToRef = false); // converts from jit type representation to typeInfo
9113 typeInfo verMakeTypeInfo(CorInfoType ciType,
9114 CORINFO_CLASS_HANDLE clsHnd); // converts from jit type representation to typeInfo
9115 BOOL verIsSDArray(typeInfo ti);
9116 typeInfo verGetArrayElemType(typeInfo ti);
9118 typeInfo verParseArgSigToTypeInfo(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args);
9119 BOOL verNeedsVerification();
9120 BOOL verIsByRefLike(const typeInfo& ti);
9121 BOOL verIsSafeToReturnByRef(const typeInfo& ti);
9123 // generic type variables range over types that satisfy IsBoxable
9124 BOOL verIsBoxable(const typeInfo& ti);
9126 void DECLSPEC_NORETURN verRaiseVerifyException(INDEBUG(const char* reason) DEBUGARG(const char* file)
9127 DEBUGARG(unsigned line));
9128 void verRaiseVerifyExceptionIfNeeded(INDEBUG(const char* reason) DEBUGARG(const char* file)
9129 DEBUGARG(unsigned line));
9130 bool verCheckTailCallConstraint(OPCODE opcode,
9131 CORINFO_RESOLVED_TOKEN* pResolvedToken,
9132 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call
9133 // on a type parameter?
9134 bool speculative // If true, won't throw if verificatoin fails. Instead it will
9135 // return false to the caller.
9136 // If false, it will throw.
9138 bool verIsBoxedValueType(typeInfo ti);
9140 void verVerifyCall(OPCODE opcode,
9141 CORINFO_RESOLVED_TOKEN* pResolvedToken,
9142 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
9144 bool readonlyCall, // is this a "readonly." call?
9145 const BYTE* delegateCreateStart,
9146 const BYTE* codeAddr,
9147 CORINFO_CALL_INFO* callInfo DEBUGARG(const char* methodName));
9149 BOOL verCheckDelegateCreation(const BYTE* delegateCreateStart, const BYTE* codeAddr, mdMemberRef& targetMemberRef);
9151 typeInfo verVerifySTIND(const typeInfo& ptr, const typeInfo& value, const typeInfo& instrType);
9152 typeInfo verVerifyLDIND(const typeInfo& ptr, const typeInfo& instrType);
9153 void verVerifyField(CORINFO_RESOLVED_TOKEN* pResolvedToken,
9154 const CORINFO_FIELD_INFO& fieldInfo,
9155 const typeInfo* tiThis,
9157 BOOL allowPlainStructAsThis = FALSE);
9158 void verVerifyCond(const typeInfo& tiOp1, const typeInfo& tiOp2, unsigned opcode);
9159 void verVerifyThisPtrInitialised();
9160 BOOL verIsCallToInitThisPtr(CORINFO_CLASS_HANDLE context, CORINFO_CLASS_HANDLE target);
9164 // One line log function. Default level is 0. Increasing it gives you
9165 // more log information
9167 // levels are currently unused: #define JITDUMP(level,...) ();
9168 void JitLogEE(unsigned level, const char* fmt, ...);
9170 bool compDebugBreak;
9172 bool compJitHaltMethod();
9177 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9178 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9180 XX GS Security checks for unsafe buffers XX
9182 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9183 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9186 struct ShadowParamVarInfo
9188 FixedBitVect* assignGroup; // the closure set of variables whose values depend on each other
9189 unsigned shadowCopy; // Lcl var num, valid only if not set to NO_SHADOW_COPY
9191 static bool mayNeedShadowCopy(LclVarDsc* varDsc)
9193 #if defined(_TARGET_AMD64_)
9194 // GS cookie logic to create shadow slots, create trees to copy reg args to shadow
9195 // slots and update all trees to refer to shadow slots is done immediately after
9196 // fgMorph(). Lsra could potentially mark a param as DoNotEnregister after JIT determines
9197 // not to shadow a parameter. Also, LSRA could potentially spill a param which is passed
9198 // in register. Therefore, conservatively all params may need a shadow copy. Note that
9199 // GS cookie logic further checks whether the param is a ptr or an unsafe buffer before
9200 // creating a shadow slot even though this routine returns true.
9202 // TODO-AMD64-CQ: Revisit this conservative approach as it could create more shadow slots than
9203 // required. There are two cases under which a reg arg could potentially be used from its
9205 // a) LSRA marks it as DoNotEnregister (see LinearScan::identifyCandidates())
9206 // b) LSRA spills it
9208 // Possible solution to address case (a)
9209 // - The conditions under which LSRA marks a varDsc as DoNotEnregister could be checked
9210 // in this routine. Note that live out of exception handler is something we may not be
9211 // able to do it here since GS cookie logic is invoked ahead of liveness computation.
9212 // Therefore, for methods with exception handling and need GS cookie check we might have
9213 // to take conservative approach.
9215 // Possible solution to address case (b)
9216 // - Whenver a parameter passed in an argument register needs to be spilled by LSRA, we
9217 // create a new spill temp if the method needs GS cookie check.
9218 return varDsc->lvIsParam;
9219 #else // !defined(_TARGET_AMD64_)
9220 return varDsc->lvIsParam && !varDsc->lvIsRegArg;
9227 printf("assignGroup [%p]; shadowCopy: [%d];\n", assignGroup, shadowCopy);
9232 GSCookie* gsGlobalSecurityCookieAddr; // Address of global cookie for unsafe buffer checks
9233 GSCookie gsGlobalSecurityCookieVal; // Value of global cookie if addr is NULL
9234 ShadowParamVarInfo* gsShadowVarInfo; // Table used by shadow param analysis code
9236 void gsGSChecksInitCookie(); // Grabs cookie variable
9237 void gsCopyShadowParams(); // Identify vulnerable params and create dhadow copies
9238 bool gsFindVulnerableParams(); // Shadow param analysis code
9239 void gsParamsToShadows(); // Insert copy code and replave param uses by shadow
9241 static fgWalkPreFn gsMarkPtrsAndAssignGroups; // Shadow param analysis tree-walk
9242 static fgWalkPreFn gsReplaceShadowParams; // Shadow param replacement tree-walk
9244 #define DEFAULT_MAX_INLINE_SIZE 100 // Methods with > DEFAULT_MAX_INLINE_SIZE IL bytes will never be inlined.
9245 // This can be overwritten by setting complus_JITInlineSize env variable.
9247 #define DEFAULT_MAX_INLINE_DEPTH 20 // Methods at more than this level deep will not be inlined
9249 #define DEFAULT_MAX_LOCALLOC_TO_LOCAL_SIZE 32 // fixed locallocs of this size or smaller will convert to local buffers
9252 #ifdef FEATURE_JIT_METHOD_PERF
9253 JitTimer* pCompJitTimer; // Timer data structure (by phases) for current compilation.
9254 static CompTimeSummaryInfo s_compJitTimerSummary; // Summary of the Timer information for the whole run.
9256 static LPCWSTR JitTimeLogCsv(); // Retrieve the file name for CSV from ConfigDWORD.
9257 static LPCWSTR compJitTimeLogFilename; // If a log file for JIT time is desired, filename to write it to.
9259 inline void EndPhase(Phases phase); // Indicate the end of the given phase.
9261 #if MEASURE_CLRAPI_CALLS
9262 // Thin wrappers that call into JitTimer (if present).
9263 inline void CLRApiCallEnter(unsigned apix);
9264 inline void CLRApiCallLeave(unsigned apix);
9267 inline void CLR_API_Enter(API_ICorJitInfo_Names ename);
9268 inline void CLR_API_Leave(API_ICorJitInfo_Names ename);
9273 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9274 // These variables are associated with maintaining SQM data about compile time.
9275 unsigned __int64 m_compCyclesAtEndOfInlining; // The thread-virtualized cycle count at the end of the inlining phase
9276 // in the current compilation.
9277 unsigned __int64 m_compCycles; // Net cycle count for current compilation
9278 DWORD m_compTickCountAtEndOfInlining; // The result of GetTickCount() (# ms since some epoch marker) at the end of
9279 // the inlining phase in the current compilation.
9280 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9282 // Records the SQM-relevant (cycles and tick count). Should be called after inlining is complete.
9283 // (We do this after inlining because this marks the last point at which the JIT is likely to cause
9284 // type-loading and class initialization).
9285 void RecordStateAtEndOfInlining();
9286 // Assumes being called at the end of compilation. Update the SQM state.
9287 void RecordStateAtEndOfCompilation();
9289 #ifdef FEATURE_CLRSQM
9290 // Does anything SQM related necessary at process shutdown time.
9291 static void ProcessShutdownSQMWork(ICorStaticInfo* statInfo);
9292 #endif // FEATURE_CLRSQM
9295 #if FUNC_INFO_LOGGING
9296 static LPCWSTR compJitFuncInfoFilename; // If a log file for per-function information is required, this is the
9297 // filename to write it to.
9298 static FILE* compJitFuncInfoFile; // And this is the actual FILE* to write to.
9299 #endif // FUNC_INFO_LOGGING
9301 Compiler* prevCompiler; // Previous compiler on stack for TLS Compiler* linked list for reentrant compilers.
9303 // Is the compilation in a full trust context?
9304 bool compIsFullTrust();
9307 void RecordNowayAssert(const char* filename, unsigned line, const char* condStr);
9308 #endif // MEASURE_NOWAY
9310 #ifndef FEATURE_TRACELOGGING
9311 // Should we actually fire the noway assert body and the exception handler?
9312 bool compShouldThrowOnNoway();
9313 #else // FEATURE_TRACELOGGING
9314 // Should we actually fire the noway assert body and the exception handler?
9315 bool compShouldThrowOnNoway(const char* filename, unsigned line);
9317 // Telemetry instance to use per method compilation.
9318 JitTelemetry compJitTelemetry;
9320 // Get common parameters that have to be logged with most telemetry data.
9321 void compGetTelemetryDefaults(const char** assemblyName,
9322 const char** scopeName,
9323 const char** methodName,
9324 unsigned* methodHash);
9325 #endif // !FEATURE_TRACELOGGING
9329 NodeToTestDataMap* m_nodeTestData;
9331 static const unsigned FIRST_LOOP_HOIST_CSE_CLASS = 1000;
9332 unsigned m_loopHoistCSEClass; // LoopHoist test annotations turn into CSE requirements; we
9333 // label them with CSE Class #'s starting at FIRST_LOOP_HOIST_CSE_CLASS.
9334 // Current kept in this.
9336 NodeToTestDataMap* GetNodeTestData()
9338 Compiler* compRoot = impInlineRoot();
9339 if (compRoot->m_nodeTestData == nullptr)
9341 compRoot->m_nodeTestData = new (getAllocatorDebugOnly()) NodeToTestDataMap(getAllocatorDebugOnly());
9343 return compRoot->m_nodeTestData;
9346 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, int> NodeToIntMap;
9348 // Returns the set (i.e., the domain of the result map) of nodes that are keys in m_nodeTestData, and
9349 // currently occur in the AST graph.
9350 NodeToIntMap* FindReachableNodesInNodeTestData();
9352 // Node "from" is being eliminated, and being replaced by node "to". If "from" had any associated
9353 // test data, associate that data with "to".
9354 void TransferTestDataToNode(GenTree* from, GenTree* to);
9356 // Requires that "to" is a clone of "from". If any nodes in the "from" tree
9357 // have annotations, attach similar annotations to the corresponding nodes in "to".
9358 void CopyTestDataToCloneTree(GenTree* from, GenTree* to);
9360 // These are the methods that test that the various conditions implied by the
9361 // test attributes are satisfied.
9362 void JitTestCheckSSA(); // SSA builder tests.
9363 void JitTestCheckVN(); // Value numbering tests.
9366 // The "FieldSeqStore", for canonicalizing field sequences. See the definition of FieldSeqStore for
9368 FieldSeqStore* m_fieldSeqStore;
9370 FieldSeqStore* GetFieldSeqStore()
9372 Compiler* compRoot = impInlineRoot();
9373 if (compRoot->m_fieldSeqStore == nullptr)
9375 // Create a CompAllocator that labels sub-structure with CMK_FieldSeqStore, and use that for allocation.
9376 CompAllocator ialloc(getAllocator(CMK_FieldSeqStore));
9377 compRoot->m_fieldSeqStore = new (ialloc) FieldSeqStore(ialloc);
9379 return compRoot->m_fieldSeqStore;
9382 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, FieldSeqNode*> NodeToFieldSeqMap;
9384 // Some nodes of "TYP_BYREF" or "TYP_I_IMPL" actually represent the address of a field within a struct, but since
9385 // the offset of the field is zero, there's no "GT_ADD" node. We normally attach a field sequence to the constant
9386 // that is added, but what do we do when that constant is zero, and is thus not present? We use this mechanism to
9387 // attach the field sequence directly to the address node.
9388 NodeToFieldSeqMap* m_zeroOffsetFieldMap;
9390 NodeToFieldSeqMap* GetZeroOffsetFieldMap()
9392 // Don't need to worry about inlining here
9393 if (m_zeroOffsetFieldMap == nullptr)
9395 // Create a CompAllocator that labels sub-structure with CMK_ZeroOffsetFieldMap, and use that for
9397 CompAllocator ialloc(getAllocator(CMK_ZeroOffsetFieldMap));
9398 m_zeroOffsetFieldMap = new (ialloc) NodeToFieldSeqMap(ialloc);
9400 return m_zeroOffsetFieldMap;
9403 // Requires that "op1" is a node of type "TYP_BYREF" or "TYP_I_IMPL". We are dereferencing this with the fields in
9404 // "fieldSeq", whose offsets are required all to be zero. Ensures that any field sequence annotation currently on
9405 // "op1" or its components is augmented by appending "fieldSeq". In practice, if "op1" is a GT_LCL_FLD, it has
9406 // a field sequence as a member; otherwise, it may be the addition of an a byref and a constant, where the const
9407 // has a field sequence -- in this case "fieldSeq" is appended to that of the constant; otherwise, we
9408 // record the the field sequence using the ZeroOffsetFieldMap described above.
9410 // One exception above is that "op1" is a node of type "TYP_REF" where "op1" is a GT_LCL_VAR.
9411 // This happens when System.Object vtable pointer is a regular field at offset 0 in System.Private.CoreLib in
9412 // CoreRT. Such case is handled same as the default case.
9413 void fgAddFieldSeqForZeroOffset(GenTree* op1, FieldSeqNode* fieldSeq);
9415 typedef JitHashTable<const GenTree*, JitPtrKeyFuncs<GenTree>, ArrayInfo> NodeToArrayInfoMap;
9416 NodeToArrayInfoMap* m_arrayInfoMap;
9418 NodeToArrayInfoMap* GetArrayInfoMap()
9420 Compiler* compRoot = impInlineRoot();
9421 if (compRoot->m_arrayInfoMap == nullptr)
9423 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9424 CompAllocator ialloc(getAllocator(CMK_ArrayInfoMap));
9425 compRoot->m_arrayInfoMap = new (ialloc) NodeToArrayInfoMap(ialloc);
9427 return compRoot->m_arrayInfoMap;
9430 //-----------------------------------------------------------------------------------------------------------------
9431 // Compiler::TryGetArrayInfo:
9432 // Given an indirection node, checks to see whether or not that indirection represents an array access, and
9433 // if so returns information about the array.
9436 // indir - The `GT_IND` node.
9437 // arrayInfo (out) - Information about the accessed array if this function returns true. Undefined otherwise.
9440 // True if the `GT_IND` node represents an array access; false otherwise.
9441 bool TryGetArrayInfo(GenTreeIndir* indir, ArrayInfo* arrayInfo)
9443 if ((indir->gtFlags & GTF_IND_ARR_INDEX) == 0)
9448 if (indir->gtOp1->OperIs(GT_INDEX_ADDR))
9450 GenTreeIndexAddr* const indexAddr = indir->gtOp1->AsIndexAddr();
9451 *arrayInfo = ArrayInfo(indexAddr->gtElemType, indexAddr->gtElemSize, indexAddr->gtElemOffset,
9452 indexAddr->gtStructElemClass);
9456 bool found = GetArrayInfoMap()->Lookup(indir, arrayInfo);
9461 NodeToUnsignedMap* m_memorySsaMap[MemoryKindCount];
9463 // In some cases, we want to assign intermediate SSA #'s to memory states, and know what nodes create those memory
9464 // states. (We do this for try blocks, where, if the try block doesn't do a call that loses track of the memory
9465 // state, all the possible memory states are possible initial states of the corresponding catch block(s).)
9466 NodeToUnsignedMap* GetMemorySsaMap(MemoryKind memoryKind)
9468 if (memoryKind == GcHeap && byrefStatesMatchGcHeapStates)
9470 // Use the same map for GCHeap and ByrefExposed when their states match.
9471 memoryKind = ByrefExposed;
9474 assert(memoryKind < MemoryKindCount);
9475 Compiler* compRoot = impInlineRoot();
9476 if (compRoot->m_memorySsaMap[memoryKind] == nullptr)
9478 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9479 CompAllocator ialloc(getAllocator(CMK_ArrayInfoMap));
9480 compRoot->m_memorySsaMap[memoryKind] = new (ialloc) NodeToUnsignedMap(ialloc);
9482 return compRoot->m_memorySsaMap[memoryKind];
9485 // The Refany type is the only struct type whose structure is implicitly assumed by IL. We need its fields.
9486 CORINFO_CLASS_HANDLE m_refAnyClass;
9487 CORINFO_FIELD_HANDLE GetRefanyDataField()
9489 if (m_refAnyClass == nullptr)
9491 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9493 return info.compCompHnd->getFieldInClass(m_refAnyClass, 0);
9495 CORINFO_FIELD_HANDLE GetRefanyTypeField()
9497 if (m_refAnyClass == nullptr)
9499 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9501 return info.compCompHnd->getFieldInClass(m_refAnyClass, 1);
9505 static BitSetSupport::BitSetOpCounter m_varsetOpCounter;
9507 #if ALLVARSET_COUNTOPS
9508 static BitSetSupport::BitSetOpCounter m_allvarsetOpCounter;
9511 static HelperCallProperties s_helperCallProperties;
9513 #ifdef UNIX_AMD64_ABI
9514 static var_types GetTypeFromClassificationAndSizes(SystemVClassificationType classType, int size);
9515 static var_types GetEightByteType(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9518 static void GetStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9521 unsigned __int8* offset0,
9522 unsigned __int8* offset1);
9524 void GetStructTypeOffset(CORINFO_CLASS_HANDLE typeHnd,
9527 unsigned __int8* offset0,
9528 unsigned __int8* offset1);
9530 #endif // defined(UNIX_AMD64_ABI)
9532 void fgMorphMultiregStructArgs(GenTreeCall* call);
9533 GenTree* fgMorphMultiregStructArg(GenTree* arg, fgArgTabEntry* fgEntryPtr);
9535 bool killGCRefs(GenTree* tree);
9537 }; // end of class Compiler
9539 //---------------------------------------------------------------------------------------------------------------------
9540 // GenTreeVisitor: a flexible tree walker implemented using the curiosly-recurring-template pattern.
9542 // This class implements a configurable walker for IR trees. There are five configuration options (defaults values are
9543 // shown in parentheses):
9545 // - ComputeStack (false): when true, the walker will push each node onto the `m_ancestors` stack. "Ancestors" is a bit
9546 // of a misnomer, as the first entry will always be the current node.
9548 // - DoPreOrder (false): when true, the walker will invoke `TVisitor::PreOrderVisit` with the current node as an
9549 // argument before visiting the node's operands.
9551 // - DoPostOrder (false): when true, the walker will invoke `TVisitor::PostOrderVisit` with the current node as an
9552 // argument after visiting the node's operands.
9554 // - DoLclVarsOnly (false): when true, the walker will only invoke `TVisitor::PreOrderVisit` for lclVar nodes.
9555 // `DoPreOrder` must be true if this option is true.
9557 // - UseExecutionOrder (false): when true, then walker will visit a node's operands in execution order (e.g. if a
9558 // binary operator has the `GTF_REVERSE_OPS` flag set, the second operand will be
9559 // visited before the first).
9561 // At least one of `DoPreOrder` and `DoPostOrder` must be specified.
9563 // A simple pre-order visitor might look something like the following:
9565 // class CountingVisitor final : public GenTreeVisitor<CountingVisitor>
9570 // DoPreOrder = true
9573 // unsigned m_count;
9575 // CountingVisitor(Compiler* compiler)
9576 // : GenTreeVisitor<CountingVisitor>(compiler), m_count(0)
9580 // Compiler::fgWalkResult PreOrderVisit(GenTree* node)
9586 // This visitor would then be used like so:
9588 // CountingVisitor countingVisitor(compiler);
9589 // countingVisitor.WalkTree(root);
9591 template <typename TVisitor>
9592 class GenTreeVisitor
9595 typedef Compiler::fgWalkResult fgWalkResult;
9599 ComputeStack = false,
9601 DoPostOrder = false,
9602 DoLclVarsOnly = false,
9603 UseExecutionOrder = false,
9606 Compiler* m_compiler;
9607 ArrayStack<GenTree*> m_ancestors;
9609 GenTreeVisitor(Compiler* compiler) : m_compiler(compiler), m_ancestors(compiler->getAllocator(CMK_ArrayStack))
9611 assert(compiler != nullptr);
9613 static_assert_no_msg(TVisitor::DoPreOrder || TVisitor::DoPostOrder);
9614 static_assert_no_msg(!TVisitor::DoLclVarsOnly || TVisitor::DoPreOrder);
9617 fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
9619 return fgWalkResult::WALK_CONTINUE;
9622 fgWalkResult PostOrderVisit(GenTree** use, GenTree* user)
9624 return fgWalkResult::WALK_CONTINUE;
9628 fgWalkResult WalkTree(GenTree** use, GenTree* user)
9630 assert(use != nullptr);
9632 GenTree* node = *use;
9634 if (TVisitor::ComputeStack)
9636 m_ancestors.Push(node);
9639 fgWalkResult result = fgWalkResult::WALK_CONTINUE;
9640 if (TVisitor::DoPreOrder && !TVisitor::DoLclVarsOnly)
9642 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9643 if (result == fgWalkResult::WALK_ABORT)
9649 if ((node == nullptr) || (result == fgWalkResult::WALK_SKIP_SUBTREES))
9655 switch (node->OperGet())
9660 case GT_LCL_VAR_ADDR:
9661 case GT_LCL_FLD_ADDR:
9662 if (TVisitor::DoLclVarsOnly)
9664 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9665 if (result == fgWalkResult::WALK_ABORT)
9681 case GT_MEMORYBARRIER:
9686 case GT_START_NONGC:
9687 case GT_START_PREEMPTGC:
9689 #if !FEATURE_EH_FUNCLETS
9691 #endif // !FEATURE_EH_FUNCLETS
9695 case GT_CLS_VAR_ADDR:
9699 case GT_PINVOKE_PROLOG:
9700 case GT_PINVOKE_EPILOG:
9704 // Lclvar unary operators
9705 case GT_STORE_LCL_VAR:
9706 case GT_STORE_LCL_FLD:
9707 if (TVisitor::DoLclVarsOnly)
9709 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9710 if (result == fgWalkResult::WALK_ABORT)
9717 // Standard unary operators
9746 case GT_RUNTIMELOOKUP:
9748 GenTreeUnOp* const unOp = node->AsUnOp();
9749 if (unOp->gtOp1 != nullptr)
9751 result = WalkTree(&unOp->gtOp1, unOp);
9752 if (result == fgWalkResult::WALK_ABORT)
9763 GenTreeCmpXchg* const cmpXchg = node->AsCmpXchg();
9765 result = WalkTree(&cmpXchg->gtOpLocation, cmpXchg);
9766 if (result == fgWalkResult::WALK_ABORT)
9770 result = WalkTree(&cmpXchg->gtOpValue, cmpXchg);
9771 if (result == fgWalkResult::WALK_ABORT)
9775 result = WalkTree(&cmpXchg->gtOpComparand, cmpXchg);
9776 if (result == fgWalkResult::WALK_ABORT)
9783 case GT_ARR_BOUNDS_CHECK:
9786 #endif // FEATURE_SIMD
9787 #ifdef FEATURE_HW_INTRINSICS
9788 case GT_HW_INTRINSIC_CHK:
9789 #endif // FEATURE_HW_INTRINSICS
9791 GenTreeBoundsChk* const boundsChk = node->AsBoundsChk();
9793 result = WalkTree(&boundsChk->gtIndex, boundsChk);
9794 if (result == fgWalkResult::WALK_ABORT)
9798 result = WalkTree(&boundsChk->gtArrLen, boundsChk);
9799 if (result == fgWalkResult::WALK_ABORT)
9808 GenTreeField* const field = node->AsField();
9810 if (field->gtFldObj != nullptr)
9812 result = WalkTree(&field->gtFldObj, field);
9813 if (result == fgWalkResult::WALK_ABORT)
9823 GenTreeArrElem* const arrElem = node->AsArrElem();
9825 result = WalkTree(&arrElem->gtArrObj, arrElem);
9826 if (result == fgWalkResult::WALK_ABORT)
9831 const unsigned rank = arrElem->gtArrRank;
9832 for (unsigned dim = 0; dim < rank; dim++)
9834 result = WalkTree(&arrElem->gtArrInds[dim], arrElem);
9835 if (result == fgWalkResult::WALK_ABORT)
9845 GenTreeArrOffs* const arrOffs = node->AsArrOffs();
9847 result = WalkTree(&arrOffs->gtOffset, arrOffs);
9848 if (result == fgWalkResult::WALK_ABORT)
9852 result = WalkTree(&arrOffs->gtIndex, arrOffs);
9853 if (result == fgWalkResult::WALK_ABORT)
9857 result = WalkTree(&arrOffs->gtArrObj, arrOffs);
9858 if (result == fgWalkResult::WALK_ABORT)
9867 GenTreeDynBlk* const dynBlock = node->AsDynBlk();
9869 GenTree** op1Use = &dynBlock->gtOp1;
9870 GenTree** op2Use = &dynBlock->gtDynamicSize;
9872 if (TVisitor::UseExecutionOrder && dynBlock->gtEvalSizeFirst)
9874 std::swap(op1Use, op2Use);
9877 result = WalkTree(op1Use, dynBlock);
9878 if (result == fgWalkResult::WALK_ABORT)
9882 result = WalkTree(op2Use, dynBlock);
9883 if (result == fgWalkResult::WALK_ABORT)
9890 case GT_STORE_DYN_BLK:
9892 GenTreeDynBlk* const dynBlock = node->AsDynBlk();
9894 GenTree** op1Use = &dynBlock->gtOp1;
9895 GenTree** op2Use = &dynBlock->gtOp2;
9896 GenTree** op3Use = &dynBlock->gtDynamicSize;
9898 if (TVisitor::UseExecutionOrder)
9900 if (dynBlock->IsReverseOp())
9902 std::swap(op1Use, op2Use);
9904 if (dynBlock->gtEvalSizeFirst)
9906 std::swap(op3Use, op2Use);
9907 std::swap(op2Use, op1Use);
9911 result = WalkTree(op1Use, dynBlock);
9912 if (result == fgWalkResult::WALK_ABORT)
9916 result = WalkTree(op2Use, dynBlock);
9917 if (result == fgWalkResult::WALK_ABORT)
9921 result = WalkTree(op3Use, dynBlock);
9922 if (result == fgWalkResult::WALK_ABORT)
9931 GenTreeCall* const call = node->AsCall();
9933 if (call->gtCallObjp != nullptr)
9935 result = WalkTree(&call->gtCallObjp, call);
9936 if (result == fgWalkResult::WALK_ABORT)
9942 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
9944 result = WalkTree(args->pCurrent(), call);
9945 if (result == fgWalkResult::WALK_ABORT)
9951 for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
9953 result = WalkTree(args->pCurrent(), call);
9954 if (result == fgWalkResult::WALK_ABORT)
9960 if (call->gtCallType == CT_INDIRECT)
9962 if (call->gtCallCookie != nullptr)
9964 result = WalkTree(&call->gtCallCookie, call);
9965 if (result == fgWalkResult::WALK_ABORT)
9971 result = WalkTree(&call->gtCallAddr, call);
9972 if (result == fgWalkResult::WALK_ABORT)
9978 if (call->gtControlExpr != nullptr)
9980 result = WalkTree(&call->gtControlExpr, call);
9981 if (result == fgWalkResult::WALK_ABORT)
9993 assert(node->OperIsBinary());
9995 GenTreeOp* const op = node->AsOp();
9997 GenTree** op1Use = &op->gtOp1;
9998 GenTree** op2Use = &op->gtOp2;
10000 if (TVisitor::UseExecutionOrder && node->IsReverseOp())
10002 std::swap(op1Use, op2Use);
10005 if (*op1Use != nullptr)
10007 result = WalkTree(op1Use, op);
10008 if (result == fgWalkResult::WALK_ABORT)
10014 if (*op2Use != nullptr)
10016 result = WalkTree(op2Use, op);
10017 if (result == fgWalkResult::WALK_ABORT)
10027 // Finally, visit the current node
10028 if (TVisitor::DoPostOrder)
10030 result = reinterpret_cast<TVisitor*>(this)->PostOrderVisit(use, user);
10033 if (TVisitor::ComputeStack)
10042 template <bool computeStack, bool doPreOrder, bool doPostOrder, bool doLclVarsOnly, bool useExecutionOrder>
10043 class GenericTreeWalker final
10044 : public GenTreeVisitor<GenericTreeWalker<computeStack, doPreOrder, doPostOrder, doLclVarsOnly, useExecutionOrder>>
10049 ComputeStack = computeStack,
10050 DoPreOrder = doPreOrder,
10051 DoPostOrder = doPostOrder,
10052 DoLclVarsOnly = doLclVarsOnly,
10053 UseExecutionOrder = useExecutionOrder,
10057 Compiler::fgWalkData* m_walkData;
10060 GenericTreeWalker(Compiler::fgWalkData* walkData)
10061 : GenTreeVisitor<GenericTreeWalker<computeStack, doPreOrder, doPostOrder, doLclVarsOnly, useExecutionOrder>>(
10062 walkData->compiler)
10063 , m_walkData(walkData)
10065 assert(walkData != nullptr);
10069 walkData->parentStack = &this->m_ancestors;
10073 Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
10075 m_walkData->parent = user;
10076 return m_walkData->wtprVisitorFn(use, m_walkData);
10079 Compiler::fgWalkResult PostOrderVisit(GenTree** use, GenTree* user)
10081 m_walkData->parent = user;
10082 return m_walkData->wtpoVisitorFn(use, m_walkData);
10087 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10088 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10090 XX Miscellaneous Compiler stuff XX
10092 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10093 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10096 // Values used to mark the types a stack slot is used for
10098 const unsigned TYPE_REF_INT = 0x01; // slot used as a 32-bit int
10099 const unsigned TYPE_REF_LNG = 0x02; // slot used as a 64-bit long
10100 const unsigned TYPE_REF_FLT = 0x04; // slot used as a 32-bit float
10101 const unsigned TYPE_REF_DBL = 0x08; // slot used as a 64-bit float
10102 const unsigned TYPE_REF_PTR = 0x10; // slot used as a 32-bit pointer
10103 const unsigned TYPE_REF_BYR = 0x20; // slot used as a byref pointer
10104 const unsigned TYPE_REF_STC = 0x40; // slot used as a struct
10105 const unsigned TYPE_REF_TYPEMASK = 0x7F; // bits that represent the type
10107 // const unsigned TYPE_REF_ADDR_TAKEN = 0x80; // slots address was taken
10109 /*****************************************************************************
10111 * Variables to keep track of total code amounts.
10116 extern size_t grossVMsize;
10117 extern size_t grossNCsize;
10118 extern size_t totalNCsize;
10120 extern unsigned genMethodICnt;
10121 extern unsigned genMethodNCnt;
10122 extern size_t gcHeaderISize;
10123 extern size_t gcPtrMapISize;
10124 extern size_t gcHeaderNSize;
10125 extern size_t gcPtrMapNSize;
10127 #endif // DISPLAY_SIZES
10129 /*****************************************************************************
10131 * Variables to keep track of basic block counts (more data on 1 BB methods)
10134 #if COUNT_BASIC_BLOCKS
10135 extern Histogram bbCntTable;
10136 extern Histogram bbOneBBSizeTable;
10139 /*****************************************************************************
10141 * Used by optFindNaturalLoops to gather statistical information such as
10142 * - total number of natural loops
10143 * - number of loops with 1, 2, ... exit conditions
10144 * - number of loops that have an iterator (for like)
10145 * - number of loops that have a constant iterator
10150 extern unsigned totalLoopMethods; // counts the total number of methods that have natural loops
10151 extern unsigned maxLoopsPerMethod; // counts the maximum number of loops a method has
10152 extern unsigned totalLoopOverflows; // # of methods that identified more loops than we can represent
10153 extern unsigned totalLoopCount; // counts the total number of natural loops
10154 extern unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
10155 extern unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
10156 extern unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
10157 extern unsigned simpleTestLoopCount; // counts the # of loops with an iterator and a simple loop condition (iter <
10159 extern unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
10160 extern bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
10161 extern unsigned loopsThisMethod; // counts the number of loops in the current method
10162 extern bool loopOverflowThisMethod; // True if we exceeded the max # of loops in the method.
10163 extern Histogram loopCountTable; // Histogram of loop counts
10164 extern Histogram loopExitCountTable; // Histogram of loop exit counts
10166 #endif // COUNT_LOOPS
10168 /*****************************************************************************
10169 * variables to keep track of how many iterations we go in a dataflow pass
10174 extern unsigned CSEiterCount; // counts the # of iteration for the CSE dataflow
10175 extern unsigned CFiterCount; // counts the # of iteration for the Const Folding dataflow
10177 #endif // DATAFLOW_ITER
10179 #if MEASURE_BLOCK_SIZE
10180 extern size_t genFlowNodeSize;
10181 extern size_t genFlowNodeCnt;
10182 #endif // MEASURE_BLOCK_SIZE
10184 #if MEASURE_NODE_SIZE
10185 struct NodeSizeStats
10189 genTreeNodeCnt = 0;
10190 genTreeNodeSize = 0;
10191 genTreeNodeActualSize = 0;
10194 // Count of tree nodes allocated.
10195 unsigned __int64 genTreeNodeCnt;
10197 // The size we allocate.
10198 unsigned __int64 genTreeNodeSize;
10200 // The actual size of the node. Note that the actual size will likely be smaller
10201 // than the allocated size, but we sometimes use SetOper()/ChangeOper() to change
10202 // a smaller node to a larger one. TODO-Cleanup: add stats on
10203 // SetOper()/ChangeOper() usage to quantify this.
10204 unsigned __int64 genTreeNodeActualSize;
10206 extern NodeSizeStats genNodeSizeStats; // Total node size stats
10207 extern NodeSizeStats genNodeSizeStatsPerFunc; // Per-function node size stats
10208 extern Histogram genTreeNcntHist;
10209 extern Histogram genTreeNsizHist;
10210 #endif // MEASURE_NODE_SIZE
10212 /*****************************************************************************
10213 * Count fatal errors (including noway_asserts).
10217 extern unsigned fatal_badCode;
10218 extern unsigned fatal_noWay;
10219 extern unsigned fatal_NOMEM;
10220 extern unsigned fatal_noWayAssertBody;
10222 extern unsigned fatal_noWayAssertBodyArgs;
10224 extern unsigned fatal_NYI;
10225 #endif // MEASURE_FATAL
10227 /*****************************************************************************
10231 #ifdef _TARGET_XARCH_
10233 const instruction INS_SHIFT_LEFT_LOGICAL = INS_shl;
10234 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_shr;
10235 const instruction INS_SHIFT_RIGHT_ARITHM = INS_sar;
10237 const instruction INS_AND = INS_and;
10238 const instruction INS_OR = INS_or;
10239 const instruction INS_XOR = INS_xor;
10240 const instruction INS_NEG = INS_neg;
10241 const instruction INS_TEST = INS_test;
10242 const instruction INS_MUL = INS_imul;
10243 const instruction INS_SIGNED_DIVIDE = INS_idiv;
10244 const instruction INS_UNSIGNED_DIVIDE = INS_div;
10245 const instruction INS_BREAKPOINT = INS_int3;
10246 const instruction INS_ADDC = INS_adc;
10247 const instruction INS_SUBC = INS_sbb;
10248 const instruction INS_NOT = INS_not;
10250 #endif // _TARGET_XARCH_
10252 #ifdef _TARGET_ARM_
10254 const instruction INS_SHIFT_LEFT_LOGICAL = INS_lsl;
10255 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_lsr;
10256 const instruction INS_SHIFT_RIGHT_ARITHM = INS_asr;
10258 const instruction INS_AND = INS_and;
10259 const instruction INS_OR = INS_orr;
10260 const instruction INS_XOR = INS_eor;
10261 const instruction INS_NEG = INS_rsb;
10262 const instruction INS_TEST = INS_tst;
10263 const instruction INS_MUL = INS_mul;
10264 const instruction INS_MULADD = INS_mla;
10265 const instruction INS_SIGNED_DIVIDE = INS_sdiv;
10266 const instruction INS_UNSIGNED_DIVIDE = INS_udiv;
10267 const instruction INS_BREAKPOINT = INS_bkpt;
10268 const instruction INS_ADDC = INS_adc;
10269 const instruction INS_SUBC = INS_sbc;
10270 const instruction INS_NOT = INS_mvn;
10272 const instruction INS_ABS = INS_vabs;
10273 const instruction INS_SQRT = INS_vsqrt;
10275 #endif // _TARGET_ARM_
10277 #ifdef _TARGET_ARM64_
10279 const instruction INS_MULADD = INS_madd;
10280 const instruction INS_BREAKPOINT = INS_bkpt;
10282 const instruction INS_ABS = INS_fabs;
10283 const instruction INS_SQRT = INS_fsqrt;
10285 #endif // _TARGET_ARM64_
10287 /*****************************************************************************/
10289 extern const BYTE genTypeSizes[];
10290 extern const BYTE genTypeAlignments[];
10291 extern const BYTE genTypeStSzs[];
10292 extern const BYTE genActualTypes[];
10294 /*****************************************************************************/
10296 // VERY_LARGE_FRAME_SIZE_REG_MASK is the set of registers we need to use for
10297 // the probing loop generated for very large stack frames (see `getVeryLargeFrameSize`).
10299 #ifdef _TARGET_ARM_
10300 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R4 | RBM_R5 | RBM_R6)
10301 #elif defined(_TARGET_ARM64_)
10302 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R9 | RBM_R10 | RBM_R11)
10305 /*****************************************************************************/
10307 extern BasicBlock dummyBB;
10309 /*****************************************************************************/
10310 /*****************************************************************************/
10312 // foreach_treenode_execution_order: An iterator that iterates through all the tree
10313 // nodes of a statement in execution order.
10314 // __stmt: a GT_STMT type GenTree*
10315 // __node: a GenTree*, already declared, that gets updated with each node in the statement, in execution order
10317 #define foreach_treenode_execution_order(__node, __stmt) \
10318 for ((__node) = (__stmt)->gtStmt.gtStmtList; (__node); (__node) = (__node)->gtNext)
10320 // foreach_block: An iterator over all blocks in the function.
10321 // __compiler: the Compiler* object
10322 // __block : a BasicBlock*, already declared, that gets updated each iteration.
10324 #define foreach_block(__compiler, __block) \
10325 for ((__block) = (__compiler)->fgFirstBB; (__block); (__block) = (__block)->bbNext)
10327 /*****************************************************************************/
10328 /*****************************************************************************/
10332 void dumpConvertedVarSet(Compiler* comp, VARSET_VALARG_TP vars);
10334 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10335 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10337 XX Debugging helpers XX
10339 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10340 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10343 /*****************************************************************************/
10344 /* The following functions are intended to be called from the debugger, to dump
10345 * various data structures. The can be used in the debugger Watch or Quick Watch
10346 * windows. They are designed to be short to type and take as few arguments as
10347 * possible. The 'c' versions take a Compiler*, whereas the 'd' versions use the TlsCompiler.
10348 * See the function definition comment for more details.
10351 void cBlock(Compiler* comp, BasicBlock* block);
10352 void cBlocks(Compiler* comp);
10353 void cBlocksV(Compiler* comp);
10354 void cTree(Compiler* comp, GenTree* tree);
10355 void cTrees(Compiler* comp);
10356 void cEH(Compiler* comp);
10357 void cVar(Compiler* comp, unsigned lclNum);
10358 void cVarDsc(Compiler* comp, LclVarDsc* varDsc);
10359 void cVars(Compiler* comp);
10360 void cVarsFinal(Compiler* comp);
10361 void cBlockPreds(Compiler* comp, BasicBlock* block);
10362 void cReach(Compiler* comp);
10363 void cDoms(Compiler* comp);
10364 void cLiveness(Compiler* comp);
10365 void cCVarSet(Compiler* comp, VARSET_VALARG_TP vars);
10367 void cFuncIR(Compiler* comp);
10368 void cBlockIR(Compiler* comp, BasicBlock* block);
10369 void cLoopIR(Compiler* comp, Compiler::LoopDsc* loop);
10370 void cTreeIR(Compiler* comp, GenTree* tree);
10371 int cTreeTypeIR(Compiler* comp, GenTree* tree);
10372 int cTreeKindsIR(Compiler* comp, GenTree* tree);
10373 int cTreeFlagsIR(Compiler* comp, GenTree* tree);
10374 int cOperandIR(Compiler* comp, GenTree* operand);
10375 int cLeafIR(Compiler* comp, GenTree* tree);
10376 int cIndirIR(Compiler* comp, GenTree* tree);
10377 int cListIR(Compiler* comp, GenTree* list);
10378 int cSsaNumIR(Compiler* comp, GenTree* tree);
10379 int cValNumIR(Compiler* comp, GenTree* tree);
10380 int cDependsIR(Compiler* comp, GenTree* comma, bool* first);
10382 void dBlock(BasicBlock* block);
10385 void dTree(GenTree* tree);
10388 void dVar(unsigned lclNum);
10389 void dVarDsc(LclVarDsc* varDsc);
10392 void dBlockPreds(BasicBlock* block);
10396 void dCVarSet(VARSET_VALARG_TP vars);
10398 void dRegMask(regMaskTP mask);
10401 void dBlockIR(BasicBlock* block);
10402 void dTreeIR(GenTree* tree);
10403 void dLoopIR(Compiler::LoopDsc* loop);
10404 void dLoopNumIR(unsigned loopNum);
10405 int dTabStopIR(int curr, int tabstop);
10406 int dTreeTypeIR(GenTree* tree);
10407 int dTreeKindsIR(GenTree* tree);
10408 int dTreeFlagsIR(GenTree* tree);
10409 int dOperandIR(GenTree* operand);
10410 int dLeafIR(GenTree* tree);
10411 int dIndirIR(GenTree* tree);
10412 int dListIR(GenTree* list);
10413 int dSsaNumIR(GenTree* tree);
10414 int dValNumIR(GenTree* tree);
10415 int dDependsIR(GenTree* comma);
10418 GenTree* dFindTree(GenTree* tree, unsigned id);
10419 GenTree* dFindTree(unsigned id);
10420 GenTreeStmt* dFindStmt(unsigned id);
10421 BasicBlock* dFindBlock(unsigned bbNum);
10425 #include "compiler.hpp" // All the shared inline functions
10427 /*****************************************************************************/
10428 #endif //_COMPILER_H_
10429 /*****************************************************************************/