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.
306 // note this only packs because var_types is a typedef of unsigned char
307 var_types lvType : 5; // TYP_INT/LONG/FLOAT/DOUBLE/REF
309 unsigned char lvIsParam : 1; // is this a parameter?
310 unsigned char lvIsRegArg : 1; // is this a register argument?
311 unsigned char lvFramePointerBased : 1; // 0 = off of REG_SPBASE (e.g., ESP), 1 = off of REG_FPBASE (e.g., EBP)
313 unsigned char lvStructGcCount : 3; // if struct, how many GC pointer (stop counting at 7). The only use of values >1
314 // is to help determine whether to use block init in the prolog.
315 unsigned char lvOnFrame : 1; // (part of) the variable lives on the frame
316 unsigned char lvRegister : 1; // assigned to live in a register? For RyuJIT backend, this is only set if the
317 // variable is in the same register for the entire function.
318 unsigned char lvTracked : 1; // is this a tracked variable?
319 bool lvTrackedNonStruct()
321 return lvTracked && lvType != TYP_STRUCT;
323 unsigned char lvPinned : 1; // is this a pinned variable?
325 unsigned char lvMustInit : 1; // must be initialized
326 unsigned char lvAddrExposed : 1; // The address of this variable is "exposed" -- passed as an argument, stored in a
327 // global location, etc.
328 // We cannot reason reliably about the value of the variable.
329 unsigned char lvDoNotEnregister : 1; // Do not enregister this variable.
330 unsigned char lvFieldAccessed : 1; // The var is a struct local, and a field of the variable is accessed. Affects
333 unsigned char lvInSsa : 1; // The variable is in SSA form (set by SsaBuilder)
336 // These further document the reasons for setting "lvDoNotEnregister". (Note that "lvAddrExposed" is one of the
338 // also, lvType == TYP_STRUCT prevents enregistration. At least one of the reasons should be true.
339 unsigned char lvVMNeedsStackAddr : 1; // The VM may have access to a stack-relative address of the variable, and
340 // read/write its value.
341 unsigned char lvLiveInOutOfHndlr : 1; // The variable was live in or out of an exception handler, and this required
342 // the variable to be
343 // in the stack (at least at those boundaries.)
344 unsigned char lvLclFieldExpr : 1; // The variable is not a struct, but was accessed like one (e.g., reading a
345 // particular byte from an int).
346 unsigned char lvLclBlockOpAddr : 1; // The variable was written to via a block operation that took its address.
347 unsigned char lvLiveAcrossUCall : 1; // The variable is live across an unmanaged call.
349 unsigned char lvIsCSE : 1; // Indicates if this LclVar is a CSE variable.
350 unsigned char lvHasLdAddrOp : 1; // has ldloca or ldarga opcode on this local.
351 unsigned char lvStackByref : 1; // This is a compiler temporary of TYP_BYREF that is known to point into our local
354 unsigned char lvHasILStoreOp : 1; // there is at least one STLOC or STARG on this local
355 unsigned char lvHasMultipleILStoreOp : 1; // there is more than one STLOC on this local
357 unsigned char lvIsTemp : 1; // Short-lifetime compiler temp (if lvIsParam is false), or implicit byref parameter
358 // (if lvIsParam is true)
360 unsigned char lvIsBoolean : 1; // set if variable is boolean
363 unsigned char lvSingleDef : 1; // variable has a single def
364 unsigned char lvDisqualify : 1; // variable is no longer OK for add copy optimization
365 unsigned char lvVolatileHint : 1; // hint for AssertionProp
368 #ifndef _TARGET_64BIT_
369 unsigned char lvStructDoubleAlign : 1; // Must we double align this struct?
370 #endif // !_TARGET_64BIT_
371 #ifdef _TARGET_64BIT_
372 unsigned char lvQuirkToLong : 1; // Quirk to allocate this LclVar as a 64-bit long
375 unsigned char lvKeepType : 1; // Don't change the type of this variable
376 unsigned char lvNoLclFldStress : 1; // Can't apply local field stress on this one
378 unsigned char lvIsPtr : 1; // Might this be used in an address computation? (used by buffer overflow security
380 unsigned char lvIsUnsafeBuffer : 1; // Does this contain an unsafe buffer requiring buffer overflow security checks?
381 unsigned char lvPromoted : 1; // True when this local is a promoted struct, a normed struct, or a "split" long on a
382 // 32-bit target. For implicit byref parameters, this gets hijacked between
383 // fgRetypeImplicitByRefArgs and fgMarkDemotedImplicitByRefArgs to indicate whether
384 // references to the arg are being rewritten as references to a promoted shadow local.
385 unsigned char lvIsStructField : 1; // Is this local var a field of a promoted struct local?
386 unsigned char lvOverlappingFields : 1; // True when we have a struct with possibly overlapping fields
387 unsigned char lvContainsHoles : 1; // True when we have a promoted struct that contains holes
388 unsigned char lvCustomLayout : 1; // True when this struct has "CustomLayout"
390 unsigned char lvIsMultiRegArg : 1; // true if this is a multireg LclVar struct used in an argument context
391 unsigned char lvIsMultiRegRet : 1; // true if this is a multireg LclVar struct assigned from a multireg call
394 unsigned char _lvIsHfa : 1; // Is this a struct variable who's class handle is an HFA type
395 unsigned char _lvIsHfaRegArg : 1; // Is this a HFA argument variable? // TODO-CLEANUP: Remove this and replace
396 // with (lvIsRegArg && lvIsHfa())
397 unsigned char _lvHfaTypeIsFloat : 1; // Is the HFA type float or double?
398 #endif // FEATURE_HFA
401 // TODO-Cleanup: See the note on lvSize() - this flag is only in use by asserts that are checking for struct
402 // types, and is needed because of cases where TYP_STRUCT is bashed to an integral type.
403 // Consider cleaning this up so this workaround is not required.
404 unsigned char lvUnusedStruct : 1; // All references to this promoted struct are through its field locals.
405 // I.e. there is no longer any reference to the struct directly.
406 // In this case we can simply remove this struct local.
409 unsigned char lvLRACandidate : 1; // Tracked for linear scan register allocation purposes
412 // Note that both SIMD vector args and locals are marked as lvSIMDType = true, but the
413 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD*.
414 unsigned char lvSIMDType : 1; // This is a SIMD struct
415 unsigned char lvUsedInSIMDIntrinsic : 1; // This tells lclvar is used for simd intrinsic
416 var_types lvBaseType : 5; // Note: this only packs because var_types is a typedef of unsigned char
417 #endif // FEATURE_SIMD
418 unsigned char lvRegStruct : 1; // This is a reg-sized non-field-addressed struct.
420 unsigned char lvClassIsExact : 1; // lvClassHandle is the exact type
423 unsigned char lvClassInfoUpdated : 1; // true if this var has updated class handle or exactness
426 unsigned char lvImplicitlyReferenced : 1; // true if there are non-IR references to this local (prolog, epilog, gc,
430 unsigned lvFieldLclStart; // The index of the local var representing the first field in the promoted struct
431 // local. For implicit byref parameters, this gets hijacked between
432 // fgRetypeImplicitByRefArgs and fgMarkDemotedImplicitByRefArgs to point to the
433 // struct local created to model the parameter's struct promotion, if any.
434 unsigned lvParentLcl; // The index of the local var representing the parent (i.e. the promoted struct local).
435 // Valid on promoted struct local fields.
438 unsigned char lvFieldCnt; // Number of fields in the promoted VarDsc.
439 unsigned char lvFldOffset;
440 unsigned char lvFldOrdinal;
442 #if FEATURE_MULTIREG_ARGS
443 regNumber lvRegNumForSlot(unsigned slotNum)
449 else if (slotNum == 1)
451 return lvOtherArgReg;
455 assert(false && "Invalid slotNum!");
460 #endif // FEATURE_MULTIREG_ARGS
478 bool lvIsHfaRegArg() const
481 return _lvIsHfaRegArg;
487 void lvSetIsHfaRegArg(bool value = true)
490 _lvIsHfaRegArg = value;
494 bool lvHfaTypeIsFloat() const
497 return _lvHfaTypeIsFloat;
503 void lvSetHfaTypeIsFloat(bool value)
506 _lvHfaTypeIsFloat = value;
510 // on Arm64 - Returns 1-4 indicating the number of register slots used by the HFA
511 // on Arm32 - Returns the total number of single FP register slots used by the HFA, max is 8
513 unsigned lvHfaSlots() const
516 assert(varTypeIsStruct(lvType));
518 return lvExactSize / sizeof(float);
519 #else // _TARGET_ARM64_
520 if (lvHfaTypeIsFloat())
522 return lvExactSize / sizeof(float);
526 return lvExactSize / sizeof(double);
528 #endif // _TARGET_ARM64_
531 // lvIsMultiRegArgOrRet()
532 // returns true if this is a multireg LclVar struct used in an argument context
533 // or if this is a multireg LclVar struct assigned from a multireg call
534 bool lvIsMultiRegArgOrRet()
536 return lvIsMultiRegArg || lvIsMultiRegRet;
540 regNumberSmall _lvRegNum; // Used to store the register this variable is in (or, the low register of a
541 // register pair). It is set during codegen any time the
542 // variable is enregistered (lvRegister is only set
543 // to non-zero if the variable gets the same register assignment for its entire
545 #if !defined(_TARGET_64BIT_)
546 regNumberSmall _lvOtherReg; // Used for "upper half" of long var.
547 #endif // !defined(_TARGET_64BIT_)
549 regNumberSmall _lvArgReg; // The register in which this argument is passed.
551 #if FEATURE_MULTIREG_ARGS
552 regNumberSmall _lvOtherArgReg; // Used for the second part of the struct passed in a register.
553 // Note this is defined but not used by ARM32
554 #endif // FEATURE_MULTIREG_ARGS
556 regNumberSmall _lvArgInitReg; // the register into which the argument is moved at entry
559 // The register number is stored in a small format (8 bits), but the getters return and the setters take
560 // a full-size (unsigned) format, to localize the casts here.
562 /////////////////////
564 __declspec(property(get = GetRegNum, put = SetRegNum)) regNumber lvRegNum;
566 regNumber GetRegNum() const
568 return (regNumber)_lvRegNum;
571 void SetRegNum(regNumber reg)
573 _lvRegNum = (regNumberSmall)reg;
574 assert(_lvRegNum == reg);
577 /////////////////////
579 #if defined(_TARGET_64BIT_)
580 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
582 regNumber GetOtherReg() const
584 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
585 // "unreachable code" warnings
589 void SetOtherReg(regNumber reg)
591 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
592 // "unreachable code" warnings
594 #else // !_TARGET_64BIT_
595 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
597 regNumber GetOtherReg() const
599 return (regNumber)_lvOtherReg;
602 void SetOtherReg(regNumber reg)
604 _lvOtherReg = (regNumberSmall)reg;
605 assert(_lvOtherReg == reg);
607 #endif // !_TARGET_64BIT_
609 /////////////////////
611 __declspec(property(get = GetArgReg, put = SetArgReg)) regNumber lvArgReg;
613 regNumber GetArgReg() const
615 return (regNumber)_lvArgReg;
618 void SetArgReg(regNumber reg)
620 _lvArgReg = (regNumberSmall)reg;
621 assert(_lvArgReg == reg);
624 #if FEATURE_MULTIREG_ARGS
625 __declspec(property(get = GetOtherArgReg, put = SetOtherArgReg)) regNumber lvOtherArgReg;
627 regNumber GetOtherArgReg() const
629 return (regNumber)_lvOtherArgReg;
632 void SetOtherArgReg(regNumber reg)
634 _lvOtherArgReg = (regNumberSmall)reg;
635 assert(_lvOtherArgReg == reg);
637 #endif // FEATURE_MULTIREG_ARGS
640 // Is this is a SIMD struct?
641 bool lvIsSIMDType() const
646 // Is this is a SIMD struct which is used for SIMD intrinsic?
647 bool lvIsUsedInSIMDIntrinsic() const
649 return lvUsedInSIMDIntrinsic;
652 // If feature_simd not enabled, return false
653 bool lvIsSIMDType() const
657 bool lvIsUsedInSIMDIntrinsic() const
663 /////////////////////
665 __declspec(property(get = GetArgInitReg, put = SetArgInitReg)) regNumber lvArgInitReg;
667 regNumber GetArgInitReg() const
669 return (regNumber)_lvArgInitReg;
672 void SetArgInitReg(regNumber reg)
674 _lvArgInitReg = (regNumberSmall)reg;
675 assert(_lvArgInitReg == reg);
678 /////////////////////
680 bool lvIsRegCandidate() const
682 return lvLRACandidate != 0;
685 bool lvIsInReg() const
687 return lvIsRegCandidate() && (lvRegNum != REG_STK);
690 regMaskTP lvRegMask() const
692 regMaskTP regMask = RBM_NONE;
693 if (varTypeIsFloating(TypeGet()))
695 if (lvRegNum != REG_STK)
697 regMask = genRegMaskFloat(lvRegNum, TypeGet());
702 if (lvRegNum != REG_STK)
704 regMask = genRegMask(lvRegNum);
710 unsigned short lvVarIndex; // variable tracking index
713 unsigned short m_lvRefCnt; // unweighted (real) reference count. For implicit by reference
714 // parameters, this gets hijacked from fgMarkImplicitByRefArgs
715 // through fgMarkDemotedImplicitByRefArgs, to provide a static
716 // appearance count (computed during address-exposed analysis)
717 // that fgMakeOutgoingStructArgCopy consults during global morph
718 // to determine if eliding its copy is legal.
720 BasicBlock::weight_t m_lvRefCntWtd; // weighted reference count
723 unsigned short lvRefCnt(RefCountState state = RCS_NORMAL) const;
724 void incLvRefCnt(unsigned short delta, RefCountState state = RCS_NORMAL);
725 void setLvRefCnt(unsigned short newValue, RefCountState state = RCS_NORMAL);
727 BasicBlock::weight_t lvRefCntWtd(RefCountState state = RCS_NORMAL) const;
728 void incLvRefCntWtd(BasicBlock::weight_t delta, RefCountState state = RCS_NORMAL);
729 void setLvRefCntWtd(BasicBlock::weight_t newValue, RefCountState state = RCS_NORMAL);
731 int lvStkOffs; // stack offset of home
732 unsigned lvExactSize; // (exact) size of the type in bytes
734 // Is this a promoted struct?
735 // This method returns true only for structs (including SIMD structs), not for
736 // locals that are split on a 32-bit target.
737 // It is only necessary to use this:
738 // 1) if only structs are wanted, and
739 // 2) if Lowering has already been done.
740 // Otherwise lvPromoted is valid.
741 bool lvPromotedStruct()
743 #if !defined(_TARGET_64BIT_)
744 return (lvPromoted && !varTypeIsLong(lvType));
745 #else // defined(_TARGET_64BIT_)
747 #endif // defined(_TARGET_64BIT_)
750 unsigned lvSize() const // Size needed for storage representation. Only used for structs or TYP_BLK.
752 // TODO-Review: Sometimes we get called on ARM with HFA struct variables that have been promoted,
753 // where the struct itself is no longer used because all access is via its member fields.
754 // When that happens, the struct is marked as unused and its type has been changed to
755 // TYP_INT (to keep the GC tracking code from looking at it).
756 // See Compiler::raAssignVars() for details. For example:
757 // N002 ( 4, 3) [00EA067C] ------------- return struct $346
758 // N001 ( 3, 2) [00EA0628] ------------- lclVar struct(U) V03 loc2
759 // float V03.f1 (offs=0x00) -> V12 tmp7
760 // f8 (last use) (last use) $345
761 // Here, the "struct(U)" shows that the "V03 loc2" variable is unused. Not shown is that V03
762 // is now TYP_INT in the local variable table. It's not really unused, because it's in the tree.
764 assert(varTypeIsStruct(lvType) || (lvType == TYP_BLK) || (lvPromoted && lvUnusedStruct));
766 #if defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
767 // For 32-bit architectures, we make local variable SIMD12 types 16 bytes instead of just 12. We can't do
768 // this for arguments, which must be passed according the defined ABI. We don't want to do this for
769 // dependently promoted struct fields, but we don't know that here. See lvaMapSimd12ToSimd16().
770 // (Note that for 64-bits, we are already rounding up to 16.)
771 if ((lvType == TYP_SIMD12) && !lvIsParam)
773 assert(lvExactSize == 12);
776 #endif // defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
778 return roundUp(lvExactSize, TARGET_POINTER_SIZE);
781 size_t lvArgStackSize() const;
783 unsigned lvSlotNum; // original slot # (if remapped)
785 typeInfo lvVerTypeInfo; // type info needed for verification
787 CORINFO_CLASS_HANDLE lvClassHnd; // class handle for the local, or null if not known
789 CORINFO_FIELD_HANDLE lvFieldHnd; // field handle for promoted struct fields
791 BYTE* lvGcLayout; // GC layout info for structs
794 BlockSet lvRefBlks; // Set of blocks that contain refs
795 GenTree* lvDefStmt; // Pointer to the statement with the single definition
796 void lvaDisqualifyVar(); // Call to disqualify a local variable from use in optAddCopies
798 var_types TypeGet() const
800 return (var_types)lvType;
802 bool lvStackAligned() const
804 assert(lvIsStructField);
805 return ((lvFldOffset % TARGET_POINTER_SIZE) == 0);
807 bool lvNormalizeOnLoad() const
809 return varTypeIsSmall(TypeGet()) &&
810 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
811 (lvIsParam || lvAddrExposed || lvIsStructField);
814 bool lvNormalizeOnStore()
816 return varTypeIsSmall(TypeGet()) &&
817 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
818 !(lvIsParam || lvAddrExposed || lvIsStructField);
821 void incRefCnts(BasicBlock::weight_t weight,
823 RefCountState state = RCS_NORMAL,
824 bool propagate = true);
825 bool IsFloatRegType() const
827 return isFloatRegType(lvType) || lvIsHfaRegArg();
829 var_types GetHfaType() const
831 return lvIsHfa() ? (lvHfaTypeIsFloat() ? TYP_FLOAT : TYP_DOUBLE) : TYP_UNDEF;
833 void SetHfaType(var_types type)
835 assert(varTypeIsFloating(type));
836 lvSetHfaTypeIsFloat(type == TYP_FLOAT);
839 var_types lvaArgType();
841 SsaDefArray<LclSsaVarDsc> lvPerSsaData;
843 // Returns the address of the per-Ssa data for the given ssaNum (which is required
844 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
845 // not an SSA variable).
846 LclSsaVarDsc* GetPerSsaData(unsigned ssaNum)
848 return lvPerSsaData.GetSsaDef(ssaNum);
853 const char* lvReason;
855 void PrintVarReg() const
857 printf("%s", getRegName(lvRegNum));
861 }; // class LclVarDsc
864 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
865 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
869 XX The temporary lclVars allocated by the compiler for code generation XX
871 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
872 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
875 /*****************************************************************************
877 * The following keeps track of temporaries allocated in the stack frame
878 * during code-generation (after register allocation). These spill-temps are
879 * only used if we run out of registers while evaluating a tree.
881 * These are different from the more common temps allocated by lvaGrabTemp().
892 static const int BAD_TEMP_OFFSET = 0xDDDDDDDD; // used as a sentinel "bad value" for tdOffs in DEBUG
900 TempDsc(int _tdNum, unsigned _tdSize, var_types _tdType) : tdNum(_tdNum), tdSize((BYTE)_tdSize), tdType(_tdType)
904 0); // temps must have a negative number (so they have a different number from all local variables)
905 tdOffs = BAD_TEMP_OFFSET;
909 IMPL_LIMITATION("too many spill temps");
914 bool tdLegalOffset() const
916 return tdOffs != BAD_TEMP_OFFSET;
920 int tdTempOffs() const
922 assert(tdLegalOffset());
925 void tdSetTempOffs(int offs)
928 assert(tdLegalOffset());
930 void tdAdjustTempOffs(int offs)
933 assert(tdLegalOffset());
936 int tdTempNum() const
941 unsigned tdTempSize() const
945 var_types tdTempType() const
951 // interface to hide linearscan implementation from rest of compiler
952 class LinearScanInterface
955 virtual void doLinearScan() = 0;
956 virtual void recordVarLocationsAtStartOfBB(BasicBlock* bb) = 0;
957 virtual bool willEnregisterLocalVars() const = 0;
960 LinearScanInterface* getLinearScanAllocator(Compiler* comp);
962 // Information about arrays: their element type and size, and the offset of the first element.
963 // We label GT_IND's that are array indices with GTF_IND_ARR_INDEX, and, for such nodes,
964 // associate an array info via the map retrieved by GetArrayInfoMap(). This information is used,
965 // for example, in value numbering of array index expressions.
968 var_types m_elemType;
969 CORINFO_CLASS_HANDLE m_elemStructType;
971 unsigned m_elemOffset;
973 ArrayInfo() : m_elemType(TYP_UNDEF), m_elemStructType(nullptr), m_elemSize(0), m_elemOffset(0)
977 ArrayInfo(var_types elemType, unsigned elemSize, unsigned elemOffset, CORINFO_CLASS_HANDLE elemStructType)
978 : m_elemType(elemType), m_elemStructType(elemStructType), m_elemSize(elemSize), m_elemOffset(elemOffset)
983 // This enumeration names the phases into which we divide compilation. The phases should completely
984 // partition a compilation.
987 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) enum_nm,
988 #include "compphases.h"
992 extern const char* PhaseNames[];
993 extern const char* PhaseEnums[];
994 extern const LPCWSTR PhaseShortNames[];
996 // The following enum provides a simple 1:1 mapping to CLR API's
997 enum API_ICorJitInfo_Names
999 #define DEF_CLR_API(name) API_##name,
1000 #include "ICorJitInfo_API_names.h"
1004 //---------------------------------------------------------------
1005 // Compilation time.
1008 // A "CompTimeInfo" is a structure for tracking the compilation time of one or more methods.
1009 // We divide a compilation into a sequence of contiguous phases, and track the total (per-thread) cycles
1010 // of the compilation, as well as the cycles for each phase. We also track the number of bytecodes.
1011 // If there is a failure in reading a timer at any point, the "CompTimeInfo" becomes invalid, as indicated
1012 // by "m_timerFailure" being true.
1013 // If FEATURE_JIT_METHOD_PERF is not set, we define a minimal form of this, enough to let other code compile.
1016 #ifdef FEATURE_JIT_METHOD_PERF
1017 // The string names of the phases.
1018 static const char* PhaseNames[];
1020 static bool PhaseHasChildren[];
1021 static int PhaseParent[];
1022 static bool PhaseReportsIRSize[];
1024 unsigned m_byteCodeBytes;
1025 unsigned __int64 m_totalCycles;
1026 unsigned __int64 m_invokesByPhase[PHASE_NUMBER_OF];
1027 unsigned __int64 m_cyclesByPhase[PHASE_NUMBER_OF];
1028 #if MEASURE_CLRAPI_CALLS
1029 unsigned __int64 m_CLRinvokesByPhase[PHASE_NUMBER_OF];
1030 unsigned __int64 m_CLRcyclesByPhase[PHASE_NUMBER_OF];
1033 unsigned m_nodeCountAfterPhase[PHASE_NUMBER_OF];
1035 // For better documentation, we call EndPhase on
1036 // non-leaf phases. We should also call EndPhase on the
1037 // last leaf subphase; obviously, the elapsed cycles between the EndPhase
1038 // for the last leaf subphase and the EndPhase for an ancestor should be very small.
1039 // We add all such "redundant end phase" intervals to this variable below; we print
1040 // it out in a report, so we can verify that it is, indeed, very small. If it ever
1041 // isn't, this means that we're doing something significant between the end of the last
1042 // declared subphase and the end of its parent.
1043 unsigned __int64 m_parentPhaseEndSlop;
1044 bool m_timerFailure;
1046 #if MEASURE_CLRAPI_CALLS
1047 // The following measures the time spent inside each individual CLR API call.
1048 unsigned m_allClrAPIcalls;
1049 unsigned m_perClrAPIcalls[API_ICorJitInfo_Names::API_COUNT];
1050 unsigned __int64 m_allClrAPIcycles;
1051 unsigned __int64 m_perClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
1052 unsigned __int32 m_maxClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
1053 #endif // MEASURE_CLRAPI_CALLS
1055 CompTimeInfo(unsigned byteCodeBytes);
1059 #ifdef FEATURE_JIT_METHOD_PERF
1061 #if MEASURE_CLRAPI_CALLS
1062 struct WrapICorJitInfo;
1065 // This class summarizes the JIT time information over the course of a run: the number of methods compiled,
1066 // and the total and maximum timings. (These are instances of the "CompTimeInfo" type described above).
1067 // The operation of adding a single method's timing to the summary may be performed concurrently by several
1068 // threads, so it is protected by a lock.
1069 // This class is intended to be used as a singleton type, with only a single instance.
1070 class CompTimeSummaryInfo
1072 // This lock protects the fields of all CompTimeSummaryInfo(s) (of which we expect there to be one).
1073 static CritSecObject s_compTimeSummaryLock;
1077 CompTimeInfo m_total;
1078 CompTimeInfo m_maximum;
1080 int m_numFilteredMethods;
1081 CompTimeInfo m_filtered;
1083 // This can use what ever data you want to determine if the value to be added
1084 // belongs in the filtered section (it's always included in the unfiltered section)
1085 bool IncludedInFilteredData(CompTimeInfo& info);
1088 // This is the unique CompTimeSummaryInfo object for this instance of the runtime.
1089 static CompTimeSummaryInfo s_compTimeSummary;
1091 CompTimeSummaryInfo()
1092 : m_numMethods(0), m_totMethods(0), m_total(0), m_maximum(0), m_numFilteredMethods(0), m_filtered(0)
1096 // Assumes that "info" is a completed CompTimeInfo for a compilation; adds it to the summary.
1097 // This is thread safe.
1098 void AddInfo(CompTimeInfo& info, bool includePhases);
1100 // Print the summary information to "f".
1101 // This is not thread-safe; assumed to be called by only one thread.
1102 void Print(FILE* f);
1105 // A JitTimer encapsulates a CompTimeInfo for a single compilation. It also tracks the start of compilation,
1106 // and when the current phase started. This is intended to be part of a Compilation object. This is
1107 // disabled (FEATURE_JIT_METHOD_PERF not defined) when FEATURE_CORECLR is set, or on non-windows platforms.
1111 unsigned __int64 m_start; // Start of the compilation.
1112 unsigned __int64 m_curPhaseStart; // Start of the current phase.
1113 #if MEASURE_CLRAPI_CALLS
1114 unsigned __int64 m_CLRcallStart; // Start of the current CLR API call (if any).
1115 unsigned __int64 m_CLRcallInvokes; // CLR API invokes under current outer so far
1116 unsigned __int64 m_CLRcallCycles; // CLR API cycles under current outer so far.
1117 int m_CLRcallAPInum; // The enum/index of the current CLR API call (or -1).
1118 static double s_cyclesPerSec; // Cached for speedier measurements
1121 Phases m_lastPhase; // The last phase that was completed (or (Phases)-1 to start).
1123 CompTimeInfo m_info; // The CompTimeInfo for this compilation.
1125 static CritSecObject s_csvLock; // Lock to protect the time log file.
1126 void PrintCsvMethodStats(Compiler* comp);
1129 void* operator new(size_t);
1130 void* operator new[](size_t);
1131 void operator delete(void*);
1132 void operator delete[](void*);
1135 // Initialized the timer instance
1136 JitTimer(unsigned byteCodeSize);
1138 static JitTimer* Create(Compiler* comp, unsigned byteCodeSize)
1140 return ::new (comp, CMK_Unknown) JitTimer(byteCodeSize);
1143 static void PrintCsvHeader();
1145 // Ends the current phase (argument is for a redundant check).
1146 void EndPhase(Compiler* compiler, Phases phase);
1148 #if MEASURE_CLRAPI_CALLS
1149 // Start and end a timed CLR API call.
1150 void CLRApiCallEnter(unsigned apix);
1151 void CLRApiCallLeave(unsigned apix);
1152 #endif // MEASURE_CLRAPI_CALLS
1154 // Completes the timing of the current method, which is assumed to have "byteCodeBytes" bytes of bytecode,
1155 // and adds it to "sum".
1156 void Terminate(Compiler* comp, CompTimeSummaryInfo& sum, bool includePhases);
1158 // Attempts to query the cycle counter of the current thread. If successful, returns "true" and sets
1159 // *cycles to the cycle counter value. Otherwise, returns false and sets the "m_timerFailure" flag of
1160 // "m_info" to true.
1161 bool GetThreadCycles(unsigned __int64* cycles)
1163 bool res = CycleTimer::GetThreadCyclesS(cycles);
1166 m_info.m_timerFailure = true;
1171 #endif // FEATURE_JIT_METHOD_PERF
1173 //------------------- Function/Funclet info -------------------------------
1174 enum FuncKind : BYTE
1176 FUNC_ROOT, // The main/root function (always id==0)
1177 FUNC_HANDLER, // a funclet associated with an EH handler (finally, fault, catch, filter handler)
1178 FUNC_FILTER, // a funclet associated with an EH filter
1187 BYTE funFlags; // Currently unused, just here for padding
1188 unsigned short funEHIndex; // index, into the ebd table, of innermost EH clause corresponding to this
1189 // funclet. It is only valid if funKind field indicates this is a
1190 // EH-related funclet: FUNC_HANDLER or FUNC_FILTER
1192 #if defined(_TARGET_AMD64_)
1194 // TODO-AMD64-Throughput: make the AMD64 info more like the ARM info to avoid having this large static array.
1195 emitLocation* startLoc;
1196 emitLocation* endLoc;
1197 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1198 emitLocation* coldEndLoc;
1199 UNWIND_INFO unwindHeader;
1200 // Maximum of 255 UNWIND_CODE 'nodes' and then the unwind header. If there are an odd
1201 // number of codes, the VM or Zapper will 4-byte align the whole thing.
1202 BYTE unwindCodes[offsetof(UNWIND_INFO, UnwindCode) + (0xFF * sizeof(UNWIND_CODE))];
1203 unsigned unwindCodeSlot;
1205 #elif defined(_TARGET_X86_)
1207 #if defined(_TARGET_UNIX_)
1208 emitLocation* startLoc;
1209 emitLocation* endLoc;
1210 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1211 emitLocation* coldEndLoc;
1212 #endif // _TARGET_UNIX_
1214 #elif defined(_TARGET_ARMARCH_)
1216 UnwindInfo uwi; // Unwind information for this function/funclet's hot section
1217 UnwindInfo* uwiCold; // Unwind information for this function/funclet's cold section
1218 // Note: we only have a pointer here instead of the actual object,
1219 // to save memory in the JIT case (compared to the NGEN case),
1220 // where we don't have any cold section.
1221 // Note 2: we currently don't support hot/cold splitting in functions
1222 // with EH, so uwiCold will be NULL for all funclets.
1224 #if defined(_TARGET_UNIX_)
1225 emitLocation* startLoc;
1226 emitLocation* endLoc;
1227 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1228 emitLocation* coldEndLoc;
1229 #endif // _TARGET_UNIX_
1231 #endif // _TARGET_ARMARCH_
1233 #if defined(_TARGET_UNIX_)
1234 jitstd::vector<CFI_CODE>* cfiCodes;
1235 #endif // _TARGET_UNIX_
1237 // Eventually we may want to move rsModifiedRegsMask, lvaOutgoingArgSize, and anything else
1238 // that isn't shared between the main function body and funclets.
1241 struct fgArgTabEntry
1243 GenTree* node; // Initially points at the Op1 field of 'parent', but if the argument is replaced with an GT_ASG or
1244 // placeholder it will point at the actual argument in the gtCallLateArgs list.
1245 GenTree* parent; // Points at the GT_LIST node in the gtCallArgs for this argument
1247 unsigned argNum; // The original argument number, also specifies the required argument evaluation order from the IL
1250 regNumberSmall regNums[MAX_ARG_REG_COUNT]; // The registers to use when passing this argument, set to REG_STK for
1251 // arguments passed on the stack
1253 unsigned numRegs; // Count of number of registers that this argument uses.
1254 // Note that on ARM, if we have a double hfa, this reflects the number
1255 // of DOUBLE registers.
1257 // A slot is a pointer sized region in the OutArg area.
1258 unsigned slotNum; // When an argument is passed in the OutArg area this is the slot number in the OutArg area
1259 unsigned numSlots; // Count of number of slots that this argument uses
1261 unsigned alignment; // 1 or 2 (slots/registers)
1263 unsigned _lateArgInx; // index into gtCallLateArgs list; UINT_MAX if this is not a late arg.
1265 unsigned tmpNum; // the LclVar number if we had to force evaluation of this arg
1267 var_types argType; // The type used to pass this argument. This is generally the original argument type, but when a
1268 // struct is passed as a scalar type, this is that type.
1269 // Note that if a struct is passed by reference, this will still be the struct type.
1271 bool needTmp : 1; // True when we force this argument's evaluation into a temp LclVar
1272 bool needPlace : 1; // True when we must replace this argument with a placeholder node
1273 bool isTmp : 1; // True when we setup a temp LclVar for this argument due to size issues with the struct
1274 bool processed : 1; // True when we have decided the evaluation order for this argument in the gtCallLateArgs
1275 bool isBackFilled : 1; // True when the argument fills a register slot skipped due to alignment requirements of
1276 // previous arguments.
1277 bool isNonStandard : 1; // True if it is an arg that is passed in a reg other than a standard arg reg, or is forced
1278 // to be on the stack despite its arg list position.
1279 bool isStruct : 1; // True if this is a struct arg
1280 bool _isVararg : 1; // True if the argument is in a vararg context.
1281 bool passedByRef : 1; // True iff the argument is passed by reference.
1282 #ifdef FEATURE_ARG_SPLIT
1283 bool _isSplit : 1; // True when this argument is split between the registers and OutArg area
1284 #endif // FEATURE_ARG_SPLIT
1286 bool _isHfaArg : 1; // True when the argument is an HFA type.
1287 bool _isDoubleHfa : 1; // True when the argument is an HFA, with an element type of DOUBLE.
1292 bool isLate = (_lateArgInx != UINT_MAX);
1296 __declspec(property(get = getLateArgInx, put = setLateArgInx)) unsigned lateArgInx;
1297 unsigned getLateArgInx()
1299 assert(isLateArg());
1302 void setLateArgInx(unsigned inx)
1306 __declspec(property(get = getRegNum)) regNumber regNum;
1307 regNumber getRegNum()
1309 return (regNumber)regNums[0];
1311 __declspec(property(get = getOtherRegNum)) regNumber otherRegNum;
1312 regNumber getOtherRegNum()
1314 return (regNumber)regNums[1];
1317 #if defined(UNIX_AMD64_ABI)
1318 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
1321 void setRegNum(unsigned int i, regNumber regNum)
1323 assert(i < MAX_ARG_REG_COUNT);
1324 regNums[i] = (regNumberSmall)regNum;
1326 regNumber getRegNum(unsigned int i)
1328 assert(i < MAX_ARG_REG_COUNT);
1329 return (regNumber)regNums[i];
1332 __declspec(property(get = getIsSplit, put = setIsSplit)) bool isSplit;
1335 #ifdef FEATURE_ARG_SPLIT
1337 #else // FEATURE_ARG_SPLIT
1341 void setIsSplit(bool value)
1343 #ifdef FEATURE_ARG_SPLIT
1348 __declspec(property(get = getIsVararg, put = setIsVararg)) bool isVararg;
1351 #ifdef FEATURE_VARARG
1357 void setIsVararg(bool value)
1359 #ifdef FEATURE_VARARG
1361 #endif // FEATURE_VARARG
1364 __declspec(property(get = getIsHfaArg)) bool isHfaArg;
1374 __declspec(property(get = getIsHfaRegArg)) bool isHfaRegArg;
1375 bool getIsHfaRegArg()
1378 return _isHfaArg && isPassedInRegisters();
1384 __declspec(property(get = getHfaType)) var_types hfaType;
1385 var_types getHfaType()
1388 return _isHfaArg ? (_isDoubleHfa ? TYP_DOUBLE : TYP_FLOAT) : TYP_UNDEF;
1394 void setHfaType(var_types type, unsigned hfaSlots)
1397 if (type != TYP_UNDEF)
1399 // We must already have set the passing mode.
1400 assert(numRegs != 0 || numSlots != 0);
1401 // We originally set numRegs according to the size of the struct, but if the size of the
1402 // hfaType is not the same as the pointer size, we need to correct it.
1403 // Note that hfaSlots is the number of registers we will use. For ARM, that is twice
1404 // the number of "double registers".
1405 unsigned numHfaRegs = hfaSlots;
1406 if (isPassedInRegisters())
1409 if (type == TYP_DOUBLE)
1411 // Must be an even number of registers.
1412 assert((numRegs & 1) == 0);
1413 numHfaRegs = hfaSlots / 2;
1415 #endif // _TARGET_ARM_
1418 // This should already be set correctly.
1419 assert(numRegs == numHfaRegs);
1420 assert(_isDoubleHfa == (type == TYP_DOUBLE));
1424 numRegs = numHfaRegs;
1427 _isDoubleHfa = (type == TYP_DOUBLE);
1430 #endif // FEATURE_HFA
1434 void SetIsBackFilled(bool backFilled)
1436 isBackFilled = backFilled;
1439 bool IsBackFilled() const
1441 return isBackFilled;
1443 #else // !_TARGET_ARM_
1444 void SetIsBackFilled(bool backFilled)
1448 bool IsBackFilled() const
1452 #endif // !_TARGET_ARM_
1454 bool isPassedInRegisters()
1456 return !isSplit && (numRegs != 0);
1459 bool isPassedInFloatRegisters()
1464 return isValidFloatArgReg(regNum);
1468 bool isSingleRegOrSlot()
1470 return !isSplit && ((numRegs == 1) || (numSlots == 1));
1473 // Returns the number of "slots" used, where for this purpose a
1474 // register counts as a slot.
1475 unsigned getSlotCount()
1479 assert(isPassedInRegisters());
1480 assert(numRegs == 1);
1482 else if (regNum == REG_STK)
1484 assert(!isPassedInRegisters());
1485 assert(numRegs == 0);
1489 assert(numRegs > 0);
1491 return numSlots + numRegs;
1494 // Returns the size as a multiple of pointer-size.
1495 // For targets without HFAs, this is the same as getSlotCount().
1498 unsigned size = getSlotCount();
1501 // We counted the number of regs, but if they are DOUBLE hfa regs we have to double the size.
1502 if (isHfaRegArg && (hfaType == TYP_DOUBLE))
1507 #elif defined(_TARGET_ARM64_)
1508 // We counted the number of regs, but if they are FLOAT hfa regs we have to halve the size.
1509 if (isHfaRegArg && (hfaType == TYP_FLOAT))
1511 // Round up in case of odd HFA count.
1512 size = (size + 1) >> 1;
1514 #endif // _TARGET_ARM64_
1519 // Set the register numbers for a multireg argument.
1520 // There's nothing to do on x64/Ux because the structDesc has already been used to set the
1521 // register numbers.
1522 void SetMultiRegNums()
1524 #if FEATURE_MULTIREG_ARGS && !defined(UNIX_AMD64_ABI)
1530 regNumber argReg = getRegNum(0);
1532 unsigned int regSize = (hfaType == TYP_DOUBLE) ? 2 : 1;
1534 unsigned int regSize = 1;
1536 for (unsigned int regIndex = 1; regIndex < numRegs; regIndex++)
1538 argReg = (regNumber)(argReg + regSize);
1539 setRegNum(regIndex, argReg);
1541 #endif // FEATURE_MULTIREG_ARGS && !defined(UNIX_AMD64_ABI)
1544 // Check that the value of 'isStruct' is consistent.
1545 // A struct arg must be one of the following:
1546 // - A node of struct type,
1547 // - A GT_FIELD_LIST, or
1548 // - A node of a scalar type, passed in a single register or slot
1549 // (or two slots in the case of a struct pass on the stack as TYP_DOUBLE).
1551 void checkIsStruct()
1555 if (!varTypeIsStruct(node) && !node->OperIs(GT_FIELD_LIST))
1557 // This is the case where we are passing a struct as a primitive type.
1558 // On most targets, this is always a single register or slot.
1559 // However, on ARM this could be two slots if it is TYP_DOUBLE.
1560 bool isPassedAsPrimitiveType = ((numRegs == 1) || ((numRegs == 0) && (numSlots == 1)));
1562 if (!isPassedAsPrimitiveType)
1564 if (node->TypeGet() == TYP_DOUBLE && numRegs == 0 && (numSlots == 2))
1566 isPassedAsPrimitiveType = true;
1569 #endif // _TARGET_ARM_
1570 assert(isPassedAsPrimitiveType);
1575 assert(!varTypeIsStruct(node));
1584 //-------------------------------------------------------------------------
1586 // The class fgArgInfo is used to handle the arguments
1587 // when morphing a GT_CALL node.
1592 Compiler* compiler; // Back pointer to the compiler instance so that we can allocate memory
1593 GenTreeCall* callTree; // Back pointer to the GT_CALL node for this fgArgInfo
1594 unsigned argCount; // Updatable arg count value
1595 unsigned nextSlotNum; // Updatable slot count value
1596 unsigned stkLevel; // Stack depth when we make this call (for x86)
1598 #if defined(UNIX_X86_ABI)
1599 bool alignmentDone; // Updateable flag, set to 'true' after we've done any required alignment.
1600 unsigned stkSizeBytes; // Size of stack used by this call, in bytes. Calculated during fgMorphArgs().
1601 unsigned padStkAlign; // Stack alignment in bytes required before arguments are pushed for this call.
1602 // Computed dynamically during codegen, based on stkSizeBytes and the current
1603 // stack level (genStackLevel) when the first stack adjustment is made for
1607 #if FEATURE_FIXED_OUT_ARGS
1608 unsigned outArgSize; // Size of the out arg area for the call, will be at least MIN_ARG_AREA_FOR_CALL
1611 unsigned argTableSize; // size of argTable array (equal to the argCount when done with fgMorphArgs)
1612 bool hasRegArgs; // true if we have one or more register arguments
1613 bool hasStackArgs; // true if we have one or more stack arguments
1614 bool argsComplete; // marker for state
1615 bool argsSorted; // marker for state
1616 fgArgTabEntry** argTable; // variable sized array of per argument descrption: (i.e. argTable[argTableSize])
1619 void AddArg(fgArgTabEntry* curArgTabEntry);
1622 fgArgInfo(Compiler* comp, GenTreeCall* call, unsigned argCount);
1623 fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall);
1625 fgArgTabEntry* AddRegArg(unsigned argNum,
1632 bool isVararg = false);
1634 #ifdef UNIX_AMD64_ABI
1635 fgArgTabEntry* AddRegArg(unsigned argNum,
1641 const bool isStruct,
1642 const bool isVararg,
1643 const regNumber otherRegNum,
1644 const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* const structDescPtr = nullptr);
1645 #endif // UNIX_AMD64_ABI
1647 fgArgTabEntry* AddStkArg(unsigned argNum,
1653 bool isVararg = false);
1655 void RemorphReset();
1656 void UpdateRegArg(fgArgTabEntry* argEntry, GenTree* node, bool reMorphing);
1657 void UpdateStkArg(fgArgTabEntry* argEntry, GenTree* node, bool reMorphing);
1659 void SplitArg(unsigned argNum, unsigned numRegs, unsigned numSlots);
1661 void EvalToTmp(fgArgTabEntry* curArgTabEntry, unsigned tmpNum, GenTree* newNode);
1663 void ArgsComplete();
1667 void EvalArgsToTemps();
1673 fgArgTabEntry** ArgTable()
1677 unsigned GetNextSlotNum()
1687 return hasStackArgs;
1689 bool AreArgsComplete() const
1691 return argsComplete;
1693 #if FEATURE_FIXED_OUT_ARGS
1694 unsigned GetOutArgSize() const
1698 void SetOutArgSize(unsigned newVal)
1700 outArgSize = newVal;
1702 #endif // FEATURE_FIXED_OUT_ARGS
1704 #if defined(UNIX_X86_ABI)
1705 void ComputeStackAlignment(unsigned curStackLevelInBytes)
1707 padStkAlign = AlignmentPad(curStackLevelInBytes, STACK_ALIGN);
1710 unsigned GetStkAlign()
1715 void SetStkSizeBytes(unsigned newStkSizeBytes)
1717 stkSizeBytes = newStkSizeBytes;
1720 unsigned GetStkSizeBytes() const
1722 return stkSizeBytes;
1725 bool IsStkAlignmentDone() const
1727 return alignmentDone;
1730 void SetStkAlignmentDone()
1732 alignmentDone = true;
1734 #endif // defined(UNIX_X86_ABI)
1736 // Get the fgArgTabEntry for the arg at position argNum.
1737 fgArgTabEntry* GetArgEntry(unsigned argNum, bool reMorphing = true)
1739 fgArgTabEntry* curArgTabEntry = nullptr;
1743 // The arg table has not yet been sorted.
1744 curArgTabEntry = argTable[argNum];
1745 assert(curArgTabEntry->argNum == argNum);
1746 return curArgTabEntry;
1749 for (unsigned i = 0; i < argCount; i++)
1751 curArgTabEntry = argTable[i];
1752 if (curArgTabEntry->argNum == argNum)
1754 return curArgTabEntry;
1757 noway_assert(!"GetArgEntry: argNum not found");
1761 // Get the node for the arg at position argIndex.
1762 // Caller must ensure that this index is a valid arg index.
1763 GenTree* GetArgNode(unsigned argIndex)
1765 return GetArgEntry(argIndex)->node;
1768 void Dump(Compiler* compiler);
1772 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1773 // We have the ability to mark source expressions with "Test Labels."
1774 // These drive assertions within the JIT, or internal JIT testing. For example, we could label expressions
1775 // that should be CSE defs, and other expressions that should uses of those defs, with a shared label.
1777 enum TestLabel // This must be kept identical to System.Runtime.CompilerServices.JitTestLabel.TestLabel.
1780 TL_VN, // Defines a "VN equivalence class". (For full VN, including exceptions thrown).
1781 TL_VNNorm, // Like above, but uses the non-exceptional value of the expression.
1782 TL_CSE_Def, // This must be identified in the JIT as a CSE def
1783 TL_CSE_Use, // This must be identified in the JIT as a CSE use
1784 TL_LoopHoist, // Expression must (or must not) be hoisted out of the loop.
1787 struct TestLabelAndNum
1792 TestLabelAndNum() : m_tl(TestLabel(0)), m_num(0)
1797 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, TestLabelAndNum> NodeToTestDataMap;
1799 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1803 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1804 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1806 XX The big guy. The sections are currently organized as : XX
1808 XX o GenTree and BasicBlock XX
1820 XX o PrologScopeInfo XX
1821 XX o CodeGenerator XX
1826 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1827 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1830 struct HWIntrinsicInfo;
1834 friend class emitter;
1835 friend class UnwindInfo;
1836 friend class UnwindFragmentInfo;
1837 friend class UnwindEpilogInfo;
1838 friend class JitTimer;
1839 friend class LinearScan;
1840 friend class fgArgInfo;
1841 friend class Rationalizer;
1843 friend class Lowering;
1844 friend class CSE_DataFlow;
1845 friend class CSE_Heuristic;
1846 friend class CodeGenInterface;
1847 friend class CodeGen;
1848 friend class LclVarDsc;
1849 friend class TempDsc;
1851 friend class ObjectAllocator;
1852 friend class LocalAddressVisitor;
1853 friend struct GenTree;
1855 #ifdef FEATURE_HW_INTRINSICS
1856 friend struct HWIntrinsicInfo;
1857 #endif // FEATURE_HW_INTRINSICS
1859 #ifndef _TARGET_64BIT_
1860 friend class DecomposeLongs;
1861 #endif // !_TARGET_64BIT_
1864 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1865 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1867 XX Misc structs definitions XX
1869 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1870 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1874 hashBvGlobalData hbvGlobalData; // Used by the hashBv bitvector package.
1893 bool dumpIRDataflow;
1894 bool dumpIRBlockHeaders;
1896 LPCWSTR dumpIRPhase;
1897 LPCWSTR dumpIRFormat;
1899 bool shouldUseVerboseTrees();
1900 bool asciiTrees; // If true, dump trees using only ASCII characters
1901 bool shouldDumpASCIITrees();
1902 bool verboseSsa; // If true, produce especially verbose dump output in SSA construction.
1903 bool shouldUseVerboseSsa();
1904 bool treesBeforeAfterMorph; // If true, print trees before/after morphing (paired by an intra-compilation id:
1905 int morphNum; // This counts the the trees that have been morphed, allowing us to label each uniquely.
1907 const char* VarNameToStr(VarName name)
1912 DWORD expensiveDebugCheckLevel;
1915 #if FEATURE_MULTIREG_RET
1916 GenTree* impAssignMultiRegTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass);
1917 #endif // FEATURE_MULTIREG_RET
1919 GenTree* impAssignSmallStructTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass);
1922 bool isSingleFloat32Struct(CORINFO_CLASS_HANDLE hClass);
1923 #endif // ARM_SOFTFP
1925 //-------------------------------------------------------------------------
1926 // Functions to handle homogeneous floating-point aggregates (HFAs) in ARM.
1927 // HFAs are one to four element structs where each element is the same
1928 // type, either all float or all double. They are treated specially
1929 // in the ARM Procedure Call Standard, specifically, they are passed in
1930 // floating-point registers instead of the general purpose registers.
1933 bool IsHfa(CORINFO_CLASS_HANDLE hClass);
1934 bool IsHfa(GenTree* tree);
1936 var_types GetHfaType(GenTree* tree);
1937 unsigned GetHfaCount(GenTree* tree);
1939 var_types GetHfaType(CORINFO_CLASS_HANDLE hClass);
1940 unsigned GetHfaCount(CORINFO_CLASS_HANDLE hClass);
1942 bool IsMultiRegReturnedType(CORINFO_CLASS_HANDLE hClass);
1944 //-------------------------------------------------------------------------
1945 // The following is used for validating format of EH table
1949 typedef struct EHNodeDsc* pEHNodeDsc;
1951 EHNodeDsc* ehnTree; // root of the tree comprising the EHnodes.
1952 EHNodeDsc* ehnNext; // root of the tree comprising the EHnodes.
1965 EHBlockType ehnBlockType; // kind of EH block
1966 IL_OFFSET ehnStartOffset; // IL offset of start of the EH block
1967 IL_OFFSET ehnEndOffset; // IL offset past end of the EH block. (TODO: looks like verInsertEhNode() sets this to
1968 // the last IL offset, not "one past the last one", i.e., the range Start to End is
1970 pEHNodeDsc ehnNext; // next (non-nested) block in sequential order
1971 pEHNodeDsc ehnChild; // leftmost nested block
1973 pEHNodeDsc ehnTryNode; // for filters and handlers, the corresponding try node
1974 pEHNodeDsc ehnHandlerNode; // for a try node, the corresponding handler node
1976 pEHNodeDsc ehnFilterNode; // if this is a try node and has a filter, otherwise 0
1977 pEHNodeDsc ehnEquivalent; // if blockType=tryNode, start offset and end offset is same,
1979 inline void ehnSetTryNodeType()
1981 ehnBlockType = TryNode;
1983 inline void ehnSetFilterNodeType()
1985 ehnBlockType = FilterNode;
1987 inline void ehnSetHandlerNodeType()
1989 ehnBlockType = HandlerNode;
1991 inline void ehnSetFinallyNodeType()
1993 ehnBlockType = FinallyNode;
1995 inline void ehnSetFaultNodeType()
1997 ehnBlockType = FaultNode;
2000 inline BOOL ehnIsTryBlock()
2002 return ehnBlockType == TryNode;
2004 inline BOOL ehnIsFilterBlock()
2006 return ehnBlockType == FilterNode;
2008 inline BOOL ehnIsHandlerBlock()
2010 return ehnBlockType == HandlerNode;
2012 inline BOOL ehnIsFinallyBlock()
2014 return ehnBlockType == FinallyNode;
2016 inline BOOL ehnIsFaultBlock()
2018 return ehnBlockType == FaultNode;
2021 // returns true if there is any overlap between the two nodes
2022 static inline BOOL ehnIsOverlap(pEHNodeDsc node1, pEHNodeDsc node2)
2024 if (node1->ehnStartOffset < node2->ehnStartOffset)
2026 return (node1->ehnEndOffset >= node2->ehnStartOffset);
2030 return (node1->ehnStartOffset <= node2->ehnEndOffset);
2034 // fails with BADCODE if inner is not completely nested inside outer
2035 static inline BOOL ehnIsNested(pEHNodeDsc inner, pEHNodeDsc outer)
2037 return ((inner->ehnStartOffset >= outer->ehnStartOffset) && (inner->ehnEndOffset <= outer->ehnEndOffset));
2041 //-------------------------------------------------------------------------
2042 // Exception handling functions
2045 #if !FEATURE_EH_FUNCLETS
2047 bool ehNeedsShadowSPslots()
2049 return (info.compXcptnsCount || opts.compDbgEnC);
2052 // 0 for methods with no EH
2053 // 1 for methods with non-nested EH, or where only the try blocks are nested
2054 // 2 for a method with a catch within a catch
2056 unsigned ehMaxHndNestingCount;
2058 #endif // !FEATURE_EH_FUNCLETS
2060 static bool jitIsBetween(unsigned value, unsigned start, unsigned end);
2061 static bool jitIsBetweenInclusive(unsigned value, unsigned start, unsigned end);
2063 bool bbInCatchHandlerILRange(BasicBlock* blk);
2064 bool bbInFilterILRange(BasicBlock* blk);
2065 bool bbInTryRegions(unsigned regionIndex, BasicBlock* blk);
2066 bool bbInExnFlowRegions(unsigned regionIndex, BasicBlock* blk);
2067 bool bbInHandlerRegions(unsigned regionIndex, BasicBlock* blk);
2068 bool bbInCatchHandlerRegions(BasicBlock* tryBlk, BasicBlock* hndBlk);
2069 unsigned short bbFindInnermostCommonTryRegion(BasicBlock* bbOne, BasicBlock* bbTwo);
2071 unsigned short bbFindInnermostTryRegionContainingHandlerRegion(unsigned handlerIndex);
2072 unsigned short bbFindInnermostHandlerRegionContainingTryRegion(unsigned tryIndex);
2074 // Returns true if "block" is the start of a try region.
2075 bool bbIsTryBeg(BasicBlock* block);
2077 // Returns true if "block" is the start of a handler or filter region.
2078 bool bbIsHandlerBeg(BasicBlock* block);
2080 // Returns true iff "block" is where control flows if an exception is raised in the
2081 // try region, and sets "*regionIndex" to the index of the try for the handler.
2082 // Differs from "IsHandlerBeg" in the case of filters, where this is true for the first
2083 // block of the filter, but not for the filter's handler.
2084 bool bbIsExFlowBlock(BasicBlock* block, unsigned* regionIndex);
2086 bool ehHasCallableHandlers();
2088 // Return the EH descriptor for the given region index.
2089 EHblkDsc* ehGetDsc(unsigned regionIndex);
2091 // Return the EH index given a region descriptor.
2092 unsigned ehGetIndex(EHblkDsc* ehDsc);
2094 // Return the EH descriptor index of the enclosing try, for the given region index.
2095 unsigned ehGetEnclosingTryIndex(unsigned regionIndex);
2097 // Return the EH descriptor index of the enclosing handler, for the given region index.
2098 unsigned ehGetEnclosingHndIndex(unsigned regionIndex);
2100 // Return the EH descriptor for the most nested 'try' region this BasicBlock is a member of (or nullptr if this
2101 // block is not in a 'try' region).
2102 EHblkDsc* ehGetBlockTryDsc(BasicBlock* block);
2104 // Return the EH descriptor for the most nested filter or handler region this BasicBlock is a member of (or nullptr
2105 // if this block is not in a filter or handler region).
2106 EHblkDsc* ehGetBlockHndDsc(BasicBlock* block);
2108 // Return the EH descriptor for the most nested region that may handle exceptions raised in this BasicBlock (or
2109 // nullptr if this block's exceptions propagate to caller).
2110 EHblkDsc* ehGetBlockExnFlowDsc(BasicBlock* block);
2112 EHblkDsc* ehIsBlockTryLast(BasicBlock* block);
2113 EHblkDsc* ehIsBlockHndLast(BasicBlock* block);
2114 bool ehIsBlockEHLast(BasicBlock* block);
2116 bool ehBlockHasExnFlowDsc(BasicBlock* block);
2118 // Return the region index of the most nested EH region this block is in.
2119 unsigned ehGetMostNestedRegionIndex(BasicBlock* block, bool* inTryRegion);
2121 // Find the true enclosing try index, ignoring 'mutual protect' try. Uses IL ranges to check.
2122 unsigned ehTrueEnclosingTryIndexIL(unsigned regionIndex);
2124 // Return the index of the most nested enclosing region for a particular EH region. Returns NO_ENCLOSING_INDEX
2125 // if there is no enclosing region. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion'
2126 // is set to 'true' if the enclosing region is a 'try', or 'false' if the enclosing region is a handler.
2127 // (It can never be a filter.)
2128 unsigned ehGetEnclosingRegionIndex(unsigned regionIndex, bool* inTryRegion);
2130 // A block has been deleted. Update the EH table appropriately.
2131 void ehUpdateForDeletedBlock(BasicBlock* block);
2133 // Determine whether a block can be deleted while preserving the EH normalization rules.
2134 bool ehCanDeleteEmptyBlock(BasicBlock* block);
2136 // Update the 'last' pointers in the EH table to reflect new or deleted blocks in an EH region.
2137 void ehUpdateLastBlocks(BasicBlock* oldLast, BasicBlock* newLast);
2139 // For a finally handler, find the region index that the BBJ_CALLFINALLY lives in that calls the handler,
2140 // or NO_ENCLOSING_INDEX if the BBJ_CALLFINALLY lives in the main function body. Normally, the index
2141 // is the same index as the handler (and the BBJ_CALLFINALLY lives in the 'try' region), but for AMD64 the
2142 // BBJ_CALLFINALLY lives in the enclosing try or handler region, whichever is more nested, or the main function
2143 // body. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion' is set to 'true' if the
2144 // BBJ_CALLFINALLY lives in the returned index's 'try' region, or 'false' if lives in the handler region. (It never
2145 // lives in a filter.)
2146 unsigned ehGetCallFinallyRegionIndex(unsigned finallyIndex, bool* inTryRegion);
2148 // Find the range of basic blocks in which all BBJ_CALLFINALLY will be found that target the 'finallyIndex' region's
2149 // handler. Set begBlk to the first block, and endBlk to the block after the last block of the range
2150 // (nullptr if the last block is the last block in the program).
2151 // Precondition: 'finallyIndex' is the EH region of a try/finally clause.
2152 void ehGetCallFinallyBlockRange(unsigned finallyIndex, BasicBlock** begBlk, BasicBlock** endBlk);
2155 // Given a BBJ_CALLFINALLY block and the EH region index of the finally it is calling, return
2156 // 'true' if the BBJ_CALLFINALLY is in the correct EH region.
2157 bool ehCallFinallyInCorrectRegion(BasicBlock* blockCallFinally, unsigned finallyIndex);
2160 #if FEATURE_EH_FUNCLETS
2161 // Do we need a PSPSym in the main function? For codegen purposes, we only need one
2162 // if there is a filter that protects a region with a nested EH clause (such as a
2163 // try/catch nested in the 'try' body of a try/filter/filter-handler). See
2164 // genFuncletProlog() for more details. However, the VM seems to use it for more
2165 // purposes, maybe including debugging. Until we are sure otherwise, always create
2166 // a PSPSym for functions with any EH.
2167 bool ehNeedsPSPSym() const
2171 #else // _TARGET_X86_
2172 return compHndBBtabCount > 0;
2173 #endif // _TARGET_X86_
2176 bool ehAnyFunclets(); // Are there any funclets in this function?
2177 unsigned ehFuncletCount(); // Return the count of funclets in the function
2179 unsigned bbThrowIndex(BasicBlock* blk); // Get the index to use as the cache key for sharing throw blocks
2180 #else // !FEATURE_EH_FUNCLETS
2181 bool ehAnyFunclets()
2185 unsigned ehFuncletCount()
2190 unsigned bbThrowIndex(BasicBlock* blk)
2192 return blk->bbTryIndex;
2193 } // Get the index to use as the cache key for sharing throw blocks
2194 #endif // !FEATURE_EH_FUNCLETS
2196 // Returns a flowList representing the "EH predecessors" of "blk". These are the normal predecessors of
2197 // "blk", plus one special case: if "blk" is the first block of a handler, considers the predecessor(s) of the first
2198 // first block of the corresponding try region to be "EH predecessors". (If there is a single such predecessor,
2199 // for example, we want to consider that the immediate dominator of the catch clause start block, so it's
2200 // convenient to also consider it a predecessor.)
2201 flowList* BlockPredsWithEH(BasicBlock* blk);
2203 // This table is useful for memoization of the method above.
2204 typedef JitHashTable<BasicBlock*, JitPtrKeyFuncs<BasicBlock>, flowList*> BlockToFlowListMap;
2205 BlockToFlowListMap* m_blockToEHPreds;
2206 BlockToFlowListMap* GetBlockToEHPreds()
2208 if (m_blockToEHPreds == nullptr)
2210 m_blockToEHPreds = new (getAllocator()) BlockToFlowListMap(getAllocator());
2212 return m_blockToEHPreds;
2215 void* ehEmitCookie(BasicBlock* block);
2216 UNATIVE_OFFSET ehCodeOffset(BasicBlock* block);
2218 EHblkDsc* ehInitHndRange(BasicBlock* src, IL_OFFSET* hndBeg, IL_OFFSET* hndEnd, bool* inFilter);
2220 EHblkDsc* ehInitTryRange(BasicBlock* src, IL_OFFSET* tryBeg, IL_OFFSET* tryEnd);
2222 EHblkDsc* ehInitHndBlockRange(BasicBlock* blk, BasicBlock** hndBeg, BasicBlock** hndLast, bool* inFilter);
2224 EHblkDsc* ehInitTryBlockRange(BasicBlock* blk, BasicBlock** tryBeg, BasicBlock** tryLast);
2226 void fgSetTryEnd(EHblkDsc* handlerTab, BasicBlock* newTryLast);
2228 void fgSetHndEnd(EHblkDsc* handlerTab, BasicBlock* newHndLast);
2230 void fgSkipRmvdBlocks(EHblkDsc* handlerTab);
2232 void fgAllocEHTable();
2234 void fgRemoveEHTableEntry(unsigned XTnum);
2236 #if FEATURE_EH_FUNCLETS
2238 EHblkDsc* fgAddEHTableEntry(unsigned XTnum);
2240 #endif // FEATURE_EH_FUNCLETS
2244 #endif // !FEATURE_EH
2246 void fgSortEHTable();
2248 // Causes the EH table to obey some well-formedness conditions, by inserting
2249 // empty BB's when necessary:
2250 // * No block is both the first block of a handler and the first block of a try.
2251 // * No block is the first block of multiple 'try' regions.
2252 // * No block is the last block of multiple EH regions.
2253 void fgNormalizeEH();
2254 bool fgNormalizeEHCase1();
2255 bool fgNormalizeEHCase2();
2256 bool fgNormalizeEHCase3();
2259 void dispIncomingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
2260 void dispOutgoingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
2261 void fgVerifyHandlerTab();
2262 void fgDispHandlerTab();
2265 bool fgNeedToSortEHTable;
2267 void verInitEHTree(unsigned numEHClauses);
2268 void verInsertEhNode(CORINFO_EH_CLAUSE* clause, EHblkDsc* handlerTab);
2269 void verInsertEhNodeInTree(EHNodeDsc** ppRoot, EHNodeDsc* node);
2270 void verInsertEhNodeParent(EHNodeDsc** ppRoot, EHNodeDsc* node);
2271 void verCheckNestingLevel(EHNodeDsc* initRoot);
2274 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2275 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2277 XX GenTree and BasicBlock XX
2279 XX Functions to allocate and display the GenTrees and BasicBlocks XX
2281 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2282 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2285 // Functions to create nodes
2286 GenTreeStmt* gtNewStmt(GenTree* expr = nullptr, IL_OFFSETX offset = BAD_IL_OFFSET);
2289 GenTree* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, bool doSimplifications = TRUE);
2291 // For binary opers.
2292 GenTree* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2);
2294 GenTree* gtNewQmarkNode(var_types type, GenTree* cond, GenTree* colon);
2296 GenTree* gtNewLargeOperNode(genTreeOps oper,
2297 var_types type = TYP_I_IMPL,
2298 GenTree* op1 = nullptr,
2299 GenTree* op2 = nullptr);
2301 GenTreeIntCon* gtNewIconNode(ssize_t value, var_types type = TYP_INT);
2303 GenTree* gtNewPhysRegNode(regNumber reg, var_types type);
2305 GenTree* gtNewJmpTableNode();
2307 GenTree* gtNewIndOfIconHandleNode(var_types indType, size_t value, unsigned iconFlags, bool isInvariant);
2309 GenTree* gtNewIconHandleNode(size_t value, unsigned flags, FieldSeqNode* fields = nullptr);
2311 unsigned gtTokenToIconFlags(unsigned token);
2313 GenTree* gtNewIconEmbHndNode(void* value, void* pValue, unsigned flags, void* compileTimeHandle);
2315 GenTree* gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd);
2316 GenTree* gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd);
2317 GenTree* gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd);
2318 GenTree* gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd);
2320 GenTree* gtNewStringLiteralNode(InfoAccessType iat, void* pValue);
2322 GenTree* gtNewLconNode(__int64 value);
2324 GenTree* gtNewDconNode(double value);
2326 GenTree* gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle);
2328 GenTree* gtNewZeroConNode(var_types type);
2330 GenTree* gtNewOneConNode(var_types type);
2333 GenTree* gtNewSIMDVectorZero(var_types simdType, var_types baseType, unsigned size);
2334 GenTree* gtNewSIMDVectorOne(var_types simdType, var_types baseType, unsigned size);
2337 GenTree* gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, unsigned size, bool isVolatile, bool isCopyBlock);
2339 GenTree* gtNewPutArgReg(var_types type, GenTree* arg, regNumber argReg);
2341 GenTree* gtNewBitCastNode(var_types type, GenTree* arg);
2344 void gtBlockOpInit(GenTree* result, GenTree* dst, GenTree* srcOrFillVal, bool isVolatile);
2347 GenTree* gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr);
2348 void gtSetObjGcInfo(GenTreeObj* objNode);
2349 GenTree* gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTree* addr);
2350 GenTree* gtNewBlockVal(GenTree* addr, unsigned size);
2352 GenTree* gtNewCpObjNode(GenTree* dst, GenTree* src, CORINFO_CLASS_HANDLE structHnd, bool isVolatile);
2354 GenTreeArgList* gtNewListNode(GenTree* op1, GenTreeArgList* op2);
2356 GenTreeCall* gtNewCallNode(gtCallTypes callType,
2357 CORINFO_METHOD_HANDLE handle,
2359 GenTreeArgList* args,
2360 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2362 GenTreeCall* gtNewIndCallNode(GenTree* addr,
2364 GenTreeArgList* args,
2365 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2367 GenTreeCall* gtNewHelperCallNode(unsigned helper, var_types type, GenTreeArgList* args = nullptr);
2369 GenTree* gtNewLclvNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs = BAD_IL_OFFSET);
2372 GenTreeSIMD* gtNewSIMDNode(
2373 var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
2374 GenTreeSIMD* gtNewSIMDNode(
2375 var_types type, GenTree* op1, GenTree* op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
2376 void SetOpLclRelatedToSIMDIntrinsic(GenTree* op);
2379 #ifdef FEATURE_HW_INTRINSICS
2380 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2381 NamedIntrinsic hwIntrinsicID,
2384 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
2385 var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
2386 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
2387 var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
2388 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2392 NamedIntrinsic hwIntrinsicID,
2395 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2400 NamedIntrinsic hwIntrinsicID,
2403 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID);
2404 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type,
2407 NamedIntrinsic hwIntrinsicID);
2408 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(
2409 var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID);
2410 GenTree* gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd);
2411 CORINFO_CLASS_HANDLE gtGetStructHandleForHWSIMD(var_types simdType, var_types simdBaseType);
2412 #endif // FEATURE_HW_INTRINSICS
2414 GenTree* gtNewLclLNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs = BAD_IL_OFFSET);
2415 GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset);
2416 GenTree* gtNewInlineCandidateReturnExpr(GenTree* inlineCandidate, var_types type);
2418 GenTree* gtNewCodeRef(BasicBlock* block);
2420 GenTree* gtNewFieldRef(var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj = nullptr, DWORD offset = 0);
2422 GenTree* gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree* indexOp);
2424 GenTreeArrLen* gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset);
2426 GenTree* gtNewIndir(var_types typ, GenTree* addr);
2428 GenTreeArgList* gtNewArgList(GenTree* op);
2429 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2);
2430 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2, GenTree* op3);
2431 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2, GenTree* op3, GenTree* op4);
2433 static fgArgTabEntry* gtArgEntryByArgNum(GenTreeCall* call, unsigned argNum);
2434 static fgArgTabEntry* gtArgEntryByNode(GenTreeCall* call, GenTree* node);
2435 fgArgTabEntry* gtArgEntryByLateArgIndex(GenTreeCall* call, unsigned lateArgInx);
2436 static GenTree* gtArgNodeByLateArgInx(GenTreeCall* call, unsigned lateArgInx);
2437 bool gtArgIsThisPtr(fgArgTabEntry* argEntry);
2439 GenTree* gtNewAssignNode(GenTree* dst, GenTree* src);
2441 GenTree* gtNewTempAssign(unsigned tmp, GenTree* val);
2443 GenTree* gtNewRefCOMfield(GenTree* objPtr,
2444 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2445 CORINFO_ACCESS_FLAGS access,
2446 CORINFO_FIELD_INFO* pFieldInfo,
2448 CORINFO_CLASS_HANDLE structType,
2451 GenTree* gtNewNothingNode();
2453 GenTree* gtNewArgPlaceHolderNode(var_types type, CORINFO_CLASS_HANDLE clsHnd);
2455 GenTree* gtUnusedValNode(GenTree* expr);
2457 GenTreeCast* gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
2459 GenTreeCast* gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
2461 GenTree* gtNewAllocObjNode(unsigned int helper, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTree* op1);
2463 GenTree* gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* lookupTree);
2465 //------------------------------------------------------------------------
2466 // Other GenTree functions
2468 GenTree* gtClone(GenTree* tree, bool complexOK = false);
2470 // If `tree` is a lclVar with lclNum `varNum`, return an IntCns with value `varVal`; otherwise,
2471 // create a copy of `tree`, adding specified flags, replacing uses of lclVar `deepVarNum` with
2472 // IntCnses with value `deepVarVal`.
2473 GenTree* gtCloneExpr(
2474 GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal);
2476 // Create a copy of `tree`, optionally adding specifed flags, and optionally mapping uses of local
2477 // `varNum` to int constants with value `varVal`.
2478 GenTree* gtCloneExpr(GenTree* tree, unsigned addFlags = 0, unsigned varNum = (unsigned)-1, int varVal = 0)
2480 return gtCloneExpr(tree, addFlags, varNum, varVal, varNum, varVal);
2483 GenTree* gtReplaceTree(GenTree* stmt, GenTree* tree, GenTree* replacementTree);
2485 void gtUpdateSideEffects(GenTree* stmt, GenTree* tree);
2487 void gtUpdateTreeAncestorsSideEffects(GenTree* tree);
2489 void gtUpdateStmtSideEffects(GenTree* stmt);
2491 void gtUpdateNodeSideEffects(GenTree* tree);
2493 void gtUpdateNodeOperSideEffects(GenTree* tree);
2495 // Returns "true" iff the complexity (not formally defined, but first interpretation
2496 // is #of nodes in subtree) of "tree" is greater than "limit".
2497 // (This is somewhat redundant with the "gtCostEx/gtCostSz" fields, but can be used
2498 // before they have been set.)
2499 bool gtComplexityExceeds(GenTree** tree, unsigned limit);
2501 bool gtCompareTree(GenTree* op1, GenTree* op2);
2503 GenTree* gtReverseCond(GenTree* tree);
2505 bool gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly);
2507 bool gtHasLocalsWithAddrOp(GenTree* tree);
2509 unsigned gtSetListOrder(GenTree* list, bool regs, bool isListCallArgs);
2511 void gtWalkOp(GenTree** op1, GenTree** op2, GenTree* base, bool constOnly);
2514 unsigned gtHashValue(GenTree* tree);
2516 GenTree* gtWalkOpEffectiveVal(GenTree* op);
2519 void gtPrepareCost(GenTree* tree);
2520 bool gtIsLikelyRegVar(GenTree* tree);
2522 // Returns true iff the secondNode can be swapped with firstNode.
2523 bool gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode);
2525 unsigned gtSetEvalOrder(GenTree* tree);
2527 void gtSetStmtInfo(GenTree* stmt);
2529 // Returns "true" iff "node" has any of the side effects in "flags".
2530 bool gtNodeHasSideEffects(GenTree* node, unsigned flags);
2532 // Returns "true" iff "tree" or its (transitive) children have any of the side effects in "flags".
2533 bool gtTreeHasSideEffects(GenTree* tree, unsigned flags);
2535 // Appends 'expr' in front of 'list'
2536 // 'list' will typically start off as 'nullptr'
2537 // when 'list' is non-null a GT_COMMA node is used to insert 'expr'
2538 GenTree* gtBuildCommaList(GenTree* list, GenTree* expr);
2540 void gtExtractSideEffList(GenTree* expr,
2542 unsigned flags = GTF_SIDE_EFFECT,
2543 bool ignoreRoot = false);
2545 GenTree* gtGetThisArg(GenTreeCall* call);
2547 // Static fields of struct types (and sometimes the types that those are reduced to) are represented by having the
2548 // static field contain an object pointer to the boxed struct. This simplifies the GC implementation...but
2549 // complicates the JIT somewhat. This predicate returns "true" iff a node with type "fieldNodeType", representing
2550 // the given "fldHnd", is such an object pointer.
2551 bool gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd);
2553 // Return true if call is a recursive call; return false otherwise.
2554 // Note when inlining, this looks for calls back to the root method.
2555 bool gtIsRecursiveCall(GenTreeCall* call)
2557 return gtIsRecursiveCall(call->gtCallMethHnd);
2560 bool gtIsRecursiveCall(CORINFO_METHOD_HANDLE callMethodHandle)
2562 return (callMethodHandle == impInlineRoot()->info.compMethodHnd);
2565 //-------------------------------------------------------------------------
2567 GenTree* gtFoldExpr(GenTree* tree);
2570 // TODO-Amd64-Unix: Remove this when the clang optimizer is fixed and/or the method implementation is
2571 // refactored in a simpler code. This is a workaround for a bug in the clang-3.5 optimizer. The issue is that in
2572 // release build the optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner case
2573 // of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div operation instead of 64 bit) - see
2574 // the implementation of the method in gentree.cpp. For the case of lval1 and lval2 equal to MIN_LONG
2575 // (0x8000000000000000) this results in raising a SIGFPE. The method implementation is rather complex. Disable
2576 // optimizations for now.
2577 __attribute__((optnone))
2579 gtFoldExprConst(GenTree* tree);
2580 GenTree* gtFoldExprSpecial(GenTree* tree);
2581 GenTree* gtFoldExprCompare(GenTree* tree);
2582 GenTree* gtFoldExprCall(GenTreeCall* call);
2583 GenTree* gtFoldTypeCompare(GenTree* tree);
2584 GenTree* gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2);
2586 // Options to control behavior of gtTryRemoveBoxUpstreamEffects
2587 enum BoxRemovalOptions
2589 BR_REMOVE_AND_NARROW, // remove effects, minimize remaining work, return possibly narrowed source tree
2590 BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE, // remove effects and minimize remaining work, return type handle tree
2591 BR_REMOVE_BUT_NOT_NARROW, // remove effects, return original source tree
2592 BR_DONT_REMOVE, // check if removal is possible, return copy source tree
2593 BR_DONT_REMOVE_WANT_TYPE_HANDLE, // check if removal is possible, return type handle tree
2594 BR_MAKE_LOCAL_COPY // revise box to copy to temp local and return local's address
2597 GenTree* gtTryRemoveBoxUpstreamEffects(GenTree* tree, BoxRemovalOptions options = BR_REMOVE_AND_NARROW);
2598 GenTree* gtOptimizeEnumHasFlag(GenTree* thisOp, GenTree* flagOp);
2600 //-------------------------------------------------------------------------
2601 // Get the handle, if any.
2602 CORINFO_CLASS_HANDLE gtGetStructHandleIfPresent(GenTree* tree);
2603 // Get the handle, and assert if not found.
2604 CORINFO_CLASS_HANDLE gtGetStructHandle(GenTree* tree);
2605 // Get the handle for a ref type.
2606 CORINFO_CLASS_HANDLE gtGetClassHandle(GenTree* tree, bool* isExact, bool* isNonNull);
2607 // Get the class handle for an helper call
2608 CORINFO_CLASS_HANDLE gtGetHelperCallClassHandle(GenTreeCall* call, bool* isExact, bool* isNonNull);
2609 // Get the element handle for an array of ref type.
2610 CORINFO_CLASS_HANDLE gtGetArrayElementClassHandle(GenTree* array);
2611 // Get a class handle from a helper call argument
2612 CORINFO_CLASS_HANDLE gtGetHelperArgClassHandle(GenTree* array,
2613 unsigned* runtimeLookupCount = nullptr,
2614 GenTree** handleTree = nullptr);
2615 // Check if this tree is a gc static base helper call
2616 bool gtIsStaticGCBaseHelperCall(GenTree* tree);
2618 //-------------------------------------------------------------------------
2619 // Functions to display the trees
2622 void gtDispNode(GenTree* tree, IndentStack* indentStack, __in_z const char* msg, bool isLIR);
2624 void gtDispVN(GenTree* tree);
2625 void gtDispConst(GenTree* tree);
2626 void gtDispLeaf(GenTree* tree, IndentStack* indentStack);
2627 void gtDispNodeName(GenTree* tree);
2628 void gtDispRegVal(GenTree* tree);
2640 void gtDispChild(GenTree* child,
2641 IndentStack* indentStack,
2643 __in_opt const char* msg = nullptr,
2644 bool topOnly = false);
2645 void gtDispTree(GenTree* tree,
2646 IndentStack* indentStack = nullptr,
2647 __in_opt const char* msg = nullptr,
2648 bool topOnly = false,
2649 bool isLIR = false);
2650 void gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut);
2651 int gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining);
2652 char* gtGetLclVarName(unsigned lclNum);
2653 void gtDispLclVar(unsigned varNum, bool padForBiggestDisp = true);
2654 void gtDispTreeList(GenTree* tree, IndentStack* indentStack = nullptr);
2655 void gtGetArgMsg(GenTreeCall* call, GenTree* arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength);
2656 void gtGetLateArgMsg(GenTreeCall* call, GenTree* arg, int argNum, int listCount, char* bufp, unsigned bufLength);
2657 void gtDispArgList(GenTreeCall* call, IndentStack* indentStack);
2658 void gtDispFieldSeq(FieldSeqNode* pfsn);
2660 void gtDispRange(LIR::ReadOnlyRange const& range);
2662 void gtDispTreeRange(LIR::Range& containingRange, GenTree* tree);
2664 void gtDispLIRNode(GenTree* node, const char* prefixMsg = nullptr);
2676 typedef fgWalkResult(fgWalkPreFn)(GenTree** pTree, fgWalkData* data);
2677 typedef fgWalkResult(fgWalkPostFn)(GenTree** pTree, fgWalkData* data);
2680 static fgWalkPreFn gtAssertColonCond;
2682 static fgWalkPreFn gtMarkColonCond;
2683 static fgWalkPreFn gtClearColonCond;
2685 GenTree** gtFindLink(GenTree* stmt, GenTree* node);
2686 bool gtHasCatchArg(GenTree* tree);
2688 typedef ArrayStack<GenTree*> GenTreeStack;
2690 static bool gtHasCallOnStack(GenTreeStack* parentStack);
2692 //=========================================================================
2693 // BasicBlock functions
2695 // This is a debug flag we will use to assert when creating block during codegen
2696 // as this interferes with procedure splitting. If you know what you're doing, set
2697 // it to true before creating the block. (DEBUG only)
2698 bool fgSafeBasicBlockCreation;
2701 BasicBlock* bbNewBasicBlock(BBjumpKinds jumpKind);
2704 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2705 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2709 XX The variables to be used by the code generator. XX
2711 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2712 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2716 // For both PROMOTION_TYPE_NONE and PROMOTION_TYPE_DEPENDENT the struct will
2717 // be placed in the stack frame and it's fields must be laid out sequentially.
2719 // For PROMOTION_TYPE_INDEPENDENT each of the struct's fields is replaced by
2720 // a local variable that can be enregistered or placed in the stack frame.
2721 // The fields do not need to be laid out sequentially
2723 enum lvaPromotionType
2725 PROMOTION_TYPE_NONE, // The struct local is not promoted
2726 PROMOTION_TYPE_INDEPENDENT, // The struct local is promoted,
2727 // and its field locals are independent of its parent struct local.
2728 PROMOTION_TYPE_DEPENDENT // The struct local is promoted,
2729 // but its field locals depend on its parent struct local.
2732 static int __cdecl RefCntCmp(const void* op1, const void* op2);
2733 static int __cdecl WtdRefCntCmp(const void* op1, const void* op2);
2735 /*****************************************************************************/
2737 enum FrameLayoutState
2740 INITIAL_FRAME_LAYOUT,
2741 PRE_REGALLOC_FRAME_LAYOUT,
2742 REGALLOC_FRAME_LAYOUT,
2743 TENTATIVE_FRAME_LAYOUT,
2748 RefCountState lvaRefCountState; // Current local ref count state
2750 bool lvaLocalVarRefCounted() const
2752 return lvaRefCountState == RCS_NORMAL;
2755 bool lvaTrackedFixed; // true: We cannot add new 'tracked' variable
2756 unsigned lvaCount; // total number of locals
2758 unsigned lvaRefCount; // total number of references to locals
2759 LclVarDsc* lvaTable; // variable descriptor table
2760 unsigned lvaTableCnt; // lvaTable size (>= lvaCount)
2762 LclVarDsc** lvaRefSorted; // table sorted by refcount
2764 unsigned short lvaTrackedCount; // actual # of locals being tracked
2765 unsigned lvaTrackedCountInSizeTUnits; // min # of size_t's sufficient to hold a bit for all the locals being tracked
2768 VARSET_TP lvaTrackedVars; // set of tracked variables
2770 #ifndef _TARGET_64BIT_
2771 VARSET_TP lvaLongVars; // set of long (64-bit) variables
2773 VARSET_TP lvaFloatVars; // set of floating-point (32-bit and 64-bit) variables
2775 unsigned lvaCurEpoch; // VarSets are relative to a specific set of tracked var indices.
2776 // It that changes, this changes. VarSets from different epochs
2777 // cannot be meaningfully combined.
2779 unsigned GetCurLVEpoch()
2784 // reverse map of tracked number to var number
2785 unsigned* lvaTrackedToVarNum;
2789 // # of procs compiled a with double-aligned stack
2790 static unsigned s_lvaDoubleAlignedProcsCount;
2794 // Getters and setters for address-exposed and do-not-enregister local var properties.
2795 bool lvaVarAddrExposed(unsigned varNum);
2796 void lvaSetVarAddrExposed(unsigned varNum);
2797 bool lvaVarDoNotEnregister(unsigned varNum);
2799 // Reasons why we can't enregister. Some of these correspond to debug properties of local vars.
2800 enum DoNotEnregisterReason
2805 DNER_VMNeedsStackAddr,
2806 DNER_LiveInOutOfHandler,
2807 DNER_LiveAcrossUnmanagedCall,
2808 DNER_BlockOp, // Is read or written via a block operation that explicitly takes the address.
2809 DNER_IsStructArg, // Is a struct passed as an argument in a way that requires a stack location.
2810 DNER_DepField, // It is a field of a dependently promoted struct
2811 DNER_NoRegVars, // opts.compFlags & CLFLG_REGVAR is not set
2812 DNER_MinOptsGC, // It is a GC Ref and we are compiling MinOpts
2813 #if !defined(_TARGET_64BIT_)
2814 DNER_LongParamField, // It is a decomposed field of a long parameter.
2816 #ifdef JIT32_GCENCODER
2821 void lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregisterReason reason));
2823 unsigned lvaVarargsHandleArg;
2825 unsigned lvaVarargsBaseOfStkArgs; // Pointer (computed based on incoming varargs handle) to the start of the stack
2827 #endif // _TARGET_X86_
2829 unsigned lvaInlinedPInvokeFrameVar; // variable representing the InlinedCallFrame
2830 unsigned lvaReversePInvokeFrameVar; // variable representing the reverse PInvoke frame
2831 #if FEATURE_FIXED_OUT_ARGS
2832 unsigned lvaPInvokeFrameRegSaveVar; // variable representing the RegSave for PInvoke inlining.
2834 unsigned lvaMonAcquired; // boolean variable introduced into in synchronized methods
2835 // that tracks whether the lock has been taken
2837 unsigned lvaArg0Var; // The lclNum of arg0. Normally this will be info.compThisArg.
2838 // However, if there is a "ldarga 0" or "starg 0" in the IL,
2839 // we will redirect all "ldarg(a) 0" and "starg 0" to this temp.
2841 unsigned lvaInlineeReturnSpillTemp; // The temp to spill the non-VOID return expression
2842 // in case there are multiple BBJ_RETURN blocks in the inlinee
2843 // or if the inlinee has GC ref locals.
2845 #if FEATURE_FIXED_OUT_ARGS
2846 unsigned lvaOutgoingArgSpaceVar; // dummy TYP_LCLBLK var for fixed outgoing argument space
2847 PhasedVar<unsigned> lvaOutgoingArgSpaceSize; // size of fixed outgoing argument space
2848 #endif // FEATURE_FIXED_OUT_ARGS
2851 // On architectures whose ABIs allow structs to be passed in registers, struct promotion will sometimes
2852 // require us to "rematerialize" a struct from it's separate constituent field variables. Packing several sub-word
2853 // field variables into an argument register is a hard problem. It's easier to reserve a word of memory into which
2854 // such field can be copied, after which the assembled memory word can be read into the register. We will allocate
2855 // this variable to be this scratch word whenever struct promotion occurs.
2856 unsigned lvaPromotedStructAssemblyScratchVar;
2857 #endif // _TARGET_ARM_
2859 #if defined(DEBUG) && defined(_TARGET_XARCH_)
2861 unsigned lvaReturnSpCheck; // Stores SP to confirm it is not corrupted on return.
2863 #endif // defined(DEBUG) && defined(_TARGET_XARCH_)
2865 #if defined(DEBUG) && defined(_TARGET_X86_)
2867 unsigned lvaCallSpCheck; // Stores SP to confirm it is not corrupted after every call.
2869 #endif // defined(DEBUG) && defined(_TARGET_X86_)
2871 unsigned lvaGenericsContextUseCount;
2873 bool lvaKeepAliveAndReportThis(); // Synchronized instance method of a reference type, or
2874 // CORINFO_GENERICS_CTXT_FROM_THIS?
2875 bool lvaReportParamTypeArg(); // Exceptions and CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG?
2877 //-------------------------------------------------------------------------
2878 // All these frame offsets are inter-related and must be kept in sync
2880 #if !FEATURE_EH_FUNCLETS
2881 // This is used for the callable handlers
2882 unsigned lvaShadowSPslotsVar; // TYP_BLK variable for all the shadow SP slots
2883 #endif // FEATURE_EH_FUNCLETS
2885 int lvaCachedGenericContextArgOffs;
2886 int lvaCachedGenericContextArgOffset(); // For CORINFO_CALLCONV_PARAMTYPE and if generic context is passed as
2889 #ifdef JIT32_GCENCODER
2891 unsigned lvaLocAllocSPvar; // variable which stores the value of ESP after the the last alloca/localloc
2893 #endif // JIT32_GCENCODER
2895 unsigned lvaNewObjArrayArgs; // variable with arguments for new MD array helper
2897 // TODO-Review: Prior to reg predict we reserve 24 bytes for Spill temps.
2898 // after the reg predict we will use a computed maxTmpSize
2899 // which is based upon the number of spill temps predicted by reg predict
2900 // All this is necessary because if we under-estimate the size of the spill
2901 // temps we could fail when encoding instructions that reference stack offsets for ARM.
2903 // Pre codegen max spill temp size.
2904 static const unsigned MAX_SPILL_TEMP_SIZE = 24;
2906 //-------------------------------------------------------------------------
2908 unsigned lvaGetMaxSpillTempSize();
2910 bool lvaIsPreSpilled(unsigned lclNum, regMaskTP preSpillMask);
2911 #endif // _TARGET_ARM_
2912 void lvaAssignFrameOffsets(FrameLayoutState curState);
2913 void lvaFixVirtualFrameOffsets();
2914 void lvaUpdateArgsWithInitialReg();
2915 void lvaAssignVirtualFrameOffsetsToArgs();
2916 #ifdef UNIX_AMD64_ABI
2917 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs, int* callerArgOffset);
2918 #else // !UNIX_AMD64_ABI
2919 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs);
2920 #endif // !UNIX_AMD64_ABI
2921 void lvaAssignVirtualFrameOffsetsToLocals();
2922 int lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, int stkOffs);
2923 #ifdef _TARGET_AMD64_
2924 // Returns true if compCalleeRegsPushed (including RBP if used as frame pointer) is even.
2925 bool lvaIsCalleeSavedIntRegCountEven();
2927 void lvaAlignFrame();
2928 void lvaAssignFrameOffsetsToPromotedStructs();
2929 int lvaAllocateTemps(int stkOffs, bool mustDoubleAlign);
2932 void lvaDumpRegLocation(unsigned lclNum);
2933 void lvaDumpFrameLocation(unsigned lclNum);
2934 void lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t refCntWtdWidth = 6);
2935 void lvaTableDump(FrameLayoutState curState = NO_FRAME_LAYOUT); // NO_FRAME_LAYOUT means use the current frame
2936 // layout state defined by lvaDoneFrameLayout
2939 // Limit frames size to 1GB. The maximum is 2GB in theory - make it intentionally smaller
2940 // to avoid bugs from borderline cases.
2941 #define MAX_FrameSize 0x3FFFFFFF
2942 void lvaIncrementFrameSize(unsigned size);
2944 unsigned lvaFrameSize(FrameLayoutState curState);
2946 // Returns the caller-SP-relative offset for the SP/FP relative offset determined by FP based.
2947 int lvaToCallerSPRelativeOffset(int offs, bool isFpBased);
2949 // Returns the caller-SP-relative offset for the local variable "varNum."
2950 int lvaGetCallerSPRelativeOffset(unsigned varNum);
2952 // Returns the SP-relative offset for the local variable "varNum". Illegal to ask this for functions with localloc.
2953 int lvaGetSPRelativeOffset(unsigned varNum);
2955 int lvaToInitialSPRelativeOffset(unsigned offset, bool isFpBased);
2956 int lvaGetInitialSPRelativeOffset(unsigned varNum);
2958 //------------------------ For splitting types ----------------------------
2960 void lvaInitTypeRef();
2962 void lvaInitArgs(InitVarDscInfo* varDscInfo);
2963 void lvaInitThisPtr(InitVarDscInfo* varDscInfo);
2964 void lvaInitRetBuffArg(InitVarDscInfo* varDscInfo);
2965 void lvaInitUserArgs(InitVarDscInfo* varDscInfo);
2966 void lvaInitGenericsCtxt(InitVarDscInfo* varDscInfo);
2967 void lvaInitVarArgsHandle(InitVarDscInfo* varDscInfo);
2969 void lvaInitVarDsc(LclVarDsc* varDsc,
2971 CorInfoType corInfoType,
2972 CORINFO_CLASS_HANDLE typeHnd,
2973 CORINFO_ARG_LIST_HANDLE varList,
2974 CORINFO_SIG_INFO* varSig);
2976 static unsigned lvaTypeRefMask(var_types type);
2978 var_types lvaGetActualType(unsigned lclNum);
2979 var_types lvaGetRealType(unsigned lclNum);
2981 //-------------------------------------------------------------------------
2985 LclVarDsc* lvaGetDesc(unsigned lclNum)
2987 assert(lclNum < lvaCount);
2988 return &lvaTable[lclNum];
2991 LclVarDsc* lvaGetDesc(GenTreeLclVarCommon* lclVar)
2993 assert(lclVar->GetLclNum() < lvaCount);
2994 return &lvaTable[lclVar->GetLclNum()];
2997 unsigned lvaLclSize(unsigned varNum);
2998 unsigned lvaLclExactSize(unsigned varNum);
3000 bool lvaHaveManyLocals() const;
3002 unsigned lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason));
3003 unsigned lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason));
3004 unsigned lvaGrabTempWithImplicitUse(bool shortLifetime DEBUGARG(const char* reason));
3007 void lvaSortByRefCount();
3008 void lvaDumpRefCounts();
3010 void lvaMarkLocalVars(); // Local variable ref-counting
3011 void lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers);
3012 void lvaMarkLocalVars(BasicBlock* block, bool isRecompute);
3014 void lvaAllocOutgoingArgSpaceVar(); // Set up lvaOutgoingArgSpaceVar
3016 VARSET_VALRET_TP lvaStmtLclMask(GenTree* stmt);
3019 struct lvaStressLclFldArgs
3021 Compiler* m_pCompiler;
3025 static fgWalkPreFn lvaStressLclFldCB;
3026 void lvaStressLclFld();
3028 void lvaDispVarSet(VARSET_VALARG_TP set, VARSET_VALARG_TP allVars);
3029 void lvaDispVarSet(VARSET_VALARG_TP set);
3034 int lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset);
3036 int lvaFrameAddress(int varNum, bool* pFPbased);
3039 bool lvaIsParameter(unsigned varNum);
3040 bool lvaIsRegArgument(unsigned varNum);
3041 BOOL lvaIsOriginalThisArg(unsigned varNum); // Is this varNum the original this argument?
3042 BOOL lvaIsOriginalThisReadOnly(); // return TRUE if there is no place in the code
3043 // that writes to arg0
3045 // Struct parameters that are passed by reference are marked as both lvIsParam and lvIsTemp
3046 // (this is an overload of lvIsTemp because there are no temp parameters).
3047 // For x64 this is 3, 5, 6, 7, >8 byte structs that are passed by reference.
3048 // For ARM64, this is structs larger than 16 bytes that are passed by reference.
3049 bool lvaIsImplicitByRefLocal(unsigned varNum)
3051 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
3052 LclVarDsc* varDsc = &(lvaTable[varNum]);
3053 if (varDsc->lvIsParam && varDsc->lvIsTemp)
3055 assert(varTypeIsStruct(varDsc) || (varDsc->lvType == TYP_BYREF));
3058 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
3062 // Returns true if this local var is a multireg struct
3063 bool lvaIsMultiregStruct(LclVarDsc* varDsc, bool isVararg);
3065 // If the local is a TYP_STRUCT, get/set a class handle describing it
3066 CORINFO_CLASS_HANDLE lvaGetStruct(unsigned varNum);
3067 void lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool unsafeValueClsCheck, bool setTypeInfo = true);
3068 void lvaSetStructUsedAsVarArg(unsigned varNum);
3070 // If the local is TYP_REF, set or update the associated class information.
3071 void lvaSetClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
3072 void lvaSetClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
3073 void lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
3074 void lvaUpdateClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
3076 #define MAX_NumOfFieldsInPromotableStruct 4 // Maximum number of fields in promotable struct
3078 // Info about struct type fields.
3079 struct lvaStructFieldInfo
3081 CORINFO_FIELD_HANDLE fldHnd;
3082 unsigned char fldOffset;
3083 unsigned char fldOrdinal;
3086 CORINFO_CLASS_HANDLE fldTypeHnd;
3088 lvaStructFieldInfo()
3089 : fldHnd(nullptr), fldOffset(0), fldOrdinal(0), fldType(TYP_UNDEF), fldSize(0), fldTypeHnd(nullptr)
3094 // Info about a struct type, instances of which may be candidates for promotion.
3095 struct lvaStructPromotionInfo
3097 CORINFO_CLASS_HANDLE typeHnd;
3102 unsigned char fieldCnt;
3103 lvaStructFieldInfo fields[MAX_NumOfFieldsInPromotableStruct];
3105 lvaStructPromotionInfo(CORINFO_CLASS_HANDLE typeHnd = nullptr)
3108 , containsHoles(false)
3109 , customLayout(false)
3110 , fieldsSorted(false)
3116 static int __cdecl lvaFieldOffsetCmp(const void* field1, const void* field2);
3118 // This class is responsible for checking validity and profitability of struct promotion.
3119 // If it is both legal and profitable, then TryPromoteStructVar promotes the struct and initializes
3120 // nessesary information for fgMorphStructField to use.
3121 class StructPromotionHelper
3124 StructPromotionHelper(Compiler* compiler);
3126 bool CanPromoteStructType(CORINFO_CLASS_HANDLE typeHnd);
3127 bool TryPromoteStructVar(unsigned lclNum);
3130 void CheckRetypedAsScalar(CORINFO_FIELD_HANDLE fieldHnd, var_types requestedType);
3134 bool GetRequiresScratchVar();
3135 #endif // _TARGET_ARM_
3138 bool CanPromoteStructVar(unsigned lclNum);
3139 bool ShouldPromoteStructVar(unsigned lclNum);
3140 void PromoteStructVar(unsigned lclNum);
3141 void SortStructFields();
3143 lvaStructFieldInfo GetFieldInfo(CORINFO_FIELD_HANDLE fieldHnd, BYTE ordinal);
3144 bool TryPromoteStructField(lvaStructFieldInfo& outerFieldInfo);
3148 lvaStructPromotionInfo structPromotionInfo;
3151 bool requiresScratchVar;
3152 #endif // _TARGET_ARM_
3155 typedef JitHashTable<CORINFO_FIELD_HANDLE, JitPtrKeyFuncs<CORINFO_FIELD_STRUCT_>, var_types>
3156 RetypedAsScalarFieldsMap;
3157 RetypedAsScalarFieldsMap retypedFieldsMap;
3161 StructPromotionHelper* structPromotionHelper;
3163 #if !defined(_TARGET_64BIT_)
3164 void lvaPromoteLongVars();
3165 #endif // !defined(_TARGET_64BIT_)
3166 unsigned lvaGetFieldLocal(const LclVarDsc* varDsc, unsigned int fldOffset);
3167 lvaPromotionType lvaGetPromotionType(const LclVarDsc* varDsc);
3168 lvaPromotionType lvaGetPromotionType(unsigned varNum);
3169 lvaPromotionType lvaGetParentPromotionType(const LclVarDsc* varDsc);
3170 lvaPromotionType lvaGetParentPromotionType(unsigned varNum);
3171 bool lvaIsFieldOfDependentlyPromotedStruct(const LclVarDsc* varDsc);
3172 bool lvaIsGCTracked(const LclVarDsc* varDsc);
3174 #if defined(FEATURE_SIMD)
3175 bool lvaMapSimd12ToSimd16(const LclVarDsc* varDsc)
3177 assert(varDsc->lvType == TYP_SIMD12);
3178 assert(varDsc->lvExactSize == 12);
3180 #if defined(_TARGET_64BIT_)
3181 assert(varDsc->lvSize() == 16);
3182 #endif // defined(_TARGET_64BIT_)
3184 // We make local variable SIMD12 types 16 bytes instead of just 12. lvSize()
3185 // already does this calculation. However, we also need to prevent mapping types if the var is a
3186 // dependently promoted struct field, which must remain its exact size within its parent struct.
3187 // However, we don't know this until late, so we may have already pretended the field is bigger
3189 if ((varDsc->lvSize() == 16) && !lvaIsFieldOfDependentlyPromotedStruct(varDsc))
3198 #endif // defined(FEATURE_SIMD)
3200 BYTE* lvaGetGcLayout(unsigned varNum);
3201 bool lvaTypeIsGC(unsigned varNum);
3202 unsigned lvaGSSecurityCookie; // LclVar number
3203 bool lvaTempsHaveLargerOffsetThanVars();
3205 // Returns "true" iff local variable "lclNum" is in SSA form.
3206 bool lvaInSsa(unsigned lclNum)
3208 assert(lclNum < lvaCount);
3209 return lvaTable[lclNum].lvInSsa;
3212 unsigned lvaSecurityObject; // variable representing the security object on the stack
3213 unsigned lvaStubArgumentVar; // variable representing the secret stub argument coming in EAX
3215 #if FEATURE_EH_FUNCLETS
3216 unsigned lvaPSPSym; // variable representing the PSPSym
3219 InlineInfo* impInlineInfo;
3220 InlineStrategy* m_inlineStrategy;
3222 // The Compiler* that is the root of the inlining tree of which "this" is a member.
3223 Compiler* impInlineRoot();
3225 #if defined(DEBUG) || defined(INLINE_DATA)
3226 unsigned __int64 getInlineCycleCount()
3228 return m_compCycles;
3230 #endif // defined(DEBUG) || defined(INLINE_DATA)
3232 bool fgNoStructPromotion; // Set to TRUE to turn off struct promotion for this method.
3233 bool fgNoStructParamPromotion; // Set to TRUE to turn off struct promotion for parameters this method.
3235 //=========================================================================
3237 //=========================================================================
3240 //---------------- Local variable ref-counting ----------------------------
3242 void lvaMarkLclRefs(GenTree* tree, BasicBlock* block, GenTreeStmt* stmt, bool isRecompute);
3243 bool IsDominatedByExceptionalEntry(BasicBlock* block);
3244 void SetVolatileHint(LclVarDsc* varDsc);
3246 // Keeps the mapping from SSA #'s to VN's for the implicit memory variables.
3247 SsaDefArray<SsaMemDef> lvMemoryPerSsaData;
3250 // Returns the address of the per-Ssa data for memory at the given ssaNum (which is required
3251 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
3252 // not an SSA variable).
3253 SsaMemDef* GetMemoryPerSsaData(unsigned ssaNum)
3255 return lvMemoryPerSsaData.GetSsaDef(ssaNum);
3259 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3260 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3264 XX Imports the given method and converts it to semantic trees XX
3266 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3267 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3273 void impImport(BasicBlock* method);
3275 CORINFO_CLASS_HANDLE impGetRefAnyClass();
3276 CORINFO_CLASS_HANDLE impGetRuntimeArgumentHandle();
3277 CORINFO_CLASS_HANDLE impGetTypeHandleClass();
3278 CORINFO_CLASS_HANDLE impGetStringClass();
3279 CORINFO_CLASS_HANDLE impGetObjectClass();
3281 // Returns underlying type of handles returned by ldtoken instruction
3282 inline var_types GetRuntimeHandleUnderlyingType()
3284 // RuntimeTypeHandle is backed by raw pointer on CoreRT and by object reference on other runtimes
3285 return IsTargetAbi(CORINFO_CORERT_ABI) ? TYP_I_IMPL : TYP_REF;
3288 //=========================================================================
3290 //=========================================================================
3293 //-------------------- Stack manipulation ---------------------------------
3295 unsigned impStkSize; // Size of the full stack
3297 #define SMALL_STACK_SIZE 16 // number of elements in impSmallStack
3299 struct SavedStack // used to save/restore stack contents.
3301 unsigned ssDepth; // number of values on stack
3302 StackEntry* ssTrees; // saved tree values
3305 bool impIsPrimitive(CorInfoType type);
3306 bool impILConsumesAddr(const BYTE* codeAddr, CORINFO_METHOD_HANDLE fncHandle, CORINFO_MODULE_HANDLE scpHandle);
3308 void impResolveToken(const BYTE* addr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CorInfoTokenKind kind);
3310 void impPushOnStack(GenTree* tree, typeInfo ti);
3311 void impPushNullObjRefOnStack();
3312 StackEntry impPopStack();
3313 StackEntry& impStackTop(unsigned n = 0);
3314 unsigned impStackHeight();
3316 void impSaveStackState(SavedStack* savePtr, bool copy);
3317 void impRestoreStackState(SavedStack* savePtr);
3319 GenTree* impImportLdvirtftn(GenTree* thisPtr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3321 void impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken);
3323 void impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3325 bool impCanPInvokeInline();
3326 bool impCanPInvokeInlineCallSite(BasicBlock* block);
3327 void impCheckForPInvokeCall(
3328 GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block);
3329 GenTreeCall* impImportIndirectCall(CORINFO_SIG_INFO* sig, IL_OFFSETX ilOffset = BAD_IL_OFFSET);
3330 void impPopArgsForUnmanagedCall(GenTree* call, CORINFO_SIG_INFO* sig);
3332 void impInsertHelperCall(CORINFO_HELPER_DESC* helperCall);
3333 void impHandleAccessAllowed(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
3334 void impHandleAccessAllowedInternal(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
3336 var_types impImportCall(OPCODE opcode,
3337 CORINFO_RESOLVED_TOKEN* pResolvedToken,
3338 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call on a
3340 GenTree* newobjThis,
3342 CORINFO_CALL_INFO* callInfo,
3343 IL_OFFSET rawILOffset);
3345 void impDevirtualizeCall(GenTreeCall* call,
3346 CORINFO_METHOD_HANDLE* method,
3347 unsigned* methodFlags,
3348 CORINFO_CONTEXT_HANDLE* contextHandle,
3349 CORINFO_CONTEXT_HANDLE* exactContextHandle);
3351 CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(CORINFO_METHOD_HANDLE specialIntrinsicHandle);
3353 bool impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo);
3355 GenTree* impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HANDLE retClsHnd);
3357 GenTree* impFixupStructReturnType(GenTree* op, CORINFO_CLASS_HANDLE retClsHnd);
3360 var_types impImportJitTestLabelMark(int numArgs);
3363 GenTree* impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken);
3365 GenTree* impImportStaticReadOnlyField(void* fldAddr, var_types lclTyp);
3367 GenTree* impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3368 CORINFO_ACCESS_FLAGS access,
3369 CORINFO_FIELD_INFO* pFieldInfo,
3372 static void impBashVarAddrsToI(GenTree* tree1, GenTree* tree2 = nullptr);
3374 GenTree* impImplicitIorI4Cast(GenTree* tree, var_types dstTyp);
3376 GenTree* impImplicitR4orR8Cast(GenTree* tree, var_types dstTyp);
3378 void impImportLeave(BasicBlock* block);
3379 void impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr);
3380 GenTree* impIntrinsic(GenTree* newobjThis,
3381 CORINFO_CLASS_HANDLE clsHnd,
3382 CORINFO_METHOD_HANDLE method,
3383 CORINFO_SIG_INFO* sig,
3384 unsigned methodFlags,
3388 CORINFO_RESOLVED_TOKEN* pContstrainedResolvedToken,
3389 CORINFO_THIS_TRANSFORM constraintCallThisTransform,
3390 CorInfoIntrinsics* pIntrinsicID,
3391 bool* isSpecialIntrinsic = nullptr);
3392 GenTree* impMathIntrinsic(CORINFO_METHOD_HANDLE method,
3393 CORINFO_SIG_INFO* sig,
3395 CorInfoIntrinsics intrinsicID,
3397 NamedIntrinsic lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method);
3399 #ifdef FEATURE_HW_INTRINSICS
3400 GenTree* impHWIntrinsic(NamedIntrinsic intrinsic,
3401 CORINFO_METHOD_HANDLE method,
3402 CORINFO_SIG_INFO* sig,
3404 GenTree* impUnsupportedHWIntrinsic(unsigned helper,
3405 CORINFO_METHOD_HANDLE method,
3406 CORINFO_SIG_INFO* sig,
3410 bool compSupportsHWIntrinsic(InstructionSet isa);
3412 #ifdef _TARGET_XARCH_
3413 GenTree* impSSEIntrinsic(NamedIntrinsic intrinsic,
3414 CORINFO_METHOD_HANDLE method,
3415 CORINFO_SIG_INFO* sig,
3417 GenTree* impSSE2Intrinsic(NamedIntrinsic intrinsic,
3418 CORINFO_METHOD_HANDLE method,
3419 CORINFO_SIG_INFO* sig,
3421 GenTree* impSSE42Intrinsic(NamedIntrinsic intrinsic,
3422 CORINFO_METHOD_HANDLE method,
3423 CORINFO_SIG_INFO* sig,
3425 GenTree* impAvxOrAvx2Intrinsic(NamedIntrinsic intrinsic,
3426 CORINFO_METHOD_HANDLE method,
3427 CORINFO_SIG_INFO* sig,
3429 GenTree* impAESIntrinsic(NamedIntrinsic intrinsic,
3430 CORINFO_METHOD_HANDLE method,
3431 CORINFO_SIG_INFO* sig,
3433 GenTree* impBMI1Intrinsic(NamedIntrinsic intrinsic,
3434 CORINFO_METHOD_HANDLE method,
3435 CORINFO_SIG_INFO* sig,
3437 GenTree* impBMI2Intrinsic(NamedIntrinsic intrinsic,
3438 CORINFO_METHOD_HANDLE method,
3439 CORINFO_SIG_INFO* sig,
3441 GenTree* impFMAIntrinsic(NamedIntrinsic intrinsic,
3442 CORINFO_METHOD_HANDLE method,
3443 CORINFO_SIG_INFO* sig,
3445 GenTree* impLZCNTIntrinsic(NamedIntrinsic intrinsic,
3446 CORINFO_METHOD_HANDLE method,
3447 CORINFO_SIG_INFO* sig,
3449 GenTree* impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic,
3450 CORINFO_METHOD_HANDLE method,
3451 CORINFO_SIG_INFO* sig,
3453 GenTree* impPOPCNTIntrinsic(NamedIntrinsic intrinsic,
3454 CORINFO_METHOD_HANDLE method,
3455 CORINFO_SIG_INFO* sig,
3459 GenTree* getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE argClass);
3460 GenTree* impNonConstFallback(NamedIntrinsic intrinsic, var_types simdType, var_types baseType);
3461 GenTree* addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* lastOp, bool mustExpand);
3462 bool hwIntrinsicSignatureTypeSupported(var_types retType, CORINFO_SIG_INFO* sig, NamedIntrinsic intrinsic);
3463 #endif // _TARGET_XARCH_
3464 #ifdef _TARGET_ARM64_
3465 InstructionSet lookupHWIntrinsicISA(const char* className);
3466 NamedIntrinsic lookupHWIntrinsic(const char* className, const char* methodName);
3467 bool impCheckImmediate(GenTree* immediateOp, unsigned int max);
3468 #endif // _TARGET_ARM64_
3469 #endif // FEATURE_HW_INTRINSICS
3470 GenTree* impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
3471 CORINFO_SIG_INFO* sig,
3474 CorInfoIntrinsics intrinsicID);
3475 GenTree* impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig);
3477 GenTree* impMethodPointer(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3479 GenTree* impTransformThis(GenTree* thisPtr,
3480 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
3481 CORINFO_THIS_TRANSFORM transform);
3483 //----------------- Manipulating the trees and stmts ----------------------
3485 GenTree* impTreeList; // Trees for the BB being imported
3486 GenTree* impTreeLast; // The last tree for the current BB
3491 CHECK_SPILL_ALL = -1,
3492 CHECK_SPILL_NONE = -2
3495 void impBeginTreeList();
3496 void impEndTreeList(BasicBlock* block, GenTree* firstStmt, GenTree* lastStmt);
3497 void impEndTreeList(BasicBlock* block);
3498 void impAppendStmtCheck(GenTree* stmt, unsigned chkLevel);
3499 void impAppendStmt(GenTree* stmt, unsigned chkLevel);
3500 void impInsertStmtBefore(GenTree* stmt, GenTree* stmtBefore);
3501 GenTree* impAppendTree(GenTree* tree, unsigned chkLevel, IL_OFFSETX offset);
3502 void impInsertTreeBefore(GenTree* tree, IL_OFFSETX offset, GenTree* stmtBefore);
3503 void impAssignTempGen(unsigned tmp,
3506 GenTree** pAfterStmt = nullptr,
3507 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3508 BasicBlock* block = nullptr);
3509 void impAssignTempGen(unsigned tmpNum,
3511 CORINFO_CLASS_HANDLE structHnd,
3513 GenTree** pAfterStmt = nullptr,
3514 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3515 BasicBlock* block = nullptr);
3516 GenTree* impCloneExpr(GenTree* tree,
3518 CORINFO_CLASS_HANDLE structHnd,
3520 GenTree** pAfterStmt DEBUGARG(const char* reason));
3521 GenTree* impAssignStruct(GenTree* dest,
3523 CORINFO_CLASS_HANDLE structHnd,
3525 GenTree** pAfterStmt = nullptr,
3526 BasicBlock* block = nullptr);
3527 GenTree* impAssignStructPtr(GenTree* dest,
3529 CORINFO_CLASS_HANDLE structHnd,
3531 GenTree** pAfterStmt = nullptr,
3532 BasicBlock* block = nullptr);
3534 GenTree* impGetStructAddr(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, unsigned curLevel, bool willDeref);
3536 var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd,
3537 BYTE* gcLayout = nullptr,
3538 unsigned* numGCVars = nullptr,
3539 var_types* simdBaseType = nullptr);
3541 GenTree* impNormStructVal(GenTree* structVal,
3542 CORINFO_CLASS_HANDLE structHnd,
3544 bool forceNormalization = false);
3546 GenTree* impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3547 BOOL* pRuntimeLookup = nullptr,
3548 BOOL mustRestoreHandle = FALSE,
3549 BOOL importParent = FALSE);
3551 GenTree* impParentClassTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3552 BOOL* pRuntimeLookup = nullptr,
3553 BOOL mustRestoreHandle = FALSE)
3555 return impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, TRUE);
3558 GenTree* impLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3559 CORINFO_LOOKUP* pLookup,
3561 void* compileTimeHandle);
3563 GenTree* getRuntimeContextTree(CORINFO_RUNTIME_LOOKUP_KIND kind);
3565 GenTree* impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3566 CORINFO_LOOKUP* pLookup,
3567 void* compileTimeHandle);
3569 GenTree* impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP* pLookup, unsigned flags, void* compileTimeHandle);
3571 GenTreeCall* impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3572 CorInfoHelpFunc helper,
3574 GenTreeArgList* arg = nullptr,
3575 CORINFO_LOOKUP_KIND* pGenericLookupKind = nullptr);
3577 GenTree* impCastClassOrIsInstToTree(GenTree* op1,
3579 CORINFO_RESOLVED_TOKEN* pResolvedToken,
3582 GenTree* impOptimizeCastClassOrIsInst(GenTree* op1, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isCastClass);
3584 bool VarTypeIsMultiByteAndCanEnreg(
3585 var_types type, CORINFO_CLASS_HANDLE typeClass, unsigned* typeSize, bool forReturn, bool isVarArg);
3587 bool IsIntrinsicImplementedByUserCall(CorInfoIntrinsics intrinsicId);
3588 bool IsTargetIntrinsic(CorInfoIntrinsics intrinsicId);
3589 bool IsMathIntrinsic(CorInfoIntrinsics intrinsicId);
3590 bool IsMathIntrinsic(GenTree* tree);
3593 //----------------- Importing the method ----------------------------------
3595 CORINFO_CONTEXT_HANDLE impTokenLookupContextHandle; // The context used for looking up tokens.
3598 unsigned impCurOpcOffs;
3599 const char* impCurOpcName;
3600 bool impNestedStackSpill;
3602 // For displaying instrs with generated native code (-n:B)
3603 GenTree* impLastILoffsStmt; // oldest stmt added for which we did not gtStmtLastILoffs
3604 void impNoteLastILoffs();
3607 /* IL offset of the stmt currently being imported. It gets set to
3608 BAD_IL_OFFSET after it has been set in the appended trees. Then it gets
3609 updated at IL offsets for which we have to report mapping info.
3610 It also includes flag bits, so use jitGetILoffs()
3611 to get the actual IL offset value.
3614 IL_OFFSETX impCurStmtOffs;
3615 void impCurStmtOffsSet(IL_OFFSET offs);
3617 void impNoteBranchOffs();
3619 unsigned impInitBlockLineInfo();
3621 GenTree* impCheckForNullPointer(GenTree* obj);
3622 bool impIsThis(GenTree* obj);
3623 bool impIsLDFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3624 bool impIsDUP_LDVIRTFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3625 bool impIsAnySTLOC(OPCODE opcode)
3627 return ((opcode == CEE_STLOC) || (opcode == CEE_STLOC_S) ||
3628 ((opcode >= CEE_STLOC_0) && (opcode <= CEE_STLOC_3)));
3631 GenTreeArgList* impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenTreeArgList* prefixTree = nullptr);
3633 GenTreeArgList* impPopRevList(unsigned count, CORINFO_SIG_INFO* sig, unsigned skipReverseCount = 0);
3636 * Get current IL offset with stack-empty info incoporated
3638 IL_OFFSETX impCurILOffset(IL_OFFSET offs, bool callInstruction = false);
3640 //---------------- Spilling the importer stack ----------------------------
3642 // The maximum number of bytes of IL processed without clean stack state.
3643 // It allows to limit the maximum tree size and depth.
3644 static const unsigned MAX_TREE_SIZE = 200;
3645 bool impCanSpillNow(OPCODE prevOpcode);
3651 SavedStack pdSavedStack;
3652 ThisInitState pdThisPtrInit;
3655 PendingDsc* impPendingList; // list of BBs currently waiting to be imported.
3656 PendingDsc* impPendingFree; // Freed up dscs that can be reused
3658 // We keep a byte-per-block map (dynamically extended) in the top-level Compiler object of a compilation.
3659 JitExpandArray<BYTE> impPendingBlockMembers;
3661 // Return the byte for "b" (allocating/extending impPendingBlockMembers if necessary.)
3662 // Operates on the map in the top-level ancestor.
3663 BYTE impGetPendingBlockMember(BasicBlock* blk)
3665 return impInlineRoot()->impPendingBlockMembers.Get(blk->bbInd());
3668 // Set the byte for "b" to "val" (allocating/extending impPendingBlockMembers if necessary.)
3669 // Operates on the map in the top-level ancestor.
3670 void impSetPendingBlockMember(BasicBlock* blk, BYTE val)
3672 impInlineRoot()->impPendingBlockMembers.Set(blk->bbInd(), val);
3675 bool impCanReimport;
3677 bool impSpillStackEntry(unsigned level,
3681 bool bAssertOnRecursion,
3686 void impSpillStackEnsure(bool spillLeaves = false);
3687 void impEvalSideEffects();
3688 void impSpillSpecialSideEff();
3689 void impSpillSideEffects(bool spillGlobEffects, unsigned chkLevel DEBUGARG(const char* reason));
3690 void impSpillValueClasses();
3691 void impSpillEvalStack();
3692 static fgWalkPreFn impFindValueClasses;
3693 void impSpillLclRefs(ssize_t lclNum);
3695 BasicBlock* impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_HANDLE clsHnd, bool isSingleBlockFilter);
3697 void impImportBlockCode(BasicBlock* block);
3699 void impReimportMarkBlock(BasicBlock* block);
3700 void impReimportMarkSuccessors(BasicBlock* block);
3702 void impVerifyEHBlock(BasicBlock* block, bool isTryStart);
3704 void impImportBlockPending(BasicBlock* block);
3706 // Similar to impImportBlockPending, but assumes that block has already been imported once and is being
3707 // reimported for some reason. It specifically does *not* look at verCurrentState to set the EntryState
3708 // for the block, but instead, just re-uses the block's existing EntryState.
3709 void impReimportBlockPending(BasicBlock* block);
3711 var_types impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTree** pOp1, GenTree** pOp2);
3713 void impImportBlock(BasicBlock* block);
3715 // Assumes that "block" is a basic block that completes with a non-empty stack. We will assign the values
3716 // on the stack to local variables (the "spill temp" variables). The successor blocks will assume that
3717 // its incoming stack contents are in those locals. This requires "block" and its successors to agree on
3718 // the variables that will be used -- and for all the predecessors of those successors, and the
3719 // successors of those predecessors, etc. Call such a set of blocks closed under alternating
3720 // successor/predecessor edges a "spill clique." A block is a "predecessor" or "successor" member of the
3721 // clique (or, conceivably, both). Each block has a specified sequence of incoming and outgoing spill
3722 // temps. If "block" already has its outgoing spill temps assigned (they are always a contiguous series
3723 // of local variable numbers, so we represent them with the base local variable number), returns that.
3724 // Otherwise, picks a set of spill temps, and propagates this choice to all blocks in the spill clique of
3725 // which "block" is a member (asserting, in debug mode, that no block in this clique had its spill temps
3726 // chosen already. More precisely, that the incoming or outgoing spill temps are not chosen, depending
3727 // on which kind of member of the clique the block is).
3728 unsigned impGetSpillTmpBase(BasicBlock* block);
3730 // Assumes that "block" is a basic block that completes with a non-empty stack. We have previously
3731 // assigned the values on the stack to local variables (the "spill temp" variables). The successor blocks
3732 // will assume that its incoming stack contents are in those locals. This requires "block" and its
3733 // successors to agree on the variables and their types that will be used. The CLI spec allows implicit
3734 // conversions between 'int' and 'native int' or 'float' and 'double' stack types. So one predecessor can
3735 // push an int and another can push a native int. For 64-bit we have chosen to implement this by typing
3736 // the "spill temp" as native int, and then importing (or re-importing as needed) so that all the
3737 // predecessors in the "spill clique" push a native int (sign-extending if needed), and all the
3738 // successors receive a native int. Similarly float and double are unified to double.
3739 // This routine is called after a type-mismatch is detected, and it will walk the spill clique to mark
3740 // blocks for re-importation as appropriate (both successors, so they get the right incoming type, and
3741 // predecessors, so they insert an upcast if needed).
3742 void impReimportSpillClique(BasicBlock* block);
3744 // When we compute a "spill clique" (see above) these byte-maps are allocated to have a byte per basic
3745 // block, and represent the predecessor and successor members of the clique currently being computed.
3746 // *** Access to these will need to be locked in a parallel compiler.
3747 JitExpandArray<BYTE> impSpillCliquePredMembers;
3748 JitExpandArray<BYTE> impSpillCliqueSuccMembers;
3756 // Abstract class for receiving a callback while walking a spill clique
3757 class SpillCliqueWalker
3760 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk) = 0;
3763 // This class is used for setting the bbStkTempsIn and bbStkTempsOut on the blocks within a spill clique
3764 class SetSpillTempsBase : public SpillCliqueWalker
3769 SetSpillTempsBase(unsigned baseTmp) : m_baseTmp(baseTmp)
3772 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3775 // This class is used for implementing impReimportSpillClique part on each block within the spill clique
3776 class ReimportSpillClique : public SpillCliqueWalker
3781 ReimportSpillClique(Compiler* pComp) : m_pComp(pComp)
3784 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
3787 // This is the heart of the algorithm for walking spill cliques. It invokes callback->Visit for each
3788 // predecessor or successor within the spill clique
3789 void impWalkSpillCliqueFromPred(BasicBlock* pred, SpillCliqueWalker* callback);
3791 // For a BasicBlock that has already been imported, the EntryState has an array of GenTrees for the
3792 // incoming locals. This walks that list an resets the types of the GenTrees to match the types of
3793 // the VarDscs. They get out of sync when we have int/native int issues (see impReimportSpillClique).
3794 void impRetypeEntryStateTemps(BasicBlock* blk);
3796 BYTE impSpillCliqueGetMember(SpillCliqueDir predOrSucc, BasicBlock* blk);
3797 void impSpillCliqueSetMember(SpillCliqueDir predOrSucc, BasicBlock* blk, BYTE val);
3799 void impPushVar(GenTree* op, typeInfo tiRetVal);
3800 void impLoadVar(unsigned lclNum, IL_OFFSET offset, typeInfo tiRetVal);
3801 void impLoadVar(unsigned lclNum, IL_OFFSET offset)
3803 impLoadVar(lclNum, offset, lvaTable[lclNum].lvVerTypeInfo);
3805 void impLoadArg(unsigned ilArgNum, IL_OFFSET offset);
3806 void impLoadLoc(unsigned ilLclNum, IL_OFFSET offset);
3807 bool impReturnInstruction(BasicBlock* block, int prefixFlags, OPCODE& opcode);
3810 void impMarkLclDstNotPromotable(unsigned tmpNum, GenTree* op, CORINFO_CLASS_HANDLE hClass);
3813 // A free list of linked list nodes used to represent to-do stacks of basic blocks.
3814 struct BlockListNode
3817 BlockListNode* m_next;
3818 BlockListNode(BasicBlock* blk, BlockListNode* next = nullptr) : m_blk(blk), m_next(next)
3821 void* operator new(size_t sz, Compiler* comp);
3823 BlockListNode* impBlockListNodeFreeList;
3825 void FreeBlockListNode(BlockListNode* node);
3827 bool impIsValueType(typeInfo* pTypeInfo);
3828 var_types mangleVarArgsType(var_types type);
3831 regNumber getCallArgIntRegister(regNumber floatReg);
3832 regNumber getCallArgFloatRegister(regNumber intReg);
3833 #endif // FEATURE_VARARG
3836 static unsigned jitTotalMethodCompiled;
3840 static LONG jitNestingLevel;
3843 static BOOL impIsAddressInLocal(GenTree* tree, GenTree** lclVarTreeOut);
3845 void impMakeDiscretionaryInlineObservations(InlineInfo* pInlineInfo, InlineResult* inlineResult);
3847 // STATIC inlining decision based on the IL code.
3848 void impCanInlineIL(CORINFO_METHOD_HANDLE fncHandle,
3849 CORINFO_METHOD_INFO* methInfo,
3851 InlineResult* inlineResult);
3853 void impCheckCanInline(GenTree* call,
3854 CORINFO_METHOD_HANDLE fncHandle,
3856 CORINFO_CONTEXT_HANDLE exactContextHnd,
3857 InlineCandidateInfo** ppInlineCandidateInfo,
3858 InlineResult* inlineResult);
3860 void impInlineRecordArgInfo(InlineInfo* pInlineInfo,
3863 InlineResult* inlineResult);
3865 void impInlineInitVars(InlineInfo* pInlineInfo);
3867 unsigned impInlineFetchLocal(unsigned lclNum DEBUGARG(const char* reason));
3869 GenTree* impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, InlLclVarInfo* lclTypeInfo);
3871 BOOL impInlineIsThis(GenTree* tree, InlArgInfo* inlArgInfo);
3873 BOOL impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTree* additionalTreesToBeEvaluatedBefore,
3874 GenTree* variableBeingDereferenced,
3875 InlArgInfo* inlArgInfo);
3877 void impMarkInlineCandidate(GenTree* call,
3878 CORINFO_CONTEXT_HANDLE exactContextHnd,
3879 bool exactContextNeedsRuntimeLookup,
3880 CORINFO_CALL_INFO* callInfo);
3882 bool impTailCallRetTypeCompatible(var_types callerRetType,
3883 CORINFO_CLASS_HANDLE callerRetTypeClass,
3884 var_types calleeRetType,
3885 CORINFO_CLASS_HANDLE calleeRetTypeClass);
3887 bool impIsTailCallILPattern(bool tailPrefixed,
3889 const BYTE* codeAddrOfNextOpcode,
3890 const BYTE* codeEnd,
3892 bool* IsCallPopRet = nullptr);
3894 bool impIsImplicitTailCallCandidate(
3895 OPCODE curOpcode, const BYTE* codeAddrOfNextOpcode, const BYTE* codeEnd, int prefixFlags, bool isRecursive);
3897 CORINFO_RESOLVED_TOKEN* impAllocateToken(CORINFO_RESOLVED_TOKEN token);
3900 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3901 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3905 XX Info about the basic-blocks, their contents and the flow analysis XX
3907 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3908 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3912 BasicBlock* fgFirstBB; // Beginning of the basic block list
3913 BasicBlock* fgLastBB; // End of the basic block list
3914 BasicBlock* fgFirstColdBlock; // First block to be placed in the cold section
3915 #if FEATURE_EH_FUNCLETS
3916 BasicBlock* fgFirstFuncletBB; // First block of outlined funclets (to allow block insertion before the funclets)
3918 BasicBlock* fgFirstBBScratch; // Block inserted for initialization stuff. Is nullptr if no such block has been
3920 BasicBlockList* fgReturnBlocks; // list of BBJ_RETURN blocks
3921 unsigned fgEdgeCount; // # of control flow edges between the BBs
3922 unsigned fgBBcount; // # of BBs in the method
3924 unsigned fgBBcountAtCodegen; // # of BBs in the method at the start of codegen
3926 unsigned fgBBNumMax; // The max bbNum that has been assigned to basic blocks
3927 unsigned fgDomBBcount; // # of BBs for which we have dominator and reachability information
3928 BasicBlock** fgBBInvPostOrder; // The flow graph stored in an array sorted in topological order, needed to compute
3929 // dominance. Indexed by block number. Size: fgBBNumMax + 1.
3931 // After the dominance tree is computed, we cache a DFS preorder number and DFS postorder number to compute
3932 // dominance queries in O(1). fgDomTreePreOrder and fgDomTreePostOrder are arrays giving the block's preorder and
3933 // postorder number, respectively. The arrays are indexed by basic block number. (Note that blocks are numbered
3934 // starting from one. Thus, we always waste element zero. This makes debugging easier and makes the code less likely
3935 // to suffer from bugs stemming from forgetting to add or subtract one from the block number to form an array
3936 // index). The arrays are of size fgBBNumMax + 1.
3937 unsigned* fgDomTreePreOrder;
3938 unsigned* fgDomTreePostOrder;
3940 bool fgBBVarSetsInited;
3942 // Allocate array like T* a = new T[fgBBNumMax + 1];
3943 // Using helper so we don't keep forgetting +1.
3944 template <typename T>
3945 T* fgAllocateTypeForEachBlk(CompMemKind cmk = CMK_Unknown)
3947 return getAllocator(cmk).allocate<T>(fgBBNumMax + 1);
3950 // BlockSets are relative to a specific set of BasicBlock numbers. If that changes
3951 // (if the blocks are renumbered), this changes. BlockSets from different epochs
3952 // cannot be meaningfully combined. Note that new blocks can be created with higher
3953 // block numbers without changing the basic block epoch. These blocks *cannot*
3954 // participate in a block set until the blocks are all renumbered, causing the epoch
3955 // to change. This is useful if continuing to use previous block sets is valuable.
3956 // If the epoch is zero, then it is uninitialized, and block sets can't be used.
3957 unsigned fgCurBBEpoch;
3959 unsigned GetCurBasicBlockEpoch()
3961 return fgCurBBEpoch;
3964 // The number of basic blocks in the current epoch. When the blocks are renumbered,
3965 // this is fgBBcount. As blocks are added, fgBBcount increases, fgCurBBEpochSize remains
3966 // the same, until a new BasicBlock epoch is created, such as when the blocks are all renumbered.
3967 unsigned fgCurBBEpochSize;
3969 // The number of "size_t" elements required to hold a bitset large enough for fgCurBBEpochSize
3970 // bits. This is precomputed to avoid doing math every time BasicBlockBitSetTraits::GetArrSize() is called.
3971 unsigned fgBBSetCountInSizeTUnits;
3973 void NewBasicBlockEpoch()
3975 INDEBUG(unsigned oldEpochArrSize = fgBBSetCountInSizeTUnits);
3977 // We have a new epoch. Compute and cache the size needed for new BlockSets.
3979 fgCurBBEpochSize = fgBBNumMax + 1;
3980 fgBBSetCountInSizeTUnits =
3981 roundUp(fgCurBBEpochSize, (unsigned)(sizeof(size_t) * 8)) / unsigned(sizeof(size_t) * 8);
3984 // All BlockSet objects are now invalid!
3985 fgReachabilitySetsValid = false; // the bbReach sets are now invalid!
3986 fgEnterBlksSetValid = false; // the fgEnterBlks set is now invalid!
3990 unsigned epochArrSize = BasicBlockBitSetTraits::GetArrSize(this, sizeof(size_t));
3991 printf("\nNew BlockSet epoch %d, # of blocks (including unused BB00): %u, bitset array size: %u (%s)",
3992 fgCurBBEpoch, fgCurBBEpochSize, epochArrSize, (epochArrSize <= 1) ? "short" : "long");
3993 if ((fgCurBBEpoch != 1) && ((oldEpochArrSize <= 1) != (epochArrSize <= 1)))
3995 // If we're not just establishing the first epoch, and the epoch array size has changed such that we're
3996 // going to change our bitset representation from short (just a size_t bitset) to long (a pointer to an
3997 // array of size_t bitsets), then print that out.
3998 printf("; NOTE: BlockSet size was previously %s!", (oldEpochArrSize <= 1) ? "short" : "long");
4005 void EnsureBasicBlockEpoch()
4007 if (fgCurBBEpochSize != fgBBNumMax + 1)
4009 NewBasicBlockEpoch();
4013 BasicBlock* fgNewBasicBlock(BBjumpKinds jumpKind);
4014 void fgEnsureFirstBBisScratch();
4015 bool fgFirstBBisScratch();
4016 bool fgBBisScratch(BasicBlock* block);
4018 void fgExtendEHRegionBefore(BasicBlock* block);
4019 void fgExtendEHRegionAfter(BasicBlock* block);
4021 BasicBlock* fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
4023 BasicBlock* fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
4025 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
4028 BasicBlock* nearBlk,
4029 bool putInFilter = false,
4030 bool runRarely = false,
4031 bool insertAtEnd = false);
4033 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
4035 bool runRarely = false,
4036 bool insertAtEnd = false);
4038 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind);
4040 BasicBlock* fgNewBBinRegionWorker(BBjumpKinds jumpKind,
4041 BasicBlock* afterBlk,
4042 unsigned xcptnIndex,
4043 bool putInTryRegion);
4045 void fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk);
4046 void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk);
4047 void fgUnlinkBlock(BasicBlock* block);
4049 unsigned fgMeasureIR();
4051 bool fgModified; // True if the flow graph has been modified recently
4052 bool fgComputePredsDone; // Have we computed the bbPreds list
4053 bool fgCheapPredsValid; // Is the bbCheapPreds list valid?
4054 bool fgDomsComputed; // Have we computed the dominator sets?
4055 bool fgOptimizedFinally; // Did we optimize any try-finallys?
4057 bool fgHasSwitch; // any BBJ_SWITCH jumps?
4059 BlockSet fgEnterBlks; // Set of blocks which have a special transfer of control; the "entry" blocks plus EH handler
4063 bool fgReachabilitySetsValid; // Are the bbReach sets valid?
4064 bool fgEnterBlksSetValid; // Is the fgEnterBlks set valid?
4067 bool fgRemoveRestOfBlock; // true if we know that we will throw
4068 bool fgStmtRemoved; // true if we remove statements -> need new DFA
4070 // There are two modes for ordering of the trees.
4071 // - In FGOrderTree, the dominant ordering is the tree order, and the nodes contained in
4072 // each tree and sub-tree are contiguous, and can be traversed (in gtNext/gtPrev order)
4073 // by traversing the tree according to the order of the operands.
4074 // - In FGOrderLinear, the dominant ordering is the linear order.
4081 FlowGraphOrder fgOrder;
4083 // The following are boolean flags that keep track of the state of internal data structures
4085 bool fgStmtListThreaded; // true if the node list is now threaded
4086 bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
4087 bool fgEdgeWeightsComputed; // true after we have called fgComputeEdgeWeights
4088 bool fgHaveValidEdgeWeights; // true if we were successful in computing all of the edge weights
4089 bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
4090 bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
4091 bool fgNeedsUpdateFlowGraph; // true if we need to run fgUpdateFlowGraph
4092 BasicBlock::weight_t fgCalledCount; // count of the number of times this method was called
4093 // This is derived from the profile data
4094 // or is BB_UNITY_WEIGHT when we don't have profile data
4096 #if FEATURE_EH_FUNCLETS
4097 bool fgFuncletsCreated; // true if the funclet creation phase has been run
4098 #endif // FEATURE_EH_FUNCLETS
4100 bool fgGlobalMorph; // indicates if we are during the global morphing phase
4101 // since fgMorphTree can be called from several places
4103 bool impBoxTempInUse; // the temp below is valid and available
4104 unsigned impBoxTemp; // a temporary that is used for boxing
4107 bool jitFallbackCompile; // Are we doing a fallback compile? That is, have we executed a NO_WAY assert,
4108 // and we are trying to compile again in a "safer", minopts mode?
4112 unsigned impInlinedCodeSize;
4115 //-------------------------------------------------------------------------
4121 void fgTransformFatCalli();
4125 void fgRemoveEmptyTry();
4127 void fgRemoveEmptyFinally();
4129 void fgMergeFinallyChains();
4131 void fgCloneFinally();
4133 void fgCleanupContinuation(BasicBlock* continuation);
4135 void fgUpdateFinallyTargetFlags();
4137 void fgClearAllFinallyTargetBits();
4139 void fgAddFinallyTargetFlags();
4141 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
4142 // Sometimes we need to defer updating the BBF_FINALLY_TARGET bit. fgNeedToAddFinallyTargetBits signals
4143 // when this is necessary.
4144 bool fgNeedToAddFinallyTargetBits;
4145 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
4147 bool fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block,
4148 BasicBlock* handler,
4149 BlockToBlockMap& continuationMap);
4151 GenTree* fgGetCritSectOfStaticMethod();
4153 #if FEATURE_EH_FUNCLETS
4155 void fgAddSyncMethodEnterExit();
4157 GenTree* fgCreateMonitorTree(unsigned lvaMonitorBool, unsigned lvaThisVar, BasicBlock* block, bool enter);
4159 void fgConvertSyncReturnToLeave(BasicBlock* block);
4161 #endif // FEATURE_EH_FUNCLETS
4163 void fgAddReversePInvokeEnterExit();
4165 bool fgMoreThanOneReturnBlock();
4167 // The number of separate return points in the method.
4168 unsigned fgReturnCount;
4170 void fgAddInternal();
4172 bool fgFoldConditional(BasicBlock* block);
4174 void fgMorphStmts(BasicBlock* block, bool* lnot, bool* loadw);
4175 void fgMorphBlocks();
4177 bool fgMorphBlockStmt(BasicBlock* block, GenTreeStmt* stmt DEBUGARG(const char* msg));
4179 void fgSetOptions();
4182 static fgWalkPreFn fgAssertNoQmark;
4183 void fgPreExpandQmarkChecks(GenTree* expr);
4184 void fgPostExpandQmarkChecks();
4185 static void fgCheckQmarkAllowedForm(GenTree* tree);
4188 IL_OFFSET fgFindBlockILOffset(BasicBlock* block);
4190 BasicBlock* fgSplitBlockAtBeginning(BasicBlock* curr);
4191 BasicBlock* fgSplitBlockAtEnd(BasicBlock* curr);
4192 BasicBlock* fgSplitBlockAfterStatement(BasicBlock* curr, GenTree* stmt);
4193 BasicBlock* fgSplitBlockAfterNode(BasicBlock* curr, GenTree* node); // for LIR
4194 BasicBlock* fgSplitEdge(BasicBlock* curr, BasicBlock* succ);
4196 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, BasicBlock* block, IL_OFFSETX offs);
4197 GenTreeStmt* fgNewStmtFromTree(GenTree* tree);
4198 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, BasicBlock* block);
4199 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, IL_OFFSETX offs);
4201 GenTree* fgGetTopLevelQmark(GenTree* expr, GenTree** ppDst = nullptr);
4202 void fgExpandQmarkForCastInstOf(BasicBlock* block, GenTree* stmt);
4203 void fgExpandQmarkStmt(BasicBlock* block, GenTree* expr);
4204 void fgExpandQmarkNodes();
4208 // Do "simple lowering." This functionality is (conceptually) part of "general"
4209 // lowering that is distributed between fgMorph and the lowering phase of LSRA.
4210 void fgSimpleLowering();
4212 GenTree* fgInitThisClass();
4214 GenTreeCall* fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper);
4216 GenTreeCall* fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls);
4218 inline bool backendRequiresLocalVarLifetimes()
4220 return !opts.MinOpts() || m_pLinearScan->willEnregisterLocalVars();
4223 void fgLocalVarLiveness();
4225 void fgLocalVarLivenessInit();
4227 void fgPerNodeLocalVarLiveness(GenTree* node);
4228 void fgPerBlockLocalVarLiveness();
4230 VARSET_VALRET_TP fgGetHandlerLiveVars(BasicBlock* block);
4232 void fgLiveVarAnalysis(bool updateInternalOnly = false);
4234 void fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call);
4236 void fgComputeLifeTrackedLocalUse(VARSET_TP& life, LclVarDsc& varDsc, GenTreeLclVarCommon* node);
4237 bool fgComputeLifeTrackedLocalDef(VARSET_TP& life,
4238 VARSET_VALARG_TP keepAliveVars,
4240 GenTreeLclVarCommon* node);
4241 void fgComputeLifeUntrackedLocal(VARSET_TP& life,
4242 VARSET_VALARG_TP keepAliveVars,
4244 GenTreeLclVarCommon* lclVarNode);
4245 bool fgComputeLifeLocal(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTree* lclVarNode);
4247 void fgComputeLife(VARSET_TP& life,
4250 VARSET_VALARG_TP volatileVars,
4251 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
4253 void fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALARG_TP volatileVars);
4255 bool fgRemoveDeadStore(GenTree** pTree,
4257 VARSET_VALARG_TP life,
4259 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
4261 // For updating liveset during traversal AFTER fgComputeLife has completed
4262 VARSET_VALRET_TP fgGetVarBits(GenTree* tree);
4263 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tree);
4265 // Returns the set of live variables after endTree,
4266 // assuming that liveSet is the set of live variables BEFORE tree.
4267 // Requires that fgComputeLife has completed, and that tree is in the same
4268 // statement as endTree, and that it comes before endTree in execution order
4270 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tree, GenTree* endTree)
4272 VARSET_TP newLiveSet(VarSetOps::MakeCopy(this, liveSet));
4273 while (tree != nullptr && tree != endTree->gtNext)
4275 VarSetOps::AssignNoCopy(this, newLiveSet, fgUpdateLiveSet(newLiveSet, tree));
4276 tree = tree->gtNext;
4278 assert(tree == endTree->gtNext);
4282 void fgInterBlockLocalVarLiveness();
4284 // The presence of a partial definition presents some difficulties for SSA: this is both a use of some SSA name
4285 // 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
4286 // whether to treat that as the use or def. It chooses the "use", and thus the old SSA name. This map allows us
4287 // to record/recover the "def" SSA number, given the lcl var node for "x" in such a tree.
4288 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, unsigned> NodeToUnsignedMap;
4289 NodeToUnsignedMap* m_opAsgnVarDefSsaNums;
4290 NodeToUnsignedMap* GetOpAsgnVarDefSsaNums()
4292 if (m_opAsgnVarDefSsaNums == nullptr)
4294 m_opAsgnVarDefSsaNums = new (getAllocator()) NodeToUnsignedMap(getAllocator());
4296 return m_opAsgnVarDefSsaNums;
4299 // Requires value numbering phase to have completed. Returns the value number ("gtVN") of the
4300 // "tree," EXCEPT in the case of GTF_VAR_USEASG, because the tree node's gtVN member is the
4301 // "use" VN. Performs a lookup into the map of (use asg tree -> def VN.) to return the "def's"
4303 inline ValueNum GetUseAsgDefVNOrTreeVN(GenTree* tree);
4305 // Requires that "lcl" has the GTF_VAR_DEF flag set. Returns the SSA number of "lcl".
4306 // Except: assumes that lcl is a def, and if it is
4307 // a partial def (GTF_VAR_USEASG), looks up and returns the SSA number for the "def",
4308 // rather than the "use" SSA number recorded in the tree "lcl".
4309 inline unsigned GetSsaNumForLocalVarDef(GenTree* lcl);
4311 // Performs SSA conversion.
4314 // Reset any data structures to the state expected by "fgSsaBuild", so it can be run again.
4315 void fgResetForSsa();
4317 unsigned fgSsaPassesCompleted; // Number of times fgSsaBuild has been run.
4319 // Returns "true" if a struct temp of the given type requires needs zero init in this block
4320 inline bool fgStructTempNeedsExplicitZeroInit(LclVarDsc* varDsc, BasicBlock* block);
4322 // The value numbers for this compilation.
4323 ValueNumStore* vnStore;
4326 ValueNumStore* GetValueNumStore()
4331 // Do value numbering (assign a value number to each
4333 void fgValueNumber();
4335 // Computes new GcHeap VN via the assignment H[elemTypeEq][arrVN][inx][fldSeq] = rhsVN.
4336 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
4337 // The 'indType' is the indirection type of the lhs of the assignment and will typically
4338 // match the element type of the array or fldSeq. When this type doesn't match
4339 // or if the fldSeq is 'NotAField' we invalidate the array contents H[elemTypeEq][arrVN]
4341 ValueNum fgValueNumberArrIndexAssign(CORINFO_CLASS_HANDLE elemTypeEq,
4344 FieldSeqNode* fldSeq,
4348 // Requires that "tree" is a GT_IND marked as an array index, and that its address argument
4349 // has been parsed to yield the other input arguments. If evaluation of the address
4350 // can raise exceptions, those should be captured in the exception set "excVN."
4351 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
4352 // Marks "tree" with the VN for H[elemTypeEq][arrVN][inx][fldSeq] (for the liberal VN; a new unique
4353 // VN for the conservative VN.) Also marks the tree's argument as the address of an array element.
4354 // The type tree->TypeGet() will typically match the element type of the array or fldSeq.
4355 // When this type doesn't match or if the fldSeq is 'NotAField' we return a new unique VN
4357 ValueNum fgValueNumberArrIndexVal(GenTree* tree,
4358 CORINFO_CLASS_HANDLE elemTypeEq,
4362 FieldSeqNode* fldSeq);
4364 // Requires "funcApp" to be a VNF_PtrToArrElem, and "addrXvn" to represent the exception set thrown
4365 // by evaluating the array index expression "tree". Returns the value number resulting from
4366 // dereferencing the array in the current GcHeap state. If "tree" is non-null, it must be the
4367 // "GT_IND" that does the dereference, and it is given the returned value number.
4368 ValueNum fgValueNumberArrIndexVal(GenTree* tree, struct VNFuncApp* funcApp, ValueNum addrXvn);
4370 // Compute the value number for a byref-exposed load of the given type via the given pointerVN.
4371 ValueNum fgValueNumberByrefExposedLoad(var_types type, ValueNum pointerVN);
4373 unsigned fgVNPassesCompleted; // Number of times fgValueNumber has been run.
4375 // Utility functions for fgValueNumber.
4377 // Perform value-numbering for the trees in "blk".
4378 void fgValueNumberBlock(BasicBlock* blk);
4380 // Requires that "entryBlock" is the entry block of loop "loopNum", and that "loopNum" is the
4381 // innermost loop of which "entryBlock" is the entry. Returns the value number that should be
4382 // assumed for the memoryKind at the start "entryBlk".
4383 ValueNum fgMemoryVNForLoopSideEffects(MemoryKind memoryKind, BasicBlock* entryBlock, unsigned loopNum);
4385 // Called when an operation (performed by "tree", described by "msg") may cause the GcHeap to be mutated.
4386 // As GcHeap is a subset of ByrefExposed, this will also annotate the ByrefExposed mutation.
4387 void fgMutateGcHeap(GenTree* tree DEBUGARG(const char* msg));
4389 // Called when an operation (performed by "tree", described by "msg") may cause an address-exposed local to be
4391 void fgMutateAddressExposedLocal(GenTree* tree DEBUGARG(const char* msg));
4393 // For a GC heap store at curTree, record the new curMemoryVN's and update curTree's MemorySsaMap.
4394 // As GcHeap is a subset of ByrefExposed, this will also record the ByrefExposed store.
4395 void recordGcHeapStore(GenTree* curTree, ValueNum gcHeapVN DEBUGARG(const char* msg));
4397 // For a store to an address-exposed local at curTree, record the new curMemoryVN and update curTree's MemorySsaMap.
4398 void recordAddressExposedLocalStore(GenTree* curTree, ValueNum memoryVN DEBUGARG(const char* msg));
4400 // Tree caused an update in the current memory VN. If "tree" has an associated heap SSA #, record that
4401 // value in that SSA #.
4402 void fgValueNumberRecordMemorySsa(MemoryKind memoryKind, GenTree* tree);
4404 // The input 'tree' is a leaf node that is a constant
4405 // Assign the proper value number to the tree
4406 void fgValueNumberTreeConst(GenTree* tree);
4408 // Assumes that all inputs to "tree" have had value numbers assigned; assigns a VN to tree.
4409 // (With some exceptions: the VN of the lhs of an assignment is assigned as part of the
4411 void fgValueNumberTree(GenTree* tree);
4413 // Does value-numbering for a block assignment.
4414 void fgValueNumberBlockAssignment(GenTree* tree);
4416 // Does value-numbering for a cast tree.
4417 void fgValueNumberCastTree(GenTree* tree);
4419 // Does value-numbering for an intrinsic tree.
4420 void fgValueNumberIntrinsic(GenTree* tree);
4422 // Does value-numbering for a call. We interpret some helper calls.
4423 void fgValueNumberCall(GenTreeCall* call);
4425 // The VN of some nodes in "args" may have changed -- reassign VNs to the arg list nodes.
4426 void fgUpdateArgListVNs(GenTreeArgList* args);
4428 // Does value-numbering for a helper "call" that has a VN function symbol "vnf".
4429 void fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc);
4431 // Requires "helpCall" to be a helper call. Assigns it a value number;
4432 // we understand the semantics of some of the calls. Returns "true" if
4433 // the call may modify the heap (we assume arbitrary memory side effects if so).
4434 bool fgValueNumberHelperCall(GenTreeCall* helpCall);
4436 // Requires that "helpFunc" is one of the pure Jit Helper methods.
4437 // Returns the corresponding VNFunc to use for value numbering
4438 VNFunc fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc);
4440 // Adds the exception set for the current tree node which is performing a memory indirection operation
4441 void fgValueNumberAddExceptionSetForIndirection(GenTree* tree);
4443 // Adds the exception sets for the current tree node which is performing a division or modulus operation
4444 void fgValueNumberAddExceptionSetForDivision(GenTree* tree);
4446 // Adds the exception set for the current tree node which is performing a overflow checking operation
4447 void fgValueNumberAddExceptionSetForOverflow(GenTree* tree);
4449 // Adds the exception set for the current tree node which is performing a ckfinite operation
4450 void fgValueNumberAddExceptionSetForCkFinite(GenTree* tree);
4452 // Adds the exception sets for the current tree node
4453 void fgValueNumberAddExceptionSet(GenTree* tree);
4455 // These are the current value number for the memory implicit variables while
4456 // doing value numbering. These are the value numbers under the "liberal" interpretation
4457 // of memory values; the "conservative" interpretation needs no VN, since every access of
4458 // memory yields an unknown value.
4459 ValueNum fgCurMemoryVN[MemoryKindCount];
4461 // Return a "pseudo"-class handle for an array element type. If "elemType" is TYP_STRUCT,
4462 // requires "elemStructType" to be non-null (and to have a low-order zero). Otherwise, low order bit
4463 // is 1, and the rest is an encoding of "elemTyp".
4464 static CORINFO_CLASS_HANDLE EncodeElemType(var_types elemTyp, CORINFO_CLASS_HANDLE elemStructType)
4466 if (elemStructType != nullptr)
4468 assert(varTypeIsStruct(elemTyp) || elemTyp == TYP_REF || elemTyp == TYP_BYREF ||
4469 varTypeIsIntegral(elemTyp));
4470 assert((size_t(elemStructType) & 0x1) == 0x0); // Make sure the encoding below is valid.
4471 return elemStructType;
4475 elemTyp = varTypeUnsignedToSigned(elemTyp);
4476 return CORINFO_CLASS_HANDLE(size_t(elemTyp) << 1 | 0x1);
4479 // If "clsHnd" is the result of an "EncodePrim" call, returns true and sets "*pPrimType" to the
4480 // var_types it represents. Otherwise, returns TYP_STRUCT (on the assumption that "clsHnd" is
4481 // the struct type of the element).
4482 static var_types DecodeElemType(CORINFO_CLASS_HANDLE clsHnd)
4484 size_t clsHndVal = size_t(clsHnd);
4485 if (clsHndVal & 0x1)
4487 return var_types(clsHndVal >> 1);
4495 // Convert a BYTE which represents the VM's CorInfoGCtype to the JIT's var_types
4496 var_types getJitGCType(BYTE gcType);
4498 enum structPassingKind
4500 SPK_Unknown, // Invalid value, never returned
4501 SPK_PrimitiveType, // The struct is passed/returned using a primitive type.
4502 SPK_EnclosingType, // Like SPK_Primitive type, but used for return types that
4503 // require a primitive type temp that is larger than the struct size.
4504 // Currently used for structs of size 3, 5, 6, or 7 bytes.
4505 SPK_ByValue, // The struct is passed/returned by value (using the ABI rules)
4506 // for ARM64 and UNIX_X64 in multiple registers. (when all of the
4507 // parameters registers are used, then the stack will be used)
4508 // for X86 passed on the stack, for ARM32 passed in registers
4509 // or the stack or split between registers and the stack.
4510 SPK_ByValueAsHfa, // The struct is passed/returned as an HFA in multiple registers.
4512 }; // The struct is passed/returned by reference to a copy/buffer.
4514 // Get the "primitive" type that is is used when we are given a struct of size 'structSize'.
4515 // For pointer sized structs the 'clsHnd' is used to determine if the struct contains GC ref.
4516 // A "primitive" type is one of the scalar types: byte, short, int, long, ref, float, double
4517 // If we can't or shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
4519 // isVarArg is passed for use on Windows Arm64 to change the decision returned regarding
4522 var_types getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS_HANDLE clsHnd, bool isVarArg);
4524 // Get the type that is used to pass values of the given struct type.
4525 // isVarArg is passed for use on Windows Arm64 to change the decision returned regarding
4528 var_types getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4529 structPassingKind* wbPassStruct,
4531 unsigned structSize);
4533 // Get the type that is used to return values of the given struct type.
4534 // If the size is unknown, pass 0 and it will be determined from 'clsHnd'.
4535 var_types getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4536 structPassingKind* wbPassStruct = nullptr,
4537 unsigned structSize = 0);
4540 // Print a representation of "vnp" or "vn" on standard output.
4541 // If "level" is non-zero, we also print out a partial expansion of the value.
4542 void vnpPrint(ValueNumPair vnp, unsigned level);
4543 void vnPrint(ValueNum vn, unsigned level);
4546 bool fgDominate(BasicBlock* b1, BasicBlock* b2); // Return true if b1 dominates b2
4548 // Dominator computation member functions
4549 // Not exposed outside Compiler
4551 bool fgReachable(BasicBlock* b1, BasicBlock* b2); // Returns true if block b1 can reach block b2
4553 void fgComputeDoms(); // Computes the immediate dominators for each basic block in the
4554 // flow graph. We first assume the fields bbIDom on each
4555 // basic block are invalid. This computation is needed later
4556 // by fgBuildDomTree to build the dominance tree structure.
4557 // Based on: A Simple, Fast Dominance Algorithm
4558 // by Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
4560 void fgCompDominatedByExceptionalEntryBlocks();
4562 BlockSet_ValRet_T fgGetDominatorSet(BasicBlock* block); // Returns a set of blocks that dominate the given block.
4563 // Note: this is relatively slow compared to calling fgDominate(),
4564 // especially if dealing with a single block versus block check.
4566 void fgComputeReachabilitySets(); // Compute bbReach sets. (Also sets BBF_GC_SAFE_POINT flag on blocks.)
4568 void fgComputeEnterBlocksSet(); // Compute the set of entry blocks, 'fgEnterBlks'.
4570 bool fgRemoveUnreachableBlocks(); // Remove blocks determined to be unreachable by the bbReach sets.
4572 void fgComputeReachability(); // Perform flow graph node reachability analysis.
4574 BasicBlock* fgIntersectDom(BasicBlock* a, BasicBlock* b); // Intersect two immediate dominator sets.
4576 void fgDfsInvPostOrder(); // In order to compute dominance using fgIntersectDom, the flow graph nodes must be
4577 // processed in topological sort, this function takes care of that.
4579 void fgDfsInvPostOrderHelper(BasicBlock* block, BlockSet& visited, unsigned* count);
4581 BlockSet_ValRet_T fgDomFindStartNodes(); // Computes which basic blocks don't have incoming edges in the flow graph.
4582 // Returns this as a set.
4584 BlockSet_ValRet_T fgDomTreeEntryNodes(BasicBlockList** domTree); // Computes which nodes in the dominance forest are
4585 // root nodes. Returns this as a set.
4588 void fgDispDomTree(BasicBlockList** domTree); // Helper that prints out the Dominator Tree in debug builds.
4591 void fgBuildDomTree(); // Once we compute all the immediate dominator sets for each node in the flow graph
4592 // (performed by fgComputeDoms), this procedure builds the dominance tree represented
4595 // In order to speed up the queries of the form 'Does A dominates B', we can perform a DFS preorder and postorder
4596 // traversal of the dominance tree and the dominance query will become A dominates B iif preOrder(A) <= preOrder(B)
4597 // && postOrder(A) >= postOrder(B) making the computation O(1).
4598 void fgTraverseDomTree(unsigned bbNum, BasicBlockList** domTree, unsigned* preNum, unsigned* postNum);
4600 // When the flow graph changes, we need to update the block numbers, predecessor lists, reachability sets, and
4602 void fgUpdateChangedFlowGraph();
4605 // Compute the predecessors of the blocks in the control flow graph.
4606 void fgComputePreds();
4608 // Remove all predecessor information.
4609 void fgRemovePreds();
4611 // Compute the cheap flow graph predecessors lists. This is used in some early phases
4612 // before the full predecessors lists are computed.
4613 void fgComputeCheapPreds();
4616 void fgAddCheapPred(BasicBlock* block, BasicBlock* blockPred);
4618 void fgRemoveCheapPred(BasicBlock* block, BasicBlock* blockPred);
4628 // Initialize the per-block variable sets (used for liveness analysis).
4629 void fgInitBlockVarSets();
4631 // true if we've gone through and created GC Poll calls.
4632 bool fgGCPollsCreated;
4633 void fgMarkGCPollBlocks();
4634 void fgCreateGCPolls();
4635 bool fgCreateGCPoll(GCPollType pollType, BasicBlock* block);
4637 // Requires that "block" is a block that returns from
4638 // a finally. Returns the number of successors (jump targets of
4639 // of blocks in the covered "try" that did a "LEAVE".)
4640 unsigned fgNSuccsOfFinallyRet(BasicBlock* block);
4642 // Requires that "block" is a block that returns (in the sense of BBJ_EHFINALLYRET) from
4643 // a finally. Returns its "i"th successor (jump targets of
4644 // of blocks in the covered "try" that did a "LEAVE".)
4645 // Requires that "i" < fgNSuccsOfFinallyRet(block).
4646 BasicBlock* fgSuccOfFinallyRet(BasicBlock* block, unsigned i);
4649 // Factor out common portions of the impls of the methods above.
4650 void fgSuccOfFinallyRetWork(BasicBlock* block, unsigned i, BasicBlock** bres, unsigned* nres);
4653 // For many purposes, it is desirable to be able to enumerate the *distinct* targets of a switch statement,
4654 // skipping duplicate targets. (E.g., in flow analyses that are only interested in the set of possible targets.)
4655 // SwitchUniqueSuccSet contains the non-duplicated switch targets.
4656 // (Code that modifies the jump table of a switch has an obligation to call Compiler::UpdateSwitchTableTarget,
4657 // which in turn will call the "UpdateTarget" method of this type if a SwitchUniqueSuccSet has already
4658 // been computed for the switch block. If a switch block is deleted or is transformed into a non-switch,
4659 // we leave the entry associated with the block, but it will no longer be accessed.)
4660 struct SwitchUniqueSuccSet
4662 unsigned numDistinctSuccs; // Number of distinct targets of the switch.
4663 BasicBlock** nonDuplicates; // Array of "numDistinctSuccs", containing all the distinct switch target
4666 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4667 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4668 // remove it from "this", and ensure that "to" is a member. Use "alloc" to do any required allocation.
4669 void UpdateTarget(CompAllocator alloc, BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4672 typedef JitHashTable<BasicBlock*, JitPtrKeyFuncs<BasicBlock>, SwitchUniqueSuccSet> BlockToSwitchDescMap;
4675 // Maps BasicBlock*'s that end in switch statements to SwitchUniqueSuccSets that allow
4676 // iteration over only the distinct successors.
4677 BlockToSwitchDescMap* m_switchDescMap;
4680 BlockToSwitchDescMap* GetSwitchDescMap(bool createIfNull = true)
4682 if ((m_switchDescMap == nullptr) && createIfNull)
4684 m_switchDescMap = new (getAllocator()) BlockToSwitchDescMap(getAllocator());
4686 return m_switchDescMap;
4689 // Invalidate the map of unique switch block successors. For example, since the hash key of the map
4690 // depends on block numbers, we must invalidate the map when the blocks are renumbered, to ensure that
4691 // we don't accidentally look up and return the wrong switch data.
4692 void InvalidateUniqueSwitchSuccMap()
4694 m_switchDescMap = nullptr;
4697 // Requires "switchBlock" to be a block that ends in a switch. Returns
4698 // the corresponding SwitchUniqueSuccSet.
4699 SwitchUniqueSuccSet GetDescriptorForSwitch(BasicBlock* switchBlk);
4701 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4702 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4703 // remove it from "this", and ensure that "to" is a member.
4704 void UpdateSwitchTableTarget(BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4706 // Remove the "SwitchUniqueSuccSet" of "switchBlk" in the BlockToSwitchDescMap.
4707 void fgInvalidateSwitchDescMapEntry(BasicBlock* switchBlk);
4709 BasicBlock* fgFirstBlockOfHandler(BasicBlock* block);
4711 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred);
4713 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred, flowList*** ptrToPred);
4715 flowList* fgSpliceOutPred(BasicBlock* block, BasicBlock* blockPred);
4717 flowList* fgRemoveRefPred(BasicBlock* block, BasicBlock* blockPred);
4719 flowList* fgRemoveAllRefPreds(BasicBlock* block, BasicBlock* blockPred);
4721 flowList* fgRemoveAllRefPreds(BasicBlock* block, flowList** ptrToPred);
4723 void fgRemoveBlockAsPred(BasicBlock* block);
4725 void fgChangeSwitchBlock(BasicBlock* oldSwitchBlock, BasicBlock* newSwitchBlock);
4727 void fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* newTarget, BasicBlock* oldTarget);
4729 void fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, BasicBlock* oldTarget);
4731 void fgReplacePred(BasicBlock* block, BasicBlock* oldPred, BasicBlock* newPred);
4733 flowList* fgAddRefPred(BasicBlock* block,
4734 BasicBlock* blockPred,
4735 flowList* oldEdge = nullptr,
4736 bool initializingPreds = false); // Only set to 'true' when we are computing preds in
4739 void fgFindBasicBlocks();
4741 bool fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt);
4743 bool fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionIndex, bool putInTryRegion);
4745 BasicBlock* fgFindInsertPoint(unsigned regionIndex,
4746 bool putInTryRegion,
4747 BasicBlock* startBlk,
4749 BasicBlock* nearBlk,
4750 BasicBlock* jumpBlk,
4753 unsigned fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNesting = nullptr);
4755 void fgRemoveEmptyBlocks();
4757 void fgRemoveStmt(BasicBlock* block, GenTree* stmt);
4759 bool fgCheckRemoveStmt(BasicBlock* block, GenTree* stmt);
4761 void fgCreateLoopPreHeader(unsigned lnum);
4763 void fgUnreachableBlock(BasicBlock* block);
4765 void fgRemoveConditionalJump(BasicBlock* block);
4767 BasicBlock* fgLastBBInMainFunction();
4769 BasicBlock* fgEndBBAfterMainFunction();
4771 void fgUnlinkRange(BasicBlock* bBeg, BasicBlock* bEnd);
4773 void fgRemoveBlock(BasicBlock* block, bool unreachable);
4775 bool fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4777 void fgCompactBlocks(BasicBlock* block, BasicBlock* bNext);
4779 void fgUpdateLoopsAfterCompacting(BasicBlock* block, BasicBlock* bNext);
4781 BasicBlock* fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst);
4783 bool fgRenumberBlocks();
4785 bool fgExpandRarelyRunBlocks();
4787 bool fgEhAllowsMoveBlock(BasicBlock* bBefore, BasicBlock* bAfter);
4789 void fgMoveBlocksAfter(BasicBlock* bStart, BasicBlock* bEnd, BasicBlock* insertAfterBlk);
4791 enum FG_RELOCATE_TYPE
4793 FG_RELOCATE_TRY, // relocate the 'try' region
4794 FG_RELOCATE_HANDLER // relocate the handler region (including the filter if necessary)
4796 BasicBlock* fgRelocateEHRange(unsigned regionIndex, FG_RELOCATE_TYPE relocateType);
4798 #if FEATURE_EH_FUNCLETS
4799 #if defined(_TARGET_ARM_)
4800 void fgClearFinallyTargetBit(BasicBlock* block);
4801 #endif // defined(_TARGET_ARM_)
4802 bool fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block);
4803 bool fgAnyIntraHandlerPreds(BasicBlock* block);
4804 void fgInsertFuncletPrologBlock(BasicBlock* block);
4805 void fgCreateFuncletPrologBlocks();
4806 void fgCreateFunclets();
4807 #else // !FEATURE_EH_FUNCLETS
4808 bool fgRelocateEHRegions();
4809 #endif // !FEATURE_EH_FUNCLETS
4811 bool fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* target);
4813 bool fgBlockEndFavorsTailDuplication(BasicBlock* block);
4815 bool fgBlockIsGoodTailDuplicationCandidate(BasicBlock* block);
4817 bool fgOptimizeEmptyBlock(BasicBlock* block);
4819 bool fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBlock* bDest);
4821 bool fgOptimizeBranch(BasicBlock* bJump);
4823 bool fgOptimizeSwitchBranches(BasicBlock* block);
4825 bool fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev);
4827 bool fgOptimizeSwitchJumps();
4829 void fgPrintEdgeWeights();
4831 void fgComputeBlockAndEdgeWeights();
4832 BasicBlock::weight_t fgComputeMissingBlockWeights();
4833 void fgComputeCalledCount(BasicBlock::weight_t returnWeight);
4834 void fgComputeEdgeWeights();
4836 void fgReorderBlocks();
4838 void fgDetermineFirstColdBlock();
4840 bool fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc = nullptr);
4842 bool fgUpdateFlowGraph(bool doTailDup = false);
4844 void fgFindOperOrder();
4846 // method that returns if you should split here
4847 typedef bool(fgSplitPredicate)(GenTree* tree, GenTree* parent, fgWalkData* data);
4849 void fgSetBlockOrder();
4851 void fgRemoveReturnBlock(BasicBlock* block);
4853 /* Helper code that has been factored out */
4854 inline void fgConvertBBToThrowBB(BasicBlock* block);
4856 bool fgCastNeeded(GenTree* tree, var_types toType);
4857 GenTree* fgDoNormalizeOnStore(GenTree* tree);
4858 GenTree* fgMakeTmpArgNode(fgArgTabEntry* curArgTabEntry);
4860 // The following check for loops that don't execute calls
4861 bool fgLoopCallMarked;
4863 void fgLoopCallTest(BasicBlock* srcBB, BasicBlock* dstBB);
4864 void fgLoopCallMark();
4866 void fgMarkLoopHead(BasicBlock* block);
4868 unsigned fgGetCodeEstimate(BasicBlock* block);
4871 const char* fgProcessEscapes(const char* nameIn, escapeMapping_t* map);
4872 FILE* fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, LPCWSTR type);
4873 bool fgDumpFlowGraph(Phases phase);
4875 #endif // DUMP_FLOWGRAPHS
4880 void fgDispBBLiveness(BasicBlock* block);
4881 void fgDispBBLiveness();
4882 void fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth = 0);
4883 void fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, bool dumpTrees);
4884 void fgDispBasicBlocks(bool dumpTrees = false);
4885 void fgDumpStmtTree(GenTree* stmt, unsigned bbNum);
4886 void fgDumpBlock(BasicBlock* block);
4887 void fgDumpTrees(BasicBlock* firstBlock, BasicBlock* lastBlock);
4889 static fgWalkPreFn fgStress64RsltMulCB;
4890 void fgStress64RsltMul();
4891 void fgDebugCheckUpdate();
4892 void fgDebugCheckBBlist(bool checkBBNum = false, bool checkBBRefs = true);
4893 void fgDebugCheckBlockLinks();
4894 void fgDebugCheckLinks(bool morphTrees = false);
4895 void fgDebugCheckStmtsList(BasicBlock* block, bool morphTrees);
4896 void fgDebugCheckNodeLinks(BasicBlock* block, GenTree* stmt);
4897 void fgDebugCheckNodesUniqueness();
4899 void fgDebugCheckFlags(GenTree* tree);
4900 void fgDebugCheckFlagsHelper(GenTree* tree, unsigned treeFlags, unsigned chkFlags);
4901 void fgDebugCheckTryFinallyExits();
4904 static GenTree* fgGetFirstNode(GenTree* tree);
4906 //--------------------- Walking the trees in the IR -----------------------
4911 fgWalkPreFn* wtprVisitorFn;
4912 fgWalkPostFn* wtpoVisitorFn;
4913 void* pCallbackData; // user-provided data
4914 bool wtprLclsOnly; // whether to only visit lclvar nodes
4915 GenTree* parent; // parent of current node, provided to callback
4916 GenTreeStack* parentStack; // stack of parent nodes, if asked for
4918 bool printModified; // callback can use this
4922 fgWalkResult fgWalkTreePre(GenTree** pTree,
4923 fgWalkPreFn* visitor,
4924 void* pCallBackData = nullptr,
4925 bool lclVarsOnly = false,
4926 bool computeStack = false);
4928 fgWalkResult fgWalkTree(GenTree** pTree,
4929 fgWalkPreFn* preVisitor,
4930 fgWalkPostFn* postVisitor,
4931 void* pCallBackData = nullptr);
4933 void fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData);
4937 fgWalkResult fgWalkTreePost(GenTree** pTree,
4938 fgWalkPostFn* visitor,
4939 void* pCallBackData = nullptr,
4940 bool computeStack = false);
4942 // An fgWalkPreFn that looks for expressions that have inline throws in
4943 // minopts mode. Basically it looks for tress with gtOverflowEx() or
4944 // GTF_IND_RNGCHK. It returns WALK_ABORT if one is found. It
4945 // returns WALK_SKIP_SUBTREES if GTF_EXCEPT is not set (assumes flags
4946 // properly propagated to parent trees). It returns WALK_CONTINUE
4948 static fgWalkResult fgChkThrowCB(GenTree** pTree, Compiler::fgWalkData* data);
4949 static fgWalkResult fgChkLocAllocCB(GenTree** pTree, Compiler::fgWalkData* data);
4950 static fgWalkResult fgChkQmarkCB(GenTree** pTree, Compiler::fgWalkData* data);
4952 /**************************************************************************
4954 *************************************************************************/
4957 friend class SsaBuilder;
4958 friend struct ValueNumberState;
4960 //--------------------- Detect the basic blocks ---------------------------
4962 BasicBlock** fgBBs; // Table of pointers to the BBs
4964 void fgInitBBLookup();
4965 BasicBlock* fgLookupBB(unsigned addr);
4967 void fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, FixedBitVect* jumpTarget);
4969 void fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock);
4971 void fgLinkBasicBlocks();
4973 unsigned fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, FixedBitVect* jumpTarget);
4975 void fgCheckBasicBlockControlFlow();
4977 void fgControlFlowPermitted(BasicBlock* blkSrc,
4978 BasicBlock* blkDest,
4979 BOOL IsLeave = false /* is the src a leave block */);
4981 bool fgFlowToFirstBlockOfInnerTry(BasicBlock* blkSrc, BasicBlock* blkDest, bool sibling);
4983 void fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, bool isInlining);
4985 void fgAdjustForAddressExposedOrWrittenThis();
4987 bool fgProfileData_ILSizeMismatch;
4988 ICorJitInfo::ProfileBuffer* fgProfileBuffer;
4989 ULONG fgProfileBufferCount;
4990 ULONG fgNumProfileRuns;
4992 unsigned fgStressBBProf()
4995 unsigned result = JitConfig.JitStressBBProf();
4998 if (compStressCompile(STRESS_BB_PROFILE, 15))
5009 bool fgHaveProfileData();
5010 bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weight);
5011 void fgInstrumentMethod();
5014 // fgIsUsingProfileWeights - returns true if we have real profile data for this method
5015 // or if we have some fake profile data for the stress mode
5016 bool fgIsUsingProfileWeights()
5018 return (fgHaveProfileData() || fgStressBBProf());
5021 // fgProfileRunsCount - returns total number of scenario runs for the profile data
5022 // or BB_UNITY_WEIGHT when we aren't using profile data.
5023 unsigned fgProfileRunsCount()
5025 return fgIsUsingProfileWeights() ? fgNumProfileRuns : BB_UNITY_WEIGHT;
5028 //-------- Insert a statement at the start or end of a basic block --------
5032 static bool fgBlockContainsStatementBounded(BasicBlock* block, GenTree* stmt, bool answerOnBoundExceeded = true);
5036 GenTreeStmt* fgInsertStmtAtEnd(BasicBlock* block, GenTree* node);
5038 public: // Used by linear scan register allocation
5039 GenTreeStmt* fgInsertStmtNearEnd(BasicBlock* block, GenTree* node);
5042 GenTree* fgInsertStmtAtBeg(BasicBlock* block, GenTree* stmt);
5043 GenTree* fgInsertStmtAfter(BasicBlock* block, GenTree* insertionPoint, GenTree* stmt);
5045 public: // Used by linear scan register allocation
5046 GenTree* fgInsertStmtBefore(BasicBlock* block, GenTree* insertionPoint, GenTree* stmt);
5049 GenTree* fgInsertStmtListAfter(BasicBlock* block, GenTree* stmtAfter, GenTree* stmtList);
5051 // Create a new temporary variable to hold the result of *ppTree,
5052 // and transform the graph accordingly.
5053 GenTree* fgInsertCommaFormTemp(GenTree** ppTree, CORINFO_CLASS_HANDLE structType = nullptr);
5054 GenTree* fgMakeMultiUse(GenTree** ppTree);
5057 // Recognize a bitwise rotation pattern and convert into a GT_ROL or a GT_ROR node.
5058 GenTree* fgRecognizeAndMorphBitwiseRotation(GenTree* tree);
5059 bool fgOperIsBitwiseRotationRoot(genTreeOps oper);
5061 //-------- Determine the order in which the trees will be evaluated -------
5063 unsigned fgTreeSeqNum;
5064 GenTree* fgTreeSeqLst;
5065 GenTree* fgTreeSeqBeg;
5067 GenTree* fgSetTreeSeq(GenTree* tree, GenTree* prev = nullptr, bool isLIR = false);
5068 void fgSetTreeSeqHelper(GenTree* tree, bool isLIR);
5069 void fgSetTreeSeqFinish(GenTree* tree, bool isLIR);
5070 void fgSetStmtSeq(GenTree* tree);
5071 void fgSetBlockOrder(BasicBlock* block);
5073 //------------------------- Morphing --------------------------------------
5075 unsigned fgPtrArgCntMax;
5078 //------------------------------------------------------------------------
5079 // fgGetPtrArgCntMax: Return the maximum number of pointer-sized stack arguments that calls inside this method
5080 // can push on the stack. This value is calculated during morph.
5083 // Returns fgPtrArgCntMax, that is a private field.
5085 unsigned fgGetPtrArgCntMax() const
5087 return fgPtrArgCntMax;
5090 //------------------------------------------------------------------------
5091 // fgSetPtrArgCntMax: Set the maximum number of pointer-sized stack arguments that calls inside this method
5092 // can push on the stack. This function is used during StackLevelSetter to fix incorrect morph calculations.
5094 void fgSetPtrArgCntMax(unsigned argCntMax)
5096 fgPtrArgCntMax = argCntMax;
5099 bool compCanEncodePtrArgCntMax();
5102 hashBv* fgOutgoingArgTemps;
5103 hashBv* fgCurrentlyInUseArgTemps;
5105 void fgSetRngChkTarget(GenTree* tree, bool delay = true);
5107 BasicBlock* fgSetRngChkTargetInner(SpecialCodeKind kind, bool delay);
5110 void fgMoveOpsLeft(GenTree* tree);
5113 bool fgIsCommaThrow(GenTree* tree, bool forFolding = false);
5115 bool fgIsThrow(GenTree* tree);
5117 bool fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2);
5118 bool fgIsBlockCold(BasicBlock* block);
5120 GenTree* fgMorphCastIntoHelper(GenTree* tree, int helper, GenTree* oper);
5122 GenTree* fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeArgList* args, bool morphArgs = true);
5124 GenTree* fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType, unsigned lclOffs);
5126 // A "MorphAddrContext" carries information from the surrounding context. If we are evaluating a byref address,
5127 // it is useful to know whether the address will be immediately dereferenced, or whether the address value will
5128 // be used, perhaps by passing it as an argument to a called method. This affects how null checking is done:
5129 // for sufficiently small offsets, we can rely on OS page protection to implicitly null-check addresses that we
5130 // know will be dereferenced. To know that reliance on implicit null checking is sound, we must further know that
5131 // all offsets between the top-level indirection and the bottom are constant, and that their sum is sufficiently
5132 // small; hence the other fields of MorphAddrContext.
5133 enum MorphAddrContextKind
5138 struct MorphAddrContext
5140 MorphAddrContextKind m_kind;
5141 bool m_allConstantOffsets; // Valid only for "m_kind == MACK_Ind". True iff all offsets between
5142 // top-level indirection and here have been constants.
5143 size_t m_totalOffset; // Valid only for "m_kind == MACK_Ind", and if "m_allConstantOffsets" is true.
5144 // In that case, is the sum of those constant offsets.
5146 MorphAddrContext(MorphAddrContextKind kind) : m_kind(kind), m_allConstantOffsets(true), m_totalOffset(0)
5151 // A MACK_CopyBlock context is immutable, so we can just make one of these and share it.
5152 static MorphAddrContext s_CopyBlockMAC;
5155 GenTree* getSIMDStructFromField(GenTree* tree,
5156 var_types* baseTypeOut,
5158 unsigned* simdSizeOut,
5159 bool ignoreUsedInSIMDIntrinsic = false);
5160 GenTree* fgMorphFieldAssignToSIMDIntrinsicSet(GenTree* tree);
5161 GenTree* fgMorphFieldToSIMDIntrinsicGet(GenTree* tree);
5162 bool fgMorphCombineSIMDFieldAssignments(BasicBlock* block, GenTree* stmt);
5163 void impMarkContiguousSIMDFieldAssignments(GenTree* stmt);
5165 // fgPreviousCandidateSIMDFieldAsgStmt is only used for tracking previous simd field assignment
5166 // in function: Complier::impMarkContiguousSIMDFieldAssignments.
5167 GenTree* fgPreviousCandidateSIMDFieldAsgStmt;
5169 #endif // FEATURE_SIMD
5170 GenTree* fgMorphArrayIndex(GenTree* tree);
5171 GenTree* fgMorphCast(GenTree* tree);
5172 GenTree* fgUnwrapProxy(GenTree* objRef);
5173 GenTreeFieldList* fgMorphLclArgToFieldlist(GenTreeLclVarCommon* lcl);
5174 void fgInitArgInfo(GenTreeCall* call);
5175 GenTreeCall* fgMorphArgs(GenTreeCall* call);
5176 GenTreeArgList* fgMorphArgList(GenTreeArgList* args, MorphAddrContext* mac);
5178 void fgMakeOutgoingStructArgCopy(GenTreeCall* call,
5181 CORINFO_CLASS_HANDLE copyBlkClass);
5183 void fgFixupStructReturn(GenTree* call);
5184 GenTree* fgMorphLocalVar(GenTree* tree, bool forceRemorph);
5187 bool fgAddrCouldBeNull(GenTree* addr);
5190 GenTree* fgMorphField(GenTree* tree, MorphAddrContext* mac);
5191 bool fgCanFastTailCall(GenTreeCall* call);
5192 bool fgCheckStmtAfterTailCall();
5193 void fgMorphTailCall(GenTreeCall* call, void* pfnCopyArgs);
5194 GenTree* fgGetStubAddrArg(GenTreeCall* call);
5195 void fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCall* recursiveTailCall);
5196 GenTree* fgAssignRecursiveCallArgToCallerParam(GenTree* arg,
5197 fgArgTabEntry* argTabEntry,
5199 IL_OFFSETX callILOffset,
5200 GenTree* tmpAssignmentInsertionPoint,
5201 GenTree* paramAssignmentInsertionPoint);
5202 static int fgEstimateCallStackSize(GenTreeCall* call);
5203 GenTree* fgMorphCall(GenTreeCall* call);
5204 void fgMorphCallInline(GenTreeCall* call, InlineResult* result);
5205 void fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result);
5207 void fgNoteNonInlineCandidate(GenTreeStmt* stmt, GenTreeCall* call);
5208 static fgWalkPreFn fgFindNonInlineCandidate;
5210 GenTree* fgOptimizeDelegateConstructor(GenTreeCall* call,
5211 CORINFO_CONTEXT_HANDLE* ExactContextHnd,
5212 CORINFO_RESOLVED_TOKEN* ldftnToken);
5213 GenTree* fgMorphLeaf(GenTree* tree);
5214 void fgAssignSetVarDef(GenTree* tree);
5215 GenTree* fgMorphOneAsgBlockOp(GenTree* tree);
5216 GenTree* fgMorphInitBlock(GenTree* tree);
5217 GenTree* fgMorphBlkToInd(GenTreeBlk* tree, var_types type);
5218 GenTree* fgMorphGetStructAddr(GenTree** pTree, CORINFO_CLASS_HANDLE clsHnd, bool isRValue = false);
5219 GenTree* fgMorphBlkNode(GenTree* tree, bool isDest);
5220 GenTree* fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigned blockWidth, bool isDest);
5221 void fgMorphUnsafeBlk(GenTreeObj* obj);
5222 GenTree* fgMorphCopyBlock(GenTree* tree);
5223 GenTree* fgMorphForRegisterFP(GenTree* tree);
5224 GenTree* fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac = nullptr);
5225 GenTree* fgMorphModToSubMulDiv(GenTreeOp* tree);
5226 GenTree* fgMorphSmpOpOptional(GenTreeOp* tree);
5227 GenTree* fgMorphRecognizeBoxNullable(GenTree* compare);
5229 GenTree* fgMorphToEmulatedFP(GenTree* tree);
5230 GenTree* fgMorphConst(GenTree* tree);
5233 GenTree* fgMorphTree(GenTree* tree, MorphAddrContext* mac = nullptr);
5236 #if LOCAL_ASSERTION_PROP
5237 void fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTree* tree));
5238 void fgKillDependentAssertions(unsigned lclNum DEBUGARG(GenTree* tree));
5240 void fgMorphTreeDone(GenTree* tree, GenTree* oldTree = nullptr DEBUGARG(int morphNum = 0));
5242 GenTreeStmt* fgMorphStmt;
5244 unsigned fgGetBigOffsetMorphingTemp(var_types type); // We cache one temp per type to be
5245 // used when morphing big offset.
5247 //----------------------- Liveness analysis -------------------------------
5249 VARSET_TP fgCurUseSet; // vars used by block (before an assignment)
5250 VARSET_TP fgCurDefSet; // vars assigned by block (before a use)
5252 MemoryKindSet fgCurMemoryUse; // True iff the current basic block uses memory.
5253 MemoryKindSet fgCurMemoryDef; // True iff the current basic block modifies memory.
5254 MemoryKindSet fgCurMemoryHavoc; // True if the current basic block is known to set memory to a "havoc" value.
5256 bool byrefStatesMatchGcHeapStates; // True iff GcHeap and ByrefExposed memory have all the same def points.
5258 void fgMarkUseDef(GenTreeLclVarCommon* tree);
5260 void fgBeginScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
5261 void fgEndScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
5263 void fgMarkInScope(BasicBlock* block, VARSET_VALARG_TP inScope);
5264 void fgUnmarkInScope(BasicBlock* block, VARSET_VALARG_TP unmarkScope);
5266 void fgExtendDbgScopes();
5267 void fgExtendDbgLifetimes();
5270 void fgDispDebugScopes();
5273 //-------------------------------------------------------------------------
5275 // The following keeps track of any code we've added for things like array
5276 // range checking or explicit calls to enable GC, and so on.
5281 AddCodeDsc* acdNext;
5282 BasicBlock* acdDstBlk; // block to which we jump
5284 SpecialCodeKind acdKind; // what kind of a special block is this?
5285 #if !FEATURE_FIXED_OUT_ARGS
5286 bool acdStkLvlInit; // has acdStkLvl value been already set?
5288 #endif // !FEATURE_FIXED_OUT_ARGS
5292 static unsigned acdHelper(SpecialCodeKind codeKind);
5294 AddCodeDsc* fgAddCodeList;
5296 bool fgRngChkThrowAdded;
5297 AddCodeDsc* fgExcptnTargetCache[SCK_COUNT];
5299 BasicBlock* fgRngChkTarget(BasicBlock* block, SpecialCodeKind kind);
5301 BasicBlock* fgAddCodeRef(BasicBlock* srcBlk, unsigned refData, SpecialCodeKind kind);
5304 AddCodeDsc* fgFindExcptnTarget(SpecialCodeKind kind, unsigned refData);
5306 bool fgUseThrowHelperBlocks();
5308 AddCodeDsc* fgGetAdditionalCodeDescriptors()
5310 return fgAddCodeList;
5314 bool fgIsCodeAdded();
5316 bool fgIsThrowHlpBlk(BasicBlock* block);
5318 #if !FEATURE_FIXED_OUT_ARGS
5319 unsigned fgThrowHlpBlkStkLevel(BasicBlock* block);
5320 #endif // !FEATURE_FIXED_OUT_ARGS
5322 unsigned fgBigOffsetMorphingTemps[TYP_COUNT];
5324 unsigned fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo);
5325 void fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* result);
5326 void fgInsertInlineeBlocks(InlineInfo* pInlineInfo);
5327 GenTree* fgInlinePrependStatements(InlineInfo* inlineInfo);
5328 void fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, GenTree* stmt);
5330 #if FEATURE_MULTIREG_RET
5331 GenTree* fgGetStructAsStructPtr(GenTree* tree);
5332 GenTree* fgAssignStructInlineeToVar(GenTree* child, CORINFO_CLASS_HANDLE retClsHnd);
5333 void fgAttachStructInlineeToAsg(GenTree* tree, GenTree* child, CORINFO_CLASS_HANDLE retClsHnd);
5334 #endif // FEATURE_MULTIREG_RET
5336 static fgWalkPreFn fgUpdateInlineReturnExpressionPlaceHolder;
5337 static fgWalkPostFn fgLateDevirtualization;
5340 static fgWalkPreFn fgDebugCheckInlineCandidates;
5342 void CheckNoFatPointerCandidatesLeft();
5343 static fgWalkPreFn fgDebugCheckFatPointerCandidates;
5346 void fgPromoteStructs();
5347 void fgMorphStructField(GenTree* tree, GenTree* parent);
5348 void fgMorphLocalField(GenTree* tree, GenTree* parent);
5350 // Identify which parameters are implicit byrefs, and flag their LclVarDscs.
5351 void fgMarkImplicitByRefArgs();
5353 // Change implicit byrefs' types from struct to pointer, and for any that were
5354 // promoted, create new promoted struct temps.
5355 void fgRetypeImplicitByRefArgs();
5357 // Rewrite appearances of implicit byrefs (manifest the implied additional level of indirection).
5358 bool fgMorphImplicitByRefArgs(GenTree* tree);
5359 GenTree* fgMorphImplicitByRefArgs(GenTree* tree, bool isAddr);
5361 // Clear up annotations for any struct promotion temps created for implicit byrefs.
5362 void fgMarkDemotedImplicitByRefArgs();
5364 void fgMarkAddressExposedLocals();
5366 static fgWalkPreFn fgUpdateSideEffectsPre;
5367 static fgWalkPostFn fgUpdateSideEffectsPost;
5369 // The given local variable, required to be a struct variable, is being assigned via
5370 // a "lclField", to make it masquerade as an integral type in the ABI. Make sure that
5371 // the variable is not enregistered, and is therefore not promoted independently.
5372 void fgLclFldAssign(unsigned lclNum);
5374 static fgWalkPreFn gtHasLocalsWithAddrOpCB;
5376 enum TypeProducerKind
5378 TPK_Unknown = 0, // May not be a RuntimeType
5379 TPK_Handle = 1, // RuntimeType via handle
5380 TPK_GetType = 2, // RuntimeType via Object.get_Type()
5381 TPK_Null = 3, // Tree value is null
5382 TPK_Other = 4 // RuntimeType via other means
5385 TypeProducerKind gtGetTypeProducerKind(GenTree* tree);
5386 bool gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call);
5387 bool gtIsActiveCSE_Candidate(GenTree* tree);
5390 bool fgPrintInlinedMethods;
5393 bool fgIsBigOffset(size_t offset);
5395 bool fgNeedReturnSpillTemp();
5398 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5399 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5403 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5404 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5410 void optRemoveRangeCheck(GenTree* tree, GenTree* stmt);
5411 bool optIsRangeCheckRemovable(GenTree* tree);
5414 static fgWalkPreFn optValidRangeCheckIndex;
5415 static fgWalkPreFn optRemoveTreeVisitor; // Helper passed to Compiler::fgWalkAllTreesPre() to decrement the LclVar
5418 void optRemoveTree(GenTree* deadTree, GenTree* keepList);
5420 /**************************************************************************
5422 *************************************************************************/
5425 // Do hoisting for all loops.
5426 void optHoistLoopCode();
5428 // To represent sets of VN's that have already been hoisted in outer loops.
5429 typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, bool> VNToBoolMap;
5430 typedef VNToBoolMap VNSet;
5432 struct LoopHoistContext
5435 // The set of variables hoisted in the current loop (or nullptr if there are none).
5436 VNSet* m_pHoistedInCurLoop;
5439 // Value numbers of expressions that have been hoisted in parent loops in the loop nest.
5440 VNSet m_hoistedInParentLoops;
5441 // Value numbers of expressions that have been hoisted in the current (or most recent) loop in the nest.
5442 // Previous decisions on loop-invariance of value numbers in the current loop.
5443 VNToBoolMap m_curLoopVnInvariantCache;
5445 VNSet* GetHoistedInCurLoop(Compiler* comp)
5447 if (m_pHoistedInCurLoop == nullptr)
5449 m_pHoistedInCurLoop = new (comp->getAllocatorLoopHoist()) VNSet(comp->getAllocatorLoopHoist());
5451 return m_pHoistedInCurLoop;
5454 VNSet* ExtractHoistedInCurLoop()
5456 VNSet* res = m_pHoistedInCurLoop;
5457 m_pHoistedInCurLoop = nullptr;
5461 LoopHoistContext(Compiler* comp)
5462 : m_pHoistedInCurLoop(nullptr)
5463 , m_hoistedInParentLoops(comp->getAllocatorLoopHoist())
5464 , m_curLoopVnInvariantCache(comp->getAllocatorLoopHoist())
5469 // Do hoisting for loop "lnum" (an index into the optLoopTable), and all loops nested within it.
5470 // Tracks the expressions that have been hoisted by containing loops by temporary recording their
5471 // value numbers in "m_hoistedInParentLoops". This set is not modified by the call.
5472 void optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);
5474 // Do hoisting for a particular loop ("lnum" is an index into the optLoopTable.)
5475 // Assumes that expressions have been hoisted in containing loops if their value numbers are in
5476 // "m_hoistedInParentLoops".
5478 void optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt);
5480 // Hoist all expressions in "blk" that are invariant in loop "lnum" (an index into the optLoopTable)
5481 // outside of that loop. Exempt expressions whose value number is in "m_hoistedInParentLoops"; add VN's of hoisted
5482 // expressions to "hoistInLoop".
5483 void optHoistLoopExprsForBlock(BasicBlock* blk, unsigned lnum, LoopHoistContext* hoistCtxt);
5485 // Return true if the tree looks profitable to hoist out of loop 'lnum'.
5486 bool optIsProfitableToHoistableTree(GenTree* tree, unsigned lnum);
5488 // Hoist all proper sub-expressions of "tree" (which occurs in "stmt", which occurs in "blk")
5489 // that are invariant in loop "lnum" (an index into the optLoopTable)
5490 // outside of that loop. Exempt expressions whose value number is in "hoistedInParents"; add VN's of hoisted
5491 // expressions to "hoistInLoop".
5492 // Returns "true" iff "tree" is loop-invariant (wrt "lnum").
5493 // Assumes that the value of "*firstBlockAndBeforeSideEffect" indicates that we're in the first block, and before
5494 // any possible globally visible side effects. Assume is called in evaluation order, and updates this.
5495 bool optHoistLoopExprsForTree(GenTree* tree,
5497 LoopHoistContext* hoistCtxt,
5498 bool* firstBlockAndBeforeSideEffect,
5500 bool* pCctorDependent);
5502 // Performs the hoisting 'tree' into the PreHeader for loop 'lnum'
5503 void optHoistCandidate(GenTree* tree, unsigned lnum, LoopHoistContext* hoistCtxt);
5505 // Returns true iff the ValueNum "vn" represents a value that is loop-invariant in "lnum".
5506 // Constants and init values are always loop invariant.
5507 // VNPhi's connect VN's to the SSA definition, so we can know if the SSA def occurs in the loop.
5508 bool optVNIsLoopInvariant(ValueNum vn, unsigned lnum, VNToBoolMap* recordedVNs);
5510 // Returns "true" iff "tree" is valid at the head of loop "lnum", in the context of the hoist substitution
5511 // "subst". If "tree" is a local SSA var, it is valid if its SSA definition occurs outside of the loop, or
5512 // if it is in the domain of "subst" (meaning that it's definition has been previously hoisted, with a "standin"
5513 // local.) If tree is a constant, it is valid. Otherwise, if it is an operator, it is valid iff its children are.
5514 bool optTreeIsValidAtLoopHead(GenTree* tree, unsigned lnum);
5516 // If "blk" is the entry block of a natural loop, returns true and sets "*pLnum" to the index of the loop
5517 // in the loop table.
5518 bool optBlockIsLoopEntry(BasicBlock* blk, unsigned* pLnum);
5520 // Records the set of "side effects" of all loops: fields (object instance and static)
5521 // written to, and SZ-array element type equivalence classes updated.
5522 void optComputeLoopSideEffects();
5525 // Requires "lnum" to be the index of an outermost loop in the loop table. Traverses the body of that loop,
5526 // including all nested loops, and records the set of "side effects" of the loop: fields (object instance and
5527 // static) written to, and SZ-array element type equivalence classes updated.
5528 void optComputeLoopNestSideEffects(unsigned lnum);
5530 // Add the side effects of "blk" (which is required to be within a loop) to all loops of which it is a part.
5531 void optComputeLoopSideEffectsOfBlock(BasicBlock* blk);
5533 // Hoist the expression "expr" out of loop "lnum".
5534 void optPerformHoistExpr(GenTree* expr, unsigned lnum);
5537 void optOptimizeBools();
5540 GenTree* optIsBoolCond(GenTree* condBranch, GenTree** compPtr, bool* boolPtr);
5542 void optOptimizeBoolsGcStress(BasicBlock* condBlock);
5545 void optOptimizeLayout(); // Optimize the BasicBlock layout of the method
5547 void optOptimizeLoops(); // for "while-do" loops duplicates simple loop conditions and transforms
5548 // the loop into a "do-while" loop
5549 // Also finds all natural loops and records them in the loop table
5551 // Optionally clone loops in the loop table.
5552 void optCloneLoops();
5554 // Clone loop "loopInd" in the loop table.
5555 void optCloneLoop(unsigned loopInd, LoopCloneContext* context);
5557 // Ensure that loop "loopInd" has a unique head block. (If the existing entry has
5558 // non-loop predecessors other than the head entry, create a new, empty block that goes (only) to the entry,
5559 // and redirects the preds of the entry to this new block.) Sets the weight of the newly created block to
5561 void optEnsureUniqueHead(unsigned loopInd, unsigned ambientWeight);
5563 void optUnrollLoops(); // Unrolls loops (needs to have cost info)
5566 // This enumeration describes what is killed by a call.
5570 CALLINT_NONE, // no interference (most helpers)
5571 CALLINT_REF_INDIRS, // kills GC ref indirections (SETFIELD OBJ)
5572 CALLINT_SCL_INDIRS, // kills non GC ref indirections (SETFIELD non-OBJ)
5573 CALLINT_ALL_INDIRS, // kills both GC ref and non GC ref indirections (SETFIELD STRUCT)
5574 CALLINT_ALL, // kills everything (normal method call)
5578 // A "LoopDsc" describes a ("natural") loop. We (currently) require the body of a loop to be a contiguous (in
5579 // bbNext order) sequence of basic blocks. (At times, we may require the blocks in a loop to be "properly numbered"
5580 // in bbNext order; we use comparisons on the bbNum to decide order.)
5581 // The blocks that define the body are
5582 // first <= top <= entry <= bottom .
5583 // The "head" of the loop is a block outside the loop that has "entry" as a successor. We only support loops with a
5584 // single 'head' block. The meanings of these blocks are given in the definitions below. Also see the picture at
5585 // Compiler::optFindNaturalLoops().
5588 BasicBlock* lpHead; // HEAD of the loop (not part of the looping of the loop) -- has ENTRY as a successor.
5589 BasicBlock* lpFirst; // FIRST block (in bbNext order) reachable within this loop. (May be part of a nested
5590 // loop, but not the outer loop.)
5591 BasicBlock* lpTop; // loop TOP (the back edge from lpBottom reaches here) (in most cases FIRST and TOP are the
5593 BasicBlock* lpEntry; // the ENTRY in the loop (in most cases TOP or BOTTOM)
5594 BasicBlock* lpBottom; // loop BOTTOM (from here we have a back edge to the TOP)
5595 BasicBlock* lpExit; // if a single exit loop this is the EXIT (in most cases BOTTOM)
5597 callInterf lpAsgCall; // "callInterf" for calls in the loop
5598 ALLVARSET_TP lpAsgVars; // set of vars assigned within the loop (all vars, not just tracked)
5599 varRefKinds lpAsgInds : 8; // set of inds modified within the loop
5601 unsigned short lpFlags; // Mask of the LPFLG_* constants
5603 unsigned char lpExitCnt; // number of exits from the loop
5605 unsigned char lpParent; // The index of the most-nested loop that completely contains this one,
5606 // or else BasicBlock::NOT_IN_LOOP if no such loop exists.
5607 unsigned char lpChild; // The index of a nested loop, or else BasicBlock::NOT_IN_LOOP if no child exists.
5608 // (Actually, an "immediately" nested loop --
5609 // no other child of this loop is a parent of lpChild.)
5610 unsigned char lpSibling; // The index of another loop that is an immediate child of lpParent,
5611 // or else BasicBlock::NOT_IN_LOOP. One can enumerate all the children of a loop
5612 // by following "lpChild" then "lpSibling" links.
5614 #define LPFLG_DO_WHILE 0x0001 // it's a do-while loop (i.e ENTRY is at the TOP)
5615 #define LPFLG_ONE_EXIT 0x0002 // the loop has only one exit
5617 #define LPFLG_ITER 0x0004 // for (i = icon or lclVar; test_condition(); i++)
5618 #define LPFLG_HOISTABLE 0x0008 // the loop is in a form that is suitable for hoisting expressions
5619 #define LPFLG_CONST 0x0010 // for (i=icon;i<icon;i++){ ... } - constant loop
5621 #define LPFLG_VAR_INIT 0x0020 // iterator is initialized with a local var (var # found in lpVarInit)
5622 #define LPFLG_CONST_INIT 0x0040 // iterator is initialized with a constant (found in lpConstInit)
5624 #define LPFLG_VAR_LIMIT 0x0100 // iterator is compared with a local var (var # found in lpVarLimit)
5625 #define LPFLG_CONST_LIMIT 0x0200 // iterator is compared with a constant (found in lpConstLimit)
5626 #define LPFLG_ARRLEN_LIMIT 0x0400 // iterator is compared with a.len or a[i].len (found in lpArrLenLimit)
5627 #define LPFLG_SIMD_LIMIT 0x0080 // iterator is compared with Vector<T>.Count (found in lpConstLimit)
5629 #define LPFLG_HAS_PREHEAD 0x0800 // lpHead is known to be a preHead for this loop
5630 #define LPFLG_REMOVED 0x1000 // has been removed from the loop table (unrolled or optimized away)
5631 #define LPFLG_DONT_UNROLL 0x2000 // do not unroll this loop
5633 #define LPFLG_ASGVARS_YES 0x4000 // "lpAsgVars" has been computed
5634 #define LPFLG_ASGVARS_INC 0x8000 // "lpAsgVars" is incomplete -- vars beyond those representable in an AllVarSet
5635 // type are assigned to.
5637 bool lpLoopHasMemoryHavoc[MemoryKindCount]; // The loop contains an operation that we assume has arbitrary
5638 // memory side effects. If this is set, the fields below
5639 // may not be accurate (since they become irrelevant.)
5640 bool lpContainsCall; // True if executing the loop body *may* execute a call
5642 VARSET_TP lpVarInOut; // The set of variables that are IN or OUT during the execution of this loop
5643 VARSET_TP lpVarUseDef; // The set of variables that are USE or DEF during the execution of this loop
5645 int lpHoistedExprCount; // The register count for the non-FP expressions from inside this loop that have been
5647 int lpLoopVarCount; // The register count for the non-FP LclVars that are read/written inside this loop
5648 int lpVarInOutCount; // The register count for the non-FP LclVars that are alive inside or accross this loop
5650 int lpHoistedFPExprCount; // The register count for the FP expressions from inside this loop that have been
5652 int lpLoopVarFPCount; // The register count for the FP LclVars that are read/written inside this loop
5653 int lpVarInOutFPCount; // The register count for the FP LclVars that are alive inside or accross this loop
5655 typedef JitHashTable<CORINFO_FIELD_HANDLE, JitPtrKeyFuncs<struct CORINFO_FIELD_STRUCT_>, bool> FieldHandleSet;
5656 FieldHandleSet* lpFieldsModified; // This has entries (mappings to "true") for all static field and object
5657 // instance fields modified
5660 typedef JitHashTable<CORINFO_CLASS_HANDLE, JitPtrKeyFuncs<struct CORINFO_CLASS_STRUCT_>, bool> ClassHandleSet;
5661 ClassHandleSet* lpArrayElemTypesModified; // Bits set indicate the set of sz array element types such that
5662 // arrays of that type are modified
5665 // Adds the variable liveness information for 'blk' to 'this' LoopDsc
5666 void AddVariableLiveness(Compiler* comp, BasicBlock* blk);
5668 inline void AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd);
5669 // This doesn't *always* take a class handle -- it can also take primitive types, encoded as class handles
5670 // (shifted left, with a low-order bit set to distinguish.)
5671 // Use the {Encode/Decode}ElemType methods to construct/destruct these.
5672 inline void AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd);
5674 /* The following values are set only for iterator loops, i.e. has the flag LPFLG_ITER set */
5676 GenTree* lpIterTree; // The "i = i <op> const" tree
5677 unsigned lpIterVar(); // iterator variable #
5678 int lpIterConst(); // the constant with which the iterator is incremented
5679 genTreeOps lpIterOper(); // the type of the operation on the iterator (ASG_ADD, ASG_SUB, etc.)
5680 void VERIFY_lpIterTree();
5682 var_types lpIterOperType(); // For overflow instructions
5685 int lpConstInit; // initial constant value of iterator : Valid if LPFLG_CONST_INIT
5686 unsigned lpVarInit; // initial local var number to which we initialize the iterator : Valid if
5690 /* The following is for LPFLG_ITER loops only (i.e. the loop condition is "i RELOP const or var" */
5692 GenTree* lpTestTree; // pointer to the node containing the loop test
5693 genTreeOps lpTestOper(); // the type of the comparison between the iterator and the limit (GT_LE, GT_GE, etc.)
5694 void VERIFY_lpTestTree();
5696 bool lpIsReversed(); // true if the iterator node is the second operand in the loop condition
5697 GenTree* lpIterator(); // the iterator node in the loop test
5698 GenTree* lpLimit(); // the limit node in the loop test
5700 int lpConstLimit(); // limit constant value of iterator - loop condition is "i RELOP const" : Valid if
5701 // LPFLG_CONST_LIMIT
5702 unsigned lpVarLimit(); // the lclVar # in the loop condition ( "i RELOP lclVar" ) : Valid if
5704 bool lpArrLenLimit(Compiler* comp, ArrIndex* index); // The array length in the loop condition ( "i RELOP
5705 // arr.len" or "i RELOP arr[i][j].len" ) : Valid if
5706 // LPFLG_ARRLEN_LIMIT
5708 // Returns "true" iff "*this" contains the blk.
5709 bool lpContains(BasicBlock* blk)
5711 return lpFirst->bbNum <= blk->bbNum && blk->bbNum <= lpBottom->bbNum;
5713 // Returns "true" iff "*this" (properly) contains the range [first, bottom] (allowing firsts
5714 // to be equal, but requiring bottoms to be different.)
5715 bool lpContains(BasicBlock* first, BasicBlock* bottom)
5717 return lpFirst->bbNum <= first->bbNum && bottom->bbNum < lpBottom->bbNum;
5720 // Returns "true" iff "*this" (properly) contains "lp2" (allowing firsts to be equal, but requiring
5721 // bottoms to be different.)
5722 bool lpContains(const LoopDsc& lp2)
5724 return lpContains(lp2.lpFirst, lp2.lpBottom);
5727 // Returns "true" iff "*this" is (properly) contained by the range [first, bottom]
5728 // (allowing firsts to be equal, but requiring bottoms to be different.)
5729 bool lpContainedBy(BasicBlock* first, BasicBlock* bottom)
5731 return first->bbNum <= lpFirst->bbNum && lpBottom->bbNum < bottom->bbNum;
5734 // Returns "true" iff "*this" is (properly) contained by "lp2"
5735 // (allowing firsts to be equal, but requiring bottoms to be different.)
5736 bool lpContainedBy(const LoopDsc& lp2)
5738 return lpContains(lp2.lpFirst, lp2.lpBottom);
5741 // Returns "true" iff "*this" is disjoint from the range [top, bottom].
5742 bool lpDisjoint(BasicBlock* first, BasicBlock* bottom)
5744 return bottom->bbNum < lpFirst->bbNum || lpBottom->bbNum < first->bbNum;
5746 // Returns "true" iff "*this" is disjoint from "lp2".
5747 bool lpDisjoint(const LoopDsc& lp2)
5749 return lpDisjoint(lp2.lpFirst, lp2.lpBottom);
5751 // Returns "true" iff the loop is well-formed (see code for defn).
5754 return lpFirst->bbNum <= lpTop->bbNum && lpTop->bbNum <= lpEntry->bbNum &&
5755 lpEntry->bbNum <= lpBottom->bbNum &&
5756 (lpHead->bbNum < lpTop->bbNum || lpHead->bbNum > lpBottom->bbNum);
5761 bool fgMightHaveLoop(); // returns true if there are any backedges
5762 bool fgHasLoops; // True if this method has any loops, set in fgComputeReachability
5765 LoopDsc* optLoopTable; // loop descriptor table
5766 unsigned char optLoopCount; // number of tracked loops
5768 bool optRecordLoop(BasicBlock* head,
5774 unsigned char exitCnt);
5777 unsigned optCallCount; // number of calls made in the method
5778 unsigned optIndirectCallCount; // number of virtual, interface and indirect calls made in the method
5779 unsigned optNativeCallCount; // number of Pinvoke/Native calls made in the method
5780 unsigned optLoopsCloned; // number of loops cloned in the current method.
5783 unsigned optFindLoopNumberFromBeginBlock(BasicBlock* begBlk);
5784 void optPrintLoopInfo(unsigned loopNum,
5786 BasicBlock* lpFirst,
5788 BasicBlock* lpEntry,
5789 BasicBlock* lpBottom,
5790 unsigned char lpExitCnt,
5792 unsigned parentLoop = BasicBlock::NOT_IN_LOOP);
5793 void optPrintLoopInfo(unsigned lnum);
5794 void optPrintLoopRecording(unsigned lnum);
5796 void optCheckPreds();
5799 void optSetBlockWeights();
5801 void optMarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk, bool excludeEndBlk);
5803 void optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk);
5805 void optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmarkLoop = false);
5807 bool optIsLoopTestEvalIntoTemp(GenTree* test, GenTree** newTest);
5808 unsigned optIsLoopIncrTree(GenTree* incr);
5809 bool optCheckIterInLoopTest(unsigned loopInd, GenTree* test, BasicBlock* from, BasicBlock* to, unsigned iterVar);
5810 bool optComputeIterInfo(GenTree* incr, BasicBlock* from, BasicBlock* to, unsigned* pIterVar);
5811 bool optPopulateInitInfo(unsigned loopInd, GenTree* init, unsigned iterVar);
5812 bool optExtractInitTestIncr(
5813 BasicBlock* head, BasicBlock* bottom, BasicBlock* exit, GenTree** ppInit, GenTree** ppTest, GenTree** ppIncr);
5815 void optFindNaturalLoops();
5817 // Ensures that all the loops in the loop nest rooted at "loopInd" (an index into the loop table) are 'canonical' --
5818 // each loop has a unique "top." Returns "true" iff the flowgraph has been modified.
5819 bool optCanonicalizeLoopNest(unsigned char loopInd);
5821 // Ensures that the loop "loopInd" (an index into the loop table) is 'canonical' -- it has a unique "top,"
5822 // unshared with any other loop. Returns "true" iff the flowgraph has been modified
5823 bool optCanonicalizeLoop(unsigned char loopInd);
5825 // Requires "l1" to be a valid loop table index, and not "BasicBlock::NOT_IN_LOOP". Requires "l2" to be
5826 // a valid loop table index, or else "BasicBlock::NOT_IN_LOOP". Returns true
5827 // iff "l2" is not NOT_IN_LOOP, and "l1" contains "l2".
5828 bool optLoopContains(unsigned l1, unsigned l2);
5830 // Requires "loopInd" to be a valid index into the loop table.
5831 // Updates the loop table by changing loop "loopInd", whose head is required
5832 // to be "from", to be "to". Also performs this transformation for any
5833 // loop nested in "loopInd" that shares the same head as "loopInd".
5834 void optUpdateLoopHead(unsigned loopInd, BasicBlock* from, BasicBlock* to);
5836 // Updates the successors of "blk": if "blk2" is a successor of "blk", and there is a mapping for "blk2->blk3" in
5837 // "redirectMap", change "blk" so that "blk3" is this successor. Note that the predecessor lists are not updated.
5838 void optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap);
5840 // Marks the containsCall information to "lnum" and any parent loops.
5841 void AddContainsCallAllContainingLoops(unsigned lnum);
5842 // Adds the variable liveness information from 'blk' to "lnum" and any parent loops.
5843 void AddVariableLivenessAllContainingLoops(unsigned lnum, BasicBlock* blk);
5844 // Adds "fldHnd" to the set of modified fields of "lnum" and any parent loops.
5845 void AddModifiedFieldAllContainingLoops(unsigned lnum, CORINFO_FIELD_HANDLE fldHnd);
5846 // Adds "elemType" to the set of modified array element types of "lnum" and any parent loops.
5847 void AddModifiedElemTypeAllContainingLoops(unsigned lnum, CORINFO_CLASS_HANDLE elemType);
5849 // Requires that "from" and "to" have the same "bbJumpKind" (perhaps because "to" is a clone
5850 // of "from".) Copies the jump destination from "from" to "to".
5851 void optCopyBlkDest(BasicBlock* from, BasicBlock* to);
5853 // The depth of the loop described by "lnum" (an index into the loop table.) (0 == top level)
5854 unsigned optLoopDepth(unsigned lnum)
5856 unsigned par = optLoopTable[lnum].lpParent;
5857 if (par == BasicBlock::NOT_IN_LOOP)
5863 return 1 + optLoopDepth(par);
5867 void fgOptWhileLoop(BasicBlock* block);
5869 bool optComputeLoopRep(int constInit,
5872 genTreeOps iterOper,
5874 genTreeOps testOper,
5877 unsigned* iterCount);
5880 static fgWalkPreFn optIsVarAssgCB;
5883 bool optIsVarAssigned(BasicBlock* beg, BasicBlock* end, GenTree* skip, unsigned var);
5885 bool optIsVarAssgLoop(unsigned lnum, unsigned var);
5887 int optIsSetAssgLoop(unsigned lnum, ALLVARSET_VALARG_TP vars, varRefKinds inds = VR_NONE);
5889 bool optNarrowTree(GenTree* tree, var_types srct, var_types dstt, ValueNumPair vnpNarrow, bool doit);
5891 /**************************************************************************
5892 * Optimization conditions
5893 *************************************************************************/
5895 bool optFastCodeOrBlendedLoop(BasicBlock::weight_t bbWeight);
5896 bool optPentium4(void);
5897 bool optAvoidIncDec(BasicBlock::weight_t bbWeight);
5898 bool optAvoidIntMult(void);
5903 // The following is the upper limit on how many expressions we'll keep track
5904 // of for the CSE analysis.
5906 static const unsigned MAX_CSE_CNT = EXPSET_SZ;
5908 static const int MIN_CSE_COST = 2;
5910 // Keeps tracked cse indices
5911 BitVecTraits* cseTraits;
5914 /* Generic list of nodes - used by the CSE logic */
5924 treeStmtLst* tslNext;
5925 GenTree* tslTree; // tree node
5926 GenTree* tslStmt; // statement containing the tree
5927 BasicBlock* tslBlock; // block containing the statement
5930 // The following logic keeps track of expressions via a simple hash table.
5934 CSEdsc* csdNextInBucket; // used by the hash table
5936 unsigned csdHashKey; // the orginal hashkey
5938 unsigned csdIndex; // 1..optCSECandidateCount
5939 char csdLiveAcrossCall; // 0 or 1
5941 unsigned short csdDefCount; // definition count
5942 unsigned short csdUseCount; // use count (excluding the implicit uses at defs)
5944 unsigned csdDefWtCnt; // weighted def count
5945 unsigned csdUseWtCnt; // weighted use count (excluding the implicit uses at defs)
5947 GenTree* csdTree; // treenode containing the 1st occurance
5948 GenTree* csdStmt; // stmt containing the 1st occurance
5949 BasicBlock* csdBlock; // block containing the 1st occurance
5951 treeStmtLst* csdTreeList; // list of matching tree nodes: head
5952 treeStmtLst* csdTreeLast; // list of matching tree nodes: tail
5954 ValueNum defExcSetPromise; // The exception set that is now required for all defs of this CSE.
5955 // This will be set to NoVN if we decide to abandon this CSE
5957 ValueNum defExcSetCurrent; // The set of exceptions we currently can use for CSE uses.
5959 ValueNum defConservNormVN; // if all def occurrences share the same conservative normal value
5960 // number, this will reflect it; otherwise, NoVN.
5963 static const size_t s_optCSEhashSize;
5964 CSEdsc** optCSEhash;
5967 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, GenTree*> NodeToNodeMap;
5969 NodeToNodeMap* optCseCheckedBoundMap; // Maps bound nodes to ancestor compares that should be
5970 // re-numbered with the bound to improve range check elimination
5972 // Given a compare, look for a cse candidate checked bound feeding it and add a map entry if found.
5973 void optCseUpdateCheckedBoundMap(GenTree* compare);
5977 CSEdsc* optCSEfindDsc(unsigned index);
5978 bool optUnmarkCSE(GenTree* tree);
5980 // user defined callback data for the tree walk function optCSE_MaskHelper()
5981 struct optCSE_MaskData
5983 EXPSET_TP CSE_defMask;
5984 EXPSET_TP CSE_useMask;
5987 // Treewalk helper for optCSE_DefMask and optCSE_UseMask
5988 static fgWalkPreFn optCSE_MaskHelper;
5990 // This function walks all the node for an given tree
5991 // and return the mask of CSE definitions and uses for the tree
5993 void optCSE_GetMaskData(GenTree* tree, optCSE_MaskData* pMaskData);
5995 // Given a binary tree node return true if it is safe to swap the order of evaluation for op1 and op2.
5996 bool optCSE_canSwap(GenTree* firstNode, GenTree* secondNode);
5997 bool optCSE_canSwap(GenTree* tree);
5999 static int __cdecl optCSEcostCmpEx(const void* op1, const void* op2);
6000 static int __cdecl optCSEcostCmpSz(const void* op1, const void* op2);
6002 void optCleanupCSEs();
6005 void optEnsureClearCSEInfo();
6008 #endif // FEATURE_ANYCSE
6010 #if FEATURE_VALNUM_CSE
6011 /**************************************************************************
6012 * Value Number based CSEs
6013 *************************************************************************/
6016 void optOptimizeValnumCSEs();
6019 void optValnumCSE_Init();
6020 unsigned optValnumCSE_Index(GenTree* tree, GenTree* stmt);
6021 unsigned optValnumCSE_Locate();
6022 void optValnumCSE_InitDataFlow();
6023 void optValnumCSE_DataFlow();
6024 void optValnumCSE_Availablity();
6025 void optValnumCSE_Heuristic();
6027 #endif // FEATURE_VALNUM_CSE
6030 bool optDoCSE; // True when we have found a duplicate CSE tree
6031 bool optValnumCSE_phase; // True when we are executing the optValnumCSE_phase
6032 unsigned optCSECandidateTotal; // Grand total of CSE candidates for both Lexical and ValNum
6033 unsigned optCSECandidateCount; // Count of CSE's candidates, reset for Lexical and ValNum CSE's
6034 unsigned optCSEstart; // The first local variable number that is a CSE
6035 unsigned optCSEcount; // The total count of CSE's introduced.
6036 unsigned optCSEweight; // The weight of the current block when we are
6037 // scanning for CSE expressions
6039 bool optIsCSEcandidate(GenTree* tree);
6041 // lclNumIsTrueCSE returns true if the LclVar was introduced by the CSE phase of the compiler
6043 bool lclNumIsTrueCSE(unsigned lclNum) const
6045 return ((optCSEcount > 0) && (lclNum >= optCSEstart) && (lclNum < optCSEstart + optCSEcount));
6048 // lclNumIsCSE returns true if the LclVar should be treated like a CSE with regards to constant prop.
6050 bool lclNumIsCSE(unsigned lclNum) const
6052 return lvaTable[lclNum].lvIsCSE;
6056 bool optConfigDisableCSE();
6057 bool optConfigDisableCSE2();
6059 void optOptimizeCSEs();
6061 #endif // FEATURE_ANYCSE
6069 unsigned ivaVar; // Variable we are interested in, or -1
6070 ALLVARSET_TP ivaMaskVal; // Set of variables assigned to. This is a set of all vars, not tracked vars.
6071 bool ivaMaskIncomplete; // Variables not representable in ivaMaskVal were assigned to.
6072 varRefKinds ivaMaskInd; // What kind of indirect assignments are there?
6073 callInterf ivaMaskCall; // What kind of calls are there?
6076 static callInterf optCallInterf(GenTreeCall* call);
6079 // VN based copy propagation.
6080 typedef ArrayStack<GenTree*> GenTreePtrStack;
6081 typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, GenTreePtrStack*> LclNumToGenTreePtrStack;
6083 // Kill set to track variables with intervening definitions.
6084 VARSET_TP optCopyPropKillSet;
6086 // Copy propagation functions.
6087 void optCopyProp(BasicBlock* block, GenTree* stmt, GenTree* tree, LclNumToGenTreePtrStack* curSsaName);
6088 void optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
6089 void optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
6090 bool optIsSsaLocal(GenTree* tree);
6091 int optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2);
6092 void optVnCopyProp();
6093 INDEBUG(void optDumpCopyPropStack(LclNumToGenTreePtrStack* curSsaName));
6095 /**************************************************************************
6096 * Early value propagation
6097 *************************************************************************/
6103 SSAName(unsigned lvNum, unsigned ssaNum) : m_lvNum(lvNum), m_ssaNum(ssaNum)
6107 static unsigned GetHashCode(SSAName ssaNm)
6109 return (ssaNm.m_lvNum << 16) | (ssaNm.m_ssaNum);
6112 static bool Equals(SSAName ssaNm1, SSAName ssaNm2)
6114 return (ssaNm1.m_lvNum == ssaNm2.m_lvNum) && (ssaNm1.m_ssaNum == ssaNm2.m_ssaNum);
6118 #define OMF_HAS_NEWARRAY 0x00000001 // Method contains 'new' of an array
6119 #define OMF_HAS_NEWOBJ 0x00000002 // Method contains 'new' of an object type.
6120 #define OMF_HAS_ARRAYREF 0x00000004 // Method contains array element loads or stores.
6121 #define OMF_HAS_VTABLEREF 0x00000008 // Method contains method table reference.
6122 #define OMF_HAS_NULLCHECK 0x00000010 // Method contains null check.
6123 #define OMF_HAS_FATPOINTER 0x00000020 // Method contains call, that needs fat pointer transformation.
6125 bool doesMethodHaveFatPointer()
6127 return (optMethodFlags & OMF_HAS_FATPOINTER) != 0;
6130 void setMethodHasFatPointer()
6132 optMethodFlags |= OMF_HAS_FATPOINTER;
6135 void clearMethodHasFatPointer()
6137 optMethodFlags &= ~OMF_HAS_FATPOINTER;
6140 void addFatPointerCandidate(GenTreeCall* call);
6142 unsigned optMethodFlags;
6144 // Recursion bound controls how far we can go backwards tracking for a SSA value.
6145 // No throughput diff was found with backward walk bound between 3-8.
6146 static const int optEarlyPropRecurBound = 5;
6148 enum class optPropKind
6156 bool gtIsVtableRef(GenTree* tree);
6157 GenTree* getArrayLengthFromAllocation(GenTree* tree);
6158 GenTree* getObjectHandleNodeFromAllocation(GenTree* tree);
6159 GenTree* optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropKind valueKind, int walkDepth);
6160 GenTree* optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind);
6161 GenTree* optEarlyPropRewriteTree(GenTree* tree);
6162 bool optDoEarlyPropForBlock(BasicBlock* block);
6163 bool optDoEarlyPropForFunc();
6164 void optEarlyProp();
6165 void optFoldNullCheck(GenTree* tree);
6166 bool optCanMoveNullCheckPastTree(GenTree* tree, bool isInsideTry);
6169 /**************************************************************************
6170 * Value/Assertion propagation
6171 *************************************************************************/
6173 // Data structures for assertion prop
6174 BitVecTraits* apTraits;
6177 enum optAssertionKind
6194 O1K_CONSTANT_LOOP_BND,
6215 optAssertionKind assertionKind;
6218 unsigned lclNum; // assigned to or property of this local var number
6226 struct AssertionDscOp1
6228 optOp1Kind kind; // a normal LclVar, or Exact-type or Subtype
6235 struct AssertionDscOp2
6237 optOp2Kind kind; // a const or copy assignment
6241 ssize_t iconVal; // integer
6242 unsigned iconFlags; // gtFlags
6244 struct Range // integer subrange
6258 bool IsCheckedBoundArithBound()
6260 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_BOUND_OPER_BND);
6262 bool IsCheckedBoundBound()
6264 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_BOUND_LOOP_BND);
6266 bool IsConstantBound()
6268 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) &&
6269 op1.kind == O1K_CONSTANT_LOOP_BND);
6271 bool IsBoundsCheckNoThrow()
6273 return ((assertionKind == OAK_NO_THROW) && (op1.kind == O1K_ARR_BND));
6276 bool IsCopyAssertion()
6278 return ((assertionKind == OAK_EQUAL) && (op1.kind == O1K_LCLVAR) && (op2.kind == O2K_LCLVAR_COPY));
6281 static bool SameKind(AssertionDsc* a1, AssertionDsc* a2)
6283 return a1->assertionKind == a2->assertionKind && a1->op1.kind == a2->op1.kind &&
6284 a1->op2.kind == a2->op2.kind;
6287 static bool ComplementaryKind(optAssertionKind kind, optAssertionKind kind2)
6289 if (kind == OAK_EQUAL)
6291 return kind2 == OAK_NOT_EQUAL;
6293 else if (kind == OAK_NOT_EQUAL)
6295 return kind2 == OAK_EQUAL;
6300 static ssize_t GetLowerBoundForIntegralType(var_types type)
6319 static ssize_t GetUpperBoundForIntegralType(var_types type)
6342 bool HasSameOp1(AssertionDsc* that, bool vnBased)
6344 if (op1.kind != that->op1.kind)
6348 else if (op1.kind == O1K_ARR_BND)
6351 return (op1.bnd.vnIdx == that->op1.bnd.vnIdx) && (op1.bnd.vnLen == that->op1.bnd.vnLen);
6355 return ((vnBased && (op1.vn == that->op1.vn)) ||
6356 (!vnBased && (op1.lcl.lclNum == that->op1.lcl.lclNum)));
6360 bool HasSameOp2(AssertionDsc* that, bool vnBased)
6362 if (op2.kind != that->op2.kind)
6368 case O2K_IND_CNS_INT:
6370 return ((op2.u1.iconVal == that->op2.u1.iconVal) && (op2.u1.iconFlags == that->op2.u1.iconFlags));
6372 case O2K_CONST_LONG:
6373 return (op2.lconVal == that->op2.lconVal);
6375 case O2K_CONST_DOUBLE:
6376 // exact match because of positive and negative zero.
6377 return (memcmp(&op2.dconVal, &that->op2.dconVal, sizeof(double)) == 0);
6379 case O2K_LCLVAR_COPY:
6381 return (op2.lcl.lclNum == that->op2.lcl.lclNum) &&
6382 (!vnBased || op2.lcl.ssaNum == that->op2.lcl.ssaNum);
6385 return ((op2.u2.loBound == that->op2.u2.loBound) && (op2.u2.hiBound == that->op2.u2.hiBound));
6388 // we will return false
6392 assert(!"Unexpected value for op2.kind in AssertionDsc.");
6398 bool Complementary(AssertionDsc* that, bool vnBased)
6400 return ComplementaryKind(assertionKind, that->assertionKind) && HasSameOp1(that, vnBased) &&
6401 HasSameOp2(that, vnBased);
6404 bool Equals(AssertionDsc* that, bool vnBased)
6406 if (assertionKind != that->assertionKind)
6410 else if (assertionKind == OAK_NO_THROW)
6412 assert(op2.kind == O2K_INVALID);
6413 return HasSameOp1(that, vnBased);
6417 return HasSameOp1(that, vnBased) && HasSameOp2(that, vnBased);
6423 static fgWalkPreFn optAddCopiesCallback;
6424 static fgWalkPreFn optVNAssertionPropCurStmtVisitor;
6425 unsigned optAddCopyLclNum;
6426 GenTree* optAddCopyAsgnNode;
6428 bool optLocalAssertionProp; // indicates that we are performing local assertion prop
6429 bool optAssertionPropagated; // set to true if we modified the trees
6430 bool optAssertionPropagatedCurrentStmt;
6432 GenTree* optAssertionPropCurrentTree;
6434 AssertionIndex* optComplementaryAssertionMap;
6435 JitExpandArray<ASSERT_TP>* optAssertionDep; // table that holds dependent assertions (assertions
6436 // using the value of a local var) for each local var
6437 AssertionDsc* optAssertionTabPrivate; // table that holds info about value assignments
6438 AssertionIndex optAssertionCount; // total number of assertions in the assertion table
6439 AssertionIndex optMaxAssertionCount;
6442 void optVnNonNullPropCurStmt(BasicBlock* block, GenTree* stmt, GenTree* tree);
6443 fgWalkResult optVNConstantPropCurStmt(BasicBlock* block, GenTree* stmt, GenTree* tree);
6444 GenTree* optVNConstantPropOnJTrue(BasicBlock* block, GenTree* stmt, GenTree* test);
6445 GenTree* optVNConstantPropOnTree(BasicBlock* block, GenTree* stmt, GenTree* tree);
6446 GenTree* optPrepareTreeForReplacement(GenTree* extractTree, GenTree* replaceTree);
6448 AssertionIndex GetAssertionCount()
6450 return optAssertionCount;
6452 ASSERT_TP* bbJtrueAssertionOut;
6453 typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, ASSERT_TP> ValueNumToAssertsMap;
6454 ValueNumToAssertsMap* optValueNumToAsserts;
6456 // Assertion prop helpers.
6457 ASSERT_TP& GetAssertionDep(unsigned lclNum);
6458 AssertionDsc* optGetAssertion(AssertionIndex assertIndex);
6459 void optAssertionInit(bool isLocalProp);
6460 void optAssertionTraitsInit(AssertionIndex assertionCount);
6461 #if LOCAL_ASSERTION_PROP
6462 void optAssertionReset(AssertionIndex limit);
6463 void optAssertionRemove(AssertionIndex index);
6466 // Assertion prop data flow functions.
6467 void optAssertionPropMain();
6468 GenTree* optVNAssertionPropCurStmt(BasicBlock* block, GenTree* stmt);
6469 bool optIsTreeKnownIntValue(bool vnBased, GenTree* tree, ssize_t* pConstant, unsigned* pIconFlags);
6470 ASSERT_TP* optInitAssertionDataflowFlags();
6471 ASSERT_TP* optComputeAssertionGen();
6473 // Assertion Gen functions.
6474 void optAssertionGen(GenTree* tree);
6475 AssertionIndex optAssertionGenPhiDefn(GenTree* tree);
6476 AssertionInfo optCreateJTrueBoundsAssertion(GenTree* tree);
6477 AssertionInfo optAssertionGenJtrue(GenTree* tree);
6478 AssertionIndex optCreateJtrueAssertions(GenTree* op1, GenTree* op2, Compiler::optAssertionKind assertionKind);
6479 AssertionIndex optFindComplementary(AssertionIndex assertionIndex);
6480 void optMapComplementary(AssertionIndex assertionIndex, AssertionIndex index);
6482 // Assertion creation functions.
6483 AssertionIndex optCreateAssertion(GenTree* op1, GenTree* op2, optAssertionKind assertionKind);
6484 AssertionIndex optCreateAssertion(GenTree* op1,
6486 optAssertionKind assertionKind,
6487 AssertionDsc* assertion);
6488 void optCreateComplementaryAssertion(AssertionIndex assertionIndex, GenTree* op1, GenTree* op2);
6490 bool optAssertionVnInvolvesNan(AssertionDsc* assertion);
6491 AssertionIndex optAddAssertion(AssertionDsc* assertion);
6492 void optAddVnAssertionMapping(ValueNum vn, AssertionIndex index);
6494 void optPrintVnAssertionMapping();
6496 ASSERT_TP optGetVnMappedAssertions(ValueNum vn);
6498 // Used for respective assertion propagations.
6499 AssertionIndex optAssertionIsSubrange(GenTree* tree, var_types toType, ASSERT_VALARG_TP assertions);
6500 AssertionIndex optAssertionIsSubtype(GenTree* tree, GenTree* methodTableArg, ASSERT_VALARG_TP assertions);
6501 AssertionIndex optAssertionIsNonNullInternal(GenTree* op, ASSERT_VALARG_TP assertions);
6502 bool optAssertionIsNonNull(GenTree* op,
6503 ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased) DEBUGARG(AssertionIndex* pIndex));
6505 // Used for Relop propagation.
6506 AssertionIndex optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP assertions, GenTree* op1, GenTree* op2);
6507 AssertionIndex optLocalAssertionIsEqualOrNotEqual(
6508 optOp1Kind op1Kind, unsigned lclNum, optOp2Kind op2Kind, ssize_t cnsVal, ASSERT_VALARG_TP assertions);
6510 // Assertion prop for lcl var functions.
6511 bool optAssertionProp_LclVarTypeCheck(GenTree* tree, LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc);
6512 GenTree* optCopyAssertionProp(AssertionDsc* curAssertion,
6514 GenTree* stmt DEBUGARG(AssertionIndex index));
6515 GenTree* optConstantAssertionProp(AssertionDsc* curAssertion,
6517 GenTree* stmt DEBUGARG(AssertionIndex index));
6519 // Assertion propagation functions.
6520 GenTree* optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6521 GenTree* optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6522 GenTree* optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6523 GenTree* optAssertionProp_Cast(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6524 GenTree* optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, GenTree* stmt);
6525 GenTree* optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6526 GenTree* optAssertionProp_Comma(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6527 GenTree* optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6528 GenTree* optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6529 GenTree* optAssertionPropLocal_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTree* stmt);
6530 GenTree* optAssertionProp_Update(GenTree* newTree, GenTree* tree, GenTree* stmt);
6531 GenTree* optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, GenTree* stmt);
6533 // Implied assertion functions.
6534 void optImpliedAssertions(AssertionIndex assertionIndex, ASSERT_TP& activeAssertions);
6535 void optImpliedByTypeOfAssertions(ASSERT_TP& activeAssertions);
6536 void optImpliedByCopyAssertion(AssertionDsc* copyAssertion, AssertionDsc* depAssertion, ASSERT_TP& result);
6537 void optImpliedByConstAssertion(AssertionDsc* curAssertion, ASSERT_TP& result);
6540 void optPrintAssertion(AssertionDsc* newAssertion, AssertionIndex assertionIndex = 0);
6541 void optDebugCheckAssertion(AssertionDsc* assertion);
6542 void optDebugCheckAssertions(AssertionIndex AssertionIndex);
6544 void optAddCopies();
6545 #endif // ASSERTION_PROP
6547 /**************************************************************************
6549 *************************************************************************/
6552 struct LoopCloneVisitorInfo
6554 LoopCloneContext* context;
6557 LoopCloneVisitorInfo(LoopCloneContext* context, unsigned loopNum, GenTree* stmt)
6558 : context(context), loopNum(loopNum), stmt(nullptr)
6563 bool optIsStackLocalInvariant(unsigned loopNum, unsigned lclNum);
6564 bool optExtractArrIndex(GenTree* tree, ArrIndex* result, unsigned lhsNum);
6565 bool optReconstructArrIndex(GenTree* tree, ArrIndex* result, unsigned lhsNum);
6566 bool optIdentifyLoopOptInfo(unsigned loopNum, LoopCloneContext* context);
6567 static fgWalkPreFn optCanOptimizeByLoopCloningVisitor;
6568 fgWalkResult optCanOptimizeByLoopCloning(GenTree* tree, LoopCloneVisitorInfo* info);
6569 void optObtainLoopCloningOpts(LoopCloneContext* context);
6570 bool optIsLoopClonable(unsigned loopInd);
6572 bool optCanCloneLoops();
6575 void optDebugLogLoopCloning(BasicBlock* block, GenTree* insertBefore);
6577 void optPerformStaticOptimizations(unsigned loopNum, LoopCloneContext* context DEBUGARG(bool fastPath));
6578 bool optComputeDerefConditions(unsigned loopNum, LoopCloneContext* context);
6579 bool optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext* context);
6580 BasicBlock* optInsertLoopChoiceConditions(LoopCloneContext* context,
6586 ssize_t optGetArrayRefScaleAndIndex(GenTree* mul, GenTree** pIndex DEBUGARG(bool bRngChk));
6588 bool optReachWithoutCall(BasicBlock* srcBB, BasicBlock* dstBB);
6591 bool optLoopsMarked;
6594 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6595 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6599 XX Does the register allocation and puts the remaining lclVars on the stack XX
6601 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6602 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6606 regNumber raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc);
6608 void raMarkStkVars();
6611 // Some things are used by both LSRA and regpredict allocators.
6613 FrameType rpFrameType;
6614 bool rpMustCreateEBPCalled; // Set to true after we have called rpMustCreateEBPFrame once
6616 bool rpMustCreateEBPFrame(INDEBUG(const char** wbReason));
6619 Lowering* m_pLowering; // Lowering; needed to Lower IR that's added or modified after Lowering.
6620 LinearScanInterface* m_pLinearScan; // Linear Scan allocator
6622 /* raIsVarargsStackArg is called by raMaskStkVars and by
6623 lvaSortByRefCount. It identifies the special case
6624 where a varargs function has a parameter passed on the
6625 stack, other than the special varargs handle. Such parameters
6626 require special treatment, because they cannot be tracked
6627 by the GC (their offsets in the stack are not known
6631 bool raIsVarargsStackArg(unsigned lclNum)
6635 LclVarDsc* varDsc = &lvaTable[lclNum];
6637 assert(varDsc->lvIsParam);
6639 return (info.compIsVarArgs && !varDsc->lvIsRegArg && (lclNum != lvaVarargsHandleArg));
6641 #else // _TARGET_X86_
6645 #endif // _TARGET_X86_
6649 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6650 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6654 XX Get to the class and method info from the Execution Engine given XX
6655 XX tokens for the class and method XX
6657 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6658 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6662 /* These are the different addressing modes used to access a local var.
6663 * The JIT has to report the location of the locals back to the EE
6664 * for debugging purposes.
6670 VLT_REG_BYREF, // this type is currently only used for value types on X64
6673 VLT_STK_BYREF, // this type is currently only used for value types on X64
6687 siVarLocType vlType;
6690 // VLT_REG/VLT_REG_FP -- Any pointer-sized enregistered value (TYP_INT, TYP_REF, etc)
6692 // VLT_REG_BYREF -- the specified register contains the address of the variable
6700 // VLT_STK -- Any 32 bit value which is on the stack
6701 // eg. [ESP+0x20], or [EBP-0x28]
6702 // VLT_STK_BYREF -- the specified stack location contains the address of the variable
6703 // eg. mov EAX, [ESP+0x20]; [EAX]
6707 regNumber vlsBaseReg;
6708 NATIVE_OFFSET vlsOffset;
6711 // VLT_REG_REG -- TYP_LONG/TYP_DOUBLE with both DWords enregistered
6720 // VLT_REG_STK -- Partly enregistered TYP_LONG/TYP_DOUBLE
6721 // eg { LowerDWord=EAX UpperDWord=[ESP+0x8] }
6729 regNumber vlrssBaseReg;
6730 NATIVE_OFFSET vlrssOffset;
6734 // VLT_STK_REG -- Partly enregistered TYP_LONG/TYP_DOUBLE
6735 // eg { LowerDWord=[ESP+0x8] UpperDWord=EAX }
6741 regNumber vlsrsBaseReg;
6742 NATIVE_OFFSET vlsrsOffset;
6748 // VLT_STK2 -- Any 64 bit value which is on the stack, in 2 successsive DWords
6749 // eg 2 DWords at [ESP+0x10]
6753 regNumber vls2BaseReg;
6754 NATIVE_OFFSET vls2Offset;
6757 // VLT_FPSTK -- enregisterd TYP_DOUBLE (on the FP stack)
6758 // eg. ST(3). Actually it is ST("FPstkHeight - vpFpStk")
6765 // VLT_FIXED_VA -- fixed argument of a varargs function.
6766 // The argument location depends on the size of the variable
6767 // arguments (...). Inspecting the VARARGS_HANDLE indicates the
6768 // location of the first arg. This argument can then be accessed
6769 // relative to the position of the first arg
6773 unsigned vlfvOffset;
6780 void* rpValue; // pointer to the in-process
6781 // location of the value.
6787 bool vlIsInReg(regNumber reg);
6788 bool vlIsOnStk(regNumber reg, signed offset);
6791 /*************************************************************************/
6796 void eeGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6797 CORINFO_RESOLVED_TOKEN* pConstrainedToken,
6798 CORINFO_CALLINFO_FLAGS flags,
6799 CORINFO_CALL_INFO* pResult);
6800 inline CORINFO_CALLINFO_FLAGS addVerifyFlag(CORINFO_CALLINFO_FLAGS flags);
6802 void eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6803 CORINFO_ACCESS_FLAGS flags,
6804 CORINFO_FIELD_INFO* pResult);
6808 BOOL eeIsValueClass(CORINFO_CLASS_HANDLE clsHnd);
6810 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(TRACK_LSRA_STATS)
6812 bool IsSuperPMIException(unsigned code)
6814 // Copied from NDP\clr\src\ToolBox\SuperPMI\SuperPMI-Shared\ErrorHandling.h
6816 const unsigned EXCEPTIONCODE_DebugBreakorAV = 0xe0421000;
6817 const unsigned EXCEPTIONCODE_MC = 0xe0422000;
6818 const unsigned EXCEPTIONCODE_LWM = 0xe0423000;
6819 const unsigned EXCEPTIONCODE_SASM = 0xe0424000;
6820 const unsigned EXCEPTIONCODE_SSYM = 0xe0425000;
6821 const unsigned EXCEPTIONCODE_CALLUTILS = 0xe0426000;
6822 const unsigned EXCEPTIONCODE_TYPEUTILS = 0xe0427000;
6823 const unsigned EXCEPTIONCODE_ASSERT = 0xe0440000;
6827 case EXCEPTIONCODE_DebugBreakorAV:
6828 case EXCEPTIONCODE_MC:
6829 case EXCEPTIONCODE_LWM:
6830 case EXCEPTIONCODE_SASM:
6831 case EXCEPTIONCODE_SSYM:
6832 case EXCEPTIONCODE_CALLUTILS:
6833 case EXCEPTIONCODE_TYPEUTILS:
6834 case EXCEPTIONCODE_ASSERT:
6841 const char* eeGetMethodName(CORINFO_METHOD_HANDLE hnd, const char** className);
6842 const char* eeGetMethodFullName(CORINFO_METHOD_HANDLE hnd);
6844 bool eeIsNativeMethod(CORINFO_METHOD_HANDLE method);
6845 CORINFO_METHOD_HANDLE eeGetMethodHandleForNative(CORINFO_METHOD_HANDLE method);
6848 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6849 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig, bool* isPinned);
6850 unsigned eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6852 // VOM info, method sigs
6854 void eeGetSig(unsigned sigTok,
6855 CORINFO_MODULE_HANDLE scope,
6856 CORINFO_CONTEXT_HANDLE context,
6857 CORINFO_SIG_INFO* retSig);
6859 void eeGetCallSiteSig(unsigned sigTok,
6860 CORINFO_MODULE_HANDLE scope,
6861 CORINFO_CONTEXT_HANDLE context,
6862 CORINFO_SIG_INFO* retSig);
6864 void eeGetMethodSig(CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* retSig, CORINFO_CLASS_HANDLE owner = nullptr);
6866 // Method entry-points, instrs
6868 CORINFO_METHOD_HANDLE eeMarkNativeTarget(CORINFO_METHOD_HANDLE method);
6870 CORINFO_EE_INFO eeInfo;
6871 bool eeInfoInitialized;
6873 CORINFO_EE_INFO* eeGetEEInfo();
6875 // Gets the offset of a SDArray's first element
6876 unsigned eeGetArrayDataOffset(var_types type);
6877 // Gets the offset of a MDArray's first element
6878 unsigned eeGetMDArrayDataOffset(var_types type, unsigned rank);
6880 GenTree* eeGetPInvokeCookie(CORINFO_SIG_INFO* szMetaSig);
6882 // Returns the page size for the target machine as reported by the EE.
6883 inline target_size_t eeGetPageSize()
6885 return (target_size_t)eeGetEEInfo()->osPageSize;
6888 // Returns the frame size at which we will generate a loop to probe the stack.
6889 inline target_size_t getVeryLargeFrameSize()
6892 // The looping probe code is 40 bytes, whereas the straight-line probing for
6893 // the (0x2000..0x3000) case is 44, so use looping for anything 0x2000 bytes
6894 // or greater, to generate smaller code.
6895 return 2 * eeGetPageSize();
6897 return 3 * eeGetPageSize();
6901 //------------------------------------------------------------------------
6902 // VirtualStubParam: virtual stub dispatch extra parameter (slot address).
6904 // It represents Abi and target specific registers for the parameter.
6906 class VirtualStubParamInfo
6909 VirtualStubParamInfo(bool isCoreRTABI)
6911 #if defined(_TARGET_X86_)
6914 #elif defined(_TARGET_AMD64_)
6925 #elif defined(_TARGET_ARM_)
6936 #elif defined(_TARGET_ARM64_)
6940 #error Unsupported or unset target architecture
6944 regNumber GetReg() const
6949 _regMask_enum GetRegMask() const
6956 _regMask_enum regMask;
6959 VirtualStubParamInfo* virtualStubParamInfo;
6961 inline bool IsTargetAbi(CORINFO_RUNTIME_ABI abi)
6963 return eeGetEEInfo()->targetAbi == abi;
6966 inline bool generateCFIUnwindCodes()
6968 #if defined(_TARGET_UNIX_)
6969 return IsTargetAbi(CORINFO_CORERT_ABI);
6975 // Debugging support - Line number info
6977 void eeGetStmtOffsets();
6979 unsigned eeBoundariesCount;
6981 struct boundariesDsc
6983 UNATIVE_OFFSET nativeIP;
6985 unsigned sourceReason;
6986 } * eeBoundaries; // Boundaries to report to EE
6987 void eeSetLIcount(unsigned count);
6988 void eeSetLIinfo(unsigned which, UNATIVE_OFFSET offs, unsigned srcIP, bool stkEmpty, bool callInstruction);
6992 static void eeDispILOffs(IL_OFFSET offs);
6993 static void eeDispLineInfo(const boundariesDsc* line);
6994 void eeDispLineInfos();
6997 // Debugging support - Local var info
7001 unsigned eeVarsCount;
7003 struct VarResultInfo
7005 UNATIVE_OFFSET startOffset;
7006 UNATIVE_OFFSET endOffset;
7010 void eeSetLVcount(unsigned count);
7011 void eeSetLVinfo(unsigned which,
7012 UNATIVE_OFFSET startOffs,
7013 UNATIVE_OFFSET length,
7018 const siVarLoc& loc);
7022 void eeDispVar(ICorDebugInfo::NativeVarInfo* var);
7023 void eeDispVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars);
7026 // ICorJitInfo wrappers
7028 void eeReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize);
7030 void eeAllocUnwindInfo(BYTE* pHotCode,
7036 CorJitFuncKind funcKind);
7038 void eeSetEHcount(unsigned cEH);
7040 void eeSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause);
7042 WORD eeGetRelocTypeHint(void* target);
7044 // ICorStaticInfo wrapper functions
7046 bool eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken);
7048 #if defined(UNIX_AMD64_ABI)
7050 static void dumpSystemVClassificationType(SystemVClassificationType ct);
7053 void eeGetSystemVAmd64PassStructInRegisterDescriptor(
7054 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
7055 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr);
7056 #endif // UNIX_AMD64_ABI
7058 template <typename ParamType>
7059 bool eeRunWithErrorTrap(void (*function)(ParamType*), ParamType* param)
7061 return eeRunWithErrorTrapImp(reinterpret_cast<void (*)(void*)>(function), reinterpret_cast<void*>(param));
7064 bool eeRunWithErrorTrapImp(void (*function)(void*), void* param);
7066 // Utility functions
7068 const char* eeGetFieldName(CORINFO_FIELD_HANDLE fieldHnd, const char** classNamePtr = nullptr);
7071 const wchar_t* eeGetCPString(size_t stringHandle);
7074 const char* eeGetClassName(CORINFO_CLASS_HANDLE clsHnd);
7076 static CORINFO_METHOD_HANDLE eeFindHelper(unsigned helper);
7077 static CorInfoHelpFunc eeGetHelperNum(CORINFO_METHOD_HANDLE method);
7079 static fgWalkPreFn CountSharedStaticHelper;
7080 static bool IsSharedStaticHelper(GenTree* tree);
7081 static bool IsTreeAlwaysHoistable(GenTree* tree);
7082 static bool IsGcSafePoint(GenTree* tree);
7084 static CORINFO_FIELD_HANDLE eeFindJitDataOffs(unsigned jitDataOffs);
7085 // returns true/false if 'field' is a Jit Data offset
7086 static bool eeIsJitDataOffs(CORINFO_FIELD_HANDLE field);
7087 // returns a number < 0 if 'field' is not a Jit Data offset, otherwise the data offset (limited to 2GB)
7088 static int eeGetJitDataOffs(CORINFO_FIELD_HANDLE field);
7090 /*****************************************************************************/
7093 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7094 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7098 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7099 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7103 CodeGenInterface* codeGen;
7105 // The following holds information about instr offsets in terms of generated code.
7109 IPmappingDsc* ipmdNext; // next line# record
7110 IL_OFFSETX ipmdILoffsx; // the instr offset
7111 emitLocation ipmdNativeLoc; // the emitter location of the native code corresponding to the IL offset
7112 bool ipmdIsLabel; // Can this code be a branch label?
7115 // Record the instr offset mapping to the generated code
7117 IPmappingDsc* genIPmappingList;
7118 IPmappingDsc* genIPmappingLast;
7120 // Managed RetVal - A side hash table meant to record the mapping from a
7121 // GT_CALL node to its IL offset. This info is used to emit sequence points
7122 // that can be used by debugger to determine the native offset at which the
7123 // managed RetVal will be available.
7125 // In fact we can store IL offset in a GT_CALL node. This was ruled out in
7126 // favor of a side table for two reasons: 1) We need IL offset for only those
7127 // GT_CALL nodes (created during importation) that correspond to an IL call and
7128 // whose return type is other than TYP_VOID. 2) GT_CALL node is a frequently used
7129 // structure and IL offset is needed only when generating debuggable code. Therefore
7130 // it is desirable to avoid memory size penalty in retail scenarios.
7131 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, IL_OFFSETX> CallSiteILOffsetTable;
7132 CallSiteILOffsetTable* genCallSite2ILOffsetMap;
7134 unsigned genReturnLocal; // Local number for the return value when applicable.
7135 BasicBlock* genReturnBB; // jumped to when not optimizing for speed.
7137 // The following properties are part of CodeGenContext. Getters are provided here for
7138 // convenience and backward compatibility, but the properties can only be set by invoking
7139 // the setter on CodeGenContext directly.
7141 __declspec(property(get = getEmitter)) emitter* genEmitter;
7142 emitter* getEmitter()
7144 return codeGen->getEmitter();
7147 bool isFramePointerUsed()
7149 return codeGen->isFramePointerUsed();
7152 __declspec(property(get = getInterruptible, put = setInterruptible)) bool genInterruptible;
7153 bool getInterruptible()
7155 return codeGen->genInterruptible;
7157 void setInterruptible(bool value)
7159 codeGen->setInterruptible(value);
7162 #ifdef _TARGET_ARMARCH_
7163 __declspec(property(get = getHasTailCalls, put = setHasTailCalls)) bool hasTailCalls;
7164 bool getHasTailCalls()
7166 return codeGen->hasTailCalls;
7168 void setHasTailCalls(bool value)
7170 codeGen->setHasTailCalls(value);
7172 #endif // _TARGET_ARMARCH_
7175 const bool genDoubleAlign()
7177 return codeGen->doDoubleAlign();
7179 DWORD getCanDoubleAlign();
7180 bool shouldDoubleAlign(unsigned refCntStk,
7182 unsigned refCntWtdReg,
7183 unsigned refCntStkParam,
7184 unsigned refCntWtdStkDbl);
7185 #endif // DOUBLE_ALIGN
7187 __declspec(property(get = getFullPtrRegMap, put = setFullPtrRegMap)) bool genFullPtrRegMap;
7188 bool getFullPtrRegMap()
7190 return codeGen->genFullPtrRegMap;
7192 void setFullPtrRegMap(bool value)
7194 codeGen->setFullPtrRegMap(value);
7197 // Things that MAY belong either in CodeGen or CodeGenContext
7199 #if FEATURE_EH_FUNCLETS
7200 FuncInfoDsc* compFuncInfos;
7201 unsigned short compCurrFuncIdx;
7202 unsigned short compFuncInfoCount;
7204 unsigned short compFuncCount()
7206 assert(fgFuncletsCreated);
7207 return compFuncInfoCount;
7210 #else // !FEATURE_EH_FUNCLETS
7212 // This is a no-op when there are no funclets!
7213 void genUpdateCurrentFunclet(BasicBlock* block)
7218 FuncInfoDsc compFuncInfoRoot;
7220 static const unsigned compCurrFuncIdx = 0;
7222 unsigned short compFuncCount()
7227 #endif // !FEATURE_EH_FUNCLETS
7229 FuncInfoDsc* funCurrentFunc();
7230 void funSetCurrentFunc(unsigned funcIdx);
7231 FuncInfoDsc* funGetFunc(unsigned funcIdx);
7232 unsigned int funGetFuncIdx(BasicBlock* block);
7236 VARSET_TP compCurLife; // current live variables
7237 GenTree* compCurLifeTree; // node after which compCurLife has been computed
7239 template <bool ForCodeGen>
7240 void compChangeLife(VARSET_VALARG_TP newLife);
7242 void genChangeLife(VARSET_VALARG_TP newLife)
7244 compChangeLife</*ForCodeGen*/ true>(newLife);
7247 template <bool ForCodeGen>
7248 inline void compUpdateLife(VARSET_VALARG_TP newLife);
7250 // Gets a register mask that represent the kill set for a helper call since
7251 // not all JIT Helper calls follow the standard ABI on the target architecture.
7252 regMaskTP compHelperCallKillSet(CorInfoHelpFunc helper);
7254 // Gets a register mask that represent the kill set for a NoGC helper call.
7255 regMaskTP compNoGCHelperCallKillSet(CorInfoHelpFunc helper);
7258 // Requires that "varDsc" be a promoted struct local variable being passed as an argument, beginning at
7259 // "firstArgRegNum", which is assumed to have already been aligned to the register alignment restriction of the
7260 // struct type. Adds bits to "*pArgSkippedRegMask" for any argument registers *not* used in passing "varDsc" --
7261 // i.e., internal "holes" caused by internal alignment constraints. For example, if the struct contained an int and
7262 // a double, and we at R0 (on ARM), then R1 would be skipped, and the bit for R1 would be added to the mask.
7263 void fgAddSkippedRegsInPromotedStructArg(LclVarDsc* varDsc, unsigned firstArgRegNum, regMaskTP* pArgSkippedRegMask);
7264 #endif // _TARGET_ARM_
7266 // 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
7268 static GenTree* fgIsIndirOfAddrOfLocal(GenTree* tree);
7270 // This map is indexed by GT_OBJ nodes that are address of promoted struct variables, which
7271 // have been annotated with the GTF_VAR_DEATH flag. If such a node is *not* mapped in this
7272 // table, one may assume that all the (tracked) field vars die at this GT_OBJ. Otherwise,
7273 // the node maps to a pointer to a VARSET_TP, containing set bits for each of the tracked field
7274 // vars of the promoted struct local that go dead at the given node (the set bits are the bits
7275 // for the tracked var indices of the field vars, as in a live var set).
7277 // The map is allocated on demand so all map operations should use one of the following three
7280 NodeToVarsetPtrMap* m_promotedStructDeathVars;
7282 NodeToVarsetPtrMap* GetPromotedStructDeathVars()
7284 if (m_promotedStructDeathVars == nullptr)
7286 m_promotedStructDeathVars = new (getAllocator()) NodeToVarsetPtrMap(getAllocator());
7288 return m_promotedStructDeathVars;
7291 void ClearPromotedStructDeathVars()
7293 if (m_promotedStructDeathVars != nullptr)
7295 m_promotedStructDeathVars->RemoveAll();
7299 bool LookupPromotedStructDeathVars(GenTree* tree, VARSET_TP** bits)
7302 bool result = false;
7304 if (m_promotedStructDeathVars != nullptr)
7306 result = m_promotedStructDeathVars->Lookup(tree, bits);
7313 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7314 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7318 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7319 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7322 #if !defined(__GNUC__)
7323 #pragma region Unwind information
7328 // Infrastructure functions: start/stop/reserve/emit.
7331 void unwindBegProlog();
7332 void unwindEndProlog();
7333 void unwindBegEpilog();
7334 void unwindEndEpilog();
7335 void unwindReserve();
7336 void unwindEmit(void* pHotCode, void* pColdCode);
7339 // Specific unwind information functions: called by code generation to indicate a particular
7340 // prolog or epilog unwindable instruction has been generated.
7343 void unwindPush(regNumber reg);
7344 void unwindAllocStack(unsigned size);
7345 void unwindSetFrameReg(regNumber reg, unsigned offset);
7346 void unwindSaveReg(regNumber reg, unsigned offset);
7348 #if defined(_TARGET_ARM_)
7349 void unwindPushMaskInt(regMaskTP mask);
7350 void unwindPushMaskFloat(regMaskTP mask);
7351 void unwindPopMaskInt(regMaskTP mask);
7352 void unwindPopMaskFloat(regMaskTP mask);
7353 void unwindBranch16(); // The epilog terminates with a 16-bit branch (e.g., "bx lr")
7354 void unwindNop(unsigned codeSizeInBytes); // Generate unwind NOP code. 'codeSizeInBytes' is 2 or 4 bytes. Only
7355 // called via unwindPadding().
7356 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7357 // instruction and the current location.
7358 #endif // _TARGET_ARM_
7360 #if defined(_TARGET_ARM64_)
7362 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7363 // instruction and the current location.
7364 void unwindSaveReg(regNumber reg, int offset); // str reg, [sp, #offset]
7365 void unwindSaveRegPreindexed(regNumber reg, int offset); // str reg, [sp, #offset]!
7366 void unwindSaveRegPair(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]
7367 void unwindSaveRegPairPreindexed(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]!
7368 void unwindSaveNext(); // unwind code: save_next
7369 void unwindReturn(regNumber reg); // ret lr
7370 #endif // defined(_TARGET_ARM64_)
7373 // Private "helper" functions for the unwind implementation.
7377 #if FEATURE_EH_FUNCLETS
7378 void unwindGetFuncLocations(FuncInfoDsc* func,
7379 bool getHotSectionData,
7380 /* OUT */ emitLocation** ppStartLoc,
7381 /* OUT */ emitLocation** ppEndLoc);
7382 #endif // FEATURE_EH_FUNCLETS
7384 void unwindReserveFunc(FuncInfoDsc* func);
7385 void unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
7387 #if defined(_TARGET_AMD64_) || (defined(_TARGET_X86_) && FEATURE_EH_FUNCLETS)
7389 void unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode);
7390 void unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode);
7392 #endif // _TARGET_AMD64_ || (_TARGET_X86_ && FEATURE_EH_FUNCLETS)
7394 UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func);
7396 #if defined(_TARGET_AMD64_)
7398 void unwindBegPrologWindows();
7399 void unwindPushWindows(regNumber reg);
7400 void unwindAllocStackWindows(unsigned size);
7401 void unwindSetFrameRegWindows(regNumber reg, unsigned offset);
7402 void unwindSaveRegWindows(regNumber reg, unsigned offset);
7404 #ifdef UNIX_AMD64_ABI
7405 void unwindSaveRegCFI(regNumber reg, unsigned offset);
7406 #endif // UNIX_AMD64_ABI
7407 #elif defined(_TARGET_ARM_)
7409 void unwindPushPopMaskInt(regMaskTP mask, bool useOpsize16);
7410 void unwindPushPopMaskFloat(regMaskTP mask);
7412 #endif // _TARGET_ARM_
7414 #if defined(_TARGET_UNIX_)
7415 int mapRegNumToDwarfReg(regNumber reg);
7416 void createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR opcode, USHORT dwarfReg, INT offset = 0);
7417 void unwindPushPopCFI(regNumber reg);
7418 void unwindBegPrologCFI();
7419 void unwindPushPopMaskCFI(regMaskTP regMask, bool isFloat);
7420 void unwindAllocStackCFI(unsigned size);
7421 void unwindSetFrameRegCFI(regNumber reg, unsigned offset);
7422 void unwindEmitFuncCFI(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
7424 void DumpCfiInfo(bool isHotCode,
7425 UNATIVE_OFFSET startOffset,
7426 UNATIVE_OFFSET endOffset,
7428 const CFI_CODE* const pCfiCode);
7430 #if defined(_TARGET_ARM_)
7431 bool unwindCfiEpilogFormed; // Avoid duplicated unwind info for methods with multiple epilogs (we expect and require
7432 // all the epilogs to be precisely the same)
7435 #endif // _TARGET_UNIX_
7437 #if !defined(__GNUC__)
7438 #pragma endregion // Note: region is NOT under !defined(__GNUC__)
7442 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7443 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7447 XX Info about SIMD types, methods and the SIMD assembly (i.e. the assembly XX
7448 XX that contains the distinguished, well-known SIMD type definitions). XX
7450 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7451 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7454 // Get highest available level for SIMD codegen
7455 SIMDLevel getSIMDSupportLevel()
7457 #if defined(_TARGET_XARCH_)
7458 if (compSupports(InstructionSet_AVX2))
7460 return SIMD_AVX2_Supported;
7463 // SIMD_SSE4_Supported actually requires all of SSE3, SSSE3, SSE4.1, and SSE4.2
7464 // to be supported. We can only enable it if all four are enabled in the compiler
7465 if (compSupports(InstructionSet_SSE42) && compSupports(InstructionSet_SSE41) &&
7466 compSupports(InstructionSet_SSSE3) && compSupports(InstructionSet_SSE3))
7468 return SIMD_SSE4_Supported;
7472 return SIMD_SSE2_Supported;
7474 assert(!"Available instruction set(s) for SIMD codegen is not defined for target arch");
7476 return SIMD_Not_Supported;
7482 // Should we support SIMD intrinsics?
7485 // Have we identified any SIMD types?
7486 // This is currently used by struct promotion to avoid getting type information for a struct
7487 // field to see if it is a SIMD type, if we haven't seen any SIMD types or operations in
7489 bool _usesSIMDTypes;
7490 bool usesSIMDTypes()
7492 return _usesSIMDTypes;
7494 void setUsesSIMDTypes(bool value)
7496 _usesSIMDTypes = value;
7499 // This is a temp lclVar allocated on the stack as TYP_SIMD. It is used to implement intrinsics
7500 // that require indexed access to the individual fields of the vector, which is not well supported
7501 // by the hardware. It is allocated when/if such situations are encountered during Lowering.
7502 unsigned lvaSIMDInitTempVarNum;
7504 struct SIMDHandlesCache
7507 CORINFO_CLASS_HANDLE SIMDFloatHandle;
7508 CORINFO_CLASS_HANDLE SIMDDoubleHandle;
7509 CORINFO_CLASS_HANDLE SIMDIntHandle;
7510 CORINFO_CLASS_HANDLE SIMDUShortHandle;
7511 CORINFO_CLASS_HANDLE SIMDUByteHandle;
7512 CORINFO_CLASS_HANDLE SIMDShortHandle;
7513 CORINFO_CLASS_HANDLE SIMDByteHandle;
7514 CORINFO_CLASS_HANDLE SIMDLongHandle;
7515 CORINFO_CLASS_HANDLE SIMDUIntHandle;
7516 CORINFO_CLASS_HANDLE SIMDULongHandle;
7517 CORINFO_CLASS_HANDLE SIMDVector2Handle;
7518 CORINFO_CLASS_HANDLE SIMDVector3Handle;
7519 CORINFO_CLASS_HANDLE SIMDVector4Handle;
7520 CORINFO_CLASS_HANDLE SIMDVectorHandle;
7522 #ifdef FEATURE_HW_INTRINSICS
7523 #if defined(_TARGET_ARM64_)
7524 CORINFO_CLASS_HANDLE Vector64FloatHandle;
7525 CORINFO_CLASS_HANDLE Vector64UIntHandle;
7526 CORINFO_CLASS_HANDLE Vector64UShortHandle;
7527 CORINFO_CLASS_HANDLE Vector64UByteHandle;
7528 CORINFO_CLASS_HANDLE Vector64ShortHandle;
7529 CORINFO_CLASS_HANDLE Vector64ByteHandle;
7530 CORINFO_CLASS_HANDLE Vector64IntHandle;
7531 #endif // defined(_TARGET_ARM64_)
7532 CORINFO_CLASS_HANDLE Vector128FloatHandle;
7533 CORINFO_CLASS_HANDLE Vector128DoubleHandle;
7534 CORINFO_CLASS_HANDLE Vector128IntHandle;
7535 CORINFO_CLASS_HANDLE Vector128UShortHandle;
7536 CORINFO_CLASS_HANDLE Vector128UByteHandle;
7537 CORINFO_CLASS_HANDLE Vector128ShortHandle;
7538 CORINFO_CLASS_HANDLE Vector128ByteHandle;
7539 CORINFO_CLASS_HANDLE Vector128LongHandle;
7540 CORINFO_CLASS_HANDLE Vector128UIntHandle;
7541 CORINFO_CLASS_HANDLE Vector128ULongHandle;
7542 #if defined(_TARGET_XARCH_)
7543 CORINFO_CLASS_HANDLE Vector256FloatHandle;
7544 CORINFO_CLASS_HANDLE Vector256DoubleHandle;
7545 CORINFO_CLASS_HANDLE Vector256IntHandle;
7546 CORINFO_CLASS_HANDLE Vector256UShortHandle;
7547 CORINFO_CLASS_HANDLE Vector256UByteHandle;
7548 CORINFO_CLASS_HANDLE Vector256ShortHandle;
7549 CORINFO_CLASS_HANDLE Vector256ByteHandle;
7550 CORINFO_CLASS_HANDLE Vector256LongHandle;
7551 CORINFO_CLASS_HANDLE Vector256UIntHandle;
7552 CORINFO_CLASS_HANDLE Vector256ULongHandle;
7553 #endif // defined(_TARGET_XARCH_)
7554 #endif // FEATURE_HW_INTRINSICS
7558 memset(this, 0, sizeof(*this));
7562 SIMDHandlesCache* m_simdHandleCache;
7564 // Get the handle for a SIMD type.
7565 CORINFO_CLASS_HANDLE gtGetStructHandleForSIMD(var_types simdType, var_types simdBaseType)
7567 if (m_simdHandleCache == nullptr)
7569 // This may happen if the JIT generates SIMD node on its own, without importing them.
7570 // Otherwise getBaseTypeAndSizeOfSIMDType should have created the cache.
7571 return NO_CLASS_HANDLE;
7574 if (simdBaseType == TYP_FLOAT)
7579 return m_simdHandleCache->SIMDVector2Handle;
7581 return m_simdHandleCache->SIMDVector3Handle;
7583 if ((getSIMDVectorType() == TYP_SIMD32) ||
7584 (m_simdHandleCache->SIMDVector4Handle != NO_CLASS_HANDLE))
7586 return m_simdHandleCache->SIMDVector4Handle;
7595 assert(simdType == getSIMDVectorType());
7596 switch (simdBaseType)
7599 return m_simdHandleCache->SIMDFloatHandle;
7601 return m_simdHandleCache->SIMDDoubleHandle;
7603 return m_simdHandleCache->SIMDIntHandle;
7605 return m_simdHandleCache->SIMDUShortHandle;
7607 return m_simdHandleCache->SIMDUByteHandle;
7609 return m_simdHandleCache->SIMDShortHandle;
7611 return m_simdHandleCache->SIMDByteHandle;
7613 return m_simdHandleCache->SIMDLongHandle;
7615 return m_simdHandleCache->SIMDUIntHandle;
7617 return m_simdHandleCache->SIMDULongHandle;
7619 assert(!"Didn't find a class handle for simdType");
7621 return NO_CLASS_HANDLE;
7624 // Returns true if the tree corresponds to a TYP_SIMD lcl var.
7625 // Note that both SIMD vector args and locals are mared as lvSIMDType = true, but
7626 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD or TYP_STRUCT.
7627 bool isSIMDTypeLocal(GenTree* tree)
7629 return tree->OperIsLocal() && lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7632 // Returns true if the type of the tree is a byref of TYP_SIMD
7633 bool isAddrOfSIMDType(GenTree* tree)
7635 if (tree->TypeGet() == TYP_BYREF || tree->TypeGet() == TYP_I_IMPL)
7637 switch (tree->OperGet())
7640 return varTypeIsSIMD(tree->gtGetOp1());
7642 case GT_LCL_VAR_ADDR:
7643 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7646 return isSIMDTypeLocal(tree);
7653 static bool isRelOpSIMDIntrinsic(SIMDIntrinsicID intrinsicId)
7655 return (intrinsicId == SIMDIntrinsicEqual || intrinsicId == SIMDIntrinsicLessThan ||
7656 intrinsicId == SIMDIntrinsicLessThanOrEqual || intrinsicId == SIMDIntrinsicGreaterThan ||
7657 intrinsicId == SIMDIntrinsicGreaterThanOrEqual);
7660 // Returns base type of a TYP_SIMD local.
7661 // Returns TYP_UNKNOWN if the local is not TYP_SIMD.
7662 var_types getBaseTypeOfSIMDLocal(GenTree* tree)
7664 if (isSIMDTypeLocal(tree))
7666 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvBaseType;
7672 bool isSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7674 return info.compCompHnd->isInSIMDModule(clsHnd);
7677 bool isIntrinsicType(CORINFO_CLASS_HANDLE clsHnd)
7679 return (info.compCompHnd->getClassAttribs(clsHnd) & CORINFO_FLG_INTRINSIC_TYPE) != 0;
7682 const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName)
7684 return info.compCompHnd->getClassNameFromMetadata(cls, namespaceName);
7687 CORINFO_CLASS_HANDLE getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index)
7689 return info.compCompHnd->getTypeInstantiationArgument(cls, index);
7692 bool isSIMDClass(typeInfo* pTypeInfo)
7694 return pTypeInfo->IsStruct() && isSIMDClass(pTypeInfo->GetClassHandleForValueClass());
7697 bool isHWSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7699 #ifdef FEATURE_HW_INTRINSICS
7700 if (isIntrinsicType(clsHnd))
7702 const char* namespaceName = nullptr;
7703 (void)getClassNameFromMetadata(clsHnd, &namespaceName);
7704 return strcmp(namespaceName, "System.Runtime.Intrinsics") == 0;
7706 #endif // FEATURE_HW_INTRINSICS
7710 bool isHWSIMDClass(typeInfo* pTypeInfo)
7712 #ifdef FEATURE_HW_INTRINSICS
7713 return pTypeInfo->IsStruct() && isHWSIMDClass(pTypeInfo->GetClassHandleForValueClass());
7719 bool isSIMDorHWSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7721 return isSIMDClass(clsHnd) || isHWSIMDClass(clsHnd);
7724 bool isSIMDorHWSIMDClass(typeInfo* pTypeInfo)
7726 return isSIMDClass(pTypeInfo) || isHWSIMDClass(pTypeInfo);
7729 // Get the base (element) type and size in bytes for a SIMD type. Returns TYP_UNKNOWN
7730 // if it is not a SIMD type or is an unsupported base type.
7731 var_types getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes = nullptr);
7733 var_types getBaseTypeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7735 return getBaseTypeAndSizeOfSIMDType(typeHnd, nullptr);
7738 // Get SIMD Intrinsic info given the method handle.
7739 // Also sets typeHnd, argCount, baseType and sizeBytes out params.
7740 const SIMDIntrinsicInfo* getSIMDIntrinsicInfo(CORINFO_CLASS_HANDLE* typeHnd,
7741 CORINFO_METHOD_HANDLE methodHnd,
7742 CORINFO_SIG_INFO* sig,
7745 var_types* baseType,
7746 unsigned* sizeBytes);
7748 // Pops and returns GenTree node from importers type stack.
7749 // Normalizes TYP_STRUCT value in case of GT_CALL, GT_RET_EXPR and arg nodes.
7750 GenTree* impSIMDPopStack(var_types type, bool expectAddr = false, CORINFO_CLASS_HANDLE structType = nullptr);
7752 // Create a GT_SIMD tree for a Get property of SIMD vector with a fixed index.
7753 GenTreeSIMD* impSIMDGetFixed(var_types simdType, var_types baseType, unsigned simdSize, int index);
7755 // Creates a GT_SIMD tree for Select operation
7756 GenTree* impSIMDSelect(CORINFO_CLASS_HANDLE typeHnd,
7758 unsigned simdVectorSize,
7763 // Creates a GT_SIMD tree for Min/Max operation
7764 GenTree* impSIMDMinMax(SIMDIntrinsicID intrinsicId,
7765 CORINFO_CLASS_HANDLE typeHnd,
7767 unsigned simdVectorSize,
7771 // Transforms operands and returns the SIMD intrinsic to be applied on
7772 // transformed operands to obtain given relop result.
7773 SIMDIntrinsicID impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId,
7774 CORINFO_CLASS_HANDLE typeHnd,
7775 unsigned simdVectorSize,
7776 var_types* baseType,
7780 // Creates a GT_SIMD tree for Abs intrinsic.
7781 GenTree* impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType, unsigned simdVectorSize, GenTree* op1);
7783 #if defined(_TARGET_XARCH_)
7785 // Transforms operands and returns the SIMD intrinsic to be applied on
7786 // transformed operands to obtain == comparison result.
7787 SIMDIntrinsicID impSIMDLongRelOpEqual(CORINFO_CLASS_HANDLE typeHnd,
7788 unsigned simdVectorSize,
7792 // Transforms operands and returns the SIMD intrinsic to be applied on
7793 // transformed operands to obtain > comparison result.
7794 SIMDIntrinsicID impSIMDLongRelOpGreaterThan(CORINFO_CLASS_HANDLE typeHnd,
7795 unsigned simdVectorSize,
7799 // Transforms operands and returns the SIMD intrinsic to be applied on
7800 // transformed operands to obtain >= comparison result.
7801 SIMDIntrinsicID impSIMDLongRelOpGreaterThanOrEqual(CORINFO_CLASS_HANDLE typeHnd,
7802 unsigned simdVectorSize,
7806 // Transforms operands and returns the SIMD intrinsic to be applied on
7807 // transformed operands to obtain >= comparison result in case of int32
7808 // and small int base type vectors.
7809 SIMDIntrinsicID impSIMDIntegralRelOpGreaterThanOrEqual(
7810 CORINFO_CLASS_HANDLE typeHnd, unsigned simdVectorSize, var_types baseType, GenTree** op1, GenTree** op2);
7812 #endif // defined(_TARGET_XARCH_)
7814 void setLclRelatedToSIMDIntrinsic(GenTree* tree);
7815 bool areFieldsContiguous(GenTree* op1, GenTree* op2);
7816 bool areArrayElementsContiguous(GenTree* op1, GenTree* op2);
7817 bool areArgumentsContiguous(GenTree* op1, GenTree* op2);
7818 GenTree* createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize);
7820 // check methodHnd to see if it is a SIMD method that is expanded as an intrinsic in the JIT.
7821 GenTree* impSIMDIntrinsic(OPCODE opcode,
7822 GenTree* newobjThis,
7823 CORINFO_CLASS_HANDLE clsHnd,
7824 CORINFO_METHOD_HANDLE method,
7825 CORINFO_SIG_INFO* sig,
7828 GenTree* getOp1ForConstructor(OPCODE opcode, GenTree* newobjThis, CORINFO_CLASS_HANDLE clsHnd);
7830 // Whether SIMD vector occupies part of SIMD register.
7831 // SSE2: vector2f/3f are considered sub register SIMD types.
7832 // AVX: vector2f, 3f and 4f are all considered sub register SIMD types.
7833 bool isSubRegisterSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7835 unsigned sizeBytes = 0;
7836 var_types baseType = getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7837 return (baseType == TYP_FLOAT) && (sizeBytes < getSIMDVectorRegisterByteLength());
7840 bool isSubRegisterSIMDType(GenTreeSIMD* simdNode)
7842 return (simdNode->gtSIMDSize < getSIMDVectorRegisterByteLength());
7845 // Get the type for the hardware SIMD vector.
7846 // This is the maximum SIMD type supported for this target.
7847 var_types getSIMDVectorType()
7849 #if defined(_TARGET_XARCH_)
7850 if (getSIMDSupportLevel() == SIMD_AVX2_Supported)
7856 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7859 #elif defined(_TARGET_ARM64_)
7862 assert(!"getSIMDVectorType() unimplemented on target arch");
7867 // Get the size of the SIMD type in bytes
7868 int getSIMDTypeSizeInBytes(CORINFO_CLASS_HANDLE typeHnd)
7870 unsigned sizeBytes = 0;
7871 (void)getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7875 // Get the the number of elements of basetype of SIMD vector given by its size and baseType
7876 static int getSIMDVectorLength(unsigned simdSize, var_types baseType);
7878 // Get the the number of elements of basetype of SIMD vector given by its type handle
7879 int getSIMDVectorLength(CORINFO_CLASS_HANDLE typeHnd);
7881 // Get preferred alignment of SIMD type.
7882 int getSIMDTypeAlignment(var_types simdType);
7884 // Get the number of bytes in a System.Numeric.Vector<T> for the current compilation.
7885 // Note - cannot be used for System.Runtime.Intrinsic
7886 unsigned getSIMDVectorRegisterByteLength()
7888 #if defined(_TARGET_XARCH_)
7889 if (getSIMDSupportLevel() == SIMD_AVX2_Supported)
7891 return YMM_REGSIZE_BYTES;
7895 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7896 return XMM_REGSIZE_BYTES;
7898 #elif defined(_TARGET_ARM64_)
7899 return FP_REGSIZE_BYTES;
7901 assert(!"getSIMDVectorRegisterByteLength() unimplemented on target arch");
7906 // The minimum and maximum possible number of bytes in a SIMD vector.
7908 // maxSIMDStructBytes
7909 // The minimum SIMD size supported by System.Numeric.Vectors or System.Runtime.Intrinsic
7910 // SSE: 16-byte Vector<T> and Vector128<T>
7911 // AVX: 32-byte Vector256<T> (Vector<T> is 16-byte)
7912 // AVX2: 32-byte Vector<T> and Vector256<T>
7913 unsigned int maxSIMDStructBytes()
7915 #if defined(FEATURE_HW_INTRINSICS) && defined(_TARGET_XARCH_)
7916 if (compSupports(InstructionSet_AVX))
7918 return YMM_REGSIZE_BYTES;
7922 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
7923 return XMM_REGSIZE_BYTES;
7926 return getSIMDVectorRegisterByteLength();
7929 unsigned int minSIMDStructBytes()
7931 return emitTypeSize(TYP_SIMD8);
7934 // Returns the codegen type for a given SIMD size.
7935 var_types getSIMDTypeForSize(unsigned size)
7937 var_types simdType = TYP_UNDEF;
7940 simdType = TYP_SIMD8;
7942 else if (size == 12)
7944 simdType = TYP_SIMD12;
7946 else if (size == 16)
7948 simdType = TYP_SIMD16;
7950 else if (size == 32)
7952 simdType = TYP_SIMD32;
7956 noway_assert(!"Unexpected size for SIMD type");
7961 unsigned getSIMDInitTempVarNum()
7963 if (lvaSIMDInitTempVarNum == BAD_VAR_NUM)
7965 lvaSIMDInitTempVarNum = lvaGrabTempWithImplicitUse(false DEBUGARG("SIMDInitTempVar"));
7966 lvaTable[lvaSIMDInitTempVarNum].lvType = getSIMDVectorType();
7968 return lvaSIMDInitTempVarNum;
7971 #endif // FEATURE_SIMD
7974 //------------------------------------------------------------------------
7975 // largestEnregisterableStruct: The size in bytes of the largest struct that can be enregistered.
7977 // Notes: It is not guaranteed that the struct of this size or smaller WILL be a
7978 // candidate for enregistration.
7980 unsigned largestEnregisterableStructSize()
7983 unsigned vectorRegSize = getSIMDVectorRegisterByteLength();
7984 if (vectorRegSize > TARGET_POINTER_SIZE)
7986 return vectorRegSize;
7989 #endif // FEATURE_SIMD
7991 return TARGET_POINTER_SIZE;
7996 // These routines need not be enclosed under FEATURE_SIMD since lvIsSIMDType()
7997 // is defined for both FEATURE_SIMD and !FEATURE_SIMD apropriately. The use
7998 // of this routines also avoids the need of #ifdef FEATURE_SIMD specific code.
8000 // Is this var is of type simd struct?
8001 bool lclVarIsSIMDType(unsigned varNum)
8003 LclVarDsc* varDsc = lvaTable + varNum;
8004 return varDsc->lvIsSIMDType();
8007 // Is this Local node a SIMD local?
8008 bool lclVarIsSIMDType(GenTreeLclVarCommon* lclVarTree)
8010 return lclVarIsSIMDType(lclVarTree->gtLclNum);
8013 // Returns true if the TYP_SIMD locals on stack are aligned at their
8014 // preferred byte boundary specified by getSIMDTypeAlignment().
8016 // As per the Intel manual, the preferred alignment for AVX vectors is 32-bytes. On Amd64,
8017 // RSP/EBP is aligned at 16-bytes, therefore to align SIMD types at 32-bytes we need even
8018 // RSP/EBP to be 32-byte aligned. It is not clear whether additional stack space used in
8019 // aligning stack is worth the benefit and for now will use 16-byte alignment for AVX
8020 // 256-bit vectors with unaligned load/stores to/from memory. On x86, the stack frame
8021 // is aligned to 4 bytes. We need to extend existing support for double (8-byte) alignment
8022 // to 16 or 32 byte alignment for frames with local SIMD vars, if that is determined to be
8025 bool isSIMDTypeLocalAligned(unsigned varNum)
8027 #if defined(FEATURE_SIMD) && ALIGN_SIMD_TYPES
8028 if (lclVarIsSIMDType(varNum) && lvaTable[varNum].lvType != TYP_BYREF)
8031 int off = lvaFrameAddress(varNum, &ebpBased);
8032 // TODO-Cleanup: Can't this use the lvExactSize on the varDsc?
8033 int alignment = getSIMDTypeAlignment(lvaTable[varNum].lvType);
8034 bool isAligned = (alignment <= STACK_ALIGN) && ((off % alignment) == 0);
8037 #endif // FEATURE_SIMD
8042 bool compSupports(InstructionSet isa) const
8044 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
8045 return (opts.compSupportsISA & (1ULL << isa)) != 0;
8051 bool canUseVexEncoding() const
8053 #ifdef _TARGET_XARCH_
8054 return compSupports(InstructionSet_AVX);
8061 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8062 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8066 XX Generic info about the compilation and the method being compiled. XX
8067 XX It is responsible for driving the other phases. XX
8068 XX It is also responsible for all the memory management. XX
8070 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8071 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8075 Compiler* InlineeCompiler; // The Compiler instance for the inlinee
8077 InlineResult* compInlineResult; // The result of importing the inlinee method.
8079 bool compDoAggressiveInlining; // If true, mark every method as CORINFO_FLG_FORCEINLINE
8080 bool compJmpOpUsed; // Does the method do a JMP
8081 bool compLongUsed; // Does the method use TYP_LONG
8082 bool compFloatingPointUsed; // Does the method use TYP_FLOAT or TYP_DOUBLE
8083 bool compTailCallUsed; // Does the method do a tailcall
8084 bool compLocallocUsed; // Does the method use localloc.
8085 bool compLocallocOptimized; // Does the method have an optimized localloc
8086 bool compQmarkUsed; // Does the method use GT_QMARK/GT_COLON
8087 bool compQmarkRationalized; // Is it allowed to use a GT_QMARK/GT_COLON node.
8088 bool compUnsafeCastUsed; // Does the method use LDIND/STIND to cast between scalar/refernce types
8090 // NOTE: These values are only reliable after
8091 // the importing is completely finished.
8094 // State information - which phases have completed?
8095 // These are kept together for easy discoverability
8097 bool bRangeAllowStress;
8098 bool compCodeGenDone;
8099 int64_t compNumStatementLinksTraversed; // # of links traversed while doing debug checks
8100 bool fgNormalizeEHDone; // Has the flowgraph EH normalization phase been done?
8101 size_t compSizeEstimate; // The estimated size of the method as per `gtSetEvalOrder`.
8102 size_t compCycleEstimate; // The estimated cycle count of the method as per `gtSetEvalOrder`
8105 bool fgLocalVarLivenessDone; // Note that this one is used outside of debug.
8106 bool fgLocalVarLivenessChanged;
8108 bool compStackProbePrologDone;
8111 bool compRationalIRForm;
8113 bool compUsesThrowHelper; // There is a call to a THOROW_HELPER for the compiled method.
8115 bool compGeneratingProlog;
8116 bool compGeneratingEpilog;
8117 bool compNeedsGSSecurityCookie; // There is an unsafe buffer (or localloc) on the stack.
8118 // Insert cookie on frame and code to check the cookie, like VC++ -GS.
8119 bool compGSReorderStackLayout; // There is an unsafe buffer on the stack, reorder locals and make local
8120 // copies of susceptible parameters to avoid buffer overrun attacks through locals/params
8121 bool getNeedsGSSecurityCookie() const
8123 return compNeedsGSSecurityCookie;
8125 void setNeedsGSSecurityCookie()
8127 compNeedsGSSecurityCookie = true;
8130 FrameLayoutState lvaDoneFrameLayout; // The highest frame layout state that we've completed. During
8131 // frame layout calculations, this is the level we are currently
8134 //---------------------------- JITing options -----------------------------
8147 JitFlags* jitFlags; // all flags passed from the EE
8148 unsigned compFlags; // method attributes
8150 codeOptimize compCodeOpt; // what type of code optimizations
8155 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
8156 uint64_t compSupportsISA;
8157 void setSupportedISA(InstructionSet isa)
8159 compSupportsISA |= 1ULL << isa;
8163 // optimize maximally and/or favor speed over size?
8165 #define DEFAULT_MIN_OPTS_CODE_SIZE 60000
8166 #define DEFAULT_MIN_OPTS_INSTR_COUNT 20000
8167 #define DEFAULT_MIN_OPTS_BB_COUNT 2000
8168 #define DEFAULT_MIN_OPTS_LV_NUM_COUNT 2000
8169 #define DEFAULT_MIN_OPTS_LV_REF_COUNT 8000
8171 // Maximun number of locals before turning off the inlining
8172 #define MAX_LV_NUM_COUNT_FOR_INLINING 512
8175 unsigned instrCount;
8176 unsigned lvRefCount;
8177 bool compMinOptsIsSet;
8179 bool compMinOptsIsUsed;
8181 inline bool MinOpts()
8183 assert(compMinOptsIsSet);
8184 compMinOptsIsUsed = true;
8187 inline bool IsMinOptsSet()
8189 return compMinOptsIsSet;
8192 inline bool MinOpts()
8196 inline bool IsMinOptsSet()
8198 return compMinOptsIsSet;
8201 inline void SetMinOpts(bool val)
8203 assert(!compMinOptsIsUsed);
8204 assert(!compMinOptsIsSet || (compMinOpts == val));
8206 compMinOptsIsSet = true;
8209 // true if the CLFLG_* for an optimization is set.
8210 inline bool OptEnabled(unsigned optFlag)
8212 return !!(compFlags & optFlag);
8215 #ifdef FEATURE_READYTORUN_COMPILER
8216 inline bool IsReadyToRun()
8218 return jitFlags->IsSet(JitFlags::JIT_FLAG_READYTORUN);
8221 inline bool IsReadyToRun()
8227 // true if we should use the PINVOKE_{BEGIN,END} helpers instead of generating
8228 // PInvoke transitions inline (e.g. when targeting CoreRT).
8229 inline bool ShouldUsePInvokeHelpers()
8231 return jitFlags->IsSet(JitFlags::JIT_FLAG_USE_PINVOKE_HELPERS);
8234 // true if we should use insert the REVERSE_PINVOKE_{ENTER,EXIT} helpers in the method
8236 inline bool IsReversePInvoke()
8238 return jitFlags->IsSet(JitFlags::JIT_FLAG_REVERSE_PINVOKE);
8241 // true if we must generate code compatible with JIT32 quirks
8242 inline bool IsJit32Compat()
8244 #if defined(_TARGET_X86_)
8245 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
8251 // true if we must generate code compatible with Jit64 quirks
8252 inline bool IsJit64Compat()
8254 #if defined(_TARGET_AMD64_)
8255 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
8256 #elif !defined(FEATURE_CORECLR)
8263 bool compScopeInfo; // Generate the LocalVar info ?
8264 bool compDbgCode; // Generate debugger-friendly code?
8265 bool compDbgInfo; // Gather debugging info?
8268 #ifdef PROFILING_SUPPORTED
8269 bool compNoPInvokeInlineCB;
8271 static const bool compNoPInvokeInlineCB;
8275 bool compGcChecks; // Check arguments and return values to ensure they are sane
8278 #if defined(DEBUG) && defined(_TARGET_XARCH_)
8280 bool compStackCheckOnRet; // Check stack pointer on return to ensure it is correct.
8282 #endif // defined(DEBUG) && defined(_TARGET_XARCH_)
8284 #if defined(DEBUG) && defined(_TARGET_X86_)
8286 bool compStackCheckOnCall; // Check stack pointer after call to ensure it is correct. Only for x86.
8288 #endif // defined(DEBUG) && defined(_TARGET_X86_)
8290 bool compNeedSecurityCheck; // This flag really means where or not a security object needs
8291 // to be allocated on the stack.
8292 // It will be set to true in the following cases:
8293 // 1. When the method being compiled has a declarative security
8294 // (i.e. when CORINFO_FLG_NOSECURITYWRAP is reset for the current method).
8295 // This is also the case when we inject a prolog and epilog in the method.
8297 // 2. When the method being compiled has imperative security (i.e. the method
8298 // calls into another method that has CORINFO_FLG_SECURITYCHECK flag set).
8300 // 3. When opts.compDbgEnC is true. (See also Compiler::compCompile).
8302 // When this flag is set, jit will allocate a gc-reference local variable (lvaSecurityObject),
8303 // which gets reported as a GC root to stackwalker.
8304 // (See also ICodeManager::GetAddrOfSecurityObject.)
8306 bool compReloc; // Generate relocs for pointers in code, true for all ngen/prejit codegen
8309 #if defined(_TARGET_XARCH_)
8310 bool compEnablePCRelAddr; // Whether absolute addr be encoded as PC-rel offset by RyuJIT where possible
8314 #ifdef UNIX_AMD64_ABI
8315 // This flag is indicating if there is a need to align the frame.
8316 // On AMD64-Windows, if there are calls, 4 slots for the outgoing ars are allocated, except for
8317 // FastTailCall. This slots makes the frame size non-zero, so alignment logic will be called.
8318 // On AMD64-Unix, there are no such slots. There is a possibility to have calls in the method with frame size of
8319 // 0. The frame alignment logic won't kick in. This flags takes care of the AMD64-Unix case by remembering that
8320 // there are calls and making sure the frame alignment logic is executed.
8321 bool compNeedToAlignFrame;
8322 #endif // UNIX_AMD64_ABI
8324 bool compProcedureSplitting; // Separate cold code from hot code
8326 bool genFPorder; // Preserve FP order (operations are non-commutative)
8327 bool genFPopt; // Can we do frame-pointer-omission optimization?
8328 bool altJit; // True if we are an altjit and are compiling this method
8331 bool optRepeat; // Repeat optimizer phases k times
8335 bool compProcedureSplittingEH; // Separate cold code from hot code for functions with EH
8336 bool dspCode; // Display native code generated
8337 bool dspEHTable; // Display the EH table reported to the VM
8338 bool dspDebugInfo; // Display the Debug info reported to the VM
8339 bool dspInstrs; // Display the IL instructions intermixed with the native code output
8340 bool dspEmit; // Display emitter output
8341 bool dspLines; // Display source-code lines intermixed with native code output
8342 bool dmpHex; // Display raw bytes in hex of native code output
8343 bool varNames; // Display variables names in native code output
8344 bool disAsm; // Display native code as it is generated
8345 bool disAsmSpilled; // Display native code when any register spilling occurs
8346 bool disDiffable; // Makes the Disassembly code 'diff-able'
8347 bool disAsm2; // Display native code after it is generated using external disassembler
8348 bool dspOrder; // Display names of each of the methods that we ngen/jit
8349 bool dspUnwind; // Display the unwind info output
8350 bool dspDiffable; // Makes the Jit Dump 'diff-able' (currently uses same COMPlus_* flag as disDiffable)
8351 bool compLongAddress; // Force using large pseudo instructions for long address
8352 // (IF_LARGEJMP/IF_LARGEADR/IF_LARGLDC)
8353 bool dspGCtbls; // Display the GC tables
8357 bool doLateDisasm; // Run the late disassembler
8358 #endif // LATE_DISASM
8360 #if DUMP_GC_TABLES && !defined(DEBUG) && defined(JIT32_GCENCODER)
8361 // Only the JIT32_GCENCODER implements GC dumping in non-DEBUG code.
8362 #pragma message("NOTE: this non-debug build has GC ptr table dumping always enabled!")
8363 static const bool dspGCtbls = true;
8366 // We need stack probes to guarantee that we won't trigger a stack overflow
8367 // when calling unmanaged code until they get a chance to set up a frame, because
8368 // the EE will have no idea where it is.
8370 // We will only be doing this currently for hosted environments. Unfortunately
8371 // we need to take care of stubs, so potentially, we will have to do the probes
8372 // for any call. We have a plan for not needing for stubs though
8373 bool compNeedStackProbes;
8375 #ifdef PROFILING_SUPPORTED
8376 // Whether to emit Enter/Leave/TailCall hooks using a dummy stub (DummyProfilerELTStub()).
8377 // This option helps make the JIT behave as if it is running under a profiler.
8378 bool compJitELTHookEnabled;
8379 #endif // PROFILING_SUPPORTED
8381 #if FEATURE_TAILCALL_OPT
8382 // Whether opportunistic or implicit tail call optimization is enabled.
8383 bool compTailCallOpt;
8384 // Whether optimization of transforming a recursive tail call into a loop is enabled.
8385 bool compTailCallLoopOpt;
8389 static const bool compUseSoftFP = true;
8390 #else // !ARM_SOFTFP
8391 static const bool compUseSoftFP = false;
8394 GCPollType compGCPollType;
8398 static bool s_pAltJitExcludeAssembliesListInitialized;
8399 static AssemblyNamesList2* s_pAltJitExcludeAssembliesList;
8403 static bool s_pJitDisasmIncludeAssembliesListInitialized;
8404 static AssemblyNamesList2* s_pJitDisasmIncludeAssembliesList;
8409 template <typename T>
8412 return (p == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : p);
8415 template <typename T>
8418 return (o == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : o);
8421 static int dspTreeID(GenTree* tree)
8423 return tree->gtTreeID;
8425 static void printTreeID(GenTree* tree)
8427 if (tree == nullptr)
8433 printf("[%06d]", dspTreeID(tree));
8440 #define STRESS_MODES \
8444 /* "Variations" stress areas which we try to mix up with each other. */ \
8445 /* These should not be exhaustively used as they might */ \
8446 /* hide/trivialize other areas */ \
8449 STRESS_MODE(DBL_ALN) \
8450 STRESS_MODE(LCL_FLDS) \
8451 STRESS_MODE(UNROLL_LOOPS) \
8452 STRESS_MODE(MAKE_CSE) \
8453 STRESS_MODE(LEGACY_INLINE) \
8454 STRESS_MODE(CLONE_EXPR) \
8455 STRESS_MODE(USE_FCOMI) \
8456 STRESS_MODE(USE_CMOV) \
8458 STRESS_MODE(BB_PROFILE) \
8459 STRESS_MODE(OPT_BOOLS_GC) \
8460 STRESS_MODE(REMORPH_TREES) \
8461 STRESS_MODE(64RSLT_MUL) \
8462 STRESS_MODE(DO_WHILE_LOOPS) \
8463 STRESS_MODE(MIN_OPTS) \
8464 STRESS_MODE(REVERSE_FLAG) /* Will set GTF_REVERSE_OPS whenever we can */ \
8465 STRESS_MODE(REVERSE_COMMA) /* Will reverse commas created with gtNewCommaNode */ \
8466 STRESS_MODE(TAILCALL) /* Will make the call as a tailcall whenever legal */ \
8467 STRESS_MODE(CATCH_ARG) /* Will spill catch arg */ \
8468 STRESS_MODE(UNSAFE_BUFFER_CHECKS) \
8469 STRESS_MODE(NULL_OBJECT_CHECK) \
8470 STRESS_MODE(PINVOKE_RESTORE_ESP) \
8471 STRESS_MODE(RANDOM_INLINE) \
8472 STRESS_MODE(SWITCH_CMP_BR_EXPANSION) \
8473 STRESS_MODE(GENERIC_VARN) \
8475 /* After COUNT_VARN, stress level 2 does all of these all the time */ \
8477 STRESS_MODE(COUNT_VARN) \
8479 /* "Check" stress areas that can be exhaustively used if we */ \
8480 /* dont care about performance at all */ \
8482 STRESS_MODE(FORCE_INLINE) /* Treat every method as AggressiveInlining */ \
8483 STRESS_MODE(CHK_FLOW_UPDATE) \
8484 STRESS_MODE(EMITTER) \
8485 STRESS_MODE(CHK_REIMPORT) \
8486 STRESS_MODE(FLATFP) \
8487 STRESS_MODE(GENERIC_CHECK) \
8492 #define STRESS_MODE(mode) STRESS_##mode,
8499 static const LPCWSTR s_compStressModeNames[STRESS_COUNT + 1];
8500 BYTE compActiveStressModes[STRESS_COUNT];
8503 #define MAX_STRESS_WEIGHT 100
8505 bool compStressCompile(compStressArea stressArea, unsigned weightPercentage);
8509 bool compInlineStress()
8511 return compStressCompile(STRESS_LEGACY_INLINE, 50);
8514 bool compRandomInlineStress()
8516 return compStressCompile(STRESS_RANDOM_INLINE, 50);
8521 bool compTailCallStress()
8524 return (JitConfig.TailcallStress() != 0 || compStressCompile(STRESS_TAILCALL, 5));
8530 codeOptimize compCodeOpt()
8533 // Switching between size & speed has measurable throughput impact
8534 // (3.5% on NGen mscorlib when measured). It used to be enabled for
8535 // DEBUG, but should generate identical code between CHK & RET builds,
8536 // so that's not acceptable.
8537 // TODO-Throughput: Figure out what to do about size vs. speed & throughput.
8538 // Investigate the cause of the throughput regression.
8540 return opts.compCodeOpt;
8542 return BLENDED_CODE;
8546 //--------------------- Info about the procedure --------------------------
8550 COMP_HANDLE compCompHnd;
8551 CORINFO_MODULE_HANDLE compScopeHnd;
8552 CORINFO_CLASS_HANDLE compClassHnd;
8553 CORINFO_METHOD_HANDLE compMethodHnd;
8554 CORINFO_METHOD_INFO* compMethodInfo;
8556 BOOL hasCircularClassConstraints;
8557 BOOL hasCircularMethodConstraints;
8559 #if defined(DEBUG) || defined(LATE_DISASM)
8560 const char* compMethodName;
8561 const char* compClassName;
8562 const char* compFullName;
8563 #endif // defined(DEBUG) || defined(LATE_DISASM)
8565 #if defined(DEBUG) || defined(INLINE_DATA)
8566 // Method hash is logcally const, but computed
8568 mutable unsigned compMethodHashPrivate;
8569 unsigned compMethodHash() const;
8570 #endif // defined(DEBUG) || defined(INLINE_DATA)
8572 #ifdef PSEUDORANDOM_NOP_INSERTION
8573 // things for pseudorandom nop insertion
8574 unsigned compChecksum;
8578 // The following holds the FLG_xxxx flags for the method we're compiling.
8581 // The following holds the class attributes for the method we're compiling.
8582 unsigned compClassAttr;
8584 const BYTE* compCode;
8585 IL_OFFSET compILCodeSize; // The IL code size
8586 UNATIVE_OFFSET compNativeCodeSize; // The native code size, after instructions are issued. This
8587 // is less than (compTotalHotCodeSize + compTotalColdCodeSize) only if:
8588 // (1) the code is not hot/cold split, and we issued less code than we expected, or
8589 // (2) the code is hot/cold split, and we issued less code than we expected
8590 // in the cold section (the hot section will always be padded out to compTotalHotCodeSize).
8592 bool compIsStatic : 1; // Is the method static (no 'this' pointer)?
8593 bool compIsVarArgs : 1; // Does the method have varargs parameters?
8594 bool compIsContextful : 1; // contextful method
8595 bool compInitMem : 1; // Is the CORINFO_OPT_INIT_LOCALS bit set in the method info options?
8596 bool compUnwrapContextful : 1; // JIT should unwrap proxies when possible
8597 bool compProfilerCallback : 1; // JIT inserted a profiler Enter callback
8598 bool compPublishStubParam : 1; // EAX captured in prolog will be available through an instrinsic
8599 bool compRetBuffDefStack : 1; // The ret buff argument definitely points into the stack.
8601 var_types compRetType; // Return type of the method as declared in IL
8602 var_types compRetNativeType; // Normalized return type as per target arch ABI
8603 unsigned compILargsCount; // Number of arguments (incl. implicit but not hidden)
8604 unsigned compArgsCount; // Number of arguments (incl. implicit and hidden)
8606 #if FEATURE_FASTTAILCALL
8607 size_t compArgStackSize; // Incoming argument stack size in bytes
8608 #endif // FEATURE_FASTTAILCALL
8610 unsigned compRetBuffArg; // position of hidden return param var (0, 1) (BAD_VAR_NUM means not present);
8611 int compTypeCtxtArg; // position of hidden param for type context for generic code (CORINFO_CALLCONV_PARAMTYPE)
8612 unsigned compThisArg; // position of implicit this pointer param (not to be confused with lvaArg0Var)
8613 unsigned compILlocalsCount; // Number of vars : args + locals (incl. implicit but not hidden)
8614 unsigned compLocalsCount; // Number of vars : args + locals (incl. implicit and hidden)
8615 unsigned compMaxStack;
8616 UNATIVE_OFFSET compTotalHotCodeSize; // Total number of bytes of Hot Code in the method
8617 UNATIVE_OFFSET compTotalColdCodeSize; // Total number of bytes of Cold Code in the method
8619 unsigned compCallUnmanaged; // count of unmanaged calls
8620 unsigned compLvFrameListRoot; // lclNum for the Frame root
8621 unsigned compXcptnsCount; // Number of exception-handling clauses read in the method's IL.
8622 // You should generally use compHndBBtabCount instead: it is the
8623 // current number of EH clauses (after additions like synchronized
8624 // methods and funclets, and removals like unreachable code deletion).
8626 bool compMatchedVM; // true if the VM is "matched": either the JIT is a cross-compiler
8627 // and the VM expects that, or the JIT is a "self-host" compiler
8628 // (e.g., x86 hosted targeting x86) and the VM expects that.
8630 /* The following holds IL scope information about local variables.
8633 unsigned compVarScopesCount;
8634 VarScopeDsc* compVarScopes;
8636 /* The following holds information about instr offsets for
8637 * which we need to report IP-mappings
8640 IL_OFFSET* compStmtOffsets; // sorted
8641 unsigned compStmtOffsetsCount;
8642 ICorDebugInfo::BoundaryTypes compStmtOffsetsImplicit;
8644 #define CPU_X86 0x0100 // The generic X86 CPU
8645 #define CPU_X86_PENTIUM_4 0x0110
8647 #define CPU_X64 0x0200 // The generic x64 CPU
8648 #define CPU_AMD_X64 0x0210 // AMD x64 CPU
8649 #define CPU_INTEL_X64 0x0240 // Intel x64 CPU
8651 #define CPU_ARM 0x0300 // The generic ARM CPU
8652 #define CPU_ARM64 0x0400 // The generic ARM64 CPU
8654 unsigned genCPU; // What CPU are we running on
8657 // Returns true if the method being compiled returns a non-void and non-struct value.
8658 // Note that lvaInitTypeRef() normalizes compRetNativeType for struct returns in a
8659 // single register as per target arch ABI (e.g on Amd64 Windows structs of size 1, 2,
8660 // 4 or 8 gets normalized to TYP_BYTE/TYP_SHORT/TYP_INT/TYP_LONG; On Arm HFA structs).
8661 // Methods returning such structs are considered to return non-struct return value and
8662 // this method returns true in that case.
8663 bool compMethodReturnsNativeScalarType()
8665 return (info.compRetType != TYP_VOID) && !varTypeIsStruct(info.compRetNativeType);
8668 // Returns true if the method being compiled returns RetBuf addr as its return value
8669 bool compMethodReturnsRetBufAddr()
8671 // There are cases where implicit RetBuf argument should be explicitly returned in a register.
8672 // In such cases the return type is changed to TYP_BYREF and appropriate IR is generated.
8674 // 1. Profiler Leave calllback expects the address of retbuf as return value for
8675 // methods with hidden RetBuf argument. impReturnInstruction() when profiler
8676 // callbacks are needed creates GT_RETURN(TYP_BYREF, op1 = Addr of RetBuf) for
8677 // methods with hidden RetBufArg.
8679 // 2. As per the System V ABI, the address of RetBuf needs to be returned by
8680 // methods with hidden RetBufArg in RAX. In such case GT_RETURN is of TYP_BYREF,
8681 // returning the address of RetBuf.
8683 // 3. Windows 64-bit native calling convention also requires the address of RetBuff
8684 // to be returned in RAX.
8685 CLANG_FORMAT_COMMENT_ANCHOR;
8687 #ifdef _TARGET_AMD64_
8688 return (info.compRetBuffArg != BAD_VAR_NUM);
8689 #else // !_TARGET_AMD64_
8690 return (compIsProfilerHookNeeded()) && (info.compRetBuffArg != BAD_VAR_NUM);
8691 #endif // !_TARGET_AMD64_
8694 // Returns true if the method returns a value in more than one return register
8695 // TODO-ARM-Bug: Deal with multi-register genReturnLocaled structs?
8696 // TODO-ARM64: Does this apply for ARM64 too?
8697 bool compMethodReturnsMultiRegRetType()
8699 #if FEATURE_MULTIREG_RET
8700 #if defined(_TARGET_X86_)
8701 // On x86 only 64-bit longs are returned in multiple registers
8702 return varTypeIsLong(info.compRetNativeType);
8703 #else // targets: X64-UNIX, ARM64 or ARM32
8704 // On all other targets that support multireg return values:
8705 // Methods returning a struct in multiple registers have a return value of TYP_STRUCT.
8706 // Such method's compRetNativeType is TYP_STRUCT without a hidden RetBufArg
8707 return varTypeIsStruct(info.compRetNativeType) && (info.compRetBuffArg == BAD_VAR_NUM);
8708 #endif // TARGET_XXX
8710 #else // not FEATURE_MULTIREG_RET
8712 // For this architecture there are no multireg returns
8715 #endif // FEATURE_MULTIREG_RET
8718 #if FEATURE_MULTIREG_ARGS
8719 // Given a GenTree node of TYP_STRUCT that represents a pass by value argument
8720 // return the gcPtr layout for the pointers sized fields
8721 void getStructGcPtrsFromOp(GenTree* op, BYTE* gcPtrsOut);
8722 #endif // FEATURE_MULTIREG_ARGS
8724 // Returns true if the method being compiled returns a value
8725 bool compMethodHasRetVal()
8727 return compMethodReturnsNativeScalarType() || compMethodReturnsRetBufAddr() ||
8728 compMethodReturnsMultiRegRetType();
8733 void compDispLocalVars();
8737 //-------------------------- Global Compiler Data ------------------------------------
8740 static unsigned s_compMethodsCount; // to produce unique label names
8741 unsigned compGenTreeID;
8742 unsigned compBasicBlockID;
8745 BasicBlock* compCurBB; // the current basic block in process
8746 GenTree* compCurStmt; // the current statement in process
8748 unsigned compCurStmtNum; // to give all statements an increasing StmtNum when printing dumps
8751 // The following is used to create the 'method JIT info' block.
8752 size_t compInfoBlkSize;
8753 BYTE* compInfoBlkAddr;
8755 EHblkDsc* compHndBBtab; // array of EH data
8756 unsigned compHndBBtabCount; // element count of used elements in EH data array
8757 unsigned compHndBBtabAllocCount; // element count of allocated elements in EH data array
8759 #if defined(_TARGET_X86_)
8761 //-------------------------------------------------------------------------
8762 // Tracking of region covered by the monitor in synchronized methods
8763 void* syncStartEmitCookie; // the emitter cookie for first instruction after the call to MON_ENTER
8764 void* syncEndEmitCookie; // the emitter cookie for first instruction after the call to MON_EXIT
8766 #endif // !_TARGET_X86_
8768 Phases previousCompletedPhase; // the most recently completed phase
8770 //-------------------------------------------------------------------------
8771 // The following keeps track of how many bytes of local frame space we've
8772 // grabbed so far in the current function, and how many argument bytes we
8773 // need to pop when we return.
8776 unsigned compLclFrameSize; // secObject+lclBlk+locals+temps
8778 // Count of callee-saved regs we pushed in the prolog.
8779 // Does not include EBP for isFramePointerUsed() and double-aligned frames.
8780 // In case of Amd64 this doesn't include float regs saved on stack.
8781 unsigned compCalleeRegsPushed;
8783 #if defined(_TARGET_XARCH_)
8784 // Mask of callee saved float regs on stack.
8785 regMaskTP compCalleeFPRegsSavedMask;
8787 #ifdef _TARGET_AMD64_
8788 // Quirk for VS debug-launch scenario to work:
8789 // Bytes of padding between save-reg area and locals.
8790 #define VSQUIRK_STACK_PAD (2 * REGSIZE_BYTES)
8791 unsigned compVSQuirkStackPaddingNeeded;
8792 bool compQuirkForPPPflag;
8795 unsigned compArgSize; // total size of arguments in bytes (including register args (lvIsRegArg))
8797 unsigned compMapILargNum(unsigned ILargNum); // map accounting for hidden args
8798 unsigned compMapILvarNum(unsigned ILvarNum); // map accounting for hidden args
8799 unsigned compMap2ILvarNum(unsigned varNum); // map accounting for hidden args
8801 //-------------------------------------------------------------------------
8803 static void compStartup(); // One-time initialization
8804 static void compShutdown(); // One-time finalization
8806 void compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo);
8809 static void compDisplayStaticSizes(FILE* fout);
8811 //------------ Some utility functions --------------
8813 void* compGetHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
8814 void** ppIndirection); /* OUT */
8816 // Several JIT/EE interface functions return a CorInfoType, and also return a
8817 // class handle as an out parameter if the type is a value class. Returns the
8818 // size of the type these describe.
8819 unsigned compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd);
8822 // Components used by the compiler may write unit test suites, and
8823 // have them run within this method. They will be run only once per process, and only
8824 // in debug. (Perhaps should be under the control of a COMPlus_ flag.)
8825 // These should fail by asserting.
8826 void compDoComponentUnitTestsOnce();
8829 int compCompile(CORINFO_METHOD_HANDLE methodHnd,
8830 CORINFO_MODULE_HANDLE classPtr,
8831 COMP_HANDLE compHnd,
8832 CORINFO_METHOD_INFO* methodInfo,
8833 void** methodCodePtr,
8834 ULONG* methodCodeSize,
8835 JitFlags* compileFlags);
8836 void compCompileFinish();
8837 int compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
8838 COMP_HANDLE compHnd,
8839 CORINFO_METHOD_INFO* methodInfo,
8840 void** methodCodePtr,
8841 ULONG* methodCodeSize,
8842 JitFlags* compileFlags,
8843 CorInfoInstantiationVerification instVerInfo);
8845 ArenaAllocator* compGetArenaAllocator();
8847 #if MEASURE_MEM_ALLOC
8848 static bool s_dspMemStats; // Display per-phase memory statistics for every function
8849 #endif // MEASURE_MEM_ALLOC
8851 #if LOOP_HOIST_STATS
8852 unsigned m_loopsConsidered;
8853 bool m_curLoopHasHoistedExpression;
8854 unsigned m_loopsWithHoistedExpressions;
8855 unsigned m_totalHoistedExpressions;
8857 void AddLoopHoistStats();
8858 void PrintPerMethodLoopHoistStats();
8860 static CritSecObject s_loopHoistStatsLock; // This lock protects the data structures below.
8861 static unsigned s_loopsConsidered;
8862 static unsigned s_loopsWithHoistedExpressions;
8863 static unsigned s_totalHoistedExpressions;
8865 static void PrintAggregateLoopHoistStats(FILE* f);
8866 #endif // LOOP_HOIST_STATS
8868 bool compIsForImportOnly();
8869 bool compIsForInlining();
8870 bool compDonotInline();
8873 unsigned char compGetJitDefaultFill(); // Get the default fill char value
8874 // we randomize this value when JitStress is enabled
8876 const char* compLocalVarName(unsigned varNum, unsigned offs);
8877 VarName compVarName(regNumber reg, bool isFloatReg = false);
8878 const char* compRegVarName(regNumber reg, bool displayVar = false, bool isFloatReg = false);
8879 const char* compRegNameForSize(regNumber reg, size_t size);
8880 const char* compFPregVarName(unsigned fpReg, bool displayVar = false);
8881 void compDspSrcLinesByNativeIP(UNATIVE_OFFSET curIP);
8882 void compDspSrcLinesByLineNum(unsigned line, bool seek = false);
8885 //-------------------------------------------------------------------------
8887 struct VarScopeListNode
8890 VarScopeListNode* next;
8891 static VarScopeListNode* Create(VarScopeDsc* value, CompAllocator alloc)
8893 VarScopeListNode* node = new (alloc) VarScopeListNode;
8895 node->next = nullptr;
8900 struct VarScopeMapInfo
8902 VarScopeListNode* head;
8903 VarScopeListNode* tail;
8904 static VarScopeMapInfo* Create(VarScopeListNode* node, CompAllocator alloc)
8906 VarScopeMapInfo* info = new (alloc) VarScopeMapInfo;
8913 // Max value of scope count for which we would use linear search; for larger values we would use hashtable lookup.
8914 static const unsigned MAX_LINEAR_FIND_LCL_SCOPELIST = 32;
8916 typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, VarScopeMapInfo*> VarNumToScopeDscMap;
8918 // Map to keep variables' scope indexed by varNum containing it's scope dscs at the index.
8919 VarNumToScopeDscMap* compVarScopeMap;
8921 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned lifeBeg, unsigned lifeEnd);
8923 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned offs);
8925 VarScopeDsc* compFindLocalVarLinear(unsigned varNum, unsigned offs);
8927 void compInitVarScopeMap();
8929 VarScopeDsc** compEnterScopeList; // List has the offsets where variables
8930 // enter scope, sorted by instr offset
8931 unsigned compNextEnterScope;
8933 VarScopeDsc** compExitScopeList; // List has the offsets where variables
8934 // go out of scope, sorted by instr offset
8935 unsigned compNextExitScope;
8937 void compInitScopeLists();
8939 void compResetScopeLists();
8941 VarScopeDsc* compGetNextEnterScope(unsigned offs, bool scan = false);
8943 VarScopeDsc* compGetNextExitScope(unsigned offs, bool scan = false);
8945 void compProcessScopesUntil(unsigned offset,
8947 void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*),
8948 void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*));
8951 void compDispScopeLists();
8954 bool compIsProfilerHookNeeded();
8956 //-------------------------------------------------------------------------
8957 /* Statistical Data Gathering */
8959 void compJitStats(); // call this function and enable
8960 // various ifdef's below for statistical data
8963 void compCallArgStats();
8964 static void compDispCallArgStats(FILE* fout);
8967 //-------------------------------------------------------------------------
8974 ArenaAllocator* compArenaAllocator;
8977 void compFunctionTraceStart();
8978 void compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, bool isNYI);
8981 size_t compMaxUncheckedOffsetForNullObject;
8983 void compInitOptions(JitFlags* compileFlags);
8985 void compSetProcessor();
8986 void compInitDebuggingInfo();
8987 void compSetOptimizationLevel();
8988 #ifdef _TARGET_ARMARCH_
8989 bool compRsvdRegCheck(FrameLayoutState curState);
8991 void compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags);
8993 // Clear annotations produced during optimizations; to be used between iterations when repeating opts.
8994 void ResetOptAnnotations();
8996 // Regenerate loop descriptors; to be used between iterations when repeating opts.
8997 void RecomputeLoopInfo();
8999 #ifdef PROFILING_SUPPORTED
9000 // Data required for generating profiler Enter/Leave/TailCall hooks
9002 bool compProfilerHookNeeded; // Whether profiler Enter/Leave/TailCall hook needs to be generated for the method
9003 void* compProfilerMethHnd; // Profiler handle of the method being compiled. Passed as param to ELT callbacks
9004 bool compProfilerMethHndIndirected; // Whether compProfilerHandle is pointer to the handle or is an actual handle
9007 #ifdef _TARGET_AMD64_
9008 bool compQuirkForPPP(); // Check if this method should be Quirked for the PPP issue
9011 // Assumes called as part of process shutdown; does any compiler-specific work associated with that.
9012 static void ProcessShutdownWork(ICorStaticInfo* statInfo);
9014 CompAllocator getAllocator(CompMemKind cmk = CMK_Generic)
9016 return CompAllocator(compArenaAllocator, cmk);
9019 CompAllocator getAllocatorGC()
9021 return getAllocator(CMK_GC);
9024 CompAllocator getAllocatorLoopHoist()
9026 return getAllocator(CMK_LoopHoist);
9030 CompAllocator getAllocatorDebugOnly()
9032 return getAllocator(CMK_DebugOnly);
9037 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9038 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9042 XX Checks for type compatibility and merges types XX
9044 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9045 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9049 // Set to TRUE if verification cannot be skipped for this method
9050 // If we detect unverifiable code, we will lazily check
9051 // canSkipMethodVerification() to see if verification is REALLY needed.
9052 BOOL tiVerificationNeeded;
9054 // It it initially TRUE, and it gets set to FALSE if we run into unverifiable code
9055 // Note that this is valid only if tiVerificationNeeded was ever TRUE.
9056 BOOL tiIsVerifiableCode;
9058 // Set to TRUE if runtime callout is needed for this method
9059 BOOL tiRuntimeCalloutNeeded;
9061 // Set to TRUE if security prolog/epilog callout is needed for this method
9062 // Note: This flag is different than compNeedSecurityCheck.
9063 // compNeedSecurityCheck means whether or not a security object needs
9064 // to be allocated on the stack, which is currently true for EnC as well.
9065 // tiSecurityCalloutNeeded means whether or not security callouts need
9066 // to be inserted in the jitted code.
9067 BOOL tiSecurityCalloutNeeded;
9069 // Returns TRUE if child is equal to or a subtype of parent for merge purposes
9070 // This support is necessary to suport attributes that are not described in
9071 // for example, signatures. For example, the permanent home byref (byref that
9072 // points to the gc heap), isn't a property of method signatures, therefore,
9073 // it is safe to have mismatches here (that tiCompatibleWith will not flag),
9074 // but when deciding if we need to reimport a block, we need to take these
9076 BOOL tiMergeCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
9078 // Returns TRUE if child is equal to or a subtype of parent.
9079 // normalisedForStack indicates that both types are normalised for the stack
9080 BOOL tiCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
9082 // Merges pDest and pSrc. Returns FALSE if merge is undefined.
9083 // *pDest is modified to represent the merged type. Sets "*changed" to true
9084 // if this changes "*pDest".
9085 BOOL tiMergeToCommonParent(typeInfo* pDest, const typeInfo* pSrc, bool* changed) const;
9088 // <BUGNUM> VSW 471305
9089 // IJW allows assigning REF to BYREF. The following allows us to temporarily
9090 // bypass the assert check in gcMarkRegSetGCref and gcMarkRegSetByref
9091 // We use a "short" as we need to push/pop this scope.
9093 short compRegSetCheckLevel;
9097 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9098 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9100 XX IL verification stuff XX
9103 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9104 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9108 // The following is used to track liveness of local variables, initialization
9109 // of valueclass constructors, and type safe use of IL instructions.
9111 // dynamic state info needed for verification
9112 EntryState verCurrentState;
9114 // this ptr of object type .ctors are considered intited only after
9115 // the base class ctor is called, or an alternate ctor is called.
9116 // An uninited this ptr can be used to access fields, but cannot
9117 // be used to call a member function.
9118 BOOL verTrackObjCtorInitState;
9120 void verInitBBEntryState(BasicBlock* block, EntryState* currentState);
9122 // Requires that "tis" is not TIS_Bottom -- it's a definite init/uninit state.
9123 void verSetThisInit(BasicBlock* block, ThisInitState tis);
9124 void verInitCurrentState();
9125 void verResetCurrentState(BasicBlock* block, EntryState* currentState);
9127 // Merges the current verification state into the entry state of "block", return FALSE if that merge fails,
9128 // TRUE if it succeeds. Further sets "*changed" to true if this changes the entry state of "block".
9129 BOOL verMergeEntryStates(BasicBlock* block, bool* changed);
9131 void verConvertBBToThrowVerificationException(BasicBlock* block DEBUGARG(bool logMsg));
9132 void verHandleVerificationFailure(BasicBlock* block DEBUGARG(bool logMsg));
9133 typeInfo verMakeTypeInfo(CORINFO_CLASS_HANDLE clsHnd,
9134 bool bashStructToRef = false); // converts from jit type representation to typeInfo
9135 typeInfo verMakeTypeInfo(CorInfoType ciType,
9136 CORINFO_CLASS_HANDLE clsHnd); // converts from jit type representation to typeInfo
9137 BOOL verIsSDArray(typeInfo ti);
9138 typeInfo verGetArrayElemType(typeInfo ti);
9140 typeInfo verParseArgSigToTypeInfo(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args);
9141 BOOL verNeedsVerification();
9142 BOOL verIsByRefLike(const typeInfo& ti);
9143 BOOL verIsSafeToReturnByRef(const typeInfo& ti);
9145 // generic type variables range over types that satisfy IsBoxable
9146 BOOL verIsBoxable(const typeInfo& ti);
9148 void DECLSPEC_NORETURN verRaiseVerifyException(INDEBUG(const char* reason) DEBUGARG(const char* file)
9149 DEBUGARG(unsigned line));
9150 void verRaiseVerifyExceptionIfNeeded(INDEBUG(const char* reason) DEBUGARG(const char* file)
9151 DEBUGARG(unsigned line));
9152 bool verCheckTailCallConstraint(OPCODE opcode,
9153 CORINFO_RESOLVED_TOKEN* pResolvedToken,
9154 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call
9155 // on a type parameter?
9156 bool speculative // If true, won't throw if verificatoin fails. Instead it will
9157 // return false to the caller.
9158 // If false, it will throw.
9160 bool verIsBoxedValueType(typeInfo ti);
9162 void verVerifyCall(OPCODE opcode,
9163 CORINFO_RESOLVED_TOKEN* pResolvedToken,
9164 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
9166 bool readonlyCall, // is this a "readonly." call?
9167 const BYTE* delegateCreateStart,
9168 const BYTE* codeAddr,
9169 CORINFO_CALL_INFO* callInfo DEBUGARG(const char* methodName));
9171 BOOL verCheckDelegateCreation(const BYTE* delegateCreateStart, const BYTE* codeAddr, mdMemberRef& targetMemberRef);
9173 typeInfo verVerifySTIND(const typeInfo& ptr, const typeInfo& value, const typeInfo& instrType);
9174 typeInfo verVerifyLDIND(const typeInfo& ptr, const typeInfo& instrType);
9175 void verVerifyField(CORINFO_RESOLVED_TOKEN* pResolvedToken,
9176 const CORINFO_FIELD_INFO& fieldInfo,
9177 const typeInfo* tiThis,
9179 BOOL allowPlainStructAsThis = FALSE);
9180 void verVerifyCond(const typeInfo& tiOp1, const typeInfo& tiOp2, unsigned opcode);
9181 void verVerifyThisPtrInitialised();
9182 BOOL verIsCallToInitThisPtr(CORINFO_CLASS_HANDLE context, CORINFO_CLASS_HANDLE target);
9186 // One line log function. Default level is 0. Increasing it gives you
9187 // more log information
9189 // levels are currently unused: #define JITDUMP(level,...) ();
9190 void JitLogEE(unsigned level, const char* fmt, ...);
9192 bool compDebugBreak;
9194 bool compJitHaltMethod();
9199 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9200 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9202 XX GS Security checks for unsafe buffers XX
9204 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9205 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9208 struct ShadowParamVarInfo
9210 FixedBitVect* assignGroup; // the closure set of variables whose values depend on each other
9211 unsigned shadowCopy; // Lcl var num, valid only if not set to NO_SHADOW_COPY
9213 static bool mayNeedShadowCopy(LclVarDsc* varDsc)
9215 #if defined(_TARGET_AMD64_)
9216 // GS cookie logic to create shadow slots, create trees to copy reg args to shadow
9217 // slots and update all trees to refer to shadow slots is done immediately after
9218 // fgMorph(). Lsra could potentially mark a param as DoNotEnregister after JIT determines
9219 // not to shadow a parameter. Also, LSRA could potentially spill a param which is passed
9220 // in register. Therefore, conservatively all params may need a shadow copy. Note that
9221 // GS cookie logic further checks whether the param is a ptr or an unsafe buffer before
9222 // creating a shadow slot even though this routine returns true.
9224 // TODO-AMD64-CQ: Revisit this conservative approach as it could create more shadow slots than
9225 // required. There are two cases under which a reg arg could potentially be used from its
9227 // a) LSRA marks it as DoNotEnregister (see LinearScan::identifyCandidates())
9228 // b) LSRA spills it
9230 // Possible solution to address case (a)
9231 // - The conditions under which LSRA marks a varDsc as DoNotEnregister could be checked
9232 // in this routine. Note that live out of exception handler is something we may not be
9233 // able to do it here since GS cookie logic is invoked ahead of liveness computation.
9234 // Therefore, for methods with exception handling and need GS cookie check we might have
9235 // to take conservative approach.
9237 // Possible solution to address case (b)
9238 // - Whenver a parameter passed in an argument register needs to be spilled by LSRA, we
9239 // create a new spill temp if the method needs GS cookie check.
9240 return varDsc->lvIsParam;
9241 #else // !defined(_TARGET_AMD64_)
9242 return varDsc->lvIsParam && !varDsc->lvIsRegArg;
9249 printf("assignGroup [%p]; shadowCopy: [%d];\n", assignGroup, shadowCopy);
9254 GSCookie* gsGlobalSecurityCookieAddr; // Address of global cookie for unsafe buffer checks
9255 GSCookie gsGlobalSecurityCookieVal; // Value of global cookie if addr is NULL
9256 ShadowParamVarInfo* gsShadowVarInfo; // Table used by shadow param analysis code
9258 void gsGSChecksInitCookie(); // Grabs cookie variable
9259 void gsCopyShadowParams(); // Identify vulnerable params and create dhadow copies
9260 bool gsFindVulnerableParams(); // Shadow param analysis code
9261 void gsParamsToShadows(); // Insert copy code and replave param uses by shadow
9263 static fgWalkPreFn gsMarkPtrsAndAssignGroups; // Shadow param analysis tree-walk
9264 static fgWalkPreFn gsReplaceShadowParams; // Shadow param replacement tree-walk
9266 #define DEFAULT_MAX_INLINE_SIZE 100 // Methods with > DEFAULT_MAX_INLINE_SIZE IL bytes will never be inlined.
9267 // This can be overwritten by setting complus_JITInlineSize env variable.
9269 #define DEFAULT_MAX_INLINE_DEPTH 20 // Methods at more than this level deep will not be inlined
9271 #define DEFAULT_MAX_LOCALLOC_TO_LOCAL_SIZE 32 // fixed locallocs of this size or smaller will convert to local buffers
9274 #ifdef FEATURE_JIT_METHOD_PERF
9275 JitTimer* pCompJitTimer; // Timer data structure (by phases) for current compilation.
9276 static CompTimeSummaryInfo s_compJitTimerSummary; // Summary of the Timer information for the whole run.
9278 static LPCWSTR JitTimeLogCsv(); // Retrieve the file name for CSV from ConfigDWORD.
9279 static LPCWSTR compJitTimeLogFilename; // If a log file for JIT time is desired, filename to write it to.
9281 inline void EndPhase(Phases phase); // Indicate the end of the given phase.
9283 #if MEASURE_CLRAPI_CALLS
9284 // Thin wrappers that call into JitTimer (if present).
9285 inline void CLRApiCallEnter(unsigned apix);
9286 inline void CLRApiCallLeave(unsigned apix);
9289 inline void CLR_API_Enter(API_ICorJitInfo_Names ename);
9290 inline void CLR_API_Leave(API_ICorJitInfo_Names ename);
9295 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9296 // These variables are associated with maintaining SQM data about compile time.
9297 unsigned __int64 m_compCyclesAtEndOfInlining; // The thread-virtualized cycle count at the end of the inlining phase
9298 // in the current compilation.
9299 unsigned __int64 m_compCycles; // Net cycle count for current compilation
9300 DWORD m_compTickCountAtEndOfInlining; // The result of GetTickCount() (# ms since some epoch marker) at the end of
9301 // the inlining phase in the current compilation.
9302 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9304 // Records the SQM-relevant (cycles and tick count). Should be called after inlining is complete.
9305 // (We do this after inlining because this marks the last point at which the JIT is likely to cause
9306 // type-loading and class initialization).
9307 void RecordStateAtEndOfInlining();
9308 // Assumes being called at the end of compilation. Update the SQM state.
9309 void RecordStateAtEndOfCompilation();
9311 #ifdef FEATURE_CLRSQM
9312 // Does anything SQM related necessary at process shutdown time.
9313 static void ProcessShutdownSQMWork(ICorStaticInfo* statInfo);
9314 #endif // FEATURE_CLRSQM
9317 #if FUNC_INFO_LOGGING
9318 static LPCWSTR compJitFuncInfoFilename; // If a log file for per-function information is required, this is the
9319 // filename to write it to.
9320 static FILE* compJitFuncInfoFile; // And this is the actual FILE* to write to.
9321 #endif // FUNC_INFO_LOGGING
9323 Compiler* prevCompiler; // Previous compiler on stack for TLS Compiler* linked list for reentrant compilers.
9325 // Is the compilation in a full trust context?
9326 bool compIsFullTrust();
9329 void RecordNowayAssert(const char* filename, unsigned line, const char* condStr);
9330 #endif // MEASURE_NOWAY
9332 #ifndef FEATURE_TRACELOGGING
9333 // Should we actually fire the noway assert body and the exception handler?
9334 bool compShouldThrowOnNoway();
9335 #else // FEATURE_TRACELOGGING
9336 // Should we actually fire the noway assert body and the exception handler?
9337 bool compShouldThrowOnNoway(const char* filename, unsigned line);
9339 // Telemetry instance to use per method compilation.
9340 JitTelemetry compJitTelemetry;
9342 // Get common parameters that have to be logged with most telemetry data.
9343 void compGetTelemetryDefaults(const char** assemblyName,
9344 const char** scopeName,
9345 const char** methodName,
9346 unsigned* methodHash);
9347 #endif // !FEATURE_TRACELOGGING
9351 NodeToTestDataMap* m_nodeTestData;
9353 static const unsigned FIRST_LOOP_HOIST_CSE_CLASS = 1000;
9354 unsigned m_loopHoistCSEClass; // LoopHoist test annotations turn into CSE requirements; we
9355 // label them with CSE Class #'s starting at FIRST_LOOP_HOIST_CSE_CLASS.
9356 // Current kept in this.
9358 NodeToTestDataMap* GetNodeTestData()
9360 Compiler* compRoot = impInlineRoot();
9361 if (compRoot->m_nodeTestData == nullptr)
9363 compRoot->m_nodeTestData = new (getAllocatorDebugOnly()) NodeToTestDataMap(getAllocatorDebugOnly());
9365 return compRoot->m_nodeTestData;
9368 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, int> NodeToIntMap;
9370 // Returns the set (i.e., the domain of the result map) of nodes that are keys in m_nodeTestData, and
9371 // currently occur in the AST graph.
9372 NodeToIntMap* FindReachableNodesInNodeTestData();
9374 // Node "from" is being eliminated, and being replaced by node "to". If "from" had any associated
9375 // test data, associate that data with "to".
9376 void TransferTestDataToNode(GenTree* from, GenTree* to);
9378 // Requires that "to" is a clone of "from". If any nodes in the "from" tree
9379 // have annotations, attach similar annotations to the corresponding nodes in "to".
9380 void CopyTestDataToCloneTree(GenTree* from, GenTree* to);
9382 // These are the methods that test that the various conditions implied by the
9383 // test attributes are satisfied.
9384 void JitTestCheckSSA(); // SSA builder tests.
9385 void JitTestCheckVN(); // Value numbering tests.
9388 // The "FieldSeqStore", for canonicalizing field sequences. See the definition of FieldSeqStore for
9390 FieldSeqStore* m_fieldSeqStore;
9392 FieldSeqStore* GetFieldSeqStore()
9394 Compiler* compRoot = impInlineRoot();
9395 if (compRoot->m_fieldSeqStore == nullptr)
9397 // Create a CompAllocator that labels sub-structure with CMK_FieldSeqStore, and use that for allocation.
9398 CompAllocator ialloc(getAllocator(CMK_FieldSeqStore));
9399 compRoot->m_fieldSeqStore = new (ialloc) FieldSeqStore(ialloc);
9401 return compRoot->m_fieldSeqStore;
9404 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, FieldSeqNode*> NodeToFieldSeqMap;
9406 // Some nodes of "TYP_BYREF" or "TYP_I_IMPL" actually represent the address of a field within a struct, but since
9407 // the offset of the field is zero, there's no "GT_ADD" node. We normally attach a field sequence to the constant
9408 // that is added, but what do we do when that constant is zero, and is thus not present? We use this mechanism to
9409 // attach the field sequence directly to the address node.
9410 NodeToFieldSeqMap* m_zeroOffsetFieldMap;
9412 NodeToFieldSeqMap* GetZeroOffsetFieldMap()
9414 // Don't need to worry about inlining here
9415 if (m_zeroOffsetFieldMap == nullptr)
9417 // Create a CompAllocator that labels sub-structure with CMK_ZeroOffsetFieldMap, and use that for
9419 CompAllocator ialloc(getAllocator(CMK_ZeroOffsetFieldMap));
9420 m_zeroOffsetFieldMap = new (ialloc) NodeToFieldSeqMap(ialloc);
9422 return m_zeroOffsetFieldMap;
9425 // Requires that "op1" is a node of type "TYP_BYREF" or "TYP_I_IMPL". We are dereferencing this with the fields in
9426 // "fieldSeq", whose offsets are required all to be zero. Ensures that any field sequence annotation currently on
9427 // "op1" or its components is augmented by appending "fieldSeq". In practice, if "op1" is a GT_LCL_FLD, it has
9428 // a field sequence as a member; otherwise, it may be the addition of an a byref and a constant, where the const
9429 // has a field sequence -- in this case "fieldSeq" is appended to that of the constant; otherwise, we
9430 // record the the field sequence using the ZeroOffsetFieldMap described above.
9432 // One exception above is that "op1" is a node of type "TYP_REF" where "op1" is a GT_LCL_VAR.
9433 // This happens when System.Object vtable pointer is a regular field at offset 0 in System.Private.CoreLib in
9434 // CoreRT. Such case is handled same as the default case.
9435 void fgAddFieldSeqForZeroOffset(GenTree* op1, FieldSeqNode* fieldSeq);
9437 typedef JitHashTable<const GenTree*, JitPtrKeyFuncs<GenTree>, ArrayInfo> NodeToArrayInfoMap;
9438 NodeToArrayInfoMap* m_arrayInfoMap;
9440 NodeToArrayInfoMap* GetArrayInfoMap()
9442 Compiler* compRoot = impInlineRoot();
9443 if (compRoot->m_arrayInfoMap == nullptr)
9445 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9446 CompAllocator ialloc(getAllocator(CMK_ArrayInfoMap));
9447 compRoot->m_arrayInfoMap = new (ialloc) NodeToArrayInfoMap(ialloc);
9449 return compRoot->m_arrayInfoMap;
9452 //-----------------------------------------------------------------------------------------------------------------
9453 // Compiler::TryGetArrayInfo:
9454 // Given an indirection node, checks to see whether or not that indirection represents an array access, and
9455 // if so returns information about the array.
9458 // indir - The `GT_IND` node.
9459 // arrayInfo (out) - Information about the accessed array if this function returns true. Undefined otherwise.
9462 // True if the `GT_IND` node represents an array access; false otherwise.
9463 inline bool TryGetArrayInfo(GenTreeIndir* indir, ArrayInfo* arrayInfo)
9465 if ((indir->gtFlags & GTF_IND_ARR_INDEX) == 0)
9470 if (indir->gtOp1->OperIs(GT_INDEX_ADDR))
9472 GenTreeIndexAddr* const indexAddr = indir->gtOp1->AsIndexAddr();
9473 *arrayInfo = ArrayInfo(indexAddr->gtElemType, indexAddr->gtElemSize, indexAddr->gtElemOffset,
9474 indexAddr->gtStructElemClass);
9478 bool found = GetArrayInfoMap()->Lookup(indir, arrayInfo);
9483 NodeToUnsignedMap* m_memorySsaMap[MemoryKindCount];
9485 // In some cases, we want to assign intermediate SSA #'s to memory states, and know what nodes create those memory
9486 // states. (We do this for try blocks, where, if the try block doesn't do a call that loses track of the memory
9487 // state, all the possible memory states are possible initial states of the corresponding catch block(s).)
9488 NodeToUnsignedMap* GetMemorySsaMap(MemoryKind memoryKind)
9490 if (memoryKind == GcHeap && byrefStatesMatchGcHeapStates)
9492 // Use the same map for GCHeap and ByrefExposed when their states match.
9493 memoryKind = ByrefExposed;
9496 assert(memoryKind < MemoryKindCount);
9497 Compiler* compRoot = impInlineRoot();
9498 if (compRoot->m_memorySsaMap[memoryKind] == nullptr)
9500 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9501 CompAllocator ialloc(getAllocator(CMK_ArrayInfoMap));
9502 compRoot->m_memorySsaMap[memoryKind] = new (ialloc) NodeToUnsignedMap(ialloc);
9504 return compRoot->m_memorySsaMap[memoryKind];
9507 // The Refany type is the only struct type whose structure is implicitly assumed by IL. We need its fields.
9508 CORINFO_CLASS_HANDLE m_refAnyClass;
9509 CORINFO_FIELD_HANDLE GetRefanyDataField()
9511 if (m_refAnyClass == nullptr)
9513 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9515 return info.compCompHnd->getFieldInClass(m_refAnyClass, 0);
9517 CORINFO_FIELD_HANDLE GetRefanyTypeField()
9519 if (m_refAnyClass == nullptr)
9521 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9523 return info.compCompHnd->getFieldInClass(m_refAnyClass, 1);
9527 static BitSetSupport::BitSetOpCounter m_varsetOpCounter;
9529 #if ALLVARSET_COUNTOPS
9530 static BitSetSupport::BitSetOpCounter m_allvarsetOpCounter;
9533 static HelperCallProperties s_helperCallProperties;
9535 #ifdef UNIX_AMD64_ABI
9536 static var_types GetTypeFromClassificationAndSizes(SystemVClassificationType classType, int size);
9537 static var_types GetEightByteType(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9540 static void GetStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9543 unsigned __int8* offset0,
9544 unsigned __int8* offset1);
9546 void GetStructTypeOffset(CORINFO_CLASS_HANDLE typeHnd,
9549 unsigned __int8* offset0,
9550 unsigned __int8* offset1);
9552 #endif // defined(UNIX_AMD64_ABI)
9554 void fgMorphMultiregStructArgs(GenTreeCall* call);
9555 GenTree* fgMorphMultiregStructArg(GenTree* arg, fgArgTabEntry* fgEntryPtr);
9557 bool killGCRefs(GenTree* tree);
9559 }; // end of class Compiler
9561 // LclVarDsc constructor. Uses Compiler, so must come after Compiler definition.
9562 inline LclVarDsc::LclVarDsc()
9563 : // Initialize the ArgRegs to REG_STK.
9564 // The morph will do the right thing to change
9565 // to the right register if passed in register.
9568 #if FEATURE_MULTIREG_ARGS
9569 _lvOtherArgReg(REG_STK)
9571 #endif // FEATURE_MULTIREG_ARGS
9573 lvRefBlks(BlockSetOps::UninitVal())
9575 #endif // ASSERTION_PROP
9580 //---------------------------------------------------------------------------------------------------------------------
9581 // GenTreeVisitor: a flexible tree walker implemented using the curiosly-recurring-template pattern.
9583 // This class implements a configurable walker for IR trees. There are five configuration options (defaults values are
9584 // shown in parentheses):
9586 // - ComputeStack (false): when true, the walker will push each node onto the `m_ancestors` stack. "Ancestors" is a bit
9587 // of a misnomer, as the first entry will always be the current node.
9589 // - DoPreOrder (false): when true, the walker will invoke `TVisitor::PreOrderVisit` with the current node as an
9590 // argument before visiting the node's operands.
9592 // - DoPostOrder (false): when true, the walker will invoke `TVisitor::PostOrderVisit` with the current node as an
9593 // argument after visiting the node's operands.
9595 // - DoLclVarsOnly (false): when true, the walker will only invoke `TVisitor::PreOrderVisit` for lclVar nodes.
9596 // `DoPreOrder` must be true if this option is true.
9598 // - UseExecutionOrder (false): when true, then walker will visit a node's operands in execution order (e.g. if a
9599 // binary operator has the `GTF_REVERSE_OPS` flag set, the second operand will be
9600 // visited before the first).
9602 // At least one of `DoPreOrder` and `DoPostOrder` must be specified.
9604 // A simple pre-order visitor might look something like the following:
9606 // class CountingVisitor final : public GenTreeVisitor<CountingVisitor>
9611 // DoPreOrder = true
9614 // unsigned m_count;
9616 // CountingVisitor(Compiler* compiler)
9617 // : GenTreeVisitor<CountingVisitor>(compiler), m_count(0)
9621 // Compiler::fgWalkResult PreOrderVisit(GenTree* node)
9627 // This visitor would then be used like so:
9629 // CountingVisitor countingVisitor(compiler);
9630 // countingVisitor.WalkTree(root);
9632 template <typename TVisitor>
9633 class GenTreeVisitor
9636 typedef Compiler::fgWalkResult fgWalkResult;
9640 ComputeStack = false,
9642 DoPostOrder = false,
9643 DoLclVarsOnly = false,
9644 UseExecutionOrder = false,
9647 Compiler* m_compiler;
9648 ArrayStack<GenTree*> m_ancestors;
9650 GenTreeVisitor(Compiler* compiler) : m_compiler(compiler), m_ancestors(compiler->getAllocator(CMK_ArrayStack))
9652 assert(compiler != nullptr);
9654 static_assert_no_msg(TVisitor::DoPreOrder || TVisitor::DoPostOrder);
9655 static_assert_no_msg(!TVisitor::DoLclVarsOnly || TVisitor::DoPreOrder);
9658 fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
9660 return fgWalkResult::WALK_CONTINUE;
9663 fgWalkResult PostOrderVisit(GenTree** use, GenTree* user)
9665 return fgWalkResult::WALK_CONTINUE;
9669 fgWalkResult WalkTree(GenTree** use, GenTree* user)
9671 assert(use != nullptr);
9673 GenTree* node = *use;
9675 if (TVisitor::ComputeStack)
9677 m_ancestors.Push(node);
9680 fgWalkResult result = fgWalkResult::WALK_CONTINUE;
9681 if (TVisitor::DoPreOrder && !TVisitor::DoLclVarsOnly)
9683 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9684 if (result == fgWalkResult::WALK_ABORT)
9690 if ((node == nullptr) || (result == fgWalkResult::WALK_SKIP_SUBTREES))
9696 switch (node->OperGet())
9701 case GT_LCL_VAR_ADDR:
9702 case GT_LCL_FLD_ADDR:
9703 if (TVisitor::DoLclVarsOnly)
9705 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9706 if (result == fgWalkResult::WALK_ABORT)
9722 case GT_MEMORYBARRIER:
9727 case GT_START_NONGC:
9729 #if !FEATURE_EH_FUNCLETS
9731 #endif // !FEATURE_EH_FUNCLETS
9736 case GT_CLS_VAR_ADDR:
9740 case GT_PINVOKE_PROLOG:
9741 case GT_PINVOKE_EPILOG:
9745 // Lclvar unary operators
9746 case GT_STORE_LCL_VAR:
9747 case GT_STORE_LCL_FLD:
9748 if (TVisitor::DoLclVarsOnly)
9750 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9751 if (result == fgWalkResult::WALK_ABORT)
9758 // Standard unary operators
9787 case GT_RUNTIMELOOKUP:
9789 GenTreeUnOp* const unOp = node->AsUnOp();
9790 if (unOp->gtOp1 != nullptr)
9792 result = WalkTree(&unOp->gtOp1, unOp);
9793 if (result == fgWalkResult::WALK_ABORT)
9804 GenTreeCmpXchg* const cmpXchg = node->AsCmpXchg();
9806 result = WalkTree(&cmpXchg->gtOpLocation, cmpXchg);
9807 if (result == fgWalkResult::WALK_ABORT)
9811 result = WalkTree(&cmpXchg->gtOpValue, cmpXchg);
9812 if (result == fgWalkResult::WALK_ABORT)
9816 result = WalkTree(&cmpXchg->gtOpComparand, cmpXchg);
9817 if (result == fgWalkResult::WALK_ABORT)
9824 case GT_ARR_BOUNDS_CHECK:
9827 #endif // FEATURE_SIMD
9828 #ifdef FEATURE_HW_INTRINSICS
9829 case GT_HW_INTRINSIC_CHK:
9830 #endif // FEATURE_HW_INTRINSICS
9832 GenTreeBoundsChk* const boundsChk = node->AsBoundsChk();
9834 result = WalkTree(&boundsChk->gtIndex, boundsChk);
9835 if (result == fgWalkResult::WALK_ABORT)
9839 result = WalkTree(&boundsChk->gtArrLen, boundsChk);
9840 if (result == fgWalkResult::WALK_ABORT)
9849 GenTreeField* const field = node->AsField();
9851 if (field->gtFldObj != nullptr)
9853 result = WalkTree(&field->gtFldObj, field);
9854 if (result == fgWalkResult::WALK_ABORT)
9864 GenTreeArrElem* const arrElem = node->AsArrElem();
9866 result = WalkTree(&arrElem->gtArrObj, arrElem);
9867 if (result == fgWalkResult::WALK_ABORT)
9872 const unsigned rank = arrElem->gtArrRank;
9873 for (unsigned dim = 0; dim < rank; dim++)
9875 result = WalkTree(&arrElem->gtArrInds[dim], arrElem);
9876 if (result == fgWalkResult::WALK_ABORT)
9886 GenTreeArrOffs* const arrOffs = node->AsArrOffs();
9888 result = WalkTree(&arrOffs->gtOffset, arrOffs);
9889 if (result == fgWalkResult::WALK_ABORT)
9893 result = WalkTree(&arrOffs->gtIndex, arrOffs);
9894 if (result == fgWalkResult::WALK_ABORT)
9898 result = WalkTree(&arrOffs->gtArrObj, arrOffs);
9899 if (result == fgWalkResult::WALK_ABORT)
9908 GenTreeDynBlk* const dynBlock = node->AsDynBlk();
9910 GenTree** op1Use = &dynBlock->gtOp1;
9911 GenTree** op2Use = &dynBlock->gtDynamicSize;
9913 if (TVisitor::UseExecutionOrder && dynBlock->gtEvalSizeFirst)
9915 std::swap(op1Use, op2Use);
9918 result = WalkTree(op1Use, dynBlock);
9919 if (result == fgWalkResult::WALK_ABORT)
9923 result = WalkTree(op2Use, dynBlock);
9924 if (result == fgWalkResult::WALK_ABORT)
9931 case GT_STORE_DYN_BLK:
9933 GenTreeDynBlk* const dynBlock = node->AsDynBlk();
9935 GenTree** op1Use = &dynBlock->gtOp1;
9936 GenTree** op2Use = &dynBlock->gtOp2;
9937 GenTree** op3Use = &dynBlock->gtDynamicSize;
9939 if (TVisitor::UseExecutionOrder)
9941 if (dynBlock->IsReverseOp())
9943 std::swap(op1Use, op2Use);
9945 if (dynBlock->gtEvalSizeFirst)
9947 std::swap(op3Use, op2Use);
9948 std::swap(op2Use, op1Use);
9952 result = WalkTree(op1Use, dynBlock);
9953 if (result == fgWalkResult::WALK_ABORT)
9957 result = WalkTree(op2Use, dynBlock);
9958 if (result == fgWalkResult::WALK_ABORT)
9962 result = WalkTree(op3Use, dynBlock);
9963 if (result == fgWalkResult::WALK_ABORT)
9972 GenTreeCall* const call = node->AsCall();
9974 if (call->gtCallObjp != nullptr)
9976 result = WalkTree(&call->gtCallObjp, call);
9977 if (result == fgWalkResult::WALK_ABORT)
9983 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
9985 result = WalkTree(args->pCurrent(), call);
9986 if (result == fgWalkResult::WALK_ABORT)
9992 for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
9994 result = WalkTree(args->pCurrent(), call);
9995 if (result == fgWalkResult::WALK_ABORT)
10001 if (call->gtCallType == CT_INDIRECT)
10003 if (call->gtCallCookie != nullptr)
10005 result = WalkTree(&call->gtCallCookie, call);
10006 if (result == fgWalkResult::WALK_ABORT)
10012 result = WalkTree(&call->gtCallAddr, call);
10013 if (result == fgWalkResult::WALK_ABORT)
10019 if (call->gtControlExpr != nullptr)
10021 result = WalkTree(&call->gtControlExpr, call);
10022 if (result == fgWalkResult::WALK_ABORT)
10034 assert(node->OperIsBinary());
10036 GenTreeOp* const op = node->AsOp();
10038 GenTree** op1Use = &op->gtOp1;
10039 GenTree** op2Use = &op->gtOp2;
10041 if (TVisitor::UseExecutionOrder && node->IsReverseOp())
10043 std::swap(op1Use, op2Use);
10046 if (*op1Use != nullptr)
10048 result = WalkTree(op1Use, op);
10049 if (result == fgWalkResult::WALK_ABORT)
10055 if (*op2Use != nullptr)
10057 result = WalkTree(op2Use, op);
10058 if (result == fgWalkResult::WALK_ABORT)
10068 // Finally, visit the current node
10069 if (TVisitor::DoPostOrder)
10071 result = reinterpret_cast<TVisitor*>(this)->PostOrderVisit(use, user);
10074 if (TVisitor::ComputeStack)
10083 template <bool computeStack, bool doPreOrder, bool doPostOrder, bool doLclVarsOnly, bool useExecutionOrder>
10084 class GenericTreeWalker final
10085 : public GenTreeVisitor<GenericTreeWalker<computeStack, doPreOrder, doPostOrder, doLclVarsOnly, useExecutionOrder>>
10090 ComputeStack = computeStack,
10091 DoPreOrder = doPreOrder,
10092 DoPostOrder = doPostOrder,
10093 DoLclVarsOnly = doLclVarsOnly,
10094 UseExecutionOrder = useExecutionOrder,
10098 Compiler::fgWalkData* m_walkData;
10101 GenericTreeWalker(Compiler::fgWalkData* walkData)
10102 : GenTreeVisitor<GenericTreeWalker<computeStack, doPreOrder, doPostOrder, doLclVarsOnly, useExecutionOrder>>(
10103 walkData->compiler)
10104 , m_walkData(walkData)
10106 assert(walkData != nullptr);
10110 walkData->parentStack = &this->m_ancestors;
10114 Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
10116 m_walkData->parent = user;
10117 return m_walkData->wtprVisitorFn(use, m_walkData);
10120 Compiler::fgWalkResult PostOrderVisit(GenTree** use, GenTree* user)
10122 m_walkData->parent = user;
10123 return m_walkData->wtpoVisitorFn(use, m_walkData);
10128 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10129 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10131 XX Miscellaneous Compiler stuff XX
10133 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10134 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10137 // Values used to mark the types a stack slot is used for
10139 const unsigned TYPE_REF_INT = 0x01; // slot used as a 32-bit int
10140 const unsigned TYPE_REF_LNG = 0x02; // slot used as a 64-bit long
10141 const unsigned TYPE_REF_FLT = 0x04; // slot used as a 32-bit float
10142 const unsigned TYPE_REF_DBL = 0x08; // slot used as a 64-bit float
10143 const unsigned TYPE_REF_PTR = 0x10; // slot used as a 32-bit pointer
10144 const unsigned TYPE_REF_BYR = 0x20; // slot used as a byref pointer
10145 const unsigned TYPE_REF_STC = 0x40; // slot used as a struct
10146 const unsigned TYPE_REF_TYPEMASK = 0x7F; // bits that represent the type
10148 // const unsigned TYPE_REF_ADDR_TAKEN = 0x80; // slots address was taken
10150 /*****************************************************************************
10152 * Variables to keep track of total code amounts.
10157 extern size_t grossVMsize;
10158 extern size_t grossNCsize;
10159 extern size_t totalNCsize;
10161 extern unsigned genMethodICnt;
10162 extern unsigned genMethodNCnt;
10163 extern size_t gcHeaderISize;
10164 extern size_t gcPtrMapISize;
10165 extern size_t gcHeaderNSize;
10166 extern size_t gcPtrMapNSize;
10168 #endif // DISPLAY_SIZES
10170 /*****************************************************************************
10172 * Variables to keep track of basic block counts (more data on 1 BB methods)
10175 #if COUNT_BASIC_BLOCKS
10176 extern Histogram bbCntTable;
10177 extern Histogram bbOneBBSizeTable;
10180 /*****************************************************************************
10182 * Used by optFindNaturalLoops to gather statistical information such as
10183 * - total number of natural loops
10184 * - number of loops with 1, 2, ... exit conditions
10185 * - number of loops that have an iterator (for like)
10186 * - number of loops that have a constant iterator
10191 extern unsigned totalLoopMethods; // counts the total number of methods that have natural loops
10192 extern unsigned maxLoopsPerMethod; // counts the maximum number of loops a method has
10193 extern unsigned totalLoopOverflows; // # of methods that identified more loops than we can represent
10194 extern unsigned totalLoopCount; // counts the total number of natural loops
10195 extern unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
10196 extern unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
10197 extern unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
10198 extern unsigned simpleTestLoopCount; // counts the # of loops with an iterator and a simple loop condition (iter <
10200 extern unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
10201 extern bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
10202 extern unsigned loopsThisMethod; // counts the number of loops in the current method
10203 extern bool loopOverflowThisMethod; // True if we exceeded the max # of loops in the method.
10204 extern Histogram loopCountTable; // Histogram of loop counts
10205 extern Histogram loopExitCountTable; // Histogram of loop exit counts
10207 #endif // COUNT_LOOPS
10209 /*****************************************************************************
10210 * variables to keep track of how many iterations we go in a dataflow pass
10215 extern unsigned CSEiterCount; // counts the # of iteration for the CSE dataflow
10216 extern unsigned CFiterCount; // counts the # of iteration for the Const Folding dataflow
10218 #endif // DATAFLOW_ITER
10220 #if MEASURE_BLOCK_SIZE
10221 extern size_t genFlowNodeSize;
10222 extern size_t genFlowNodeCnt;
10223 #endif // MEASURE_BLOCK_SIZE
10225 #if MEASURE_NODE_SIZE
10226 struct NodeSizeStats
10230 genTreeNodeCnt = 0;
10231 genTreeNodeSize = 0;
10232 genTreeNodeActualSize = 0;
10235 // Count of tree nodes allocated.
10236 unsigned __int64 genTreeNodeCnt;
10238 // The size we allocate.
10239 unsigned __int64 genTreeNodeSize;
10241 // The actual size of the node. Note that the actual size will likely be smaller
10242 // than the allocated size, but we sometimes use SetOper()/ChangeOper() to change
10243 // a smaller node to a larger one. TODO-Cleanup: add stats on
10244 // SetOper()/ChangeOper() usage to quantify this.
10245 unsigned __int64 genTreeNodeActualSize;
10247 extern NodeSizeStats genNodeSizeStats; // Total node size stats
10248 extern NodeSizeStats genNodeSizeStatsPerFunc; // Per-function node size stats
10249 extern Histogram genTreeNcntHist;
10250 extern Histogram genTreeNsizHist;
10251 #endif // MEASURE_NODE_SIZE
10253 /*****************************************************************************
10254 * Count fatal errors (including noway_asserts).
10258 extern unsigned fatal_badCode;
10259 extern unsigned fatal_noWay;
10260 extern unsigned fatal_NOMEM;
10261 extern unsigned fatal_noWayAssertBody;
10263 extern unsigned fatal_noWayAssertBodyArgs;
10265 extern unsigned fatal_NYI;
10266 #endif // MEASURE_FATAL
10268 /*****************************************************************************
10272 #ifdef _TARGET_XARCH_
10274 const instruction INS_SHIFT_LEFT_LOGICAL = INS_shl;
10275 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_shr;
10276 const instruction INS_SHIFT_RIGHT_ARITHM = INS_sar;
10278 const instruction INS_AND = INS_and;
10279 const instruction INS_OR = INS_or;
10280 const instruction INS_XOR = INS_xor;
10281 const instruction INS_NEG = INS_neg;
10282 const instruction INS_TEST = INS_test;
10283 const instruction INS_MUL = INS_imul;
10284 const instruction INS_SIGNED_DIVIDE = INS_idiv;
10285 const instruction INS_UNSIGNED_DIVIDE = INS_div;
10286 const instruction INS_BREAKPOINT = INS_int3;
10287 const instruction INS_ADDC = INS_adc;
10288 const instruction INS_SUBC = INS_sbb;
10289 const instruction INS_NOT = INS_not;
10291 #endif // _TARGET_XARCH_
10293 #ifdef _TARGET_ARM_
10295 const instruction INS_SHIFT_LEFT_LOGICAL = INS_lsl;
10296 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_lsr;
10297 const instruction INS_SHIFT_RIGHT_ARITHM = INS_asr;
10299 const instruction INS_AND = INS_and;
10300 const instruction INS_OR = INS_orr;
10301 const instruction INS_XOR = INS_eor;
10302 const instruction INS_NEG = INS_rsb;
10303 const instruction INS_TEST = INS_tst;
10304 const instruction INS_MUL = INS_mul;
10305 const instruction INS_MULADD = INS_mla;
10306 const instruction INS_SIGNED_DIVIDE = INS_sdiv;
10307 const instruction INS_UNSIGNED_DIVIDE = INS_udiv;
10308 const instruction INS_BREAKPOINT = INS_bkpt;
10309 const instruction INS_ADDC = INS_adc;
10310 const instruction INS_SUBC = INS_sbc;
10311 const instruction INS_NOT = INS_mvn;
10313 const instruction INS_ABS = INS_vabs;
10314 const instruction INS_SQRT = INS_vsqrt;
10316 #endif // _TARGET_ARM_
10318 #ifdef _TARGET_ARM64_
10320 const instruction INS_MULADD = INS_madd;
10321 const instruction INS_BREAKPOINT = INS_bkpt;
10323 const instruction INS_ABS = INS_fabs;
10324 const instruction INS_SQRT = INS_fsqrt;
10326 #endif // _TARGET_ARM64_
10328 /*****************************************************************************/
10330 extern const BYTE genTypeSizes[];
10331 extern const BYTE genTypeAlignments[];
10332 extern const BYTE genTypeStSzs[];
10333 extern const BYTE genActualTypes[];
10335 /*****************************************************************************/
10337 // VERY_LARGE_FRAME_SIZE_REG_MASK is the set of registers we need to use for
10338 // the probing loop generated for very large stack frames (see `getVeryLargeFrameSize`).
10340 #ifdef _TARGET_ARM_
10341 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R4 | RBM_R5 | RBM_R6)
10342 #elif defined(_TARGET_ARM64_)
10343 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R9 | RBM_R10 | RBM_R11)
10346 /*****************************************************************************/
10348 extern BasicBlock dummyBB;
10350 /*****************************************************************************/
10351 /*****************************************************************************/
10353 // foreach_treenode_execution_order: An iterator that iterates through all the tree
10354 // nodes of a statement in execution order.
10355 // __stmt: a GT_STMT type GenTree*
10356 // __node: a GenTree*, already declared, that gets updated with each node in the statement, in execution order
10358 #define foreach_treenode_execution_order(__node, __stmt) \
10359 for ((__node) = (__stmt)->gtStmt.gtStmtList; (__node); (__node) = (__node)->gtNext)
10361 // foreach_block: An iterator over all blocks in the function.
10362 // __compiler: the Compiler* object
10363 // __block : a BasicBlock*, already declared, that gets updated each iteration.
10365 #define foreach_block(__compiler, __block) \
10366 for ((__block) = (__compiler)->fgFirstBB; (__block); (__block) = (__block)->bbNext)
10368 /*****************************************************************************/
10369 /*****************************************************************************/
10373 void dumpConvertedVarSet(Compiler* comp, VARSET_VALARG_TP vars);
10375 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10376 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10378 XX Debugging helpers XX
10380 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10381 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10384 /*****************************************************************************/
10385 /* The following functions are intended to be called from the debugger, to dump
10386 * various data structures. The can be used in the debugger Watch or Quick Watch
10387 * windows. They are designed to be short to type and take as few arguments as
10388 * possible. The 'c' versions take a Compiler*, whereas the 'd' versions use the TlsCompiler.
10389 * See the function definition comment for more details.
10392 void cBlock(Compiler* comp, BasicBlock* block);
10393 void cBlocks(Compiler* comp);
10394 void cBlocksV(Compiler* comp);
10395 void cTree(Compiler* comp, GenTree* tree);
10396 void cTrees(Compiler* comp);
10397 void cEH(Compiler* comp);
10398 void cVar(Compiler* comp, unsigned lclNum);
10399 void cVarDsc(Compiler* comp, LclVarDsc* varDsc);
10400 void cVars(Compiler* comp);
10401 void cVarsFinal(Compiler* comp);
10402 void cBlockPreds(Compiler* comp, BasicBlock* block);
10403 void cReach(Compiler* comp);
10404 void cDoms(Compiler* comp);
10405 void cLiveness(Compiler* comp);
10406 void cCVarSet(Compiler* comp, VARSET_VALARG_TP vars);
10408 void cFuncIR(Compiler* comp);
10409 void cBlockIR(Compiler* comp, BasicBlock* block);
10410 void cLoopIR(Compiler* comp, Compiler::LoopDsc* loop);
10411 void cTreeIR(Compiler* comp, GenTree* tree);
10412 int cTreeTypeIR(Compiler* comp, GenTree* tree);
10413 int cTreeKindsIR(Compiler* comp, GenTree* tree);
10414 int cTreeFlagsIR(Compiler* comp, GenTree* tree);
10415 int cOperandIR(Compiler* comp, GenTree* operand);
10416 int cLeafIR(Compiler* comp, GenTree* tree);
10417 int cIndirIR(Compiler* comp, GenTree* tree);
10418 int cListIR(Compiler* comp, GenTree* list);
10419 int cSsaNumIR(Compiler* comp, GenTree* tree);
10420 int cValNumIR(Compiler* comp, GenTree* tree);
10421 int cDependsIR(Compiler* comp, GenTree* comma, bool* first);
10423 void dBlock(BasicBlock* block);
10426 void dTree(GenTree* tree);
10429 void dVar(unsigned lclNum);
10430 void dVarDsc(LclVarDsc* varDsc);
10433 void dBlockPreds(BasicBlock* block);
10437 void dCVarSet(VARSET_VALARG_TP vars);
10439 void dRegMask(regMaskTP mask);
10442 void dBlockIR(BasicBlock* block);
10443 void dTreeIR(GenTree* tree);
10444 void dLoopIR(Compiler::LoopDsc* loop);
10445 void dLoopNumIR(unsigned loopNum);
10446 int dTabStopIR(int curr, int tabstop);
10447 int dTreeTypeIR(GenTree* tree);
10448 int dTreeKindsIR(GenTree* tree);
10449 int dTreeFlagsIR(GenTree* tree);
10450 int dOperandIR(GenTree* operand);
10451 int dLeafIR(GenTree* tree);
10452 int dIndirIR(GenTree* tree);
10453 int dListIR(GenTree* list);
10454 int dSsaNumIR(GenTree* tree);
10455 int dValNumIR(GenTree* tree);
10456 int dDependsIR(GenTree* comma);
10459 GenTree* dFindTree(GenTree* tree, unsigned id);
10460 GenTree* dFindTree(unsigned id);
10461 GenTreeStmt* dFindStmt(unsigned id);
10462 BasicBlock* dFindBlock(unsigned bbNum);
10466 #include "compiler.hpp" // All the shared inline functions
10468 /*****************************************************************************/
10469 #endif //_COMPILER_H_
10470 /*****************************************************************************/