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)
300 #ifdef USING_VARIABLE_LIVE_RANGE
301 //--------------------------------------------
303 // VariableLiveKeeper: Holds an array of "VariableLiveDescriptor", one for each variable
304 // whose location we track. It provides start/end/update/count operations over the
305 // "LiveRangeList" of any variable.
308 // This method could be implemented on Compiler class too, but the intention is to move code
309 // out of that class, which is huge. With this solution the only code needed in Compiler is
310 // a getter and an initializer of this class.
311 // The index of each variable in this array corresponds to the one in "compiler->lvaTable".
312 // We care about tracking the variable locations of arguments, special arguments, and local IL
313 // variables, and we ignore any other variable (like JIT temporary variables).
315 class VariableLiveKeeper
318 //--------------------------------------------
320 // VariableLiveRange: Represent part of the life of a variable. A
321 // variable lives in a location (represented with struct "siVarLoc")
322 // between two native offsets.
325 // We use emitLocation and not NATTIVE_OFFSET because location
326 // is captured when code is being generated (genCodeForBBList
327 // and genGeneratePrologsAndEpilogs) but only after the whole
328 // method's code is generated can we obtain a final, fixed
329 // NATIVE_OFFSET representing the actual generated code offset.
330 // There is also a IL_OFFSET, but this is more accurate and the
331 // debugger is expecting assembly offsets.
332 // This class doesn't have behaviour attached to itself, it is
333 // just putting a name to a representation. It is used to build
334 // typedefs LiveRangeList and LiveRangeListIterator, which are
335 // basically a list of this class and a const_iterator of that
338 class VariableLiveRange
341 emitLocation m_StartEmitLocation; // first position from where "m_VarLocation" becomes valid
342 emitLocation m_EndEmitLocation; // last position where "m_VarLocation" is valid
343 CodeGenInterface::siVarLoc m_VarLocation; // variable location
345 VariableLiveRange(CodeGenInterface::siVarLoc varLocation,
346 emitLocation startEmitLocation,
347 emitLocation endEmitLocation)
348 : m_StartEmitLocation(startEmitLocation), m_EndEmitLocation(endEmitLocation), m_VarLocation(varLocation)
353 // Dump "VariableLiveRange" when code has not been generated. We don't have the native code offset,
354 // but we do have "emitLocation"s and "siVarLoc".
355 void dumpVariableLiveRange(const CodeGenInterface* codeGen) const;
357 // Dump "VariableLiveRange" when code has been generated and we have the native code offset of each
359 void dumpVariableLiveRange(emitter* emit, const CodeGenInterface* codeGen) const;
363 typedef jitstd::list<VariableLiveRange> LiveRangeList;
364 typedef LiveRangeList::const_iterator LiveRangeListIterator;
368 //--------------------------------------------
370 // LiveRangeDumper: Used for debugging purposes during code
371 // generation on genCodeForBBList. Keeps an iterator to the first
372 // edited/added "VariableLiveRange" of a variable during the
373 // generation of code of one block.
376 // The first "VariableLiveRange" reported for a variable during
377 // a BasicBlock is sent to "setDumperStartAt" so we can dump all
378 // the "VariableLiveRange"s from that one.
379 // After we dump all the "VariableLiveRange"s we call "reset" with
380 // the "liveRangeList" to set the barrier to nullptr or the last
381 // "VariableLiveRange" if it is opened.
382 // If no "VariableLiveRange" was edited/added during block,
383 // the iterator points to the end of variable's LiveRangeList.
385 class LiveRangeDumper
387 // Iterator to the first edited/added position during actual block code generation. If last
388 // block had a closed "VariableLiveRange" (with a valid "m_EndEmitLocation") and not changes
389 // were applied to variable liveness, it points to the end of variable's LiveRangeList.
390 LiveRangeListIterator m_StartingLiveRange;
391 bool m_hasLiveRangestoDump; // True if a live range for this variable has been
392 // reported from last call to EndBlock
395 LiveRangeDumper(const LiveRangeList* liveRanges)
396 : m_StartingLiveRange(liveRanges->end()), m_hasLiveRangestoDump(false){};
398 // Make the dumper point to the last "VariableLiveRange" opened or nullptr if all are closed
399 void resetDumper(const LiveRangeList* list);
401 // Make "LiveRangeDumper" instance points the last "VariableLiveRange" added so we can
402 // start dumping from there after the actual "BasicBlock"s code is generated.
403 void setDumperStartAt(const LiveRangeListIterator liveRangeIt);
405 // Return an iterator to the first "VariableLiveRange" edited/added during the current
407 LiveRangeListIterator getStartForDump() const;
409 // Return whether at least a "VariableLiveRange" was alive during the current "BasicBlock"'s
411 bool hasLiveRangesToDump() const;
415 //--------------------------------------------
417 // VariableLiveDescriptor: This class persist and update all the changes
418 // to the home of a variable. It has an instance of "LiveRangeList"
419 // and methods to report the start/end of a VariableLiveRange.
421 class VariableLiveDescriptor
423 LiveRangeList* m_VariableLiveRanges; // the variable locations of this variable
424 INDEBUG(LiveRangeDumper* m_VariableLifeBarrier);
427 VariableLiveDescriptor(CompAllocator allocator);
429 bool hasVariableLiveRangeOpen() const;
430 LiveRangeList* getLiveRanges() const;
432 void startLiveRangeFromEmitter(CodeGenInterface::siVarLoc varLocation, emitter* emit) const;
433 void endLiveRangeAtEmitter(emitter* emit) const;
434 void updateLiveRangeAtEmitter(CodeGenInterface::siVarLoc varLocation, emitter* emit) const;
437 void dumpAllRegisterLiveRangesForBlock(emitter* emit, const CodeGenInterface* codeGen) const;
438 void dumpRegisterLiveRangesForBlockBeforeCodeGenerated(const CodeGenInterface* codeGen) const;
439 bool hasVarLiveRangesToDump() const;
440 bool hasVarLiverRangesFromLastBlockToDump() const;
441 void endBlockLiveRanges();
445 unsigned int m_LiveDscCount; // count of args, special args, and IL local variables to report home
446 unsigned int m_LiveArgsCount; // count of arguments to report home
448 Compiler* m_Compiler;
450 VariableLiveDescriptor* m_vlrLiveDsc; // Array of descriptors that manage VariableLiveRanges.
451 // Its indices correspond to lvaTable indexes (or lvSlotNum).
453 bool m_LastBasicBlockHasBeenEmited; // When true no more siEndVariableLiveRange is considered.
454 // No update/start happens when code has been generated.
457 VariableLiveKeeper(unsigned int totalLocalCount,
458 unsigned int argsCount,
460 CompAllocator allocator);
462 // For tracking locations during code generation
463 void siStartOrCloseVariableLiveRange(const LclVarDsc* varDsc, unsigned int varNum, bool isBorn, bool isDying);
464 void siStartOrCloseVariableLiveRanges(VARSET_VALARG_TP varsIndexSet, bool isBorn, bool isDying);
465 void siStartVariableLiveRange(const LclVarDsc* varDsc, unsigned int varNum);
466 void siEndVariableLiveRange(unsigned int varNum);
467 void siUpdateVariableLiveRange(const LclVarDsc* varDsc, unsigned int varNum);
468 void siEndAllVariableLiveRange(VARSET_VALARG_TP varsToClose);
469 void siEndAllVariableLiveRange();
471 LiveRangeList* getLiveRangesForVar(unsigned int varNum) const;
472 size_t getLiveRangesCount() const;
474 // For parameters locations on prolog
475 void psiStartVariableLiveRange(CodeGenInterface::siVarLoc varLocation, unsigned int varNum);
476 void psiClosePrologVariableRanges();
479 void dumpBlockVariableLiveRanges(const BasicBlock* block);
480 void dumpLvaVariableLiveRanges() const;
483 #endif // USING_VARIABLE_LIVE_RANGE
488 // The constructor. Most things can just be zero'ed.
490 // Initialize the ArgRegs to REG_STK.
491 // Morph will update if this local is passed in a register.
495 #if FEATURE_MULTIREG_ARGS
496 _lvOtherArgReg(REG_STK)
498 #endif // FEATURE_MULTIREG_ARGS
500 lvRefBlks(BlockSetOps::UninitVal())
502 #endif // ASSERTION_PROP
507 // note this only packs because var_types is a typedef of unsigned char
508 var_types lvType : 5; // TYP_INT/LONG/FLOAT/DOUBLE/REF
510 unsigned char lvIsParam : 1; // is this a parameter?
511 unsigned char lvIsRegArg : 1; // is this a register argument?
512 unsigned char lvFramePointerBased : 1; // 0 = off of REG_SPBASE (e.g., ESP), 1 = off of REG_FPBASE (e.g., EBP)
514 unsigned char lvStructGcCount : 3; // if struct, how many GC pointer (stop counting at 7). The only use of values >1
515 // is to help determine whether to use block init in the prolog.
516 unsigned char lvOnFrame : 1; // (part of) the variable lives on the frame
517 unsigned char lvRegister : 1; // assigned to live in a register? For RyuJIT backend, this is only set if the
518 // variable is in the same register for the entire function.
519 unsigned char lvTracked : 1; // is this a tracked variable?
520 bool lvTrackedNonStruct()
522 return lvTracked && lvType != TYP_STRUCT;
524 unsigned char lvPinned : 1; // is this a pinned variable?
526 unsigned char lvMustInit : 1; // must be initialized
527 unsigned char lvAddrExposed : 1; // The address of this variable is "exposed" -- passed as an argument, stored in a
528 // global location, etc.
529 // We cannot reason reliably about the value of the variable.
530 unsigned char lvDoNotEnregister : 1; // Do not enregister this variable.
531 unsigned char lvFieldAccessed : 1; // The var is a struct local, and a field of the variable is accessed. Affects
534 unsigned char lvInSsa : 1; // The variable is in SSA form (set by SsaBuilder)
537 // These further document the reasons for setting "lvDoNotEnregister". (Note that "lvAddrExposed" is one of the
539 // also, lvType == TYP_STRUCT prevents enregistration. At least one of the reasons should be true.
540 unsigned char lvVMNeedsStackAddr : 1; // The VM may have access to a stack-relative address of the variable, and
541 // read/write its value.
542 unsigned char lvLiveInOutOfHndlr : 1; // The variable was live in or out of an exception handler, and this required
543 // the variable to be
544 // in the stack (at least at those boundaries.)
545 unsigned char lvLclFieldExpr : 1; // The variable is not a struct, but was accessed like one (e.g., reading a
546 // particular byte from an int).
547 unsigned char lvLclBlockOpAddr : 1; // The variable was written to via a block operation that took its address.
548 unsigned char lvLiveAcrossUCall : 1; // The variable is live across an unmanaged call.
550 unsigned char lvIsCSE : 1; // Indicates if this LclVar is a CSE variable.
551 unsigned char lvHasLdAddrOp : 1; // has ldloca or ldarga opcode on this local.
552 unsigned char lvStackByref : 1; // This is a compiler temporary of TYP_BYREF that is known to point into our local
555 unsigned char lvHasILStoreOp : 1; // there is at least one STLOC or STARG on this local
556 unsigned char lvHasMultipleILStoreOp : 1; // there is more than one STLOC on this local
558 unsigned char lvIsTemp : 1; // Short-lifetime compiler temp (if lvIsParam is false), or implicit byref parameter
559 // (if lvIsParam is true)
561 unsigned char lvIsBoolean : 1; // set if variable is boolean
563 unsigned char lvSingleDef : 1; // variable has a single def
564 // before lvaMarkLocalVars: identifies ref type locals that can get type updates
565 // after lvaMarkLocalVars: identifies locals that are suitable for optAddCopies
568 unsigned char lvDisqualify : 1; // variable is no longer OK for add copy optimization
569 unsigned char lvVolatileHint : 1; // hint for AssertionProp
572 #ifndef _TARGET_64BIT_
573 unsigned char lvStructDoubleAlign : 1; // Must we double align this struct?
574 #endif // !_TARGET_64BIT_
575 #ifdef _TARGET_64BIT_
576 unsigned char lvQuirkToLong : 1; // Quirk to allocate this LclVar as a 64-bit long
579 unsigned char lvKeepType : 1; // Don't change the type of this variable
580 unsigned char lvNoLclFldStress : 1; // Can't apply local field stress on this one
582 unsigned char lvIsPtr : 1; // Might this be used in an address computation? (used by buffer overflow security
584 unsigned char lvIsUnsafeBuffer : 1; // Does this contain an unsafe buffer requiring buffer overflow security checks?
585 unsigned char lvPromoted : 1; // True when this local is a promoted struct, a normed struct, or a "split" long on a
586 // 32-bit target. For implicit byref parameters, this gets hijacked between
587 // fgRetypeImplicitByRefArgs and fgMarkDemotedImplicitByRefArgs to indicate whether
588 // references to the arg are being rewritten as references to a promoted shadow local.
589 unsigned char lvIsStructField : 1; // Is this local var a field of a promoted struct local?
590 unsigned char lvOverlappingFields : 1; // True when we have a struct with possibly overlapping fields
591 unsigned char lvContainsHoles : 1; // True when we have a promoted struct that contains holes
592 unsigned char lvCustomLayout : 1; // True when this struct has "CustomLayout"
594 unsigned char lvIsMultiRegArg : 1; // true if this is a multireg LclVar struct used in an argument context
595 unsigned char lvIsMultiRegRet : 1; // true if this is a multireg LclVar struct assigned from a multireg call
598 unsigned char _lvIsHfa : 1; // Is this a struct variable who's class handle is an HFA type
599 unsigned char _lvIsHfaRegArg : 1; // Is this a HFA argument variable? // TODO-CLEANUP: Remove this and replace
600 // with (lvIsRegArg && lvIsHfa())
601 unsigned char _lvHfaTypeIsFloat : 1; // Is the HFA type float or double?
602 #endif // FEATURE_HFA
605 // TODO-Cleanup: See the note on lvSize() - this flag is only in use by asserts that are checking for struct
606 // types, and is needed because of cases where TYP_STRUCT is bashed to an integral type.
607 // Consider cleaning this up so this workaround is not required.
608 unsigned char lvUnusedStruct : 1; // All references to this promoted struct are through its field locals.
609 // I.e. there is no longer any reference to the struct directly.
610 // In this case we can simply remove this struct local.
613 unsigned char lvLRACandidate : 1; // Tracked for linear scan register allocation purposes
616 // Note that both SIMD vector args and locals are marked as lvSIMDType = true, but the
617 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD*.
618 unsigned char lvSIMDType : 1; // This is a SIMD struct
619 unsigned char lvUsedInSIMDIntrinsic : 1; // This tells lclvar is used for simd intrinsic
620 var_types lvBaseType : 5; // Note: this only packs because var_types is a typedef of unsigned char
621 #endif // FEATURE_SIMD
622 unsigned char lvRegStruct : 1; // This is a reg-sized non-field-addressed struct.
624 unsigned char lvClassIsExact : 1; // lvClassHandle is the exact type
627 unsigned char lvClassInfoUpdated : 1; // true if this var has updated class handle or exactness
630 unsigned char lvImplicitlyReferenced : 1; // true if there are non-IR references to this local (prolog, epilog, gc,
634 unsigned lvFieldLclStart; // The index of the local var representing the first field in the promoted struct
635 // local. For implicit byref parameters, this gets hijacked between
636 // fgRetypeImplicitByRefArgs and fgMarkDemotedImplicitByRefArgs to point to the
637 // struct local created to model the parameter's struct promotion, if any.
638 unsigned lvParentLcl; // The index of the local var representing the parent (i.e. the promoted struct local).
639 // Valid on promoted struct local fields.
642 unsigned char lvFieldCnt; // Number of fields in the promoted VarDsc.
643 unsigned char lvFldOffset;
644 unsigned char lvFldOrdinal;
646 #if FEATURE_MULTIREG_ARGS
647 regNumber lvRegNumForSlot(unsigned slotNum)
653 else if (slotNum == 1)
655 return lvOtherArgReg;
659 assert(false && "Invalid slotNum!");
664 #endif // FEATURE_MULTIREG_ARGS
682 bool lvIsHfaRegArg() const
685 return _lvIsHfaRegArg;
691 void lvSetIsHfaRegArg(bool value = true)
694 _lvIsHfaRegArg = value;
698 bool lvHfaTypeIsFloat() const
701 return _lvHfaTypeIsFloat;
707 void lvSetHfaTypeIsFloat(bool value)
710 _lvHfaTypeIsFloat = value;
714 // on Arm64 - Returns 1-4 indicating the number of register slots used by the HFA
715 // on Arm32 - Returns the total number of single FP register slots used by the HFA, max is 8
717 unsigned lvHfaSlots() const
720 assert(varTypeIsStruct(lvType));
722 return lvExactSize / sizeof(float);
723 #else // _TARGET_ARM64_
724 if (lvHfaTypeIsFloat())
726 return lvExactSize / sizeof(float);
730 return lvExactSize / sizeof(double);
732 #endif // _TARGET_ARM64_
735 // lvIsMultiRegArgOrRet()
736 // returns true if this is a multireg LclVar struct used in an argument context
737 // or if this is a multireg LclVar struct assigned from a multireg call
738 bool lvIsMultiRegArgOrRet()
740 return lvIsMultiRegArg || lvIsMultiRegRet;
744 regNumberSmall _lvRegNum; // Used to store the register this variable is in (or, the low register of a
745 // register pair). It is set during codegen any time the
746 // variable is enregistered (lvRegister is only set
747 // to non-zero if the variable gets the same register assignment for its entire
749 #if !defined(_TARGET_64BIT_)
750 regNumberSmall _lvOtherReg; // Used for "upper half" of long var.
751 #endif // !defined(_TARGET_64BIT_)
753 regNumberSmall _lvArgReg; // The register in which this argument is passed.
755 #if FEATURE_MULTIREG_ARGS
756 regNumberSmall _lvOtherArgReg; // Used for the second part of the struct passed in a register.
757 // Note this is defined but not used by ARM32
758 #endif // FEATURE_MULTIREG_ARGS
760 regNumberSmall _lvArgInitReg; // the register into which the argument is moved at entry
763 // The register number is stored in a small format (8 bits), but the getters return and the setters take
764 // a full-size (unsigned) format, to localize the casts here.
766 /////////////////////
768 __declspec(property(get = GetRegNum, put = SetRegNum)) regNumber lvRegNum;
770 regNumber GetRegNum() const
772 return (regNumber)_lvRegNum;
775 void SetRegNum(regNumber reg)
777 _lvRegNum = (regNumberSmall)reg;
778 assert(_lvRegNum == reg);
781 /////////////////////
783 #if defined(_TARGET_64BIT_)
784 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
786 regNumber GetOtherReg() const
788 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
789 // "unreachable code" warnings
793 void SetOtherReg(regNumber reg)
795 assert(!"shouldn't get here"); // can't use "unreached();" because it's NORETURN, which causes C4072
796 // "unreachable code" warnings
798 #else // !_TARGET_64BIT_
799 __declspec(property(get = GetOtherReg, put = SetOtherReg)) regNumber lvOtherReg;
801 regNumber GetOtherReg() const
803 return (regNumber)_lvOtherReg;
806 void SetOtherReg(regNumber reg)
808 _lvOtherReg = (regNumberSmall)reg;
809 assert(_lvOtherReg == reg);
811 #endif // !_TARGET_64BIT_
813 /////////////////////
815 __declspec(property(get = GetArgReg, put = SetArgReg)) regNumber lvArgReg;
817 regNumber GetArgReg() const
819 return (regNumber)_lvArgReg;
822 void SetArgReg(regNumber reg)
824 _lvArgReg = (regNumberSmall)reg;
825 assert(_lvArgReg == reg);
828 #if FEATURE_MULTIREG_ARGS
829 __declspec(property(get = GetOtherArgReg, put = SetOtherArgReg)) regNumber lvOtherArgReg;
831 regNumber GetOtherArgReg() const
833 return (regNumber)_lvOtherArgReg;
836 void SetOtherArgReg(regNumber reg)
838 _lvOtherArgReg = (regNumberSmall)reg;
839 assert(_lvOtherArgReg == reg);
841 #endif // FEATURE_MULTIREG_ARGS
844 // Is this is a SIMD struct?
845 bool lvIsSIMDType() const
850 // Is this is a SIMD struct which is used for SIMD intrinsic?
851 bool lvIsUsedInSIMDIntrinsic() const
853 return lvUsedInSIMDIntrinsic;
856 // If feature_simd not enabled, return false
857 bool lvIsSIMDType() const
861 bool lvIsUsedInSIMDIntrinsic() const
867 /////////////////////
869 __declspec(property(get = GetArgInitReg, put = SetArgInitReg)) regNumber lvArgInitReg;
871 regNumber GetArgInitReg() const
873 return (regNumber)_lvArgInitReg;
876 void SetArgInitReg(regNumber reg)
878 _lvArgInitReg = (regNumberSmall)reg;
879 assert(_lvArgInitReg == reg);
882 /////////////////////
884 bool lvIsRegCandidate() const
886 return lvLRACandidate != 0;
889 bool lvIsInReg() const
891 return lvIsRegCandidate() && (lvRegNum != REG_STK);
894 regMaskTP lvRegMask() const
896 regMaskTP regMask = RBM_NONE;
897 if (varTypeIsFloating(TypeGet()))
899 if (lvRegNum != REG_STK)
901 regMask = genRegMaskFloat(lvRegNum, TypeGet());
906 if (lvRegNum != REG_STK)
908 regMask = genRegMask(lvRegNum);
914 unsigned short lvVarIndex; // variable tracking index
917 unsigned short m_lvRefCnt; // unweighted (real) reference count. For implicit by reference
918 // parameters, this gets hijacked from fgMarkImplicitByRefArgs
919 // through fgMarkDemotedImplicitByRefArgs, to provide a static
920 // appearance count (computed during address-exposed analysis)
921 // that fgMakeOutgoingStructArgCopy consults during global morph
922 // to determine if eliding its copy is legal.
924 BasicBlock::weight_t m_lvRefCntWtd; // weighted reference count
927 unsigned short lvRefCnt(RefCountState state = RCS_NORMAL) const;
928 void incLvRefCnt(unsigned short delta, RefCountState state = RCS_NORMAL);
929 void setLvRefCnt(unsigned short newValue, RefCountState state = RCS_NORMAL);
931 BasicBlock::weight_t lvRefCntWtd(RefCountState state = RCS_NORMAL) const;
932 void incLvRefCntWtd(BasicBlock::weight_t delta, RefCountState state = RCS_NORMAL);
933 void setLvRefCntWtd(BasicBlock::weight_t newValue, RefCountState state = RCS_NORMAL);
935 int lvStkOffs; // stack offset of home
936 unsigned lvExactSize; // (exact) size of the type in bytes
938 // Is this a promoted struct?
939 // This method returns true only for structs (including SIMD structs), not for
940 // locals that are split on a 32-bit target.
941 // It is only necessary to use this:
942 // 1) if only structs are wanted, and
943 // 2) if Lowering has already been done.
944 // Otherwise lvPromoted is valid.
945 bool lvPromotedStruct()
947 #if !defined(_TARGET_64BIT_)
948 return (lvPromoted && !varTypeIsLong(lvType));
949 #else // defined(_TARGET_64BIT_)
951 #endif // defined(_TARGET_64BIT_)
954 unsigned lvSize() const // Size needed for storage representation. Only used for structs or TYP_BLK.
956 // TODO-Review: Sometimes we get called on ARM with HFA struct variables that have been promoted,
957 // where the struct itself is no longer used because all access is via its member fields.
958 // When that happens, the struct is marked as unused and its type has been changed to
959 // TYP_INT (to keep the GC tracking code from looking at it).
960 // See Compiler::raAssignVars() for details. For example:
961 // N002 ( 4, 3) [00EA067C] ------------- return struct $346
962 // N001 ( 3, 2) [00EA0628] ------------- lclVar struct(U) V03 loc2
963 // float V03.f1 (offs=0x00) -> V12 tmp7
964 // f8 (last use) (last use) $345
965 // Here, the "struct(U)" shows that the "V03 loc2" variable is unused. Not shown is that V03
966 // is now TYP_INT in the local variable table. It's not really unused, because it's in the tree.
968 assert(varTypeIsStruct(lvType) || (lvType == TYP_BLK) || (lvPromoted && lvUnusedStruct));
970 #if defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
971 // For 32-bit architectures, we make local variable SIMD12 types 16 bytes instead of just 12. We can't do
972 // this for arguments, which must be passed according the defined ABI. We don't want to do this for
973 // dependently promoted struct fields, but we don't know that here. See lvaMapSimd12ToSimd16().
974 // (Note that for 64-bits, we are already rounding up to 16.)
975 if ((lvType == TYP_SIMD12) && !lvIsParam)
977 assert(lvExactSize == 12);
980 #endif // defined(FEATURE_SIMD) && !defined(_TARGET_64BIT_)
982 return roundUp(lvExactSize, TARGET_POINTER_SIZE);
985 size_t lvArgStackSize() const;
987 unsigned lvSlotNum; // original slot # (if remapped)
989 typeInfo lvVerTypeInfo; // type info needed for verification
991 CORINFO_CLASS_HANDLE lvClassHnd; // class handle for the local, or null if not known
993 CORINFO_FIELD_HANDLE lvFieldHnd; // field handle for promoted struct fields
995 BYTE* lvGcLayout; // GC layout info for structs
998 BlockSet lvRefBlks; // Set of blocks that contain refs
999 GenTreeStmt* lvDefStmt; // Pointer to the statement with the single definition
1000 void lvaDisqualifyVar(); // Call to disqualify a local variable from use in optAddCopies
1002 var_types TypeGet() const
1004 return (var_types)lvType;
1006 bool lvStackAligned() const
1008 assert(lvIsStructField);
1009 return ((lvFldOffset % TARGET_POINTER_SIZE) == 0);
1011 bool lvNormalizeOnLoad() const
1013 return varTypeIsSmall(TypeGet()) &&
1014 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
1015 (lvIsParam || lvAddrExposed || lvIsStructField);
1018 bool lvNormalizeOnStore()
1020 return varTypeIsSmall(TypeGet()) &&
1021 // lvIsStructField is treated the same as the aliased local, see fgDoNormalizeOnStore.
1022 !(lvIsParam || lvAddrExposed || lvIsStructField);
1025 void incRefCnts(BasicBlock::weight_t weight,
1027 RefCountState state = RCS_NORMAL,
1028 bool propagate = true);
1029 bool IsFloatRegType() const
1031 return isFloatRegType(lvType) || lvIsHfaRegArg();
1033 var_types GetHfaType() const
1035 return lvIsHfa() ? (lvHfaTypeIsFloat() ? TYP_FLOAT : TYP_DOUBLE) : TYP_UNDEF;
1037 void SetHfaType(var_types type)
1039 assert(varTypeIsFloating(type));
1040 lvSetHfaTypeIsFloat(type == TYP_FLOAT);
1043 var_types lvaArgType();
1045 SsaDefArray<LclSsaVarDsc> lvPerSsaData;
1047 // Returns the address of the per-Ssa data for the given ssaNum (which is required
1048 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
1049 // not an SSA variable).
1050 LclSsaVarDsc* GetPerSsaData(unsigned ssaNum)
1052 return lvPerSsaData.GetSsaDef(ssaNum);
1057 const char* lvReason;
1059 void PrintVarReg() const
1061 printf("%s", getRegName(lvRegNum));
1065 }; // class LclVarDsc
1068 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1069 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1073 XX The temporary lclVars allocated by the compiler for code generation XX
1075 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1076 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1079 /*****************************************************************************
1081 * The following keeps track of temporaries allocated in the stack frame
1082 * during code-generation (after register allocation). These spill-temps are
1083 * only used if we run out of registers while evaluating a tree.
1085 * These are different from the more common temps allocated by lvaGrabTemp().
1096 static const int BAD_TEMP_OFFSET = 0xDDDDDDDD; // used as a sentinel "bad value" for tdOffs in DEBUG
1104 TempDsc(int _tdNum, unsigned _tdSize, var_types _tdType) : tdNum(_tdNum), tdSize((BYTE)_tdSize), tdType(_tdType)
1108 0); // temps must have a negative number (so they have a different number from all local variables)
1109 tdOffs = BAD_TEMP_OFFSET;
1111 if (tdNum != _tdNum)
1113 IMPL_LIMITATION("too many spill temps");
1118 bool tdLegalOffset() const
1120 return tdOffs != BAD_TEMP_OFFSET;
1124 int tdTempOffs() const
1126 assert(tdLegalOffset());
1129 void tdSetTempOffs(int offs)
1132 assert(tdLegalOffset());
1134 void tdAdjustTempOffs(int offs)
1137 assert(tdLegalOffset());
1140 int tdTempNum() const
1145 unsigned tdTempSize() const
1149 var_types tdTempType() const
1155 // interface to hide linearscan implementation from rest of compiler
1156 class LinearScanInterface
1159 virtual void doLinearScan() = 0;
1160 virtual void recordVarLocationsAtStartOfBB(BasicBlock* bb) = 0;
1161 virtual bool willEnregisterLocalVars() const = 0;
1164 LinearScanInterface* getLinearScanAllocator(Compiler* comp);
1166 // Information about arrays: their element type and size, and the offset of the first element.
1167 // We label GT_IND's that are array indices with GTF_IND_ARR_INDEX, and, for such nodes,
1168 // associate an array info via the map retrieved by GetArrayInfoMap(). This information is used,
1169 // for example, in value numbering of array index expressions.
1172 var_types m_elemType;
1173 CORINFO_CLASS_HANDLE m_elemStructType;
1174 unsigned m_elemSize;
1175 unsigned m_elemOffset;
1177 ArrayInfo() : m_elemType(TYP_UNDEF), m_elemStructType(nullptr), m_elemSize(0), m_elemOffset(0)
1181 ArrayInfo(var_types elemType, unsigned elemSize, unsigned elemOffset, CORINFO_CLASS_HANDLE elemStructType)
1182 : m_elemType(elemType), m_elemStructType(elemStructType), m_elemSize(elemSize), m_elemOffset(elemOffset)
1187 // This enumeration names the phases into which we divide compilation. The phases should completely
1188 // partition a compilation.
1191 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) enum_nm,
1192 #include "compphases.h"
1196 extern const char* PhaseNames[];
1197 extern const char* PhaseEnums[];
1198 extern const LPCWSTR PhaseShortNames[];
1200 // The following enum provides a simple 1:1 mapping to CLR API's
1201 enum API_ICorJitInfo_Names
1203 #define DEF_CLR_API(name) API_##name,
1204 #include "ICorJitInfo_API_names.h"
1208 //---------------------------------------------------------------
1209 // Compilation time.
1212 // A "CompTimeInfo" is a structure for tracking the compilation time of one or more methods.
1213 // We divide a compilation into a sequence of contiguous phases, and track the total (per-thread) cycles
1214 // of the compilation, as well as the cycles for each phase. We also track the number of bytecodes.
1215 // If there is a failure in reading a timer at any point, the "CompTimeInfo" becomes invalid, as indicated
1216 // by "m_timerFailure" being true.
1217 // If FEATURE_JIT_METHOD_PERF is not set, we define a minimal form of this, enough to let other code compile.
1220 #ifdef FEATURE_JIT_METHOD_PERF
1221 // The string names of the phases.
1222 static const char* PhaseNames[];
1224 static bool PhaseHasChildren[];
1225 static int PhaseParent[];
1226 static bool PhaseReportsIRSize[];
1228 unsigned m_byteCodeBytes;
1229 unsigned __int64 m_totalCycles;
1230 unsigned __int64 m_invokesByPhase[PHASE_NUMBER_OF];
1231 unsigned __int64 m_cyclesByPhase[PHASE_NUMBER_OF];
1232 #if MEASURE_CLRAPI_CALLS
1233 unsigned __int64 m_CLRinvokesByPhase[PHASE_NUMBER_OF];
1234 unsigned __int64 m_CLRcyclesByPhase[PHASE_NUMBER_OF];
1237 unsigned m_nodeCountAfterPhase[PHASE_NUMBER_OF];
1239 // For better documentation, we call EndPhase on
1240 // non-leaf phases. We should also call EndPhase on the
1241 // last leaf subphase; obviously, the elapsed cycles between the EndPhase
1242 // for the last leaf subphase and the EndPhase for an ancestor should be very small.
1243 // We add all such "redundant end phase" intervals to this variable below; we print
1244 // it out in a report, so we can verify that it is, indeed, very small. If it ever
1245 // isn't, this means that we're doing something significant between the end of the last
1246 // declared subphase and the end of its parent.
1247 unsigned __int64 m_parentPhaseEndSlop;
1248 bool m_timerFailure;
1250 #if MEASURE_CLRAPI_CALLS
1251 // The following measures the time spent inside each individual CLR API call.
1252 unsigned m_allClrAPIcalls;
1253 unsigned m_perClrAPIcalls[API_ICorJitInfo_Names::API_COUNT];
1254 unsigned __int64 m_allClrAPIcycles;
1255 unsigned __int64 m_perClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
1256 unsigned __int32 m_maxClrAPIcycles[API_ICorJitInfo_Names::API_COUNT];
1257 #endif // MEASURE_CLRAPI_CALLS
1259 CompTimeInfo(unsigned byteCodeBytes);
1263 #ifdef FEATURE_JIT_METHOD_PERF
1265 #if MEASURE_CLRAPI_CALLS
1266 struct WrapICorJitInfo;
1269 // This class summarizes the JIT time information over the course of a run: the number of methods compiled,
1270 // and the total and maximum timings. (These are instances of the "CompTimeInfo" type described above).
1271 // The operation of adding a single method's timing to the summary may be performed concurrently by several
1272 // threads, so it is protected by a lock.
1273 // This class is intended to be used as a singleton type, with only a single instance.
1274 class CompTimeSummaryInfo
1276 // This lock protects the fields of all CompTimeSummaryInfo(s) (of which we expect there to be one).
1277 static CritSecObject s_compTimeSummaryLock;
1281 CompTimeInfo m_total;
1282 CompTimeInfo m_maximum;
1284 int m_numFilteredMethods;
1285 CompTimeInfo m_filtered;
1287 // This can use what ever data you want to determine if the value to be added
1288 // belongs in the filtered section (it's always included in the unfiltered section)
1289 bool IncludedInFilteredData(CompTimeInfo& info);
1292 // This is the unique CompTimeSummaryInfo object for this instance of the runtime.
1293 static CompTimeSummaryInfo s_compTimeSummary;
1295 CompTimeSummaryInfo()
1296 : m_numMethods(0), m_totMethods(0), m_total(0), m_maximum(0), m_numFilteredMethods(0), m_filtered(0)
1300 // Assumes that "info" is a completed CompTimeInfo for a compilation; adds it to the summary.
1301 // This is thread safe.
1302 void AddInfo(CompTimeInfo& info, bool includePhases);
1304 // Print the summary information to "f".
1305 // This is not thread-safe; assumed to be called by only one thread.
1306 void Print(FILE* f);
1309 // A JitTimer encapsulates a CompTimeInfo for a single compilation. It also tracks the start of compilation,
1310 // and when the current phase started. This is intended to be part of a Compilation object. This is
1311 // disabled (FEATURE_JIT_METHOD_PERF not defined) when FEATURE_CORECLR is set, or on non-windows platforms.
1315 unsigned __int64 m_start; // Start of the compilation.
1316 unsigned __int64 m_curPhaseStart; // Start of the current phase.
1317 #if MEASURE_CLRAPI_CALLS
1318 unsigned __int64 m_CLRcallStart; // Start of the current CLR API call (if any).
1319 unsigned __int64 m_CLRcallInvokes; // CLR API invokes under current outer so far
1320 unsigned __int64 m_CLRcallCycles; // CLR API cycles under current outer so far.
1321 int m_CLRcallAPInum; // The enum/index of the current CLR API call (or -1).
1322 static double s_cyclesPerSec; // Cached for speedier measurements
1325 Phases m_lastPhase; // The last phase that was completed (or (Phases)-1 to start).
1327 CompTimeInfo m_info; // The CompTimeInfo for this compilation.
1329 static CritSecObject s_csvLock; // Lock to protect the time log file.
1330 void PrintCsvMethodStats(Compiler* comp);
1333 void* operator new(size_t);
1334 void* operator new[](size_t);
1335 void operator delete(void*);
1336 void operator delete[](void*);
1339 // Initialized the timer instance
1340 JitTimer(unsigned byteCodeSize);
1342 static JitTimer* Create(Compiler* comp, unsigned byteCodeSize)
1344 return ::new (comp, CMK_Unknown) JitTimer(byteCodeSize);
1347 static void PrintCsvHeader();
1349 // Ends the current phase (argument is for a redundant check).
1350 void EndPhase(Compiler* compiler, Phases phase);
1352 #if MEASURE_CLRAPI_CALLS
1353 // Start and end a timed CLR API call.
1354 void CLRApiCallEnter(unsigned apix);
1355 void CLRApiCallLeave(unsigned apix);
1356 #endif // MEASURE_CLRAPI_CALLS
1358 // Completes the timing of the current method, which is assumed to have "byteCodeBytes" bytes of bytecode,
1359 // and adds it to "sum".
1360 void Terminate(Compiler* comp, CompTimeSummaryInfo& sum, bool includePhases);
1362 // Attempts to query the cycle counter of the current thread. If successful, returns "true" and sets
1363 // *cycles to the cycle counter value. Otherwise, returns false and sets the "m_timerFailure" flag of
1364 // "m_info" to true.
1365 bool GetThreadCycles(unsigned __int64* cycles)
1367 bool res = CycleTimer::GetThreadCyclesS(cycles);
1370 m_info.m_timerFailure = true;
1375 #endif // FEATURE_JIT_METHOD_PERF
1377 //------------------- Function/Funclet info -------------------------------
1378 enum FuncKind : BYTE
1380 FUNC_ROOT, // The main/root function (always id==0)
1381 FUNC_HANDLER, // a funclet associated with an EH handler (finally, fault, catch, filter handler)
1382 FUNC_FILTER, // a funclet associated with an EH filter
1391 BYTE funFlags; // Currently unused, just here for padding
1392 unsigned short funEHIndex; // index, into the ebd table, of innermost EH clause corresponding to this
1393 // funclet. It is only valid if funKind field indicates this is a
1394 // EH-related funclet: FUNC_HANDLER or FUNC_FILTER
1396 #if defined(_TARGET_AMD64_)
1398 // TODO-AMD64-Throughput: make the AMD64 info more like the ARM info to avoid having this large static array.
1399 emitLocation* startLoc;
1400 emitLocation* endLoc;
1401 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1402 emitLocation* coldEndLoc;
1403 UNWIND_INFO unwindHeader;
1404 // Maximum of 255 UNWIND_CODE 'nodes' and then the unwind header. If there are an odd
1405 // number of codes, the VM or Zapper will 4-byte align the whole thing.
1406 BYTE unwindCodes[offsetof(UNWIND_INFO, UnwindCode) + (0xFF * sizeof(UNWIND_CODE))];
1407 unsigned unwindCodeSlot;
1409 #elif defined(_TARGET_X86_)
1411 #if defined(_TARGET_UNIX_)
1412 emitLocation* startLoc;
1413 emitLocation* endLoc;
1414 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1415 emitLocation* coldEndLoc;
1416 #endif // _TARGET_UNIX_
1418 #elif defined(_TARGET_ARMARCH_)
1420 UnwindInfo uwi; // Unwind information for this function/funclet's hot section
1421 UnwindInfo* uwiCold; // Unwind information for this function/funclet's cold section
1422 // Note: we only have a pointer here instead of the actual object,
1423 // to save memory in the JIT case (compared to the NGEN case),
1424 // where we don't have any cold section.
1425 // Note 2: we currently don't support hot/cold splitting in functions
1426 // with EH, so uwiCold will be NULL for all funclets.
1428 #if defined(_TARGET_UNIX_)
1429 emitLocation* startLoc;
1430 emitLocation* endLoc;
1431 emitLocation* coldStartLoc; // locations for the cold section, if there is one.
1432 emitLocation* coldEndLoc;
1433 #endif // _TARGET_UNIX_
1435 #endif // _TARGET_ARMARCH_
1437 #if defined(_TARGET_UNIX_)
1438 jitstd::vector<CFI_CODE>* cfiCodes;
1439 #endif // _TARGET_UNIX_
1441 // Eventually we may want to move rsModifiedRegsMask, lvaOutgoingArgSize, and anything else
1442 // that isn't shared between the main function body and funclets.
1445 struct fgArgTabEntry
1447 GenTree* node; // Initially points at the Op1 field of 'parent', but if the argument is replaced with an GT_ASG or
1448 // placeholder it will point at the actual argument in the gtCallLateArgs list.
1449 GenTree* parent; // Points at the GT_LIST node in the gtCallArgs for this argument
1451 unsigned argNum; // The original argument number, also specifies the required argument evaluation order from the IL
1454 regNumberSmall regNums[MAX_ARG_REG_COUNT]; // The registers to use when passing this argument, set to REG_STK for
1455 // arguments passed on the stack
1457 unsigned numRegs; // Count of number of registers that this argument uses.
1458 // Note that on ARM, if we have a double hfa, this reflects the number
1459 // of DOUBLE registers.
1461 // A slot is a pointer sized region in the OutArg area.
1462 unsigned slotNum; // When an argument is passed in the OutArg area this is the slot number in the OutArg area
1463 unsigned numSlots; // Count of number of slots that this argument uses
1465 unsigned alignment; // 1 or 2 (slots/registers)
1467 unsigned _lateArgInx; // index into gtCallLateArgs list; UINT_MAX if this is not a late arg.
1469 unsigned tmpNum; // the LclVar number if we had to force evaluation of this arg
1471 var_types argType; // The type used to pass this argument. This is generally the original argument type, but when a
1472 // struct is passed as a scalar type, this is that type.
1473 // Note that if a struct is passed by reference, this will still be the struct type.
1475 bool needTmp : 1; // True when we force this argument's evaluation into a temp LclVar
1476 bool needPlace : 1; // True when we must replace this argument with a placeholder node
1477 bool isTmp : 1; // True when we setup a temp LclVar for this argument due to size issues with the struct
1478 bool processed : 1; // True when we have decided the evaluation order for this argument in the gtCallLateArgs
1479 bool isBackFilled : 1; // True when the argument fills a register slot skipped due to alignment requirements of
1480 // previous arguments.
1481 bool isNonStandard : 1; // True if it is an arg that is passed in a reg other than a standard arg reg, or is forced
1482 // to be on the stack despite its arg list position.
1483 bool isStruct : 1; // True if this is a struct arg
1484 bool _isVararg : 1; // True if the argument is in a vararg context.
1485 bool passedByRef : 1; // True iff the argument is passed by reference.
1486 #ifdef FEATURE_ARG_SPLIT
1487 bool _isSplit : 1; // True when this argument is split between the registers and OutArg area
1488 #endif // FEATURE_ARG_SPLIT
1490 bool _isHfaArg : 1; // True when the argument is an HFA type.
1491 bool _isDoubleHfa : 1; // True when the argument is an HFA, with an element type of DOUBLE.
1496 bool isLate = (_lateArgInx != UINT_MAX);
1500 __declspec(property(get = getLateArgInx, put = setLateArgInx)) unsigned lateArgInx;
1501 unsigned getLateArgInx()
1503 assert(isLateArg());
1506 void setLateArgInx(unsigned inx)
1510 __declspec(property(get = getRegNum)) regNumber regNum;
1511 regNumber getRegNum()
1513 return (regNumber)regNums[0];
1515 __declspec(property(get = getOtherRegNum)) regNumber otherRegNum;
1516 regNumber getOtherRegNum()
1518 return (regNumber)regNums[1];
1521 #if defined(UNIX_AMD64_ABI)
1522 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
1525 void setRegNum(unsigned int i, regNumber regNum)
1527 assert(i < MAX_ARG_REG_COUNT);
1528 regNums[i] = (regNumberSmall)regNum;
1530 regNumber getRegNum(unsigned int i)
1532 assert(i < MAX_ARG_REG_COUNT);
1533 return (regNumber)regNums[i];
1536 __declspec(property(get = getIsSplit, put = setIsSplit)) bool isSplit;
1539 #ifdef FEATURE_ARG_SPLIT
1541 #else // FEATURE_ARG_SPLIT
1545 void setIsSplit(bool value)
1547 #ifdef FEATURE_ARG_SPLIT
1552 __declspec(property(get = getIsVararg, put = setIsVararg)) bool isVararg;
1555 #ifdef FEATURE_VARARG
1561 void setIsVararg(bool value)
1563 #ifdef FEATURE_VARARG
1565 #endif // FEATURE_VARARG
1568 __declspec(property(get = getIsHfaArg)) bool isHfaArg;
1578 __declspec(property(get = getIsHfaRegArg)) bool isHfaRegArg;
1579 bool getIsHfaRegArg()
1582 return _isHfaArg && isPassedInRegisters();
1588 __declspec(property(get = getHfaType)) var_types hfaType;
1589 var_types getHfaType()
1592 return _isHfaArg ? (_isDoubleHfa ? TYP_DOUBLE : TYP_FLOAT) : TYP_UNDEF;
1598 void setHfaType(var_types type, unsigned hfaSlots)
1601 if (type != TYP_UNDEF)
1603 // We must already have set the passing mode.
1604 assert(numRegs != 0 || numSlots != 0);
1605 // We originally set numRegs according to the size of the struct, but if the size of the
1606 // hfaType is not the same as the pointer size, we need to correct it.
1607 // Note that hfaSlots is the number of registers we will use. For ARM, that is twice
1608 // the number of "double registers".
1609 unsigned numHfaRegs = hfaSlots;
1610 if (isPassedInRegisters())
1613 if (type == TYP_DOUBLE)
1615 // Must be an even number of registers.
1616 assert((numRegs & 1) == 0);
1617 numHfaRegs = hfaSlots / 2;
1619 #endif // _TARGET_ARM_
1622 // This should already be set correctly.
1623 assert(numRegs == numHfaRegs);
1624 assert(_isDoubleHfa == (type == TYP_DOUBLE));
1628 numRegs = numHfaRegs;
1631 _isDoubleHfa = (type == TYP_DOUBLE);
1634 #endif // FEATURE_HFA
1638 void SetIsBackFilled(bool backFilled)
1640 isBackFilled = backFilled;
1643 bool IsBackFilled() const
1645 return isBackFilled;
1647 #else // !_TARGET_ARM_
1648 void SetIsBackFilled(bool backFilled)
1652 bool IsBackFilled() const
1656 #endif // !_TARGET_ARM_
1658 bool isPassedInRegisters()
1660 return !isSplit && (numRegs != 0);
1663 bool isPassedInFloatRegisters()
1668 return isValidFloatArgReg(regNum);
1672 bool isSingleRegOrSlot()
1674 return !isSplit && ((numRegs == 1) || (numSlots == 1));
1677 // Returns the number of "slots" used, where for this purpose a
1678 // register counts as a slot.
1679 unsigned getSlotCount()
1683 assert(isPassedInRegisters());
1684 assert(numRegs == 1);
1686 else if (regNum == REG_STK)
1688 assert(!isPassedInRegisters());
1689 assert(numRegs == 0);
1693 assert(numRegs > 0);
1695 return numSlots + numRegs;
1698 // Returns the size as a multiple of pointer-size.
1699 // For targets without HFAs, this is the same as getSlotCount().
1702 unsigned size = getSlotCount();
1705 // We counted the number of regs, but if they are DOUBLE hfa regs we have to double the size.
1706 if (isHfaRegArg && (hfaType == TYP_DOUBLE))
1711 #elif defined(_TARGET_ARM64_)
1712 // We counted the number of regs, but if they are FLOAT hfa regs we have to halve the size.
1713 if (isHfaRegArg && (hfaType == TYP_FLOAT))
1715 // Round up in case of odd HFA count.
1716 size = (size + 1) >> 1;
1718 #endif // _TARGET_ARM64_
1723 // Set the register numbers for a multireg argument.
1724 // There's nothing to do on x64/Ux because the structDesc has already been used to set the
1725 // register numbers.
1726 void SetMultiRegNums()
1728 #if FEATURE_MULTIREG_ARGS && !defined(UNIX_AMD64_ABI)
1734 regNumber argReg = getRegNum(0);
1736 unsigned int regSize = (hfaType == TYP_DOUBLE) ? 2 : 1;
1738 unsigned int regSize = 1;
1740 for (unsigned int regIndex = 1; regIndex < numRegs; regIndex++)
1742 argReg = (regNumber)(argReg + regSize);
1743 setRegNum(regIndex, argReg);
1745 #endif // FEATURE_MULTIREG_ARGS && !defined(UNIX_AMD64_ABI)
1748 // Check that the value of 'isStruct' is consistent.
1749 // A struct arg must be one of the following:
1750 // - A node of struct type,
1751 // - A GT_FIELD_LIST, or
1752 // - A node of a scalar type, passed in a single register or slot
1753 // (or two slots in the case of a struct pass on the stack as TYP_DOUBLE).
1755 void checkIsStruct()
1759 if (!varTypeIsStruct(node) && !node->OperIs(GT_FIELD_LIST))
1761 // This is the case where we are passing a struct as a primitive type.
1762 // On most targets, this is always a single register or slot.
1763 // However, on ARM this could be two slots if it is TYP_DOUBLE.
1764 bool isPassedAsPrimitiveType = ((numRegs == 1) || ((numRegs == 0) && (numSlots == 1)));
1766 if (!isPassedAsPrimitiveType)
1768 if (node->TypeGet() == TYP_DOUBLE && numRegs == 0 && (numSlots == 2))
1770 isPassedAsPrimitiveType = true;
1773 #endif // _TARGET_ARM_
1774 assert(isPassedAsPrimitiveType);
1779 assert(!varTypeIsStruct(node));
1788 //-------------------------------------------------------------------------
1790 // The class fgArgInfo is used to handle the arguments
1791 // when morphing a GT_CALL node.
1796 Compiler* compiler; // Back pointer to the compiler instance so that we can allocate memory
1797 GenTreeCall* callTree; // Back pointer to the GT_CALL node for this fgArgInfo
1798 unsigned argCount; // Updatable arg count value
1799 unsigned nextSlotNum; // Updatable slot count value
1800 unsigned stkLevel; // Stack depth when we make this call (for x86)
1802 #if defined(UNIX_X86_ABI)
1803 bool alignmentDone; // Updateable flag, set to 'true' after we've done any required alignment.
1804 unsigned stkSizeBytes; // Size of stack used by this call, in bytes. Calculated during fgMorphArgs().
1805 unsigned padStkAlign; // Stack alignment in bytes required before arguments are pushed for this call.
1806 // Computed dynamically during codegen, based on stkSizeBytes and the current
1807 // stack level (genStackLevel) when the first stack adjustment is made for
1811 #if FEATURE_FIXED_OUT_ARGS
1812 unsigned outArgSize; // Size of the out arg area for the call, will be at least MIN_ARG_AREA_FOR_CALL
1815 unsigned argTableSize; // size of argTable array (equal to the argCount when done with fgMorphArgs)
1816 bool hasRegArgs; // true if we have one or more register arguments
1817 bool hasStackArgs; // true if we have one or more stack arguments
1818 bool argsComplete; // marker for state
1819 bool argsSorted; // marker for state
1820 bool needsTemps; // one or more arguments must be copied to a temp by EvalArgsToTemps
1821 fgArgTabEntry** argTable; // variable sized array of per argument descrption: (i.e. argTable[argTableSize])
1824 void AddArg(fgArgTabEntry* curArgTabEntry);
1827 fgArgInfo(Compiler* comp, GenTreeCall* call, unsigned argCount);
1828 fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall);
1830 fgArgTabEntry* AddRegArg(unsigned argNum,
1837 bool isVararg = false);
1839 #ifdef UNIX_AMD64_ABI
1840 fgArgTabEntry* AddRegArg(unsigned argNum,
1846 const bool isStruct,
1847 const bool isVararg,
1848 const regNumber otherRegNum,
1849 const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* const structDescPtr = nullptr);
1850 #endif // UNIX_AMD64_ABI
1852 fgArgTabEntry* AddStkArg(unsigned argNum,
1858 bool isVararg = false);
1860 void RemorphReset();
1861 void UpdateRegArg(fgArgTabEntry* argEntry, GenTree* node, bool reMorphing);
1862 void UpdateStkArg(fgArgTabEntry* argEntry, GenTree* node, bool reMorphing);
1864 void SplitArg(unsigned argNum, unsigned numRegs, unsigned numSlots);
1866 void EvalToTmp(fgArgTabEntry* curArgTabEntry, unsigned tmpNum, GenTree* newNode);
1868 void ArgsComplete();
1872 void EvalArgsToTemps();
1878 fgArgTabEntry** ArgTable()
1882 unsigned GetNextSlotNum()
1896 return hasStackArgs;
1898 bool AreArgsComplete() const
1900 return argsComplete;
1902 #if FEATURE_FIXED_OUT_ARGS
1903 unsigned GetOutArgSize() const
1907 void SetOutArgSize(unsigned newVal)
1909 outArgSize = newVal;
1911 #endif // FEATURE_FIXED_OUT_ARGS
1913 #if defined(UNIX_X86_ABI)
1914 void ComputeStackAlignment(unsigned curStackLevelInBytes)
1916 padStkAlign = AlignmentPad(curStackLevelInBytes, STACK_ALIGN);
1919 unsigned GetStkAlign()
1924 void SetStkSizeBytes(unsigned newStkSizeBytes)
1926 stkSizeBytes = newStkSizeBytes;
1929 unsigned GetStkSizeBytes() const
1931 return stkSizeBytes;
1934 bool IsStkAlignmentDone() const
1936 return alignmentDone;
1939 void SetStkAlignmentDone()
1941 alignmentDone = true;
1943 #endif // defined(UNIX_X86_ABI)
1945 // Get the fgArgTabEntry for the arg at position argNum.
1946 fgArgTabEntry* GetArgEntry(unsigned argNum, bool reMorphing = true)
1948 fgArgTabEntry* curArgTabEntry = nullptr;
1952 // The arg table has not yet been sorted.
1953 curArgTabEntry = argTable[argNum];
1954 assert(curArgTabEntry->argNum == argNum);
1955 return curArgTabEntry;
1958 for (unsigned i = 0; i < argCount; i++)
1960 curArgTabEntry = argTable[i];
1961 if (curArgTabEntry->argNum == argNum)
1963 return curArgTabEntry;
1966 noway_assert(!"GetArgEntry: argNum not found");
1970 // Get the node for the arg at position argIndex.
1971 // Caller must ensure that this index is a valid arg index.
1972 GenTree* GetArgNode(unsigned argIndex)
1974 return GetArgEntry(argIndex)->node;
1977 void Dump(Compiler* compiler);
1981 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1982 // We have the ability to mark source expressions with "Test Labels."
1983 // These drive assertions within the JIT, or internal JIT testing. For example, we could label expressions
1984 // that should be CSE defs, and other expressions that should uses of those defs, with a shared label.
1986 enum TestLabel // This must be kept identical to System.Runtime.CompilerServices.JitTestLabel.TestLabel.
1989 TL_VN, // Defines a "VN equivalence class". (For full VN, including exceptions thrown).
1990 TL_VNNorm, // Like above, but uses the non-exceptional value of the expression.
1991 TL_CSE_Def, // This must be identified in the JIT as a CSE def
1992 TL_CSE_Use, // This must be identified in the JIT as a CSE use
1993 TL_LoopHoist, // Expression must (or must not) be hoisted out of the loop.
1996 struct TestLabelAndNum
2001 TestLabelAndNum() : m_tl(TestLabel(0)), m_num(0)
2006 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, TestLabelAndNum> NodeToTestDataMap;
2008 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2012 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2013 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2015 XX The big guy. The sections are currently organized as : XX
2017 XX o GenTree and BasicBlock XX
2029 XX o PrologScopeInfo XX
2030 XX o CodeGenerator XX
2035 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2036 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2039 struct HWIntrinsicInfo;
2043 friend class emitter;
2044 friend class UnwindInfo;
2045 friend class UnwindFragmentInfo;
2046 friend class UnwindEpilogInfo;
2047 friend class JitTimer;
2048 friend class LinearScan;
2049 friend class fgArgInfo;
2050 friend class Rationalizer;
2052 friend class Lowering;
2053 friend class CSE_DataFlow;
2054 friend class CSE_Heuristic;
2055 friend class CodeGenInterface;
2056 friend class CodeGen;
2057 friend class LclVarDsc;
2058 friend class TempDsc;
2060 friend class ObjectAllocator;
2061 friend class LocalAddressVisitor;
2062 friend struct GenTree;
2064 #ifdef FEATURE_HW_INTRINSICS
2065 friend struct HWIntrinsicInfo;
2066 #endif // FEATURE_HW_INTRINSICS
2068 #ifndef _TARGET_64BIT_
2069 friend class DecomposeLongs;
2070 #endif // !_TARGET_64BIT_
2073 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2074 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2076 XX Misc structs definitions XX
2078 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2079 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2083 #ifdef USING_VARIABLE_LIVE_RANGE
2084 VariableLiveKeeper* varLiveKeeper; // Used to manage VariableLiveRanges of variables
2086 void initializeVariableLiveKeeper();
2088 VariableLiveKeeper* getVariableLiveKeeper() const;
2089 #endif // USING_VARIABLE_LIVE_RANGE
2091 hashBvGlobalData hbvGlobalData; // Used by the hashBv bitvector package.
2110 bool dumpIRDataflow;
2111 bool dumpIRBlockHeaders;
2113 LPCWSTR dumpIRPhase;
2114 LPCWSTR dumpIRFormat;
2116 bool shouldUseVerboseTrees();
2117 bool asciiTrees; // If true, dump trees using only ASCII characters
2118 bool shouldDumpASCIITrees();
2119 bool verboseSsa; // If true, produce especially verbose dump output in SSA construction.
2120 bool shouldUseVerboseSsa();
2121 bool treesBeforeAfterMorph; // If true, print trees before/after morphing (paired by an intra-compilation id:
2122 int morphNum; // This counts the the trees that have been morphed, allowing us to label each uniquely.
2124 const char* VarNameToStr(VarName name)
2129 DWORD expensiveDebugCheckLevel;
2132 #if FEATURE_MULTIREG_RET
2133 GenTree* impAssignMultiRegTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass);
2134 #endif // FEATURE_MULTIREG_RET
2136 GenTree* impAssignSmallStructTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass);
2139 bool isSingleFloat32Struct(CORINFO_CLASS_HANDLE hClass);
2140 #endif // ARM_SOFTFP
2142 //-------------------------------------------------------------------------
2143 // Functions to handle homogeneous floating-point aggregates (HFAs) in ARM.
2144 // HFAs are one to four element structs where each element is the same
2145 // type, either all float or all double. They are treated specially
2146 // in the ARM Procedure Call Standard, specifically, they are passed in
2147 // floating-point registers instead of the general purpose registers.
2150 bool IsHfa(CORINFO_CLASS_HANDLE hClass);
2151 bool IsHfa(GenTree* tree);
2153 var_types GetHfaType(GenTree* tree);
2154 unsigned GetHfaCount(GenTree* tree);
2156 var_types GetHfaType(CORINFO_CLASS_HANDLE hClass);
2157 unsigned GetHfaCount(CORINFO_CLASS_HANDLE hClass);
2159 bool IsMultiRegReturnedType(CORINFO_CLASS_HANDLE hClass);
2161 //-------------------------------------------------------------------------
2162 // The following is used for validating format of EH table
2166 typedef struct EHNodeDsc* pEHNodeDsc;
2168 EHNodeDsc* ehnTree; // root of the tree comprising the EHnodes.
2169 EHNodeDsc* ehnNext; // root of the tree comprising the EHnodes.
2182 EHBlockType ehnBlockType; // kind of EH block
2183 IL_OFFSET ehnStartOffset; // IL offset of start of the EH block
2184 IL_OFFSET ehnEndOffset; // IL offset past end of the EH block. (TODO: looks like verInsertEhNode() sets this to
2185 // the last IL offset, not "one past the last one", i.e., the range Start to End is
2187 pEHNodeDsc ehnNext; // next (non-nested) block in sequential order
2188 pEHNodeDsc ehnChild; // leftmost nested block
2190 pEHNodeDsc ehnTryNode; // for filters and handlers, the corresponding try node
2191 pEHNodeDsc ehnHandlerNode; // for a try node, the corresponding handler node
2193 pEHNodeDsc ehnFilterNode; // if this is a try node and has a filter, otherwise 0
2194 pEHNodeDsc ehnEquivalent; // if blockType=tryNode, start offset and end offset is same,
2196 void ehnSetTryNodeType()
2198 ehnBlockType = TryNode;
2200 void ehnSetFilterNodeType()
2202 ehnBlockType = FilterNode;
2204 void ehnSetHandlerNodeType()
2206 ehnBlockType = HandlerNode;
2208 void ehnSetFinallyNodeType()
2210 ehnBlockType = FinallyNode;
2212 void ehnSetFaultNodeType()
2214 ehnBlockType = FaultNode;
2217 BOOL ehnIsTryBlock()
2219 return ehnBlockType == TryNode;
2221 BOOL ehnIsFilterBlock()
2223 return ehnBlockType == FilterNode;
2225 BOOL ehnIsHandlerBlock()
2227 return ehnBlockType == HandlerNode;
2229 BOOL ehnIsFinallyBlock()
2231 return ehnBlockType == FinallyNode;
2233 BOOL ehnIsFaultBlock()
2235 return ehnBlockType == FaultNode;
2238 // returns true if there is any overlap between the two nodes
2239 static BOOL ehnIsOverlap(pEHNodeDsc node1, pEHNodeDsc node2)
2241 if (node1->ehnStartOffset < node2->ehnStartOffset)
2243 return (node1->ehnEndOffset >= node2->ehnStartOffset);
2247 return (node1->ehnStartOffset <= node2->ehnEndOffset);
2251 // fails with BADCODE if inner is not completely nested inside outer
2252 static BOOL ehnIsNested(pEHNodeDsc inner, pEHNodeDsc outer)
2254 return ((inner->ehnStartOffset >= outer->ehnStartOffset) && (inner->ehnEndOffset <= outer->ehnEndOffset));
2258 //-------------------------------------------------------------------------
2259 // Exception handling functions
2262 #if !FEATURE_EH_FUNCLETS
2264 bool ehNeedsShadowSPslots()
2266 return (info.compXcptnsCount || opts.compDbgEnC);
2269 // 0 for methods with no EH
2270 // 1 for methods with non-nested EH, or where only the try blocks are nested
2271 // 2 for a method with a catch within a catch
2273 unsigned ehMaxHndNestingCount;
2275 #endif // !FEATURE_EH_FUNCLETS
2277 static bool jitIsBetween(unsigned value, unsigned start, unsigned end);
2278 static bool jitIsBetweenInclusive(unsigned value, unsigned start, unsigned end);
2280 bool bbInCatchHandlerILRange(BasicBlock* blk);
2281 bool bbInFilterILRange(BasicBlock* blk);
2282 bool bbInTryRegions(unsigned regionIndex, BasicBlock* blk);
2283 bool bbInExnFlowRegions(unsigned regionIndex, BasicBlock* blk);
2284 bool bbInHandlerRegions(unsigned regionIndex, BasicBlock* blk);
2285 bool bbInCatchHandlerRegions(BasicBlock* tryBlk, BasicBlock* hndBlk);
2286 unsigned short bbFindInnermostCommonTryRegion(BasicBlock* bbOne, BasicBlock* bbTwo);
2288 unsigned short bbFindInnermostTryRegionContainingHandlerRegion(unsigned handlerIndex);
2289 unsigned short bbFindInnermostHandlerRegionContainingTryRegion(unsigned tryIndex);
2291 // Returns true if "block" is the start of a try region.
2292 bool bbIsTryBeg(BasicBlock* block);
2294 // Returns true if "block" is the start of a handler or filter region.
2295 bool bbIsHandlerBeg(BasicBlock* block);
2297 // Returns true iff "block" is where control flows if an exception is raised in the
2298 // try region, and sets "*regionIndex" to the index of the try for the handler.
2299 // Differs from "IsHandlerBeg" in the case of filters, where this is true for the first
2300 // block of the filter, but not for the filter's handler.
2301 bool bbIsExFlowBlock(BasicBlock* block, unsigned* regionIndex);
2303 bool ehHasCallableHandlers();
2305 // Return the EH descriptor for the given region index.
2306 EHblkDsc* ehGetDsc(unsigned regionIndex);
2308 // Return the EH index given a region descriptor.
2309 unsigned ehGetIndex(EHblkDsc* ehDsc);
2311 // Return the EH descriptor index of the enclosing try, for the given region index.
2312 unsigned ehGetEnclosingTryIndex(unsigned regionIndex);
2314 // Return the EH descriptor index of the enclosing handler, for the given region index.
2315 unsigned ehGetEnclosingHndIndex(unsigned regionIndex);
2317 // Return the EH descriptor for the most nested 'try' region this BasicBlock is a member of (or nullptr if this
2318 // block is not in a 'try' region).
2319 EHblkDsc* ehGetBlockTryDsc(BasicBlock* block);
2321 // Return the EH descriptor for the most nested filter or handler region this BasicBlock is a member of (or nullptr
2322 // if this block is not in a filter or handler region).
2323 EHblkDsc* ehGetBlockHndDsc(BasicBlock* block);
2325 // Return the EH descriptor for the most nested region that may handle exceptions raised in this BasicBlock (or
2326 // nullptr if this block's exceptions propagate to caller).
2327 EHblkDsc* ehGetBlockExnFlowDsc(BasicBlock* block);
2329 EHblkDsc* ehIsBlockTryLast(BasicBlock* block);
2330 EHblkDsc* ehIsBlockHndLast(BasicBlock* block);
2331 bool ehIsBlockEHLast(BasicBlock* block);
2333 bool ehBlockHasExnFlowDsc(BasicBlock* block);
2335 // Return the region index of the most nested EH region this block is in.
2336 unsigned ehGetMostNestedRegionIndex(BasicBlock* block, bool* inTryRegion);
2338 // Find the true enclosing try index, ignoring 'mutual protect' try. Uses IL ranges to check.
2339 unsigned ehTrueEnclosingTryIndexIL(unsigned regionIndex);
2341 // Return the index of the most nested enclosing region for a particular EH region. Returns NO_ENCLOSING_INDEX
2342 // if there is no enclosing region. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion'
2343 // is set to 'true' if the enclosing region is a 'try', or 'false' if the enclosing region is a handler.
2344 // (It can never be a filter.)
2345 unsigned ehGetEnclosingRegionIndex(unsigned regionIndex, bool* inTryRegion);
2347 // A block has been deleted. Update the EH table appropriately.
2348 void ehUpdateForDeletedBlock(BasicBlock* block);
2350 // Determine whether a block can be deleted while preserving the EH normalization rules.
2351 bool ehCanDeleteEmptyBlock(BasicBlock* block);
2353 // Update the 'last' pointers in the EH table to reflect new or deleted blocks in an EH region.
2354 void ehUpdateLastBlocks(BasicBlock* oldLast, BasicBlock* newLast);
2356 // For a finally handler, find the region index that the BBJ_CALLFINALLY lives in that calls the handler,
2357 // or NO_ENCLOSING_INDEX if the BBJ_CALLFINALLY lives in the main function body. Normally, the index
2358 // is the same index as the handler (and the BBJ_CALLFINALLY lives in the 'try' region), but for AMD64 the
2359 // BBJ_CALLFINALLY lives in the enclosing try or handler region, whichever is more nested, or the main function
2360 // body. If the returned index is not NO_ENCLOSING_INDEX, then '*inTryRegion' is set to 'true' if the
2361 // BBJ_CALLFINALLY lives in the returned index's 'try' region, or 'false' if lives in the handler region. (It never
2362 // lives in a filter.)
2363 unsigned ehGetCallFinallyRegionIndex(unsigned finallyIndex, bool* inTryRegion);
2365 // Find the range of basic blocks in which all BBJ_CALLFINALLY will be found that target the 'finallyIndex' region's
2366 // handler. Set begBlk to the first block, and endBlk to the block after the last block of the range
2367 // (nullptr if the last block is the last block in the program).
2368 // Precondition: 'finallyIndex' is the EH region of a try/finally clause.
2369 void ehGetCallFinallyBlockRange(unsigned finallyIndex, BasicBlock** begBlk, BasicBlock** endBlk);
2372 // Given a BBJ_CALLFINALLY block and the EH region index of the finally it is calling, return
2373 // 'true' if the BBJ_CALLFINALLY is in the correct EH region.
2374 bool ehCallFinallyInCorrectRegion(BasicBlock* blockCallFinally, unsigned finallyIndex);
2377 #if FEATURE_EH_FUNCLETS
2378 // Do we need a PSPSym in the main function? For codegen purposes, we only need one
2379 // if there is a filter that protects a region with a nested EH clause (such as a
2380 // try/catch nested in the 'try' body of a try/filter/filter-handler). See
2381 // genFuncletProlog() for more details. However, the VM seems to use it for more
2382 // purposes, maybe including debugging. Until we are sure otherwise, always create
2383 // a PSPSym for functions with any EH.
2384 bool ehNeedsPSPSym() const
2388 #else // _TARGET_X86_
2389 return compHndBBtabCount > 0;
2390 #endif // _TARGET_X86_
2393 bool ehAnyFunclets(); // Are there any funclets in this function?
2394 unsigned ehFuncletCount(); // Return the count of funclets in the function
2396 unsigned bbThrowIndex(BasicBlock* blk); // Get the index to use as the cache key for sharing throw blocks
2397 #else // !FEATURE_EH_FUNCLETS
2398 bool ehAnyFunclets()
2402 unsigned ehFuncletCount()
2407 unsigned bbThrowIndex(BasicBlock* blk)
2409 return blk->bbTryIndex;
2410 } // Get the index to use as the cache key for sharing throw blocks
2411 #endif // !FEATURE_EH_FUNCLETS
2413 // Returns a flowList representing the "EH predecessors" of "blk". These are the normal predecessors of
2414 // "blk", plus one special case: if "blk" is the first block of a handler, considers the predecessor(s) of the first
2415 // first block of the corresponding try region to be "EH predecessors". (If there is a single such predecessor,
2416 // for example, we want to consider that the immediate dominator of the catch clause start block, so it's
2417 // convenient to also consider it a predecessor.)
2418 flowList* BlockPredsWithEH(BasicBlock* blk);
2420 // This table is useful for memoization of the method above.
2421 typedef JitHashTable<BasicBlock*, JitPtrKeyFuncs<BasicBlock>, flowList*> BlockToFlowListMap;
2422 BlockToFlowListMap* m_blockToEHPreds;
2423 BlockToFlowListMap* GetBlockToEHPreds()
2425 if (m_blockToEHPreds == nullptr)
2427 m_blockToEHPreds = new (getAllocator()) BlockToFlowListMap(getAllocator());
2429 return m_blockToEHPreds;
2432 void* ehEmitCookie(BasicBlock* block);
2433 UNATIVE_OFFSET ehCodeOffset(BasicBlock* block);
2435 EHblkDsc* ehInitHndRange(BasicBlock* src, IL_OFFSET* hndBeg, IL_OFFSET* hndEnd, bool* inFilter);
2437 EHblkDsc* ehInitTryRange(BasicBlock* src, IL_OFFSET* tryBeg, IL_OFFSET* tryEnd);
2439 EHblkDsc* ehInitHndBlockRange(BasicBlock* blk, BasicBlock** hndBeg, BasicBlock** hndLast, bool* inFilter);
2441 EHblkDsc* ehInitTryBlockRange(BasicBlock* blk, BasicBlock** tryBeg, BasicBlock** tryLast);
2443 void fgSetTryEnd(EHblkDsc* handlerTab, BasicBlock* newTryLast);
2445 void fgSetHndEnd(EHblkDsc* handlerTab, BasicBlock* newHndLast);
2447 void fgSkipRmvdBlocks(EHblkDsc* handlerTab);
2449 void fgAllocEHTable();
2451 void fgRemoveEHTableEntry(unsigned XTnum);
2453 #if FEATURE_EH_FUNCLETS
2455 EHblkDsc* fgAddEHTableEntry(unsigned XTnum);
2457 #endif // FEATURE_EH_FUNCLETS
2461 #endif // !FEATURE_EH
2463 void fgSortEHTable();
2465 // Causes the EH table to obey some well-formedness conditions, by inserting
2466 // empty BB's when necessary:
2467 // * No block is both the first block of a handler and the first block of a try.
2468 // * No block is the first block of multiple 'try' regions.
2469 // * No block is the last block of multiple EH regions.
2470 void fgNormalizeEH();
2471 bool fgNormalizeEHCase1();
2472 bool fgNormalizeEHCase2();
2473 bool fgNormalizeEHCase3();
2476 void dispIncomingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
2477 void dispOutgoingEHClause(unsigned num, const CORINFO_EH_CLAUSE& clause);
2478 void fgVerifyHandlerTab();
2479 void fgDispHandlerTab();
2482 bool fgNeedToSortEHTable;
2484 void verInitEHTree(unsigned numEHClauses);
2485 void verInsertEhNode(CORINFO_EH_CLAUSE* clause, EHblkDsc* handlerTab);
2486 void verInsertEhNodeInTree(EHNodeDsc** ppRoot, EHNodeDsc* node);
2487 void verInsertEhNodeParent(EHNodeDsc** ppRoot, EHNodeDsc* node);
2488 void verCheckNestingLevel(EHNodeDsc* initRoot);
2491 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2492 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2494 XX GenTree and BasicBlock XX
2496 XX Functions to allocate and display the GenTrees and BasicBlocks XX
2498 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2499 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2502 // Functions to create nodes
2503 GenTreeStmt* gtNewStmt(GenTree* expr = nullptr, IL_OFFSETX offset = BAD_IL_OFFSET);
2506 GenTree* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, bool doSimplifications = TRUE);
2508 // For binary opers.
2509 GenTree* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2);
2511 GenTree* gtNewQmarkNode(var_types type, GenTree* cond, GenTree* colon);
2513 GenTree* gtNewLargeOperNode(genTreeOps oper,
2514 var_types type = TYP_I_IMPL,
2515 GenTree* op1 = nullptr,
2516 GenTree* op2 = nullptr);
2518 GenTreeIntCon* gtNewIconNode(ssize_t value, var_types type = TYP_INT);
2520 GenTree* gtNewPhysRegNode(regNumber reg, var_types type);
2522 GenTree* gtNewJmpTableNode();
2524 GenTree* gtNewIndOfIconHandleNode(var_types indType, size_t value, unsigned iconFlags, bool isInvariant);
2526 GenTree* gtNewIconHandleNode(size_t value, unsigned flags, FieldSeqNode* fields = nullptr);
2528 unsigned gtTokenToIconFlags(unsigned token);
2530 GenTree* gtNewIconEmbHndNode(void* value, void* pValue, unsigned flags, void* compileTimeHandle);
2532 GenTree* gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd);
2533 GenTree* gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd);
2534 GenTree* gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd);
2535 GenTree* gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd);
2537 GenTree* gtNewStringLiteralNode(InfoAccessType iat, void* pValue);
2539 GenTree* gtNewLconNode(__int64 value);
2541 GenTree* gtNewDconNode(double value, var_types type = TYP_DOUBLE);
2543 GenTree* gtNewSconNode(int CPX, CORINFO_MODULE_HANDLE scpHandle);
2545 GenTree* gtNewZeroConNode(var_types type);
2547 GenTree* gtNewOneConNode(var_types type);
2550 GenTree* gtNewSIMDVectorZero(var_types simdType, var_types baseType, unsigned size);
2551 GenTree* gtNewSIMDVectorOne(var_types simdType, var_types baseType, unsigned size);
2554 GenTree* gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, unsigned size, bool isVolatile, bool isCopyBlock);
2556 GenTree* gtNewPutArgReg(var_types type, GenTree* arg, regNumber argReg);
2558 GenTree* gtNewBitCastNode(var_types type, GenTree* arg);
2561 void gtBlockOpInit(GenTree* result, GenTree* dst, GenTree* srcOrFillVal, bool isVolatile);
2564 GenTree* gtNewObjNode(CORINFO_CLASS_HANDLE structHnd, GenTree* addr);
2565 void gtSetObjGcInfo(GenTreeObj* objNode);
2566 GenTree* gtNewStructVal(CORINFO_CLASS_HANDLE structHnd, GenTree* addr);
2567 GenTree* gtNewBlockVal(GenTree* addr, unsigned size);
2569 GenTree* gtNewCpObjNode(GenTree* dst, GenTree* src, CORINFO_CLASS_HANDLE structHnd, bool isVolatile);
2571 GenTreeArgList* gtNewListNode(GenTree* op1, GenTreeArgList* op2);
2573 GenTreeCall* gtNewCallNode(gtCallTypes callType,
2574 CORINFO_METHOD_HANDLE handle,
2576 GenTreeArgList* args,
2577 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2579 GenTreeCall* gtNewIndCallNode(GenTree* addr,
2581 GenTreeArgList* args,
2582 IL_OFFSETX ilOffset = BAD_IL_OFFSET);
2584 GenTreeCall* gtNewHelperCallNode(unsigned helper, var_types type, GenTreeArgList* args = nullptr);
2586 GenTree* gtNewLclvNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));
2587 GenTree* gtNewLclLNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));
2590 GenTreeSIMD* gtNewSIMDNode(
2591 var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
2592 GenTreeSIMD* gtNewSIMDNode(
2593 var_types type, GenTree* op1, GenTree* op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size);
2594 void SetOpLclRelatedToSIMDIntrinsic(GenTree* op);
2597 #ifdef FEATURE_HW_INTRINSICS
2598 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2599 NamedIntrinsic hwIntrinsicID,
2602 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
2603 var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
2604 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
2605 var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
2606 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2610 NamedIntrinsic hwIntrinsicID,
2613 GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(var_types type,
2618 NamedIntrinsic hwIntrinsicID,
2621 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID);
2622 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type,
2625 NamedIntrinsic hwIntrinsicID);
2626 GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(
2627 var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID);
2628 GenTree* gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd);
2629 CORINFO_CLASS_HANDLE gtGetStructHandleForHWSIMD(var_types simdType, var_types simdBaseType);
2630 #endif // FEATURE_HW_INTRINSICS
2632 GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset);
2633 GenTree* gtNewInlineCandidateReturnExpr(GenTree* inlineCandidate, var_types type);
2635 GenTree* gtNewFieldRef(var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj = nullptr, DWORD offset = 0);
2637 GenTree* gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree* indexOp);
2639 GenTreeArrLen* gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset);
2641 GenTree* gtNewIndir(var_types typ, GenTree* addr);
2643 GenTreeArgList* gtNewArgList(GenTree* op);
2644 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2);
2645 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2, GenTree* op3);
2646 GenTreeArgList* gtNewArgList(GenTree* op1, GenTree* op2, GenTree* op3, GenTree* op4);
2648 static fgArgTabEntry* gtArgEntryByArgNum(GenTreeCall* call, unsigned argNum);
2649 static fgArgTabEntry* gtArgEntryByNode(GenTreeCall* call, GenTree* node);
2650 fgArgTabEntry* gtArgEntryByLateArgIndex(GenTreeCall* call, unsigned lateArgInx);
2651 static GenTree* gtArgNodeByLateArgInx(GenTreeCall* call, unsigned lateArgInx);
2652 bool gtArgIsThisPtr(fgArgTabEntry* argEntry);
2654 GenTree* gtNewAssignNode(GenTree* dst, GenTree* src);
2656 GenTree* gtNewTempAssign(unsigned tmp,
2658 GenTreeStmt** pAfterStmt = nullptr,
2659 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
2660 BasicBlock* block = nullptr);
2662 GenTree* gtNewRefCOMfield(GenTree* objPtr,
2663 CORINFO_RESOLVED_TOKEN* pResolvedToken,
2664 CORINFO_ACCESS_FLAGS access,
2665 CORINFO_FIELD_INFO* pFieldInfo,
2667 CORINFO_CLASS_HANDLE structType,
2670 GenTree* gtNewNothingNode();
2672 GenTree* gtNewArgPlaceHolderNode(var_types type, CORINFO_CLASS_HANDLE clsHnd);
2674 GenTree* gtUnusedValNode(GenTree* expr);
2676 GenTreeCast* gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
2678 GenTreeCast* gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
2680 GenTreeAllocObj* gtNewAllocObjNode(
2681 unsigned int helper, bool helperHasSideEffects, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTree* op1);
2683 GenTreeAllocObj* gtNewAllocObjNode(CORINFO_RESOLVED_TOKEN* pResolvedToken, BOOL useParent);
2685 GenTree* gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* lookupTree);
2687 //------------------------------------------------------------------------
2688 // Other GenTree functions
2690 GenTree* gtClone(GenTree* tree, bool complexOK = false);
2692 // If `tree` is a lclVar with lclNum `varNum`, return an IntCns with value `varVal`; otherwise,
2693 // create a copy of `tree`, adding specified flags, replacing uses of lclVar `deepVarNum` with
2694 // IntCnses with value `deepVarVal`.
2695 GenTree* gtCloneExpr(
2696 GenTree* tree, unsigned addFlags, unsigned varNum, int varVal, unsigned deepVarNum, int deepVarVal);
2698 // Create a copy of `tree`, optionally adding specifed flags, and optionally mapping uses of local
2699 // `varNum` to int constants with value `varVal`.
2700 GenTree* gtCloneExpr(GenTree* tree, unsigned addFlags = 0, unsigned varNum = BAD_VAR_NUM, int varVal = 0)
2702 return gtCloneExpr(tree, addFlags, varNum, varVal, varNum, varVal);
2705 // Internal helper for cloning a call
2706 GenTreeCall* gtCloneExprCallHelper(GenTreeCall* call,
2707 unsigned addFlags = 0,
2708 unsigned deepVarNum = BAD_VAR_NUM,
2709 int deepVarVal = 0);
2711 // Create copy of an inline or guarded devirtualization candidate tree.
2712 GenTreeCall* gtCloneCandidateCall(GenTreeCall* call);
2714 GenTree* gtReplaceTree(GenTreeStmt* stmt, GenTree* tree, GenTree* replacementTree);
2716 void gtUpdateSideEffects(GenTreeStmt* stmt, GenTree* tree);
2718 void gtUpdateTreeAncestorsSideEffects(GenTree* tree);
2720 void gtUpdateStmtSideEffects(GenTreeStmt* stmt);
2722 void gtUpdateNodeSideEffects(GenTree* tree);
2724 void gtUpdateNodeOperSideEffects(GenTree* tree);
2726 // Returns "true" iff the complexity (not formally defined, but first interpretation
2727 // is #of nodes in subtree) of "tree" is greater than "limit".
2728 // (This is somewhat redundant with the "gtCostEx/gtCostSz" fields, but can be used
2729 // before they have been set.)
2730 bool gtComplexityExceeds(GenTree** tree, unsigned limit);
2732 bool gtCompareTree(GenTree* op1, GenTree* op2);
2734 GenTree* gtReverseCond(GenTree* tree);
2736 bool gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly);
2738 bool gtHasLocalsWithAddrOp(GenTree* tree);
2740 unsigned gtSetListOrder(GenTree* list, bool regs, bool isListCallArgs);
2742 void gtWalkOp(GenTree** op1, GenTree** op2, GenTree* base, bool constOnly);
2745 unsigned gtHashValue(GenTree* tree);
2747 GenTree* gtWalkOpEffectiveVal(GenTree* op);
2750 void gtPrepareCost(GenTree* tree);
2751 bool gtIsLikelyRegVar(GenTree* tree);
2753 // Returns true iff the secondNode can be swapped with firstNode.
2754 bool gtCanSwapOrder(GenTree* firstNode, GenTree* secondNode);
2756 // Given an address expression, compute its costs and addressing mode opportunities,
2757 // and mark addressing mode candidates as GTF_DONT_CSE.
2758 // TODO-Throughput - Consider actually instantiating these early, to avoid
2759 // having to re-run the algorithm that looks for them (might also improve CQ).
2760 bool gtMarkAddrMode(GenTree* addr, int* costEx, int* costSz, var_types type);
2762 unsigned gtSetEvalOrder(GenTree* tree);
2764 void gtSetStmtInfo(GenTreeStmt* stmt);
2766 // Returns "true" iff "node" has any of the side effects in "flags".
2767 bool gtNodeHasSideEffects(GenTree* node, unsigned flags);
2769 // Returns "true" iff "tree" or its (transitive) children have any of the side effects in "flags".
2770 bool gtTreeHasSideEffects(GenTree* tree, unsigned flags);
2772 // Appends 'expr' in front of 'list'
2773 // 'list' will typically start off as 'nullptr'
2774 // when 'list' is non-null a GT_COMMA node is used to insert 'expr'
2775 GenTree* gtBuildCommaList(GenTree* list, GenTree* expr);
2777 void gtExtractSideEffList(GenTree* expr,
2779 unsigned flags = GTF_SIDE_EFFECT,
2780 bool ignoreRoot = false);
2782 GenTree* gtGetThisArg(GenTreeCall* call);
2784 // Static fields of struct types (and sometimes the types that those are reduced to) are represented by having the
2785 // static field contain an object pointer to the boxed struct. This simplifies the GC implementation...but
2786 // complicates the JIT somewhat. This predicate returns "true" iff a node with type "fieldNodeType", representing
2787 // the given "fldHnd", is such an object pointer.
2788 bool gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd);
2790 // Return true if call is a recursive call; return false otherwise.
2791 // Note when inlining, this looks for calls back to the root method.
2792 bool gtIsRecursiveCall(GenTreeCall* call)
2794 return gtIsRecursiveCall(call->gtCallMethHnd);
2797 bool gtIsRecursiveCall(CORINFO_METHOD_HANDLE callMethodHandle)
2799 return (callMethodHandle == impInlineRoot()->info.compMethodHnd);
2802 //-------------------------------------------------------------------------
2804 GenTree* gtFoldExpr(GenTree* tree);
2807 // TODO-Amd64-Unix: Remove this when the clang optimizer is fixed and/or the method implementation is
2808 // refactored in a simpler code. This is a workaround for a bug in the clang-3.5 optimizer. The issue is that in
2809 // release build the optimizer is mistyping (or just wrongly decides to use 32 bit operation for a corner case
2810 // of MIN_LONG) the args of the (ltemp / lval2) to int (it does a 32 bit div operation instead of 64 bit) - see
2811 // the implementation of the method in gentree.cpp. For the case of lval1 and lval2 equal to MIN_LONG
2812 // (0x8000000000000000) this results in raising a SIGFPE. The method implementation is rather complex. Disable
2813 // optimizations for now.
2814 __attribute__((optnone))
2816 gtFoldExprConst(GenTree* tree);
2817 GenTree* gtFoldExprSpecial(GenTree* tree);
2818 GenTree* gtFoldExprCompare(GenTree* tree);
2819 GenTree* gtCreateHandleCompare(genTreeOps oper,
2822 CorInfoInlineTypeCheck typeCheckInliningResult);
2823 GenTree* gtFoldExprCall(GenTreeCall* call);
2824 GenTree* gtFoldTypeCompare(GenTree* tree);
2825 GenTree* gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2);
2827 // Options to control behavior of gtTryRemoveBoxUpstreamEffects
2828 enum BoxRemovalOptions
2830 BR_REMOVE_AND_NARROW, // remove effects, minimize remaining work, return possibly narrowed source tree
2831 BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE, // remove effects and minimize remaining work, return type handle tree
2832 BR_REMOVE_BUT_NOT_NARROW, // remove effects, return original source tree
2833 BR_DONT_REMOVE, // check if removal is possible, return copy source tree
2834 BR_DONT_REMOVE_WANT_TYPE_HANDLE, // check if removal is possible, return type handle tree
2835 BR_MAKE_LOCAL_COPY // revise box to copy to temp local and return local's address
2838 GenTree* gtTryRemoveBoxUpstreamEffects(GenTree* tree, BoxRemovalOptions options = BR_REMOVE_AND_NARROW);
2839 GenTree* gtOptimizeEnumHasFlag(GenTree* thisOp, GenTree* flagOp);
2841 //-------------------------------------------------------------------------
2842 // Get the handle, if any.
2843 CORINFO_CLASS_HANDLE gtGetStructHandleIfPresent(GenTree* tree);
2844 // Get the handle, and assert if not found.
2845 CORINFO_CLASS_HANDLE gtGetStructHandle(GenTree* tree);
2846 // Get the handle for a ref type.
2847 CORINFO_CLASS_HANDLE gtGetClassHandle(GenTree* tree, bool* pIsExact, bool* pIsNonNull);
2848 // Get the class handle for an helper call
2849 CORINFO_CLASS_HANDLE gtGetHelperCallClassHandle(GenTreeCall* call, bool* pIsExact, bool* pIsNonNull);
2850 // Get the element handle for an array of ref type.
2851 CORINFO_CLASS_HANDLE gtGetArrayElementClassHandle(GenTree* array);
2852 // Get a class handle from a helper call argument
2853 CORINFO_CLASS_HANDLE gtGetHelperArgClassHandle(GenTree* array,
2854 unsigned* runtimeLookupCount = nullptr,
2855 GenTree** handleTree = nullptr);
2856 // Get the class handle for a field
2857 CORINFO_CLASS_HANDLE gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull);
2858 // Check if this tree is a gc static base helper call
2859 bool gtIsStaticGCBaseHelperCall(GenTree* tree);
2861 //-------------------------------------------------------------------------
2862 // Functions to display the trees
2865 void gtDispNode(GenTree* tree, IndentStack* indentStack, __in_z const char* msg, bool isLIR);
2867 void gtDispVN(GenTree* tree);
2868 void gtDispConst(GenTree* tree);
2869 void gtDispLeaf(GenTree* tree, IndentStack* indentStack);
2870 void gtDispNodeName(GenTree* tree);
2871 void gtDispRegVal(GenTree* tree);
2883 void gtDispChild(GenTree* child,
2884 IndentStack* indentStack,
2886 __in_opt const char* msg = nullptr,
2887 bool topOnly = false);
2888 void gtDispTree(GenTree* tree,
2889 IndentStack* indentStack = nullptr,
2890 __in_opt const char* msg = nullptr,
2891 bool topOnly = false,
2892 bool isLIR = false);
2893 void gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, const char** ilNameOut, unsigned* ilNumOut);
2894 int gtGetLclVarName(unsigned lclNum, char* buf, unsigned buf_remaining);
2895 char* gtGetLclVarName(unsigned lclNum);
2896 void gtDispLclVar(unsigned varNum, bool padForBiggestDisp = true);
2897 void gtDispTreeList(GenTree* tree, IndentStack* indentStack = nullptr);
2898 void gtGetArgMsg(GenTreeCall* call, GenTree* arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength);
2899 void gtGetLateArgMsg(GenTreeCall* call, GenTree* arg, int argNum, int listCount, char* bufp, unsigned bufLength);
2900 void gtDispArgList(GenTreeCall* call, IndentStack* indentStack);
2901 void gtDispFieldSeq(FieldSeqNode* pfsn);
2903 void gtDispRange(LIR::ReadOnlyRange const& range);
2905 void gtDispTreeRange(LIR::Range& containingRange, GenTree* tree);
2907 void gtDispLIRNode(GenTree* node, const char* prefixMsg = nullptr);
2919 typedef fgWalkResult(fgWalkPreFn)(GenTree** pTree, fgWalkData* data);
2920 typedef fgWalkResult(fgWalkPostFn)(GenTree** pTree, fgWalkData* data);
2923 static fgWalkPreFn gtAssertColonCond;
2925 static fgWalkPreFn gtMarkColonCond;
2926 static fgWalkPreFn gtClearColonCond;
2928 GenTree** gtFindLink(GenTreeStmt* stmt, GenTree* node);
2929 bool gtHasCatchArg(GenTree* tree);
2931 typedef ArrayStack<GenTree*> GenTreeStack;
2933 static bool gtHasCallOnStack(GenTreeStack* parentStack);
2935 //=========================================================================
2936 // BasicBlock functions
2938 // This is a debug flag we will use to assert when creating block during codegen
2939 // as this interferes with procedure splitting. If you know what you're doing, set
2940 // it to true before creating the block. (DEBUG only)
2941 bool fgSafeBasicBlockCreation;
2944 BasicBlock* bbNewBasicBlock(BBjumpKinds jumpKind);
2947 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2948 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2952 XX The variables to be used by the code generator. XX
2954 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2955 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2959 // For both PROMOTION_TYPE_NONE and PROMOTION_TYPE_DEPENDENT the struct will
2960 // be placed in the stack frame and it's fields must be laid out sequentially.
2962 // For PROMOTION_TYPE_INDEPENDENT each of the struct's fields is replaced by
2963 // a local variable that can be enregistered or placed in the stack frame.
2964 // The fields do not need to be laid out sequentially
2966 enum lvaPromotionType
2968 PROMOTION_TYPE_NONE, // The struct local is not promoted
2969 PROMOTION_TYPE_INDEPENDENT, // The struct local is promoted,
2970 // and its field locals are independent of its parent struct local.
2971 PROMOTION_TYPE_DEPENDENT // The struct local is promoted,
2972 // but its field locals depend on its parent struct local.
2975 static int __cdecl RefCntCmp(const void* op1, const void* op2);
2976 static int __cdecl WtdRefCntCmp(const void* op1, const void* op2);
2978 /*****************************************************************************/
2980 enum FrameLayoutState
2983 INITIAL_FRAME_LAYOUT,
2984 PRE_REGALLOC_FRAME_LAYOUT,
2985 REGALLOC_FRAME_LAYOUT,
2986 TENTATIVE_FRAME_LAYOUT,
2991 RefCountState lvaRefCountState; // Current local ref count state
2993 bool lvaLocalVarRefCounted() const
2995 return lvaRefCountState == RCS_NORMAL;
2998 bool lvaTrackedFixed; // true: We cannot add new 'tracked' variable
2999 unsigned lvaCount; // total number of locals
3001 unsigned lvaRefCount; // total number of references to locals
3002 LclVarDsc* lvaTable; // variable descriptor table
3003 unsigned lvaTableCnt; // lvaTable size (>= lvaCount)
3005 LclVarDsc** lvaRefSorted; // table sorted by refcount
3007 unsigned short lvaTrackedCount; // actual # of locals being tracked
3008 unsigned lvaTrackedCountInSizeTUnits; // min # of size_t's sufficient to hold a bit for all the locals being tracked
3011 VARSET_TP lvaTrackedVars; // set of tracked variables
3013 #ifndef _TARGET_64BIT_
3014 VARSET_TP lvaLongVars; // set of long (64-bit) variables
3016 VARSET_TP lvaFloatVars; // set of floating-point (32-bit and 64-bit) variables
3018 unsigned lvaCurEpoch; // VarSets are relative to a specific set of tracked var indices.
3019 // It that changes, this changes. VarSets from different epochs
3020 // cannot be meaningfully combined.
3022 unsigned GetCurLVEpoch()
3027 // reverse map of tracked number to var number
3028 unsigned* lvaTrackedToVarNum;
3032 // # of procs compiled a with double-aligned stack
3033 static unsigned s_lvaDoubleAlignedProcsCount;
3037 // Getters and setters for address-exposed and do-not-enregister local var properties.
3038 bool lvaVarAddrExposed(unsigned varNum);
3039 void lvaSetVarAddrExposed(unsigned varNum);
3040 bool lvaVarDoNotEnregister(unsigned varNum);
3042 // Reasons why we can't enregister. Some of these correspond to debug properties of local vars.
3043 enum DoNotEnregisterReason
3048 DNER_VMNeedsStackAddr,
3049 DNER_LiveInOutOfHandler,
3050 DNER_LiveAcrossUnmanagedCall,
3051 DNER_BlockOp, // Is read or written via a block operation that explicitly takes the address.
3052 DNER_IsStructArg, // Is a struct passed as an argument in a way that requires a stack location.
3053 DNER_DepField, // It is a field of a dependently promoted struct
3054 DNER_NoRegVars, // opts.compFlags & CLFLG_REGVAR is not set
3055 DNER_MinOptsGC, // It is a GC Ref and we are compiling MinOpts
3056 #if !defined(_TARGET_64BIT_)
3057 DNER_LongParamField, // It is a decomposed field of a long parameter.
3059 #ifdef JIT32_GCENCODER
3064 void lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregisterReason reason));
3066 unsigned lvaVarargsHandleArg;
3068 unsigned lvaVarargsBaseOfStkArgs; // Pointer (computed based on incoming varargs handle) to the start of the stack
3070 #endif // _TARGET_X86_
3072 unsigned lvaInlinedPInvokeFrameVar; // variable representing the InlinedCallFrame
3073 unsigned lvaReversePInvokeFrameVar; // variable representing the reverse PInvoke frame
3074 #if FEATURE_FIXED_OUT_ARGS
3075 unsigned lvaPInvokeFrameRegSaveVar; // variable representing the RegSave for PInvoke inlining.
3077 unsigned lvaMonAcquired; // boolean variable introduced into in synchronized methods
3078 // that tracks whether the lock has been taken
3080 unsigned lvaArg0Var; // The lclNum of arg0. Normally this will be info.compThisArg.
3081 // However, if there is a "ldarga 0" or "starg 0" in the IL,
3082 // we will redirect all "ldarg(a) 0" and "starg 0" to this temp.
3084 unsigned lvaInlineeReturnSpillTemp; // The temp to spill the non-VOID return expression
3085 // in case there are multiple BBJ_RETURN blocks in the inlinee
3086 // or if the inlinee has GC ref locals.
3088 #if FEATURE_FIXED_OUT_ARGS
3089 unsigned lvaOutgoingArgSpaceVar; // dummy TYP_LCLBLK var for fixed outgoing argument space
3090 PhasedVar<unsigned> lvaOutgoingArgSpaceSize; // size of fixed outgoing argument space
3091 #endif // FEATURE_FIXED_OUT_ARGS
3094 // On architectures whose ABIs allow structs to be passed in registers, struct promotion will sometimes
3095 // require us to "rematerialize" a struct from it's separate constituent field variables. Packing several sub-word
3096 // field variables into an argument register is a hard problem. It's easier to reserve a word of memory into which
3097 // such field can be copied, after which the assembled memory word can be read into the register. We will allocate
3098 // this variable to be this scratch word whenever struct promotion occurs.
3099 unsigned lvaPromotedStructAssemblyScratchVar;
3100 #endif // _TARGET_ARM_
3102 #if defined(DEBUG) && defined(_TARGET_XARCH_)
3104 unsigned lvaReturnSpCheck; // Stores SP to confirm it is not corrupted on return.
3106 #endif // defined(DEBUG) && defined(_TARGET_XARCH_)
3108 #if defined(DEBUG) && defined(_TARGET_X86_)
3110 unsigned lvaCallSpCheck; // Stores SP to confirm it is not corrupted after every call.
3112 #endif // defined(DEBUG) && defined(_TARGET_X86_)
3114 unsigned lvaGenericsContextUseCount;
3116 bool lvaKeepAliveAndReportThis(); // Synchronized instance method of a reference type, or
3117 // CORINFO_GENERICS_CTXT_FROM_THIS?
3118 bool lvaReportParamTypeArg(); // Exceptions and CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG?
3120 //-------------------------------------------------------------------------
3121 // All these frame offsets are inter-related and must be kept in sync
3123 #if !FEATURE_EH_FUNCLETS
3124 // This is used for the callable handlers
3125 unsigned lvaShadowSPslotsVar; // TYP_BLK variable for all the shadow SP slots
3126 #endif // FEATURE_EH_FUNCLETS
3128 int lvaCachedGenericContextArgOffs;
3129 int lvaCachedGenericContextArgOffset(); // For CORINFO_CALLCONV_PARAMTYPE and if generic context is passed as
3132 #ifdef JIT32_GCENCODER
3134 unsigned lvaLocAllocSPvar; // variable which stores the value of ESP after the the last alloca/localloc
3136 #endif // JIT32_GCENCODER
3138 unsigned lvaNewObjArrayArgs; // variable with arguments for new MD array helper
3140 // TODO-Review: Prior to reg predict we reserve 24 bytes for Spill temps.
3141 // after the reg predict we will use a computed maxTmpSize
3142 // which is based upon the number of spill temps predicted by reg predict
3143 // All this is necessary because if we under-estimate the size of the spill
3144 // temps we could fail when encoding instructions that reference stack offsets for ARM.
3146 // Pre codegen max spill temp size.
3147 static const unsigned MAX_SPILL_TEMP_SIZE = 24;
3149 //-------------------------------------------------------------------------
3151 unsigned lvaGetMaxSpillTempSize();
3153 bool lvaIsPreSpilled(unsigned lclNum, regMaskTP preSpillMask);
3154 #endif // _TARGET_ARM_
3155 void lvaAssignFrameOffsets(FrameLayoutState curState);
3156 void lvaFixVirtualFrameOffsets();
3157 void lvaUpdateArgsWithInitialReg();
3158 void lvaAssignVirtualFrameOffsetsToArgs();
3159 #ifdef UNIX_AMD64_ABI
3160 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs, int* callerArgOffset);
3161 #else // !UNIX_AMD64_ABI
3162 int lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, unsigned argSize, int argOffs);
3163 #endif // !UNIX_AMD64_ABI
3164 void lvaAssignVirtualFrameOffsetsToLocals();
3165 int lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, int stkOffs);
3166 #ifdef _TARGET_AMD64_
3167 // Returns true if compCalleeRegsPushed (including RBP if used as frame pointer) is even.
3168 bool lvaIsCalleeSavedIntRegCountEven();
3170 void lvaAlignFrame();
3171 void lvaAssignFrameOffsetsToPromotedStructs();
3172 int lvaAllocateTemps(int stkOffs, bool mustDoubleAlign);
3175 void lvaDumpRegLocation(unsigned lclNum);
3176 void lvaDumpFrameLocation(unsigned lclNum);
3177 void lvaDumpEntry(unsigned lclNum, FrameLayoutState curState, size_t refCntWtdWidth = 6);
3178 void lvaTableDump(FrameLayoutState curState = NO_FRAME_LAYOUT); // NO_FRAME_LAYOUT means use the current frame
3179 // layout state defined by lvaDoneFrameLayout
3182 // Limit frames size to 1GB. The maximum is 2GB in theory - make it intentionally smaller
3183 // to avoid bugs from borderline cases.
3184 #define MAX_FrameSize 0x3FFFFFFF
3185 void lvaIncrementFrameSize(unsigned size);
3187 unsigned lvaFrameSize(FrameLayoutState curState);
3189 // Returns the caller-SP-relative offset for the SP/FP relative offset determined by FP based.
3190 int lvaToCallerSPRelativeOffset(int offs, bool isFpBased) const;
3192 // Returns the caller-SP-relative offset for the local variable "varNum."
3193 int lvaGetCallerSPRelativeOffset(unsigned varNum);
3195 // Returns the SP-relative offset for the local variable "varNum". Illegal to ask this for functions with localloc.
3196 int lvaGetSPRelativeOffset(unsigned varNum);
3198 int lvaToInitialSPRelativeOffset(unsigned offset, bool isFpBased);
3199 int lvaGetInitialSPRelativeOffset(unsigned varNum);
3201 //------------------------ For splitting types ----------------------------
3203 void lvaInitTypeRef();
3205 void lvaInitArgs(InitVarDscInfo* varDscInfo);
3206 void lvaInitThisPtr(InitVarDscInfo* varDscInfo);
3207 void lvaInitRetBuffArg(InitVarDscInfo* varDscInfo);
3208 void lvaInitUserArgs(InitVarDscInfo* varDscInfo);
3209 void lvaInitGenericsCtxt(InitVarDscInfo* varDscInfo);
3210 void lvaInitVarArgsHandle(InitVarDscInfo* varDscInfo);
3212 void lvaInitVarDsc(LclVarDsc* varDsc,
3214 CorInfoType corInfoType,
3215 CORINFO_CLASS_HANDLE typeHnd,
3216 CORINFO_ARG_LIST_HANDLE varList,
3217 CORINFO_SIG_INFO* varSig);
3219 static unsigned lvaTypeRefMask(var_types type);
3221 var_types lvaGetActualType(unsigned lclNum);
3222 var_types lvaGetRealType(unsigned lclNum);
3224 //-------------------------------------------------------------------------
3228 LclVarDsc* lvaGetDesc(unsigned lclNum)
3230 assert(lclNum < lvaCount);
3231 return &lvaTable[lclNum];
3234 LclVarDsc* lvaGetDesc(GenTreeLclVarCommon* lclVar)
3236 assert(lclVar->GetLclNum() < lvaCount);
3237 return &lvaTable[lclVar->GetLclNum()];
3240 unsigned lvaLclSize(unsigned varNum);
3241 unsigned lvaLclExactSize(unsigned varNum);
3243 bool lvaHaveManyLocals() const;
3245 unsigned lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason));
3246 unsigned lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason));
3247 unsigned lvaGrabTempWithImplicitUse(bool shortLifetime DEBUGARG(const char* reason));
3250 void lvaSortByRefCount();
3251 void lvaDumpRefCounts();
3253 void lvaMarkLocalVars(); // Local variable ref-counting
3254 void lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers);
3255 void lvaMarkLocalVars(BasicBlock* block, bool isRecompute);
3257 void lvaAllocOutgoingArgSpaceVar(); // Set up lvaOutgoingArgSpaceVar
3259 VARSET_VALRET_TP lvaStmtLclMask(GenTreeStmt* stmt);
3262 struct lvaStressLclFldArgs
3264 Compiler* m_pCompiler;
3268 static fgWalkPreFn lvaStressLclFldCB;
3269 void lvaStressLclFld();
3271 void lvaDispVarSet(VARSET_VALARG_TP set, VARSET_VALARG_TP allVars);
3272 void lvaDispVarSet(VARSET_VALARG_TP set);
3277 int lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset, bool isFloatUsage);
3279 int lvaFrameAddress(int varNum, bool* pFPbased);
3282 bool lvaIsParameter(unsigned varNum);
3283 bool lvaIsRegArgument(unsigned varNum);
3284 BOOL lvaIsOriginalThisArg(unsigned varNum); // Is this varNum the original this argument?
3285 BOOL lvaIsOriginalThisReadOnly(); // return TRUE if there is no place in the code
3286 // that writes to arg0
3288 // Struct parameters that are passed by reference are marked as both lvIsParam and lvIsTemp
3289 // (this is an overload of lvIsTemp because there are no temp parameters).
3290 // For x64 this is 3, 5, 6, 7, >8 byte structs that are passed by reference.
3291 // For ARM64, this is structs larger than 16 bytes that are passed by reference.
3292 bool lvaIsImplicitByRefLocal(unsigned varNum)
3294 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
3295 LclVarDsc* varDsc = &(lvaTable[varNum]);
3296 if (varDsc->lvIsParam && varDsc->lvIsTemp)
3298 assert(varTypeIsStruct(varDsc) || (varDsc->lvType == TYP_BYREF));
3301 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
3305 // Returns true if this local var is a multireg struct
3306 bool lvaIsMultiregStruct(LclVarDsc* varDsc, bool isVararg);
3308 // If the local is a TYP_STRUCT, get/set a class handle describing it
3309 CORINFO_CLASS_HANDLE lvaGetStruct(unsigned varNum);
3310 void lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool unsafeValueClsCheck, bool setTypeInfo = true);
3311 void lvaSetStructUsedAsVarArg(unsigned varNum);
3313 // If the local is TYP_REF, set or update the associated class information.
3314 void lvaSetClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
3315 void lvaSetClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
3316 void lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
3317 void lvaUpdateClass(unsigned varNum, GenTree* tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
3319 #define MAX_NumOfFieldsInPromotableStruct 4 // Maximum number of fields in promotable struct
3321 // Info about struct type fields.
3322 struct lvaStructFieldInfo
3324 CORINFO_FIELD_HANDLE fldHnd;
3325 unsigned char fldOffset;
3326 unsigned char fldOrdinal;
3329 CORINFO_CLASS_HANDLE fldTypeHnd;
3331 lvaStructFieldInfo()
3332 : fldHnd(nullptr), fldOffset(0), fldOrdinal(0), fldType(TYP_UNDEF), fldSize(0), fldTypeHnd(nullptr)
3337 // Info about a struct type, instances of which may be candidates for promotion.
3338 struct lvaStructPromotionInfo
3340 CORINFO_CLASS_HANDLE typeHnd;
3345 unsigned char fieldCnt;
3346 lvaStructFieldInfo fields[MAX_NumOfFieldsInPromotableStruct];
3348 lvaStructPromotionInfo(CORINFO_CLASS_HANDLE typeHnd = nullptr)
3351 , containsHoles(false)
3352 , customLayout(false)
3353 , fieldsSorted(false)
3359 static int __cdecl lvaFieldOffsetCmp(const void* field1, const void* field2);
3361 // This class is responsible for checking validity and profitability of struct promotion.
3362 // If it is both legal and profitable, then TryPromoteStructVar promotes the struct and initializes
3363 // nessesary information for fgMorphStructField to use.
3364 class StructPromotionHelper
3367 StructPromotionHelper(Compiler* compiler);
3369 bool CanPromoteStructType(CORINFO_CLASS_HANDLE typeHnd);
3370 bool TryPromoteStructVar(unsigned lclNum);
3373 void CheckRetypedAsScalar(CORINFO_FIELD_HANDLE fieldHnd, var_types requestedType);
3377 bool GetRequiresScratchVar();
3378 #endif // _TARGET_ARM_
3381 bool CanPromoteStructVar(unsigned lclNum);
3382 bool ShouldPromoteStructVar(unsigned lclNum);
3383 void PromoteStructVar(unsigned lclNum);
3384 void SortStructFields();
3386 lvaStructFieldInfo GetFieldInfo(CORINFO_FIELD_HANDLE fieldHnd, BYTE ordinal);
3387 bool TryPromoteStructField(lvaStructFieldInfo& outerFieldInfo);
3391 lvaStructPromotionInfo structPromotionInfo;
3394 bool requiresScratchVar;
3395 #endif // _TARGET_ARM_
3398 typedef JitHashTable<CORINFO_FIELD_HANDLE, JitPtrKeyFuncs<CORINFO_FIELD_STRUCT_>, var_types>
3399 RetypedAsScalarFieldsMap;
3400 RetypedAsScalarFieldsMap retypedFieldsMap;
3404 StructPromotionHelper* structPromotionHelper;
3406 #if !defined(_TARGET_64BIT_)
3407 void lvaPromoteLongVars();
3408 #endif // !defined(_TARGET_64BIT_)
3409 unsigned lvaGetFieldLocal(const LclVarDsc* varDsc, unsigned int fldOffset);
3410 lvaPromotionType lvaGetPromotionType(const LclVarDsc* varDsc);
3411 lvaPromotionType lvaGetPromotionType(unsigned varNum);
3412 lvaPromotionType lvaGetParentPromotionType(const LclVarDsc* varDsc);
3413 lvaPromotionType lvaGetParentPromotionType(unsigned varNum);
3414 bool lvaIsFieldOfDependentlyPromotedStruct(const LclVarDsc* varDsc);
3415 bool lvaIsGCTracked(const LclVarDsc* varDsc);
3417 #if defined(FEATURE_SIMD)
3418 bool lvaMapSimd12ToSimd16(const LclVarDsc* varDsc)
3420 assert(varDsc->lvType == TYP_SIMD12);
3421 assert(varDsc->lvExactSize == 12);
3423 #if defined(_TARGET_64BIT_)
3424 assert(varDsc->lvSize() == 16);
3425 #endif // defined(_TARGET_64BIT_)
3427 // We make local variable SIMD12 types 16 bytes instead of just 12. lvSize()
3428 // already does this calculation. However, we also need to prevent mapping types if the var is a
3429 // dependently promoted struct field, which must remain its exact size within its parent struct.
3430 // However, we don't know this until late, so we may have already pretended the field is bigger
3432 if ((varDsc->lvSize() == 16) && !lvaIsFieldOfDependentlyPromotedStruct(varDsc))
3441 #endif // defined(FEATURE_SIMD)
3443 BYTE* lvaGetGcLayout(unsigned varNum);
3444 bool lvaTypeIsGC(unsigned varNum);
3445 unsigned lvaGSSecurityCookie; // LclVar number
3446 bool lvaTempsHaveLargerOffsetThanVars();
3448 // Returns "true" iff local variable "lclNum" is in SSA form.
3449 bool lvaInSsa(unsigned lclNum)
3451 assert(lclNum < lvaCount);
3452 return lvaTable[lclNum].lvInSsa;
3455 unsigned lvaSecurityObject; // variable representing the security object on the stack
3456 unsigned lvaStubArgumentVar; // variable representing the secret stub argument coming in EAX
3458 #if FEATURE_EH_FUNCLETS
3459 unsigned lvaPSPSym; // variable representing the PSPSym
3462 InlineInfo* impInlineInfo;
3463 InlineStrategy* m_inlineStrategy;
3465 // The Compiler* that is the root of the inlining tree of which "this" is a member.
3466 Compiler* impInlineRoot();
3468 #if defined(DEBUG) || defined(INLINE_DATA)
3469 unsigned __int64 getInlineCycleCount()
3471 return m_compCycles;
3473 #endif // defined(DEBUG) || defined(INLINE_DATA)
3475 bool fgNoStructPromotion; // Set to TRUE to turn off struct promotion for this method.
3476 bool fgNoStructParamPromotion; // Set to TRUE to turn off struct promotion for parameters this method.
3478 //=========================================================================
3480 //=========================================================================
3483 //---------------- Local variable ref-counting ----------------------------
3485 void lvaMarkLclRefs(GenTree* tree, BasicBlock* block, GenTreeStmt* stmt, bool isRecompute);
3486 bool IsDominatedByExceptionalEntry(BasicBlock* block);
3487 void SetVolatileHint(LclVarDsc* varDsc);
3489 // Keeps the mapping from SSA #'s to VN's for the implicit memory variables.
3490 SsaDefArray<SsaMemDef> lvMemoryPerSsaData;
3493 // Returns the address of the per-Ssa data for memory at the given ssaNum (which is required
3494 // not to be the SsaConfig::RESERVED_SSA_NUM, which indicates that the variable is
3495 // not an SSA variable).
3496 SsaMemDef* GetMemoryPerSsaData(unsigned ssaNum)
3498 return lvMemoryPerSsaData.GetSsaDef(ssaNum);
3502 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3503 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3507 XX Imports the given method and converts it to semantic trees XX
3509 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3510 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3516 void impImport(BasicBlock* method);
3518 CORINFO_CLASS_HANDLE impGetRefAnyClass();
3519 CORINFO_CLASS_HANDLE impGetRuntimeArgumentHandle();
3520 CORINFO_CLASS_HANDLE impGetTypeHandleClass();
3521 CORINFO_CLASS_HANDLE impGetStringClass();
3522 CORINFO_CLASS_HANDLE impGetObjectClass();
3524 // Returns underlying type of handles returned by ldtoken instruction
3525 var_types GetRuntimeHandleUnderlyingType()
3527 // RuntimeTypeHandle is backed by raw pointer on CoreRT and by object reference on other runtimes
3528 return IsTargetAbi(CORINFO_CORERT_ABI) ? TYP_I_IMPL : TYP_REF;
3531 void impDevirtualizeCall(GenTreeCall* call,
3532 CORINFO_METHOD_HANDLE* method,
3533 unsigned* methodFlags,
3534 CORINFO_CONTEXT_HANDLE* contextHandle,
3535 CORINFO_CONTEXT_HANDLE* exactContextHandle,
3536 bool isLateDevirtualization,
3537 bool isExplicitTailCall);
3539 //=========================================================================
3541 //=========================================================================
3544 //-------------------- Stack manipulation ---------------------------------
3546 unsigned impStkSize; // Size of the full stack
3548 #define SMALL_STACK_SIZE 16 // number of elements in impSmallStack
3550 struct SavedStack // used to save/restore stack contents.
3552 unsigned ssDepth; // number of values on stack
3553 StackEntry* ssTrees; // saved tree values
3556 bool impIsPrimitive(CorInfoType type);
3557 bool impILConsumesAddr(const BYTE* codeAddr, CORINFO_METHOD_HANDLE fncHandle, CORINFO_MODULE_HANDLE scpHandle);
3559 void impResolveToken(const BYTE* addr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CorInfoTokenKind kind);
3561 void impPushOnStack(GenTree* tree, typeInfo ti);
3562 void impPushNullObjRefOnStack();
3563 StackEntry impPopStack();
3564 StackEntry& impStackTop(unsigned n = 0);
3565 unsigned impStackHeight();
3567 void impSaveStackState(SavedStack* savePtr, bool copy);
3568 void impRestoreStackState(SavedStack* savePtr);
3570 GenTree* impImportLdvirtftn(GenTree* thisPtr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3572 int impBoxPatternMatch(CORINFO_RESOLVED_TOKEN* pResolvedToken, const BYTE* codeAddr, const BYTE* codeEndp);
3573 void impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken);
3575 void impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3577 bool impCanPInvokeInline();
3578 bool impCanPInvokeInlineCallSite(BasicBlock* block);
3579 void impCheckForPInvokeCall(
3580 GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block);
3581 GenTreeCall* impImportIndirectCall(CORINFO_SIG_INFO* sig, IL_OFFSETX ilOffset = BAD_IL_OFFSET);
3582 void impPopArgsForUnmanagedCall(GenTree* call, CORINFO_SIG_INFO* sig);
3584 void impInsertHelperCall(CORINFO_HELPER_DESC* helperCall);
3585 void impHandleAccessAllowed(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
3586 void impHandleAccessAllowedInternal(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
3588 var_types impImportCall(OPCODE opcode,
3589 CORINFO_RESOLVED_TOKEN* pResolvedToken,
3590 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call on a
3592 GenTree* newobjThis,
3594 CORINFO_CALL_INFO* callInfo,
3595 IL_OFFSET rawILOffset);
3597 CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(CORINFO_METHOD_HANDLE specialIntrinsicHandle);
3599 bool impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo);
3601 GenTree* impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HANDLE retClsHnd);
3603 GenTree* impFixupStructReturnType(GenTree* op, CORINFO_CLASS_HANDLE retClsHnd);
3606 var_types impImportJitTestLabelMark(int numArgs);
3609 GenTree* impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken);
3611 GenTree* impImportStaticReadOnlyField(void* fldAddr, var_types lclTyp);
3613 GenTree* impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3614 CORINFO_ACCESS_FLAGS access,
3615 CORINFO_FIELD_INFO* pFieldInfo,
3618 static void impBashVarAddrsToI(GenTree* tree1, GenTree* tree2 = nullptr);
3620 GenTree* impImplicitIorI4Cast(GenTree* tree, var_types dstTyp);
3622 GenTree* impImplicitR4orR8Cast(GenTree* tree, var_types dstTyp);
3624 void impImportLeave(BasicBlock* block);
3625 void impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr);
3626 GenTree* impIntrinsic(GenTree* newobjThis,
3627 CORINFO_CLASS_HANDLE clsHnd,
3628 CORINFO_METHOD_HANDLE method,
3629 CORINFO_SIG_INFO* sig,
3630 unsigned methodFlags,
3634 CORINFO_RESOLVED_TOKEN* pContstrainedResolvedToken,
3635 CORINFO_THIS_TRANSFORM constraintCallThisTransform,
3636 CorInfoIntrinsics* pIntrinsicID,
3637 bool* isSpecialIntrinsic = nullptr);
3638 GenTree* impMathIntrinsic(CORINFO_METHOD_HANDLE method,
3639 CORINFO_SIG_INFO* sig,
3641 CorInfoIntrinsics intrinsicID,
3643 NamedIntrinsic lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method);
3645 #ifdef FEATURE_HW_INTRINSICS
3646 GenTree* impHWIntrinsic(NamedIntrinsic intrinsic,
3647 CORINFO_METHOD_HANDLE method,
3648 CORINFO_SIG_INFO* sig,
3650 GenTree* impUnsupportedHWIntrinsic(unsigned helper,
3651 CORINFO_METHOD_HANDLE method,
3652 CORINFO_SIG_INFO* sig,
3656 bool compSupportsHWIntrinsic(InstructionSet isa);
3658 #ifdef _TARGET_XARCH_
3659 GenTree* impBaseIntrinsic(NamedIntrinsic intrinsic,
3660 CORINFO_METHOD_HANDLE method,
3661 CORINFO_SIG_INFO* sig,
3663 GenTree* impSSEIntrinsic(NamedIntrinsic intrinsic,
3664 CORINFO_METHOD_HANDLE method,
3665 CORINFO_SIG_INFO* sig,
3667 GenTree* impSSE2Intrinsic(NamedIntrinsic intrinsic,
3668 CORINFO_METHOD_HANDLE method,
3669 CORINFO_SIG_INFO* sig,
3671 GenTree* impSSE42Intrinsic(NamedIntrinsic intrinsic,
3672 CORINFO_METHOD_HANDLE method,
3673 CORINFO_SIG_INFO* sig,
3675 GenTree* impAvxOrAvx2Intrinsic(NamedIntrinsic intrinsic,
3676 CORINFO_METHOD_HANDLE method,
3677 CORINFO_SIG_INFO* sig,
3679 GenTree* impAESIntrinsic(NamedIntrinsic intrinsic,
3680 CORINFO_METHOD_HANDLE method,
3681 CORINFO_SIG_INFO* sig,
3683 GenTree* impBMI1OrBMI2Intrinsic(NamedIntrinsic intrinsic,
3684 CORINFO_METHOD_HANDLE method,
3685 CORINFO_SIG_INFO* sig,
3687 GenTree* impFMAIntrinsic(NamedIntrinsic intrinsic,
3688 CORINFO_METHOD_HANDLE method,
3689 CORINFO_SIG_INFO* sig,
3691 GenTree* impLZCNTIntrinsic(NamedIntrinsic intrinsic,
3692 CORINFO_METHOD_HANDLE method,
3693 CORINFO_SIG_INFO* sig,
3695 GenTree* impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic,
3696 CORINFO_METHOD_HANDLE method,
3697 CORINFO_SIG_INFO* sig,
3699 GenTree* impPOPCNTIntrinsic(NamedIntrinsic intrinsic,
3700 CORINFO_METHOD_HANDLE method,
3701 CORINFO_SIG_INFO* sig,
3705 GenTree* getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE argClass);
3706 GenTree* impNonConstFallback(NamedIntrinsic intrinsic, var_types simdType, var_types baseType);
3707 GenTree* addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* lastOp, bool mustExpand);
3708 #endif // _TARGET_XARCH_
3709 #ifdef _TARGET_ARM64_
3710 InstructionSet lookupHWIntrinsicISA(const char* className);
3711 NamedIntrinsic lookupHWIntrinsic(const char* className, const char* methodName);
3712 GenTree* addRangeCheckIfNeeded(GenTree* lastOp, unsigned int max, bool mustExpand);
3713 #endif // _TARGET_ARM64_
3714 #endif // FEATURE_HW_INTRINSICS
3715 GenTree* impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
3716 CORINFO_SIG_INFO* sig,
3719 CorInfoIntrinsics intrinsicID);
3720 GenTree* impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig);
3722 GenTree* impMethodPointer(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo);
3724 GenTree* impTransformThis(GenTree* thisPtr,
3725 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
3726 CORINFO_THIS_TRANSFORM transform);
3728 //----------------- Manipulating the trees and stmts ----------------------
3730 GenTreeStmt* impStmtList; // Statements for the BB being imported.
3731 GenTreeStmt* impLastStmt; // The last statement for the current BB.
3736 CHECK_SPILL_ALL = -1,
3737 CHECK_SPILL_NONE = -2
3740 void impBeginTreeList();
3741 void impEndTreeList(BasicBlock* block, GenTreeStmt* firstStmt, GenTreeStmt* lastStmt);
3742 void impEndTreeList(BasicBlock* block);
3743 void impAppendStmtCheck(GenTreeStmt* stmt, unsigned chkLevel);
3744 void impAppendStmt(GenTreeStmt* stmt, unsigned chkLevel);
3745 void impAppendStmt(GenTreeStmt* stmt);
3746 void impInsertStmtBefore(GenTreeStmt* stmt, GenTreeStmt* stmtBefore);
3747 GenTreeStmt* impAppendTree(GenTree* tree, unsigned chkLevel, IL_OFFSETX offset);
3748 void impInsertTreeBefore(GenTree* tree, IL_OFFSETX offset, GenTreeStmt* stmtBefore);
3749 void impAssignTempGen(unsigned tmp,
3752 GenTreeStmt** pAfterStmt = nullptr,
3753 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3754 BasicBlock* block = nullptr);
3755 void impAssignTempGen(unsigned tmpNum,
3757 CORINFO_CLASS_HANDLE structHnd,
3759 GenTreeStmt** pAfterStmt = nullptr,
3760 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3761 BasicBlock* block = nullptr);
3763 GenTreeStmt* impExtractLastStmt();
3764 GenTree* impCloneExpr(GenTree* tree,
3766 CORINFO_CLASS_HANDLE structHnd,
3768 GenTreeStmt** pAfterStmt DEBUGARG(const char* reason));
3769 GenTree* impAssignStruct(GenTree* dest,
3771 CORINFO_CLASS_HANDLE structHnd,
3773 GenTreeStmt** pAfterStmt = nullptr,
3774 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3775 BasicBlock* block = nullptr);
3776 GenTree* impAssignStructPtr(GenTree* dest,
3778 CORINFO_CLASS_HANDLE structHnd,
3780 GenTreeStmt** pAfterStmt = nullptr,
3781 IL_OFFSETX ilOffset = BAD_IL_OFFSET,
3782 BasicBlock* block = nullptr);
3784 GenTree* impGetStructAddr(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, unsigned curLevel, bool willDeref);
3786 var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd,
3787 BYTE* gcLayout = nullptr,
3788 unsigned* numGCVars = nullptr,
3789 var_types* simdBaseType = nullptr);
3791 GenTree* impNormStructVal(GenTree* structVal,
3792 CORINFO_CLASS_HANDLE structHnd,
3794 bool forceNormalization = false);
3796 GenTree* impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3797 BOOL* pRuntimeLookup = nullptr,
3798 BOOL mustRestoreHandle = FALSE,
3799 BOOL importParent = FALSE);
3801 GenTree* impParentClassTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3802 BOOL* pRuntimeLookup = nullptr,
3803 BOOL mustRestoreHandle = FALSE)
3805 return impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, TRUE);
3808 GenTree* impLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3809 CORINFO_LOOKUP* pLookup,
3811 void* compileTimeHandle);
3813 GenTree* getRuntimeContextTree(CORINFO_RUNTIME_LOOKUP_KIND kind);
3815 GenTree* impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3816 CORINFO_LOOKUP* pLookup,
3817 void* compileTimeHandle);
3819 GenTree* impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP* pLookup, unsigned flags, void* compileTimeHandle);
3821 GenTreeCall* impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
3822 CorInfoHelpFunc helper,
3824 GenTreeArgList* arg = nullptr,
3825 CORINFO_LOOKUP_KIND* pGenericLookupKind = nullptr);
3827 GenTree* impCastClassOrIsInstToTree(GenTree* op1,
3829 CORINFO_RESOLVED_TOKEN* pResolvedToken,
3832 GenTree* impOptimizeCastClassOrIsInst(GenTree* op1, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isCastClass);
3834 bool VarTypeIsMultiByteAndCanEnreg(
3835 var_types type, CORINFO_CLASS_HANDLE typeClass, unsigned* typeSize, bool forReturn, bool isVarArg);
3837 bool IsIntrinsicImplementedByUserCall(CorInfoIntrinsics intrinsicId);
3838 bool IsTargetIntrinsic(CorInfoIntrinsics intrinsicId);
3839 bool IsMathIntrinsic(CorInfoIntrinsics intrinsicId);
3840 bool IsMathIntrinsic(GenTree* tree);
3843 //----------------- Importing the method ----------------------------------
3845 CORINFO_CONTEXT_HANDLE impTokenLookupContextHandle; // The context used for looking up tokens.
3848 unsigned impCurOpcOffs;
3849 const char* impCurOpcName;
3850 bool impNestedStackSpill;
3852 // For displaying instrs with generated native code (-n:B)
3853 GenTreeStmt* impLastILoffsStmt; // oldest stmt added for which we did not gtStmtLastILoffs
3854 void impNoteLastILoffs();
3857 /* IL offset of the stmt currently being imported. It gets set to
3858 BAD_IL_OFFSET after it has been set in the appended trees. Then it gets
3859 updated at IL offsets for which we have to report mapping info.
3860 It also includes flag bits, so use jitGetILoffs()
3861 to get the actual IL offset value.
3864 IL_OFFSETX impCurStmtOffs;
3865 void impCurStmtOffsSet(IL_OFFSET offs);
3867 void impNoteBranchOffs();
3869 unsigned impInitBlockLineInfo();
3871 GenTree* impCheckForNullPointer(GenTree* obj);
3872 bool impIsThis(GenTree* obj);
3873 bool impIsLDFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3874 bool impIsDUP_LDVIRTFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr);
3875 bool impIsAnySTLOC(OPCODE opcode)
3877 return ((opcode == CEE_STLOC) || (opcode == CEE_STLOC_S) ||
3878 ((opcode >= CEE_STLOC_0) && (opcode <= CEE_STLOC_3)));
3881 GenTreeArgList* impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenTreeArgList* prefixTree = nullptr);
3883 GenTreeArgList* impPopRevList(unsigned count, CORINFO_SIG_INFO* sig, unsigned skipReverseCount = 0);
3886 * Get current IL offset with stack-empty info incoporated
3888 IL_OFFSETX impCurILOffset(IL_OFFSET offs, bool callInstruction = false);
3890 //---------------- Spilling the importer stack ----------------------------
3892 // The maximum number of bytes of IL processed without clean stack state.
3893 // It allows to limit the maximum tree size and depth.
3894 static const unsigned MAX_TREE_SIZE = 200;
3895 bool impCanSpillNow(OPCODE prevOpcode);
3901 SavedStack pdSavedStack;
3902 ThisInitState pdThisPtrInit;
3905 PendingDsc* impPendingList; // list of BBs currently waiting to be imported.
3906 PendingDsc* impPendingFree; // Freed up dscs that can be reused
3908 // We keep a byte-per-block map (dynamically extended) in the top-level Compiler object of a compilation.
3909 JitExpandArray<BYTE> impPendingBlockMembers;
3911 // Return the byte for "b" (allocating/extending impPendingBlockMembers if necessary.)
3912 // Operates on the map in the top-level ancestor.
3913 BYTE impGetPendingBlockMember(BasicBlock* blk)
3915 return impInlineRoot()->impPendingBlockMembers.Get(blk->bbInd());
3918 // Set the byte for "b" to "val" (allocating/extending impPendingBlockMembers if necessary.)
3919 // Operates on the map in the top-level ancestor.
3920 void impSetPendingBlockMember(BasicBlock* blk, BYTE val)
3922 impInlineRoot()->impPendingBlockMembers.Set(blk->bbInd(), val);
3925 bool impCanReimport;
3927 bool impSpillStackEntry(unsigned level,
3931 bool bAssertOnRecursion,
3936 void impSpillStackEnsure(bool spillLeaves = false);
3937 void impEvalSideEffects();
3938 void impSpillSpecialSideEff();
3939 void impSpillSideEffects(bool spillGlobEffects, unsigned chkLevel DEBUGARG(const char* reason));
3940 void impSpillValueClasses();
3941 void impSpillEvalStack();
3942 static fgWalkPreFn impFindValueClasses;
3943 void impSpillLclRefs(ssize_t lclNum);
3945 BasicBlock* impPushCatchArgOnStack(BasicBlock* hndBlk, CORINFO_CLASS_HANDLE clsHnd, bool isSingleBlockFilter);
3947 void impImportBlockCode(BasicBlock* block);
3949 void impReimportMarkBlock(BasicBlock* block);
3950 void impReimportMarkSuccessors(BasicBlock* block);
3952 void impVerifyEHBlock(BasicBlock* block, bool isTryStart);
3954 void impImportBlockPending(BasicBlock* block);
3956 // Similar to impImportBlockPending, but assumes that block has already been imported once and is being
3957 // reimported for some reason. It specifically does *not* look at verCurrentState to set the EntryState
3958 // for the block, but instead, just re-uses the block's existing EntryState.
3959 void impReimportBlockPending(BasicBlock* block);
3961 var_types impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTree** pOp1, GenTree** pOp2);
3963 void impImportBlock(BasicBlock* block);
3965 // Assumes that "block" is a basic block that completes with a non-empty stack. We will assign the values
3966 // on the stack to local variables (the "spill temp" variables). The successor blocks will assume that
3967 // its incoming stack contents are in those locals. This requires "block" and its successors to agree on
3968 // the variables that will be used -- and for all the predecessors of those successors, and the
3969 // successors of those predecessors, etc. Call such a set of blocks closed under alternating
3970 // successor/predecessor edges a "spill clique." A block is a "predecessor" or "successor" member of the
3971 // clique (or, conceivably, both). Each block has a specified sequence of incoming and outgoing spill
3972 // temps. If "block" already has its outgoing spill temps assigned (they are always a contiguous series
3973 // of local variable numbers, so we represent them with the base local variable number), returns that.
3974 // Otherwise, picks a set of spill temps, and propagates this choice to all blocks in the spill clique of
3975 // which "block" is a member (asserting, in debug mode, that no block in this clique had its spill temps
3976 // chosen already. More precisely, that the incoming or outgoing spill temps are not chosen, depending
3977 // on which kind of member of the clique the block is).
3978 unsigned impGetSpillTmpBase(BasicBlock* block);
3980 // Assumes that "block" is a basic block that completes with a non-empty stack. We have previously
3981 // assigned the values on the stack to local variables (the "spill temp" variables). The successor blocks
3982 // will assume that its incoming stack contents are in those locals. This requires "block" and its
3983 // successors to agree on the variables and their types that will be used. The CLI spec allows implicit
3984 // conversions between 'int' and 'native int' or 'float' and 'double' stack types. So one predecessor can
3985 // push an int and another can push a native int. For 64-bit we have chosen to implement this by typing
3986 // the "spill temp" as native int, and then importing (or re-importing as needed) so that all the
3987 // predecessors in the "spill clique" push a native int (sign-extending if needed), and all the
3988 // successors receive a native int. Similarly float and double are unified to double.
3989 // This routine is called after a type-mismatch is detected, and it will walk the spill clique to mark
3990 // blocks for re-importation as appropriate (both successors, so they get the right incoming type, and
3991 // predecessors, so they insert an upcast if needed).
3992 void impReimportSpillClique(BasicBlock* block);
3994 // When we compute a "spill clique" (see above) these byte-maps are allocated to have a byte per basic
3995 // block, and represent the predecessor and successor members of the clique currently being computed.
3996 // *** Access to these will need to be locked in a parallel compiler.
3997 JitExpandArray<BYTE> impSpillCliquePredMembers;
3998 JitExpandArray<BYTE> impSpillCliqueSuccMembers;
4006 // Abstract class for receiving a callback while walking a spill clique
4007 class SpillCliqueWalker
4010 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk) = 0;
4013 // This class is used for setting the bbStkTempsIn and bbStkTempsOut on the blocks within a spill clique
4014 class SetSpillTempsBase : public SpillCliqueWalker
4019 SetSpillTempsBase(unsigned baseTmp) : m_baseTmp(baseTmp)
4022 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
4025 // This class is used for implementing impReimportSpillClique part on each block within the spill clique
4026 class ReimportSpillClique : public SpillCliqueWalker
4031 ReimportSpillClique(Compiler* pComp) : m_pComp(pComp)
4034 virtual void Visit(SpillCliqueDir predOrSucc, BasicBlock* blk);
4037 // This is the heart of the algorithm for walking spill cliques. It invokes callback->Visit for each
4038 // predecessor or successor within the spill clique
4039 void impWalkSpillCliqueFromPred(BasicBlock* pred, SpillCliqueWalker* callback);
4041 // For a BasicBlock that has already been imported, the EntryState has an array of GenTrees for the
4042 // incoming locals. This walks that list an resets the types of the GenTrees to match the types of
4043 // the VarDscs. They get out of sync when we have int/native int issues (see impReimportSpillClique).
4044 void impRetypeEntryStateTemps(BasicBlock* blk);
4046 BYTE impSpillCliqueGetMember(SpillCliqueDir predOrSucc, BasicBlock* blk);
4047 void impSpillCliqueSetMember(SpillCliqueDir predOrSucc, BasicBlock* blk, BYTE val);
4049 void impPushVar(GenTree* op, typeInfo tiRetVal);
4050 void impLoadVar(unsigned lclNum, IL_OFFSET offset, typeInfo tiRetVal);
4051 void impLoadVar(unsigned lclNum, IL_OFFSET offset)
4053 impLoadVar(lclNum, offset, lvaTable[lclNum].lvVerTypeInfo);
4055 void impLoadArg(unsigned ilArgNum, IL_OFFSET offset);
4056 void impLoadLoc(unsigned ilLclNum, IL_OFFSET offset);
4057 bool impReturnInstruction(BasicBlock* block, int prefixFlags, OPCODE& opcode);
4060 void impMarkLclDstNotPromotable(unsigned tmpNum, GenTree* op, CORINFO_CLASS_HANDLE hClass);
4063 // A free list of linked list nodes used to represent to-do stacks of basic blocks.
4064 struct BlockListNode
4067 BlockListNode* m_next;
4068 BlockListNode(BasicBlock* blk, BlockListNode* next = nullptr) : m_blk(blk), m_next(next)
4071 void* operator new(size_t sz, Compiler* comp);
4073 BlockListNode* impBlockListNodeFreeList;
4075 void FreeBlockListNode(BlockListNode* node);
4077 bool impIsValueType(typeInfo* pTypeInfo);
4078 var_types mangleVarArgsType(var_types type);
4081 regNumber getCallArgIntRegister(regNumber floatReg);
4082 regNumber getCallArgFloatRegister(regNumber intReg);
4083 #endif // FEATURE_VARARG
4086 static unsigned jitTotalMethodCompiled;
4090 static LONG jitNestingLevel;
4093 static BOOL impIsAddressInLocal(GenTree* tree, GenTree** lclVarTreeOut);
4095 void impMakeDiscretionaryInlineObservations(InlineInfo* pInlineInfo, InlineResult* inlineResult);
4097 // STATIC inlining decision based on the IL code.
4098 void impCanInlineIL(CORINFO_METHOD_HANDLE fncHandle,
4099 CORINFO_METHOD_INFO* methInfo,
4101 InlineResult* inlineResult);
4103 void impCheckCanInline(GenTreeCall* call,
4104 CORINFO_METHOD_HANDLE fncHandle,
4106 CORINFO_CONTEXT_HANDLE exactContextHnd,
4107 InlineCandidateInfo** ppInlineCandidateInfo,
4108 InlineResult* inlineResult);
4110 void impInlineRecordArgInfo(InlineInfo* pInlineInfo,
4113 InlineResult* inlineResult);
4115 void impInlineInitVars(InlineInfo* pInlineInfo);
4117 unsigned impInlineFetchLocal(unsigned lclNum DEBUGARG(const char* reason));
4119 GenTree* impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, InlLclVarInfo* lclTypeInfo);
4121 BOOL impInlineIsThis(GenTree* tree, InlArgInfo* inlArgInfo);
4123 BOOL impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTree* additionalTreesToBeEvaluatedBefore,
4124 GenTree* variableBeingDereferenced,
4125 InlArgInfo* inlArgInfo);
4127 void impMarkInlineCandidate(GenTree* call,
4128 CORINFO_CONTEXT_HANDLE exactContextHnd,
4129 bool exactContextNeedsRuntimeLookup,
4130 CORINFO_CALL_INFO* callInfo);
4132 void impMarkInlineCandidateHelper(GenTreeCall* call,
4133 CORINFO_CONTEXT_HANDLE exactContextHnd,
4134 bool exactContextNeedsRuntimeLookup,
4135 CORINFO_CALL_INFO* callInfo);
4137 bool impTailCallRetTypeCompatible(var_types callerRetType,
4138 CORINFO_CLASS_HANDLE callerRetTypeClass,
4139 var_types calleeRetType,
4140 CORINFO_CLASS_HANDLE calleeRetTypeClass);
4142 bool impIsTailCallILPattern(bool tailPrefixed,
4144 const BYTE* codeAddrOfNextOpcode,
4145 const BYTE* codeEnd,
4147 bool* IsCallPopRet = nullptr);
4149 bool impIsImplicitTailCallCandidate(
4150 OPCODE curOpcode, const BYTE* codeAddrOfNextOpcode, const BYTE* codeEnd, int prefixFlags, bool isRecursive);
4152 CORINFO_RESOLVED_TOKEN* impAllocateToken(CORINFO_RESOLVED_TOKEN token);
4155 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4156 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4160 XX Info about the basic-blocks, their contents and the flow analysis XX
4162 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4163 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4167 BasicBlock* fgFirstBB; // Beginning of the basic block list
4168 BasicBlock* fgLastBB; // End of the basic block list
4169 BasicBlock* fgFirstColdBlock; // First block to be placed in the cold section
4170 #if FEATURE_EH_FUNCLETS
4171 BasicBlock* fgFirstFuncletBB; // First block of outlined funclets (to allow block insertion before the funclets)
4173 BasicBlock* fgFirstBBScratch; // Block inserted for initialization stuff. Is nullptr if no such block has been
4175 BasicBlockList* fgReturnBlocks; // list of BBJ_RETURN blocks
4176 unsigned fgEdgeCount; // # of control flow edges between the BBs
4177 unsigned fgBBcount; // # of BBs in the method
4179 unsigned fgBBcountAtCodegen; // # of BBs in the method at the start of codegen
4181 unsigned fgBBNumMax; // The max bbNum that has been assigned to basic blocks
4182 unsigned fgDomBBcount; // # of BBs for which we have dominator and reachability information
4183 BasicBlock** fgBBInvPostOrder; // The flow graph stored in an array sorted in topological order, needed to compute
4184 // dominance. Indexed by block number. Size: fgBBNumMax + 1.
4186 // After the dominance tree is computed, we cache a DFS preorder number and DFS postorder number to compute
4187 // dominance queries in O(1). fgDomTreePreOrder and fgDomTreePostOrder are arrays giving the block's preorder and
4188 // postorder number, respectively. The arrays are indexed by basic block number. (Note that blocks are numbered
4189 // starting from one. Thus, we always waste element zero. This makes debugging easier and makes the code less likely
4190 // to suffer from bugs stemming from forgetting to add or subtract one from the block number to form an array
4191 // index). The arrays are of size fgBBNumMax + 1.
4192 unsigned* fgDomTreePreOrder;
4193 unsigned* fgDomTreePostOrder;
4195 bool fgBBVarSetsInited;
4197 // Allocate array like T* a = new T[fgBBNumMax + 1];
4198 // Using helper so we don't keep forgetting +1.
4199 template <typename T>
4200 T* fgAllocateTypeForEachBlk(CompMemKind cmk = CMK_Unknown)
4202 return getAllocator(cmk).allocate<T>(fgBBNumMax + 1);
4205 // BlockSets are relative to a specific set of BasicBlock numbers. If that changes
4206 // (if the blocks are renumbered), this changes. BlockSets from different epochs
4207 // cannot be meaningfully combined. Note that new blocks can be created with higher
4208 // block numbers without changing the basic block epoch. These blocks *cannot*
4209 // participate in a block set until the blocks are all renumbered, causing the epoch
4210 // to change. This is useful if continuing to use previous block sets is valuable.
4211 // If the epoch is zero, then it is uninitialized, and block sets can't be used.
4212 unsigned fgCurBBEpoch;
4214 unsigned GetCurBasicBlockEpoch()
4216 return fgCurBBEpoch;
4219 // The number of basic blocks in the current epoch. When the blocks are renumbered,
4220 // this is fgBBcount. As blocks are added, fgBBcount increases, fgCurBBEpochSize remains
4221 // the same, until a new BasicBlock epoch is created, such as when the blocks are all renumbered.
4222 unsigned fgCurBBEpochSize;
4224 // The number of "size_t" elements required to hold a bitset large enough for fgCurBBEpochSize
4225 // bits. This is precomputed to avoid doing math every time BasicBlockBitSetTraits::GetArrSize() is called.
4226 unsigned fgBBSetCountInSizeTUnits;
4228 void NewBasicBlockEpoch()
4230 INDEBUG(unsigned oldEpochArrSize = fgBBSetCountInSizeTUnits);
4232 // We have a new epoch. Compute and cache the size needed for new BlockSets.
4234 fgCurBBEpochSize = fgBBNumMax + 1;
4235 fgBBSetCountInSizeTUnits =
4236 roundUp(fgCurBBEpochSize, (unsigned)(sizeof(size_t) * 8)) / unsigned(sizeof(size_t) * 8);
4239 // All BlockSet objects are now invalid!
4240 fgReachabilitySetsValid = false; // the bbReach sets are now invalid!
4241 fgEnterBlksSetValid = false; // the fgEnterBlks set is now invalid!
4245 unsigned epochArrSize = BasicBlockBitSetTraits::GetArrSize(this, sizeof(size_t));
4246 printf("\nNew BlockSet epoch %d, # of blocks (including unused BB00): %u, bitset array size: %u (%s)",
4247 fgCurBBEpoch, fgCurBBEpochSize, epochArrSize, (epochArrSize <= 1) ? "short" : "long");
4248 if ((fgCurBBEpoch != 1) && ((oldEpochArrSize <= 1) != (epochArrSize <= 1)))
4250 // If we're not just establishing the first epoch, and the epoch array size has changed such that we're
4251 // going to change our bitset representation from short (just a size_t bitset) to long (a pointer to an
4252 // array of size_t bitsets), then print that out.
4253 printf("; NOTE: BlockSet size was previously %s!", (oldEpochArrSize <= 1) ? "short" : "long");
4260 void EnsureBasicBlockEpoch()
4262 if (fgCurBBEpochSize != fgBBNumMax + 1)
4264 NewBasicBlockEpoch();
4268 BasicBlock* fgNewBasicBlock(BBjumpKinds jumpKind);
4269 void fgEnsureFirstBBisScratch();
4270 bool fgFirstBBisScratch();
4271 bool fgBBisScratch(BasicBlock* block);
4273 void fgExtendEHRegionBefore(BasicBlock* block);
4274 void fgExtendEHRegionAfter(BasicBlock* block);
4276 BasicBlock* fgNewBBbefore(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
4278 BasicBlock* fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion);
4280 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
4283 BasicBlock* nearBlk,
4284 bool putInFilter = false,
4285 bool runRarely = false,
4286 bool insertAtEnd = false);
4288 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind,
4290 bool runRarely = false,
4291 bool insertAtEnd = false);
4293 BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind);
4295 BasicBlock* fgNewBBinRegionWorker(BBjumpKinds jumpKind,
4296 BasicBlock* afterBlk,
4297 unsigned xcptnIndex,
4298 bool putInTryRegion);
4300 void fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk);
4301 void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk);
4302 void fgUnlinkBlock(BasicBlock* block);
4304 unsigned fgMeasureIR();
4306 bool fgModified; // True if the flow graph has been modified recently
4307 bool fgComputePredsDone; // Have we computed the bbPreds list
4308 bool fgCheapPredsValid; // Is the bbCheapPreds list valid?
4309 bool fgDomsComputed; // Have we computed the dominator sets?
4310 bool fgOptimizedFinally; // Did we optimize any try-finallys?
4312 bool fgHasSwitch; // any BBJ_SWITCH jumps?
4314 BlockSet fgEnterBlks; // Set of blocks which have a special transfer of control; the "entry" blocks plus EH handler
4318 bool fgReachabilitySetsValid; // Are the bbReach sets valid?
4319 bool fgEnterBlksSetValid; // Is the fgEnterBlks set valid?
4322 bool fgRemoveRestOfBlock; // true if we know that we will throw
4323 bool fgStmtRemoved; // true if we remove statements -> need new DFA
4325 // There are two modes for ordering of the trees.
4326 // - In FGOrderTree, the dominant ordering is the tree order, and the nodes contained in
4327 // each tree and sub-tree are contiguous, and can be traversed (in gtNext/gtPrev order)
4328 // by traversing the tree according to the order of the operands.
4329 // - In FGOrderLinear, the dominant ordering is the linear order.
4336 FlowGraphOrder fgOrder;
4338 // The following are boolean flags that keep track of the state of internal data structures
4340 bool fgStmtListThreaded; // true if the node list is now threaded
4341 bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
4342 bool fgEdgeWeightsComputed; // true after we have called fgComputeEdgeWeights
4343 bool fgHaveValidEdgeWeights; // true if we were successful in computing all of the edge weights
4344 bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
4345 bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
4346 bool fgNeedsUpdateFlowGraph; // true if we need to run fgUpdateFlowGraph
4347 BasicBlock::weight_t fgCalledCount; // count of the number of times this method was called
4348 // This is derived from the profile data
4349 // or is BB_UNITY_WEIGHT when we don't have profile data
4351 #if FEATURE_EH_FUNCLETS
4352 bool fgFuncletsCreated; // true if the funclet creation phase has been run
4353 #endif // FEATURE_EH_FUNCLETS
4355 bool fgGlobalMorph; // indicates if we are during the global morphing phase
4356 // since fgMorphTree can be called from several places
4358 bool impBoxTempInUse; // the temp below is valid and available
4359 unsigned impBoxTemp; // a temporary that is used for boxing
4362 bool jitFallbackCompile; // Are we doing a fallback compile? That is, have we executed a NO_WAY assert,
4363 // and we are trying to compile again in a "safer", minopts mode?
4367 unsigned impInlinedCodeSize;
4370 //-------------------------------------------------------------------------
4376 void fgTransformIndirectCalls();
4380 void fgRemoveEmptyTry();
4382 void fgRemoveEmptyFinally();
4384 void fgMergeFinallyChains();
4386 void fgCloneFinally();
4388 void fgCleanupContinuation(BasicBlock* continuation);
4390 void fgUpdateFinallyTargetFlags();
4392 void fgClearAllFinallyTargetBits();
4394 void fgAddFinallyTargetFlags();
4396 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
4397 // Sometimes we need to defer updating the BBF_FINALLY_TARGET bit. fgNeedToAddFinallyTargetBits signals
4398 // when this is necessary.
4399 bool fgNeedToAddFinallyTargetBits;
4400 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
4402 bool fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block,
4403 BasicBlock* handler,
4404 BlockToBlockMap& continuationMap);
4406 GenTree* fgGetCritSectOfStaticMethod();
4408 #if FEATURE_EH_FUNCLETS
4410 void fgAddSyncMethodEnterExit();
4412 GenTree* fgCreateMonitorTree(unsigned lvaMonitorBool, unsigned lvaThisVar, BasicBlock* block, bool enter);
4414 void fgConvertSyncReturnToLeave(BasicBlock* block);
4416 #endif // FEATURE_EH_FUNCLETS
4418 void fgAddReversePInvokeEnterExit();
4420 bool fgMoreThanOneReturnBlock();
4422 // The number of separate return points in the method.
4423 unsigned fgReturnCount;
4425 void fgAddInternal();
4427 bool fgFoldConditional(BasicBlock* block);
4429 void fgMorphStmts(BasicBlock* block, bool* lnot, bool* loadw);
4430 void fgMorphBlocks();
4432 bool fgMorphBlockStmt(BasicBlock* block, GenTreeStmt* stmt DEBUGARG(const char* msg));
4434 void fgSetOptions();
4437 static fgWalkPreFn fgAssertNoQmark;
4438 void fgPreExpandQmarkChecks(GenTree* expr);
4439 void fgPostExpandQmarkChecks();
4440 static void fgCheckQmarkAllowedForm(GenTree* tree);
4443 IL_OFFSET fgFindBlockILOffset(BasicBlock* block);
4445 BasicBlock* fgSplitBlockAtBeginning(BasicBlock* curr);
4446 BasicBlock* fgSplitBlockAtEnd(BasicBlock* curr);
4447 BasicBlock* fgSplitBlockAfterStatement(BasicBlock* curr, GenTreeStmt* stmt);
4448 BasicBlock* fgSplitBlockAfterNode(BasicBlock* curr, GenTree* node); // for LIR
4449 BasicBlock* fgSplitEdge(BasicBlock* curr, BasicBlock* succ);
4451 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, BasicBlock* block, IL_OFFSETX offs);
4452 GenTreeStmt* fgNewStmtFromTree(GenTree* tree);
4453 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, BasicBlock* block);
4454 GenTreeStmt* fgNewStmtFromTree(GenTree* tree, IL_OFFSETX offs);
4456 GenTree* fgGetTopLevelQmark(GenTree* expr, GenTree** ppDst = nullptr);
4457 void fgExpandQmarkForCastInstOf(BasicBlock* block, GenTreeStmt* stmt);
4458 void fgExpandQmarkStmt(BasicBlock* block, GenTreeStmt* stmt);
4459 void fgExpandQmarkNodes();
4463 // Do "simple lowering." This functionality is (conceptually) part of "general"
4464 // lowering that is distributed between fgMorph and the lowering phase of LSRA.
4465 void fgSimpleLowering();
4467 GenTree* fgInitThisClass();
4469 GenTreeCall* fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper);
4471 GenTreeCall* fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls);
4473 bool backendRequiresLocalVarLifetimes()
4475 return !opts.MinOpts() || m_pLinearScan->willEnregisterLocalVars();
4478 void fgLocalVarLiveness();
4480 void fgLocalVarLivenessInit();
4482 void fgPerNodeLocalVarLiveness(GenTree* node);
4483 void fgPerBlockLocalVarLiveness();
4485 VARSET_VALRET_TP fgGetHandlerLiveVars(BasicBlock* block);
4487 void fgLiveVarAnalysis(bool updateInternalOnly = false);
4489 void fgComputeLifeCall(VARSET_TP& life, GenTreeCall* call);
4491 void fgComputeLifeTrackedLocalUse(VARSET_TP& life, LclVarDsc& varDsc, GenTreeLclVarCommon* node);
4492 bool fgComputeLifeTrackedLocalDef(VARSET_TP& life,
4493 VARSET_VALARG_TP keepAliveVars,
4495 GenTreeLclVarCommon* node);
4496 void fgComputeLifeUntrackedLocal(VARSET_TP& life,
4497 VARSET_VALARG_TP keepAliveVars,
4499 GenTreeLclVarCommon* lclVarNode);
4500 bool fgComputeLifeLocal(VARSET_TP& life, VARSET_VALARG_TP keepAliveVars, GenTree* lclVarNode);
4502 void fgComputeLife(VARSET_TP& life,
4505 VARSET_VALARG_TP volatileVars,
4506 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
4508 void fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALARG_TP volatileVars);
4510 bool fgRemoveDeadStore(GenTree** pTree,
4512 VARSET_VALARG_TP life,
4514 bool* pStmtInfoDirty DEBUGARG(bool* treeModf));
4516 // For updating liveset during traversal AFTER fgComputeLife has completed
4517 VARSET_VALRET_TP fgGetVarBits(GenTree* tree);
4518 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tree);
4520 // Returns the set of live variables after endTree,
4521 // assuming that liveSet is the set of live variables BEFORE tree.
4522 // Requires that fgComputeLife has completed, and that tree is in the same
4523 // statement as endTree, and that it comes before endTree in execution order
4525 VARSET_VALRET_TP fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tree, GenTree* endTree)
4527 VARSET_TP newLiveSet(VarSetOps::MakeCopy(this, liveSet));
4528 while (tree != nullptr && tree != endTree->gtNext)
4530 VarSetOps::AssignNoCopy(this, newLiveSet, fgUpdateLiveSet(newLiveSet, tree));
4531 tree = tree->gtNext;
4533 assert(tree == endTree->gtNext);
4537 void fgInterBlockLocalVarLiveness();
4539 // The presence of a partial definition presents some difficulties for SSA: this is both a use of some SSA name
4540 // 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
4541 // whether to treat that as the use or def. It chooses the "use", and thus the old SSA name. This map allows us
4542 // to record/recover the "def" SSA number, given the lcl var node for "x" in such a tree.
4543 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, unsigned> NodeToUnsignedMap;
4544 NodeToUnsignedMap* m_opAsgnVarDefSsaNums;
4545 NodeToUnsignedMap* GetOpAsgnVarDefSsaNums()
4547 if (m_opAsgnVarDefSsaNums == nullptr)
4549 m_opAsgnVarDefSsaNums = new (getAllocator()) NodeToUnsignedMap(getAllocator());
4551 return m_opAsgnVarDefSsaNums;
4554 // Requires value numbering phase to have completed. Returns the value number ("gtVN") of the
4555 // "tree," EXCEPT in the case of GTF_VAR_USEASG, because the tree node's gtVN member is the
4556 // "use" VN. Performs a lookup into the map of (use asg tree -> def VN.) to return the "def's"
4558 inline ValueNum GetUseAsgDefVNOrTreeVN(GenTree* tree);
4560 // Requires that "lcl" has the GTF_VAR_DEF flag set. Returns the SSA number of "lcl".
4561 // Except: assumes that lcl is a def, and if it is
4562 // a partial def (GTF_VAR_USEASG), looks up and returns the SSA number for the "def",
4563 // rather than the "use" SSA number recorded in the tree "lcl".
4564 inline unsigned GetSsaNumForLocalVarDef(GenTree* lcl);
4566 // Performs SSA conversion.
4569 // Reset any data structures to the state expected by "fgSsaBuild", so it can be run again.
4570 void fgResetForSsa();
4572 unsigned fgSsaPassesCompleted; // Number of times fgSsaBuild has been run.
4574 // Returns "true" if a struct temp of the given type requires needs zero init in this block
4575 inline bool fgStructTempNeedsExplicitZeroInit(LclVarDsc* varDsc, BasicBlock* block);
4577 // The value numbers for this compilation.
4578 ValueNumStore* vnStore;
4581 ValueNumStore* GetValueNumStore()
4586 // Do value numbering (assign a value number to each
4588 void fgValueNumber();
4590 // Computes new GcHeap VN via the assignment H[elemTypeEq][arrVN][inx][fldSeq] = rhsVN.
4591 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
4592 // The 'indType' is the indirection type of the lhs of the assignment and will typically
4593 // match the element type of the array or fldSeq. When this type doesn't match
4594 // or if the fldSeq is 'NotAField' we invalidate the array contents H[elemTypeEq][arrVN]
4596 ValueNum fgValueNumberArrIndexAssign(CORINFO_CLASS_HANDLE elemTypeEq,
4599 FieldSeqNode* fldSeq,
4603 // Requires that "tree" is a GT_IND marked as an array index, and that its address argument
4604 // has been parsed to yield the other input arguments. If evaluation of the address
4605 // can raise exceptions, those should be captured in the exception set "excVN."
4606 // Assumes that "elemTypeEq" is the (equivalence class rep) of the array element type.
4607 // Marks "tree" with the VN for H[elemTypeEq][arrVN][inx][fldSeq] (for the liberal VN; a new unique
4608 // VN for the conservative VN.) Also marks the tree's argument as the address of an array element.
4609 // The type tree->TypeGet() will typically match the element type of the array or fldSeq.
4610 // When this type doesn't match or if the fldSeq is 'NotAField' we return a new unique VN
4612 ValueNum fgValueNumberArrIndexVal(GenTree* tree,
4613 CORINFO_CLASS_HANDLE elemTypeEq,
4617 FieldSeqNode* fldSeq);
4619 // Requires "funcApp" to be a VNF_PtrToArrElem, and "addrXvn" to represent the exception set thrown
4620 // by evaluating the array index expression "tree". Returns the value number resulting from
4621 // dereferencing the array in the current GcHeap state. If "tree" is non-null, it must be the
4622 // "GT_IND" that does the dereference, and it is given the returned value number.
4623 ValueNum fgValueNumberArrIndexVal(GenTree* tree, struct VNFuncApp* funcApp, ValueNum addrXvn);
4625 // Compute the value number for a byref-exposed load of the given type via the given pointerVN.
4626 ValueNum fgValueNumberByrefExposedLoad(var_types type, ValueNum pointerVN);
4628 unsigned fgVNPassesCompleted; // Number of times fgValueNumber has been run.
4630 // Utility functions for fgValueNumber.
4632 // Perform value-numbering for the trees in "blk".
4633 void fgValueNumberBlock(BasicBlock* blk);
4635 // Requires that "entryBlock" is the entry block of loop "loopNum", and that "loopNum" is the
4636 // innermost loop of which "entryBlock" is the entry. Returns the value number that should be
4637 // assumed for the memoryKind at the start "entryBlk".
4638 ValueNum fgMemoryVNForLoopSideEffects(MemoryKind memoryKind, BasicBlock* entryBlock, unsigned loopNum);
4640 // Called when an operation (performed by "tree", described by "msg") may cause the GcHeap to be mutated.
4641 // As GcHeap is a subset of ByrefExposed, this will also annotate the ByrefExposed mutation.
4642 void fgMutateGcHeap(GenTree* tree DEBUGARG(const char* msg));
4644 // Called when an operation (performed by "tree", described by "msg") may cause an address-exposed local to be
4646 void fgMutateAddressExposedLocal(GenTree* tree DEBUGARG(const char* msg));
4648 // For a GC heap store at curTree, record the new curMemoryVN's and update curTree's MemorySsaMap.
4649 // As GcHeap is a subset of ByrefExposed, this will also record the ByrefExposed store.
4650 void recordGcHeapStore(GenTree* curTree, ValueNum gcHeapVN DEBUGARG(const char* msg));
4652 // For a store to an address-exposed local at curTree, record the new curMemoryVN and update curTree's MemorySsaMap.
4653 void recordAddressExposedLocalStore(GenTree* curTree, ValueNum memoryVN DEBUGARG(const char* msg));
4655 // Tree caused an update in the current memory VN. If "tree" has an associated heap SSA #, record that
4656 // value in that SSA #.
4657 void fgValueNumberRecordMemorySsa(MemoryKind memoryKind, GenTree* tree);
4659 // The input 'tree' is a leaf node that is a constant
4660 // Assign the proper value number to the tree
4661 void fgValueNumberTreeConst(GenTree* tree);
4663 // Assumes that all inputs to "tree" have had value numbers assigned; assigns a VN to tree.
4664 // (With some exceptions: the VN of the lhs of an assignment is assigned as part of the
4666 void fgValueNumberTree(GenTree* tree);
4668 // Does value-numbering for a block assignment.
4669 void fgValueNumberBlockAssignment(GenTree* tree);
4671 // Does value-numbering for a cast tree.
4672 void fgValueNumberCastTree(GenTree* tree);
4674 // Does value-numbering for an intrinsic tree.
4675 void fgValueNumberIntrinsic(GenTree* tree);
4677 // Does value-numbering for a call. We interpret some helper calls.
4678 void fgValueNumberCall(GenTreeCall* call);
4680 // The VN of some nodes in "args" may have changed -- reassign VNs to the arg list nodes.
4681 void fgUpdateArgListVNs(GenTreeArgList* args);
4683 // Does value-numbering for a helper "call" that has a VN function symbol "vnf".
4684 void fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc);
4686 // Requires "helpCall" to be a helper call. Assigns it a value number;
4687 // we understand the semantics of some of the calls. Returns "true" if
4688 // the call may modify the heap (we assume arbitrary memory side effects if so).
4689 bool fgValueNumberHelperCall(GenTreeCall* helpCall);
4691 // Requires that "helpFunc" is one of the pure Jit Helper methods.
4692 // Returns the corresponding VNFunc to use for value numbering
4693 VNFunc fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc);
4695 // Adds the exception set for the current tree node which has a memory indirection operation
4696 void fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree* baseAddr);
4698 // Adds the exception sets for the current tree node which is performing a division or modulus operation
4699 void fgValueNumberAddExceptionSetForDivision(GenTree* tree);
4701 // Adds the exception set for the current tree node which is performing a overflow checking operation
4702 void fgValueNumberAddExceptionSetForOverflow(GenTree* tree);
4704 // Adds the exception set for the current tree node which is performing a ckfinite operation
4705 void fgValueNumberAddExceptionSetForCkFinite(GenTree* tree);
4707 // Adds the exception sets for the current tree node
4708 void fgValueNumberAddExceptionSet(GenTree* tree);
4710 // These are the current value number for the memory implicit variables while
4711 // doing value numbering. These are the value numbers under the "liberal" interpretation
4712 // of memory values; the "conservative" interpretation needs no VN, since every access of
4713 // memory yields an unknown value.
4714 ValueNum fgCurMemoryVN[MemoryKindCount];
4716 // Return a "pseudo"-class handle for an array element type. If "elemType" is TYP_STRUCT,
4717 // requires "elemStructType" to be non-null (and to have a low-order zero). Otherwise, low order bit
4718 // is 1, and the rest is an encoding of "elemTyp".
4719 static CORINFO_CLASS_HANDLE EncodeElemType(var_types elemTyp, CORINFO_CLASS_HANDLE elemStructType)
4721 if (elemStructType != nullptr)
4723 assert(varTypeIsStruct(elemTyp) || elemTyp == TYP_REF || elemTyp == TYP_BYREF ||
4724 varTypeIsIntegral(elemTyp));
4725 assert((size_t(elemStructType) & 0x1) == 0x0); // Make sure the encoding below is valid.
4726 return elemStructType;
4730 assert(elemTyp != TYP_STRUCT);
4731 elemTyp = varTypeUnsignedToSigned(elemTyp);
4732 return CORINFO_CLASS_HANDLE(size_t(elemTyp) << 1 | 0x1);
4735 // If "clsHnd" is the result of an "EncodePrim" call, returns true and sets "*pPrimType" to the
4736 // var_types it represents. Otherwise, returns TYP_STRUCT (on the assumption that "clsHnd" is
4737 // the struct type of the element).
4738 static var_types DecodeElemType(CORINFO_CLASS_HANDLE clsHnd)
4740 size_t clsHndVal = size_t(clsHnd);
4741 if (clsHndVal & 0x1)
4743 return var_types(clsHndVal >> 1);
4751 // Convert a BYTE which represents the VM's CorInfoGCtype to the JIT's var_types
4752 var_types getJitGCType(BYTE gcType);
4754 enum structPassingKind
4756 SPK_Unknown, // Invalid value, never returned
4757 SPK_PrimitiveType, // The struct is passed/returned using a primitive type.
4758 SPK_EnclosingType, // Like SPK_Primitive type, but used for return types that
4759 // require a primitive type temp that is larger than the struct size.
4760 // Currently used for structs of size 3, 5, 6, or 7 bytes.
4761 SPK_ByValue, // The struct is passed/returned by value (using the ABI rules)
4762 // for ARM64 and UNIX_X64 in multiple registers. (when all of the
4763 // parameters registers are used, then the stack will be used)
4764 // for X86 passed on the stack, for ARM32 passed in registers
4765 // or the stack or split between registers and the stack.
4766 SPK_ByValueAsHfa, // The struct is passed/returned as an HFA in multiple registers.
4768 }; // The struct is passed/returned by reference to a copy/buffer.
4770 // Get the "primitive" type that is is used when we are given a struct of size 'structSize'.
4771 // For pointer sized structs the 'clsHnd' is used to determine if the struct contains GC ref.
4772 // A "primitive" type is one of the scalar types: byte, short, int, long, ref, float, double
4773 // If we can't or shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
4775 // isVarArg is passed for use on Windows Arm64 to change the decision returned regarding
4778 var_types getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS_HANDLE clsHnd, bool isVarArg);
4780 // Get the type that is used to pass values of the given struct type.
4781 // isVarArg is passed for use on Windows Arm64 to change the decision returned regarding
4784 var_types getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4785 structPassingKind* wbPassStruct,
4787 unsigned structSize);
4789 // Get the type that is used to return values of the given struct type.
4790 // If the size is unknown, pass 0 and it will be determined from 'clsHnd'.
4791 var_types getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
4792 structPassingKind* wbPassStruct = nullptr,
4793 unsigned structSize = 0);
4796 // Print a representation of "vnp" or "vn" on standard output.
4797 // If "level" is non-zero, we also print out a partial expansion of the value.
4798 void vnpPrint(ValueNumPair vnp, unsigned level);
4799 void vnPrint(ValueNum vn, unsigned level);
4802 bool fgDominate(BasicBlock* b1, BasicBlock* b2); // Return true if b1 dominates b2
4804 // Dominator computation member functions
4805 // Not exposed outside Compiler
4807 bool fgReachable(BasicBlock* b1, BasicBlock* b2); // Returns true if block b1 can reach block b2
4809 void fgComputeDoms(); // Computes the immediate dominators for each basic block in the
4810 // flow graph. We first assume the fields bbIDom on each
4811 // basic block are invalid. This computation is needed later
4812 // by fgBuildDomTree to build the dominance tree structure.
4813 // Based on: A Simple, Fast Dominance Algorithm
4814 // by Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
4816 void fgCompDominatedByExceptionalEntryBlocks();
4818 BlockSet_ValRet_T fgGetDominatorSet(BasicBlock* block); // Returns a set of blocks that dominate the given block.
4819 // Note: this is relatively slow compared to calling fgDominate(),
4820 // especially if dealing with a single block versus block check.
4822 void fgComputeReachabilitySets(); // Compute bbReach sets. (Also sets BBF_GC_SAFE_POINT flag on blocks.)
4824 void fgComputeEnterBlocksSet(); // Compute the set of entry blocks, 'fgEnterBlks'.
4826 bool fgRemoveUnreachableBlocks(); // Remove blocks determined to be unreachable by the bbReach sets.
4828 void fgComputeReachability(); // Perform flow graph node reachability analysis.
4830 BasicBlock* fgIntersectDom(BasicBlock* a, BasicBlock* b); // Intersect two immediate dominator sets.
4832 void fgDfsInvPostOrder(); // In order to compute dominance using fgIntersectDom, the flow graph nodes must be
4833 // processed in topological sort, this function takes care of that.
4835 void fgDfsInvPostOrderHelper(BasicBlock* block, BlockSet& visited, unsigned* count);
4837 BlockSet_ValRet_T fgDomFindStartNodes(); // Computes which basic blocks don't have incoming edges in the flow graph.
4838 // Returns this as a set.
4840 BlockSet_ValRet_T fgDomTreeEntryNodes(BasicBlockList** domTree); // Computes which nodes in the dominance forest are
4841 // root nodes. Returns this as a set.
4844 void fgDispDomTree(BasicBlockList** domTree); // Helper that prints out the Dominator Tree in debug builds.
4847 void fgBuildDomTree(); // Once we compute all the immediate dominator sets for each node in the flow graph
4848 // (performed by fgComputeDoms), this procedure builds the dominance tree represented
4851 // In order to speed up the queries of the form 'Does A dominates B', we can perform a DFS preorder and postorder
4852 // traversal of the dominance tree and the dominance query will become A dominates B iif preOrder(A) <= preOrder(B)
4853 // && postOrder(A) >= postOrder(B) making the computation O(1).
4854 void fgTraverseDomTree(unsigned bbNum, BasicBlockList** domTree, unsigned* preNum, unsigned* postNum);
4856 // When the flow graph changes, we need to update the block numbers, predecessor lists, reachability sets, and
4858 void fgUpdateChangedFlowGraph();
4861 // Compute the predecessors of the blocks in the control flow graph.
4862 void fgComputePreds();
4864 // Remove all predecessor information.
4865 void fgRemovePreds();
4867 // Compute the cheap flow graph predecessors lists. This is used in some early phases
4868 // before the full predecessors lists are computed.
4869 void fgComputeCheapPreds();
4872 void fgAddCheapPred(BasicBlock* block, BasicBlock* blockPred);
4874 void fgRemoveCheapPred(BasicBlock* block, BasicBlock* blockPred);
4884 // Initialize the per-block variable sets (used for liveness analysis).
4885 void fgInitBlockVarSets();
4887 // true if we've gone through and created GC Poll calls.
4888 bool fgGCPollsCreated;
4889 void fgMarkGCPollBlocks();
4890 void fgCreateGCPolls();
4891 bool fgCreateGCPoll(GCPollType pollType, BasicBlock* block);
4893 // Requires that "block" is a block that returns from
4894 // a finally. Returns the number of successors (jump targets of
4895 // of blocks in the covered "try" that did a "LEAVE".)
4896 unsigned fgNSuccsOfFinallyRet(BasicBlock* block);
4898 // Requires that "block" is a block that returns (in the sense of BBJ_EHFINALLYRET) from
4899 // a finally. Returns its "i"th successor (jump targets of
4900 // of blocks in the covered "try" that did a "LEAVE".)
4901 // Requires that "i" < fgNSuccsOfFinallyRet(block).
4902 BasicBlock* fgSuccOfFinallyRet(BasicBlock* block, unsigned i);
4905 // Factor out common portions of the impls of the methods above.
4906 void fgSuccOfFinallyRetWork(BasicBlock* block, unsigned i, BasicBlock** bres, unsigned* nres);
4909 // For many purposes, it is desirable to be able to enumerate the *distinct* targets of a switch statement,
4910 // skipping duplicate targets. (E.g., in flow analyses that are only interested in the set of possible targets.)
4911 // SwitchUniqueSuccSet contains the non-duplicated switch targets.
4912 // (Code that modifies the jump table of a switch has an obligation to call Compiler::UpdateSwitchTableTarget,
4913 // which in turn will call the "UpdateTarget" method of this type if a SwitchUniqueSuccSet has already
4914 // been computed for the switch block. If a switch block is deleted or is transformed into a non-switch,
4915 // we leave the entry associated with the block, but it will no longer be accessed.)
4916 struct SwitchUniqueSuccSet
4918 unsigned numDistinctSuccs; // Number of distinct targets of the switch.
4919 BasicBlock** nonDuplicates; // Array of "numDistinctSuccs", containing all the distinct switch target
4922 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4923 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4924 // remove it from "this", and ensure that "to" is a member. Use "alloc" to do any required allocation.
4925 void UpdateTarget(CompAllocator alloc, BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4928 typedef JitHashTable<BasicBlock*, JitPtrKeyFuncs<BasicBlock>, SwitchUniqueSuccSet> BlockToSwitchDescMap;
4931 // Maps BasicBlock*'s that end in switch statements to SwitchUniqueSuccSets that allow
4932 // iteration over only the distinct successors.
4933 BlockToSwitchDescMap* m_switchDescMap;
4936 BlockToSwitchDescMap* GetSwitchDescMap(bool createIfNull = true)
4938 if ((m_switchDescMap == nullptr) && createIfNull)
4940 m_switchDescMap = new (getAllocator()) BlockToSwitchDescMap(getAllocator());
4942 return m_switchDescMap;
4945 // Invalidate the map of unique switch block successors. For example, since the hash key of the map
4946 // depends on block numbers, we must invalidate the map when the blocks are renumbered, to ensure that
4947 // we don't accidentally look up and return the wrong switch data.
4948 void InvalidateUniqueSwitchSuccMap()
4950 m_switchDescMap = nullptr;
4953 // Requires "switchBlock" to be a block that ends in a switch. Returns
4954 // the corresponding SwitchUniqueSuccSet.
4955 SwitchUniqueSuccSet GetDescriptorForSwitch(BasicBlock* switchBlk);
4957 // The switch block "switchBlk" just had an entry with value "from" modified to the value "to".
4958 // Update "this" as necessary: if "from" is no longer an element of the jump table of "switchBlk",
4959 // remove it from "this", and ensure that "to" is a member.
4960 void UpdateSwitchTableTarget(BasicBlock* switchBlk, BasicBlock* from, BasicBlock* to);
4962 // Remove the "SwitchUniqueSuccSet" of "switchBlk" in the BlockToSwitchDescMap.
4963 void fgInvalidateSwitchDescMapEntry(BasicBlock* switchBlk);
4965 BasicBlock* fgFirstBlockOfHandler(BasicBlock* block);
4967 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred);
4969 flowList* fgGetPredForBlock(BasicBlock* block, BasicBlock* blockPred, flowList*** ptrToPred);
4971 flowList* fgSpliceOutPred(BasicBlock* block, BasicBlock* blockPred);
4973 flowList* fgRemoveRefPred(BasicBlock* block, BasicBlock* blockPred);
4975 flowList* fgRemoveAllRefPreds(BasicBlock* block, BasicBlock* blockPred);
4977 flowList* fgRemoveAllRefPreds(BasicBlock* block, flowList** ptrToPred);
4979 void fgRemoveBlockAsPred(BasicBlock* block);
4981 void fgChangeSwitchBlock(BasicBlock* oldSwitchBlock, BasicBlock* newSwitchBlock);
4983 void fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* newTarget, BasicBlock* oldTarget);
4985 void fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, BasicBlock* oldTarget);
4987 void fgReplacePred(BasicBlock* block, BasicBlock* oldPred, BasicBlock* newPred);
4989 flowList* fgAddRefPred(BasicBlock* block,
4990 BasicBlock* blockPred,
4991 flowList* oldEdge = nullptr,
4992 bool initializingPreds = false); // Only set to 'true' when we are computing preds in
4995 void fgFindBasicBlocks();
4997 bool fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt);
4999 bool fgCheckEHCanInsertAfterBlock(BasicBlock* blk, unsigned regionIndex, bool putInTryRegion);
5001 BasicBlock* fgFindInsertPoint(unsigned regionIndex,
5002 bool putInTryRegion,
5003 BasicBlock* startBlk,
5005 BasicBlock* nearBlk,
5006 BasicBlock* jumpBlk,
5009 unsigned fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNesting = nullptr);
5011 void fgRemoveEmptyBlocks();
5013 void fgRemoveStmt(BasicBlock* block, GenTreeStmt* stmt);
5015 bool fgCheckRemoveStmt(BasicBlock* block, GenTreeStmt* stmt);
5017 void fgCreateLoopPreHeader(unsigned lnum);
5019 void fgUnreachableBlock(BasicBlock* block);
5021 void fgRemoveConditionalJump(BasicBlock* block);
5023 BasicBlock* fgLastBBInMainFunction();
5025 BasicBlock* fgEndBBAfterMainFunction();
5027 void fgUnlinkRange(BasicBlock* bBeg, BasicBlock* bEnd);
5029 void fgRemoveBlock(BasicBlock* block, bool unreachable);
5031 bool fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext);
5033 void fgCompactBlocks(BasicBlock* block, BasicBlock* bNext);
5035 void fgUpdateLoopsAfterCompacting(BasicBlock* block, BasicBlock* bNext);
5037 BasicBlock* fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst);
5039 bool fgRenumberBlocks();
5041 bool fgExpandRarelyRunBlocks();
5043 bool fgEhAllowsMoveBlock(BasicBlock* bBefore, BasicBlock* bAfter);
5045 void fgMoveBlocksAfter(BasicBlock* bStart, BasicBlock* bEnd, BasicBlock* insertAfterBlk);
5047 enum FG_RELOCATE_TYPE
5049 FG_RELOCATE_TRY, // relocate the 'try' region
5050 FG_RELOCATE_HANDLER // relocate the handler region (including the filter if necessary)
5052 BasicBlock* fgRelocateEHRange(unsigned regionIndex, FG_RELOCATE_TYPE relocateType);
5054 #if FEATURE_EH_FUNCLETS
5055 #if defined(_TARGET_ARM_)
5056 void fgClearFinallyTargetBit(BasicBlock* block);
5057 #endif // defined(_TARGET_ARM_)
5058 bool fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block);
5059 bool fgAnyIntraHandlerPreds(BasicBlock* block);
5060 void fgInsertFuncletPrologBlock(BasicBlock* block);
5061 void fgCreateFuncletPrologBlocks();
5062 void fgCreateFunclets();
5063 #else // !FEATURE_EH_FUNCLETS
5064 bool fgRelocateEHRegions();
5065 #endif // !FEATURE_EH_FUNCLETS
5067 bool fgOptimizeUncondBranchToSimpleCond(BasicBlock* block, BasicBlock* target);
5069 bool fgBlockEndFavorsTailDuplication(BasicBlock* block);
5071 bool fgBlockIsGoodTailDuplicationCandidate(BasicBlock* block);
5073 bool fgOptimizeEmptyBlock(BasicBlock* block);
5075 bool fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBlock* bDest);
5077 bool fgOptimizeBranch(BasicBlock* bJump);
5079 bool fgOptimizeSwitchBranches(BasicBlock* block);
5081 bool fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, BasicBlock* bPrev);
5083 bool fgOptimizeSwitchJumps();
5085 void fgPrintEdgeWeights();
5087 void fgComputeBlockAndEdgeWeights();
5088 BasicBlock::weight_t fgComputeMissingBlockWeights();
5089 void fgComputeCalledCount(BasicBlock::weight_t returnWeight);
5090 void fgComputeEdgeWeights();
5092 void fgReorderBlocks();
5094 void fgDetermineFirstColdBlock();
5096 bool fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc = nullptr);
5098 bool fgUpdateFlowGraph(bool doTailDup = false);
5100 void fgFindOperOrder();
5102 // method that returns if you should split here
5103 typedef bool(fgSplitPredicate)(GenTree* tree, GenTree* parent, fgWalkData* data);
5105 void fgSetBlockOrder();
5107 void fgRemoveReturnBlock(BasicBlock* block);
5109 /* Helper code that has been factored out */
5110 inline void fgConvertBBToThrowBB(BasicBlock* block);
5112 bool fgCastNeeded(GenTree* tree, var_types toType);
5113 GenTree* fgDoNormalizeOnStore(GenTree* tree);
5114 GenTree* fgMakeTmpArgNode(fgArgTabEntry* curArgTabEntry);
5116 // The following check for loops that don't execute calls
5117 bool fgLoopCallMarked;
5119 void fgLoopCallTest(BasicBlock* srcBB, BasicBlock* dstBB);
5120 void fgLoopCallMark();
5122 void fgMarkLoopHead(BasicBlock* block);
5124 unsigned fgGetCodeEstimate(BasicBlock* block);
5127 const char* fgProcessEscapes(const char* nameIn, escapeMapping_t* map);
5128 FILE* fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, LPCWSTR type);
5129 bool fgDumpFlowGraph(Phases phase);
5131 #endif // DUMP_FLOWGRAPHS
5136 void fgDispBBLiveness(BasicBlock* block);
5137 void fgDispBBLiveness();
5138 void fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth = 0);
5139 void fgDispBasicBlocks(BasicBlock* firstBlock, BasicBlock* lastBlock, bool dumpTrees);
5140 void fgDispBasicBlocks(bool dumpTrees = false);
5141 void fgDumpStmtTree(GenTreeStmt* stmt, unsigned bbNum);
5142 void fgDumpBlock(BasicBlock* block);
5143 void fgDumpTrees(BasicBlock* firstBlock, BasicBlock* lastBlock);
5145 static fgWalkPreFn fgStress64RsltMulCB;
5146 void fgStress64RsltMul();
5147 void fgDebugCheckUpdate();
5148 void fgDebugCheckBBlist(bool checkBBNum = false, bool checkBBRefs = true);
5149 void fgDebugCheckBlockLinks();
5150 void fgDebugCheckLinks(bool morphTrees = false);
5151 void fgDebugCheckStmtsList(BasicBlock* block, bool morphTrees);
5152 void fgDebugCheckNodeLinks(BasicBlock* block, GenTreeStmt* stmt);
5153 void fgDebugCheckNodesUniqueness();
5155 void fgDebugCheckFlags(GenTree* tree);
5156 void fgDebugCheckFlagsHelper(GenTree* tree, unsigned treeFlags, unsigned chkFlags);
5157 void fgDebugCheckTryFinallyExits();
5160 static GenTree* fgGetFirstNode(GenTree* tree);
5162 //--------------------- Walking the trees in the IR -----------------------
5167 fgWalkPreFn* wtprVisitorFn;
5168 fgWalkPostFn* wtpoVisitorFn;
5169 void* pCallbackData; // user-provided data
5170 bool wtprLclsOnly; // whether to only visit lclvar nodes
5171 GenTree* parent; // parent of current node, provided to callback
5172 GenTreeStack* parentStack; // stack of parent nodes, if asked for
5174 bool printModified; // callback can use this
5178 fgWalkResult fgWalkTreePre(GenTree** pTree,
5179 fgWalkPreFn* visitor,
5180 void* pCallBackData = nullptr,
5181 bool lclVarsOnly = false,
5182 bool computeStack = false);
5184 fgWalkResult fgWalkTree(GenTree** pTree,
5185 fgWalkPreFn* preVisitor,
5186 fgWalkPostFn* postVisitor,
5187 void* pCallBackData = nullptr);
5189 void fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData);
5193 fgWalkResult fgWalkTreePost(GenTree** pTree,
5194 fgWalkPostFn* visitor,
5195 void* pCallBackData = nullptr,
5196 bool computeStack = false);
5198 // An fgWalkPreFn that looks for expressions that have inline throws in
5199 // minopts mode. Basically it looks for tress with gtOverflowEx() or
5200 // GTF_IND_RNGCHK. It returns WALK_ABORT if one is found. It
5201 // returns WALK_SKIP_SUBTREES if GTF_EXCEPT is not set (assumes flags
5202 // properly propagated to parent trees). It returns WALK_CONTINUE
5204 static fgWalkResult fgChkThrowCB(GenTree** pTree, Compiler::fgWalkData* data);
5205 static fgWalkResult fgChkLocAllocCB(GenTree** pTree, Compiler::fgWalkData* data);
5206 static fgWalkResult fgChkQmarkCB(GenTree** pTree, Compiler::fgWalkData* data);
5208 /**************************************************************************
5210 *************************************************************************/
5213 friend class SsaBuilder;
5214 friend struct ValueNumberState;
5216 //--------------------- Detect the basic blocks ---------------------------
5218 BasicBlock** fgBBs; // Table of pointers to the BBs
5220 void fgInitBBLookup();
5221 BasicBlock* fgLookupBB(unsigned addr);
5223 void fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, FixedBitVect* jumpTarget);
5225 void fgMarkBackwardJump(BasicBlock* startBlock, BasicBlock* endBlock);
5227 void fgLinkBasicBlocks();
5229 unsigned fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, FixedBitVect* jumpTarget);
5231 void fgCheckBasicBlockControlFlow();
5233 void fgControlFlowPermitted(BasicBlock* blkSrc,
5234 BasicBlock* blkDest,
5235 BOOL IsLeave = false /* is the src a leave block */);
5237 bool fgFlowToFirstBlockOfInnerTry(BasicBlock* blkSrc, BasicBlock* blkDest, bool sibling);
5239 void fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, bool isInlining);
5241 void fgAdjustForAddressExposedOrWrittenThis();
5243 bool fgProfileData_ILSizeMismatch;
5244 ICorJitInfo::ProfileBuffer* fgProfileBuffer;
5245 ULONG fgProfileBufferCount;
5246 ULONG fgNumProfileRuns;
5248 unsigned fgStressBBProf()
5251 unsigned result = JitConfig.JitStressBBProf();
5254 if (compStressCompile(STRESS_BB_PROFILE, 15))
5265 bool fgHaveProfileData();
5266 bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weight);
5267 void fgInstrumentMethod();
5270 // fgIsUsingProfileWeights - returns true if we have real profile data for this method
5271 // or if we have some fake profile data for the stress mode
5272 bool fgIsUsingProfileWeights()
5274 return (fgHaveProfileData() || fgStressBBProf());
5277 // fgProfileRunsCount - returns total number of scenario runs for the profile data
5278 // or BB_UNITY_WEIGHT when we aren't using profile data.
5279 unsigned fgProfileRunsCount()
5281 return fgIsUsingProfileWeights() ? fgNumProfileRuns : BB_UNITY_WEIGHT;
5284 //-------- Insert a statement at the start or end of a basic block --------
5288 static bool fgBlockContainsStatementBounded(BasicBlock* block,
5290 bool answerOnBoundExceeded = true);
5294 GenTreeStmt* fgInsertStmtAtEnd(BasicBlock* block, GenTree* node);
5296 public: // Used by linear scan register allocation
5297 GenTreeStmt* fgInsertStmtNearEnd(BasicBlock* block, GenTree* node);
5300 GenTreeStmt* fgInsertStmtAtBeg(BasicBlock* block, GenTree* node);
5301 GenTreeStmt* fgInsertStmtAfter(BasicBlock* block, GenTreeStmt* insertionPoint, GenTreeStmt* stmt);
5303 public: // Used by linear scan register allocation
5304 GenTreeStmt* fgInsertStmtBefore(BasicBlock* block, GenTreeStmt* insertionPoint, GenTreeStmt* stmt);
5307 GenTreeStmt* fgInsertStmtListAfter(BasicBlock* block, GenTreeStmt* stmtAfter, GenTreeStmt* stmtList);
5309 // Create a new temporary variable to hold the result of *ppTree,
5310 // and transform the graph accordingly.
5311 GenTree* fgInsertCommaFormTemp(GenTree** ppTree, CORINFO_CLASS_HANDLE structType = nullptr);
5312 GenTree* fgMakeMultiUse(GenTree** ppTree);
5315 // Recognize a bitwise rotation pattern and convert into a GT_ROL or a GT_ROR node.
5316 GenTree* fgRecognizeAndMorphBitwiseRotation(GenTree* tree);
5317 bool fgOperIsBitwiseRotationRoot(genTreeOps oper);
5319 //-------- Determine the order in which the trees will be evaluated -------
5321 unsigned fgTreeSeqNum;
5322 GenTree* fgTreeSeqLst;
5323 GenTree* fgTreeSeqBeg;
5325 GenTree* fgSetTreeSeq(GenTree* tree, GenTree* prev = nullptr, bool isLIR = false);
5326 void fgSetTreeSeqHelper(GenTree* tree, bool isLIR);
5327 void fgSetTreeSeqFinish(GenTree* tree, bool isLIR);
5328 void fgSetStmtSeq(GenTreeStmt* stmt);
5329 void fgSetBlockOrder(BasicBlock* block);
5331 //------------------------- Morphing --------------------------------------
5333 unsigned fgPtrArgCntMax;
5336 //------------------------------------------------------------------------
5337 // fgGetPtrArgCntMax: Return the maximum number of pointer-sized stack arguments that calls inside this method
5338 // can push on the stack. This value is calculated during morph.
5341 // Returns fgPtrArgCntMax, that is a private field.
5343 unsigned fgGetPtrArgCntMax() const
5345 return fgPtrArgCntMax;
5348 //------------------------------------------------------------------------
5349 // fgSetPtrArgCntMax: Set the maximum number of pointer-sized stack arguments that calls inside this method
5350 // can push on the stack. This function is used during StackLevelSetter to fix incorrect morph calculations.
5352 void fgSetPtrArgCntMax(unsigned argCntMax)
5354 fgPtrArgCntMax = argCntMax;
5357 bool compCanEncodePtrArgCntMax();
5360 hashBv* fgOutgoingArgTemps;
5361 hashBv* fgCurrentlyInUseArgTemps;
5363 void fgSetRngChkTarget(GenTree* tree, bool delay = true);
5365 BasicBlock* fgSetRngChkTargetInner(SpecialCodeKind kind, bool delay);
5368 void fgMoveOpsLeft(GenTree* tree);
5371 bool fgIsCommaThrow(GenTree* tree, bool forFolding = false);
5373 bool fgIsThrow(GenTree* tree);
5375 bool fgInDifferentRegions(BasicBlock* blk1, BasicBlock* blk2);
5376 bool fgIsBlockCold(BasicBlock* block);
5378 GenTree* fgMorphCastIntoHelper(GenTree* tree, int helper, GenTree* oper);
5380 GenTree* fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeArgList* args, bool morphArgs = true);
5382 GenTree* fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType, unsigned lclOffs);
5384 // A "MorphAddrContext" carries information from the surrounding context. If we are evaluating a byref address,
5385 // it is useful to know whether the address will be immediately dereferenced, or whether the address value will
5386 // be used, perhaps by passing it as an argument to a called method. This affects how null checking is done:
5387 // for sufficiently small offsets, we can rely on OS page protection to implicitly null-check addresses that we
5388 // know will be dereferenced. To know that reliance on implicit null checking is sound, we must further know that
5389 // all offsets between the top-level indirection and the bottom are constant, and that their sum is sufficiently
5390 // small; hence the other fields of MorphAddrContext.
5391 enum MorphAddrContextKind
5396 struct MorphAddrContext
5398 MorphAddrContextKind m_kind;
5399 bool m_allConstantOffsets; // Valid only for "m_kind == MACK_Ind". True iff all offsets between
5400 // top-level indirection and here have been constants.
5401 size_t m_totalOffset; // Valid only for "m_kind == MACK_Ind", and if "m_allConstantOffsets" is true.
5402 // In that case, is the sum of those constant offsets.
5404 MorphAddrContext(MorphAddrContextKind kind) : m_kind(kind), m_allConstantOffsets(true), m_totalOffset(0)
5409 // A MACK_CopyBlock context is immutable, so we can just make one of these and share it.
5410 static MorphAddrContext s_CopyBlockMAC;
5413 GenTree* getSIMDStructFromField(GenTree* tree,
5414 var_types* baseTypeOut,
5416 unsigned* simdSizeOut,
5417 bool ignoreUsedInSIMDIntrinsic = false);
5418 GenTree* fgMorphFieldAssignToSIMDIntrinsicSet(GenTree* tree);
5419 GenTree* fgMorphFieldToSIMDIntrinsicGet(GenTree* tree);
5420 bool fgMorphCombineSIMDFieldAssignments(BasicBlock* block, GenTreeStmt* stmt);
5421 void impMarkContiguousSIMDFieldAssignments(GenTreeStmt* stmt);
5423 // fgPreviousCandidateSIMDFieldAsgStmt is only used for tracking previous simd field assignment
5424 // in function: Complier::impMarkContiguousSIMDFieldAssignments.
5425 GenTreeStmt* fgPreviousCandidateSIMDFieldAsgStmt;
5427 #endif // FEATURE_SIMD
5428 GenTree* fgMorphArrayIndex(GenTree* tree);
5429 GenTree* fgMorphCast(GenTree* tree);
5430 GenTree* fgUnwrapProxy(GenTree* objRef);
5431 GenTreeFieldList* fgMorphLclArgToFieldlist(GenTreeLclVarCommon* lcl);
5432 void fgInitArgInfo(GenTreeCall* call);
5433 GenTreeCall* fgMorphArgs(GenTreeCall* call);
5434 GenTreeArgList* fgMorphArgList(GenTreeArgList* args, MorphAddrContext* mac);
5436 void fgMakeOutgoingStructArgCopy(GenTreeCall* call,
5439 CORINFO_CLASS_HANDLE copyBlkClass);
5441 void fgFixupStructReturn(GenTree* call);
5442 GenTree* fgMorphLocalVar(GenTree* tree, bool forceRemorph);
5445 bool fgAddrCouldBeNull(GenTree* addr);
5448 GenTree* fgMorphField(GenTree* tree, MorphAddrContext* mac);
5449 bool fgCanFastTailCall(GenTreeCall* call);
5450 bool fgCheckStmtAfterTailCall();
5451 void fgMorphTailCall(GenTreeCall* call, void* pfnCopyArgs);
5452 GenTree* fgGetStubAddrArg(GenTreeCall* call);
5453 void fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCall* recursiveTailCall);
5454 GenTreeStmt* fgAssignRecursiveCallArgToCallerParam(GenTree* arg,
5455 fgArgTabEntry* argTabEntry,
5457 IL_OFFSETX callILOffset,
5458 GenTreeStmt* tmpAssignmentInsertionPoint,
5459 GenTreeStmt* paramAssignmentInsertionPoint);
5460 static int fgEstimateCallStackSize(GenTreeCall* call);
5461 GenTree* fgMorphCall(GenTreeCall* call);
5462 void fgMorphCallInline(GenTreeCall* call, InlineResult* result);
5463 void fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result);
5465 void fgNoteNonInlineCandidate(GenTreeStmt* stmt, GenTreeCall* call);
5466 static fgWalkPreFn fgFindNonInlineCandidate;
5468 GenTree* fgOptimizeDelegateConstructor(GenTreeCall* call,
5469 CORINFO_CONTEXT_HANDLE* ExactContextHnd,
5470 CORINFO_RESOLVED_TOKEN* ldftnToken);
5471 GenTree* fgMorphLeaf(GenTree* tree);
5472 void fgAssignSetVarDef(GenTree* tree);
5473 GenTree* fgMorphOneAsgBlockOp(GenTree* tree);
5474 GenTree* fgMorphInitBlock(GenTree* tree);
5475 GenTree* fgMorphPromoteLocalInitBlock(GenTreeLclVar* destLclNode, GenTree* initVal, unsigned blockSize);
5476 GenTree* fgMorphBlkToInd(GenTreeBlk* tree, var_types type);
5477 GenTree* fgMorphGetStructAddr(GenTree** pTree, CORINFO_CLASS_HANDLE clsHnd, bool isRValue = false);
5478 GenTree* fgMorphBlkNode(GenTree* tree, bool isDest);
5479 GenTree* fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigned blockWidth, bool isDest);
5480 void fgMorphUnsafeBlk(GenTreeObj* obj);
5481 GenTree* fgMorphCopyBlock(GenTree* tree);
5482 GenTree* fgMorphForRegisterFP(GenTree* tree);
5483 GenTree* fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac = nullptr);
5484 GenTree* fgMorphModToSubMulDiv(GenTreeOp* tree);
5485 GenTree* fgMorphSmpOpOptional(GenTreeOp* tree);
5486 GenTree* fgMorphRecognizeBoxNullable(GenTree* compare);
5488 GenTree* fgMorphToEmulatedFP(GenTree* tree);
5489 GenTree* fgMorphConst(GenTree* tree);
5492 GenTree* fgMorphTree(GenTree* tree, MorphAddrContext* mac = nullptr);
5495 #if LOCAL_ASSERTION_PROP
5496 void fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTree* tree));
5497 void fgKillDependentAssertions(unsigned lclNum DEBUGARG(GenTree* tree));
5499 void fgMorphTreeDone(GenTree* tree, GenTree* oldTree = nullptr DEBUGARG(int morphNum = 0));
5501 GenTreeStmt* fgMorphStmt;
5503 unsigned fgGetBigOffsetMorphingTemp(var_types type); // We cache one temp per type to be
5504 // used when morphing big offset.
5506 //----------------------- Liveness analysis -------------------------------
5508 VARSET_TP fgCurUseSet; // vars used by block (before an assignment)
5509 VARSET_TP fgCurDefSet; // vars assigned by block (before a use)
5511 MemoryKindSet fgCurMemoryUse; // True iff the current basic block uses memory.
5512 MemoryKindSet fgCurMemoryDef; // True iff the current basic block modifies memory.
5513 MemoryKindSet fgCurMemoryHavoc; // True if the current basic block is known to set memory to a "havoc" value.
5515 bool byrefStatesMatchGcHeapStates; // True iff GcHeap and ByrefExposed memory have all the same def points.
5517 void fgMarkUseDef(GenTreeLclVarCommon* tree);
5519 void fgBeginScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
5520 void fgEndScopeLife(VARSET_TP* inScope, VarScopeDsc* var);
5522 void fgMarkInScope(BasicBlock* block, VARSET_VALARG_TP inScope);
5523 void fgUnmarkInScope(BasicBlock* block, VARSET_VALARG_TP unmarkScope);
5525 void fgExtendDbgScopes();
5526 void fgExtendDbgLifetimes();
5529 void fgDispDebugScopes();
5532 //-------------------------------------------------------------------------
5534 // The following keeps track of any code we've added for things like array
5535 // range checking or explicit calls to enable GC, and so on.
5540 AddCodeDsc* acdNext;
5541 BasicBlock* acdDstBlk; // block to which we jump
5543 SpecialCodeKind acdKind; // what kind of a special block is this?
5544 #if !FEATURE_FIXED_OUT_ARGS
5545 bool acdStkLvlInit; // has acdStkLvl value been already set?
5547 #endif // !FEATURE_FIXED_OUT_ARGS
5551 static unsigned acdHelper(SpecialCodeKind codeKind);
5553 AddCodeDsc* fgAddCodeList;
5555 bool fgRngChkThrowAdded;
5556 AddCodeDsc* fgExcptnTargetCache[SCK_COUNT];
5558 BasicBlock* fgRngChkTarget(BasicBlock* block, SpecialCodeKind kind);
5560 BasicBlock* fgAddCodeRef(BasicBlock* srcBlk, unsigned refData, SpecialCodeKind kind);
5563 AddCodeDsc* fgFindExcptnTarget(SpecialCodeKind kind, unsigned refData);
5565 bool fgUseThrowHelperBlocks();
5567 AddCodeDsc* fgGetAdditionalCodeDescriptors()
5569 return fgAddCodeList;
5573 bool fgIsCodeAdded();
5575 bool fgIsThrowHlpBlk(BasicBlock* block);
5577 #if !FEATURE_FIXED_OUT_ARGS
5578 unsigned fgThrowHlpBlkStkLevel(BasicBlock* block);
5579 #endif // !FEATURE_FIXED_OUT_ARGS
5581 unsigned fgBigOffsetMorphingTemps[TYP_COUNT];
5583 unsigned fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo);
5584 void fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* result);
5585 void fgInsertInlineeBlocks(InlineInfo* pInlineInfo);
5586 GenTreeStmt* fgInlinePrependStatements(InlineInfo* inlineInfo);
5587 void fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, GenTreeStmt* stmt);
5589 #if FEATURE_MULTIREG_RET
5590 GenTree* fgGetStructAsStructPtr(GenTree* tree);
5591 GenTree* fgAssignStructInlineeToVar(GenTree* child, CORINFO_CLASS_HANDLE retClsHnd);
5592 void fgAttachStructInlineeToAsg(GenTree* tree, GenTree* child, CORINFO_CLASS_HANDLE retClsHnd);
5593 #endif // FEATURE_MULTIREG_RET
5595 static fgWalkPreFn fgUpdateInlineReturnExpressionPlaceHolder;
5596 static fgWalkPostFn fgLateDevirtualization;
5599 static fgWalkPreFn fgDebugCheckInlineCandidates;
5601 void CheckNoTransformableIndirectCallsRemain();
5602 static fgWalkPreFn fgDebugCheckForTransformableIndirectCalls;
5605 void fgPromoteStructs();
5606 void fgMorphStructField(GenTree* tree, GenTree* parent);
5607 void fgMorphLocalField(GenTree* tree, GenTree* parent);
5609 // Identify which parameters are implicit byrefs, and flag their LclVarDscs.
5610 void fgMarkImplicitByRefArgs();
5612 // Change implicit byrefs' types from struct to pointer, and for any that were
5613 // promoted, create new promoted struct temps.
5614 void fgRetypeImplicitByRefArgs();
5616 // Rewrite appearances of implicit byrefs (manifest the implied additional level of indirection).
5617 bool fgMorphImplicitByRefArgs(GenTree* tree);
5618 GenTree* fgMorphImplicitByRefArgs(GenTree* tree, bool isAddr);
5620 // Clear up annotations for any struct promotion temps created for implicit byrefs.
5621 void fgMarkDemotedImplicitByRefArgs();
5623 void fgMarkAddressExposedLocals();
5625 static fgWalkPreFn fgUpdateSideEffectsPre;
5626 static fgWalkPostFn fgUpdateSideEffectsPost;
5628 // The given local variable, required to be a struct variable, is being assigned via
5629 // a "lclField", to make it masquerade as an integral type in the ABI. Make sure that
5630 // the variable is not enregistered, and is therefore not promoted independently.
5631 void fgLclFldAssign(unsigned lclNum);
5633 static fgWalkPreFn gtHasLocalsWithAddrOpCB;
5635 enum TypeProducerKind
5637 TPK_Unknown = 0, // May not be a RuntimeType
5638 TPK_Handle = 1, // RuntimeType via handle
5639 TPK_GetType = 2, // RuntimeType via Object.get_Type()
5640 TPK_Null = 3, // Tree value is null
5641 TPK_Other = 4 // RuntimeType via other means
5644 TypeProducerKind gtGetTypeProducerKind(GenTree* tree);
5645 bool gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call);
5646 bool gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper = nullptr);
5647 bool gtIsActiveCSE_Candidate(GenTree* tree);
5650 bool fgPrintInlinedMethods;
5653 bool fgIsBigOffset(size_t offset);
5655 bool fgNeedReturnSpillTemp();
5658 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5659 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5663 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5664 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5670 void optRemoveRangeCheck(GenTree* tree, GenTreeStmt* stmt);
5671 bool optIsRangeCheckRemovable(GenTree* tree);
5674 static fgWalkPreFn optValidRangeCheckIndex;
5676 /**************************************************************************
5678 *************************************************************************/
5681 // Do hoisting for all loops.
5682 void optHoistLoopCode();
5684 // To represent sets of VN's that have already been hoisted in outer loops.
5685 typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, bool> VNToBoolMap;
5686 typedef VNToBoolMap VNSet;
5688 struct LoopHoistContext
5691 // The set of variables hoisted in the current loop (or nullptr if there are none).
5692 VNSet* m_pHoistedInCurLoop;
5695 // Value numbers of expressions that have been hoisted in parent loops in the loop nest.
5696 VNSet m_hoistedInParentLoops;
5697 // Value numbers of expressions that have been hoisted in the current (or most recent) loop in the nest.
5698 // Previous decisions on loop-invariance of value numbers in the current loop.
5699 VNToBoolMap m_curLoopVnInvariantCache;
5701 VNSet* GetHoistedInCurLoop(Compiler* comp)
5703 if (m_pHoistedInCurLoop == nullptr)
5705 m_pHoistedInCurLoop = new (comp->getAllocatorLoopHoist()) VNSet(comp->getAllocatorLoopHoist());
5707 return m_pHoistedInCurLoop;
5710 VNSet* ExtractHoistedInCurLoop()
5712 VNSet* res = m_pHoistedInCurLoop;
5713 m_pHoistedInCurLoop = nullptr;
5717 LoopHoistContext(Compiler* comp)
5718 : m_pHoistedInCurLoop(nullptr)
5719 , m_hoistedInParentLoops(comp->getAllocatorLoopHoist())
5720 , m_curLoopVnInvariantCache(comp->getAllocatorLoopHoist())
5725 // Do hoisting for loop "lnum" (an index into the optLoopTable), and all loops nested within it.
5726 // Tracks the expressions that have been hoisted by containing loops by temporary recording their
5727 // value numbers in "m_hoistedInParentLoops". This set is not modified by the call.
5728 void optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);
5730 // Do hoisting for a particular loop ("lnum" is an index into the optLoopTable.)
5731 // Assumes that expressions have been hoisted in containing loops if their value numbers are in
5732 // "m_hoistedInParentLoops".
5734 void optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt);
5736 // Hoist all expressions in "blk" that are invariant in loop "lnum" (an index into the optLoopTable)
5737 // outside of that loop. Exempt expressions whose value number is in "m_hoistedInParentLoops"; add VN's of hoisted
5738 // expressions to "hoistInLoop".
5739 void optHoistLoopExprsForBlock(BasicBlock* blk, unsigned lnum, LoopHoistContext* hoistCtxt);
5741 // Return true if the tree looks profitable to hoist out of loop 'lnum'.
5742 bool optIsProfitableToHoistableTree(GenTree* tree, unsigned lnum);
5744 // Hoist all proper sub-expressions of "tree" (which occurs in "stmt", which occurs in "blk")
5745 // that are invariant in loop "lnum" (an index into the optLoopTable)
5746 // outside of that loop. Exempt expressions whose value number is in "hoistedInParents"; add VN's of hoisted
5747 // expressions to "hoistInLoop".
5748 // Returns "true" iff "tree" is loop-invariant (wrt "lnum").
5749 // Assumes that the value of "*firstBlockAndBeforeSideEffect" indicates that we're in the first block, and before
5750 // any possible globally visible side effects. Assume is called in evaluation order, and updates this.
5751 bool optHoistLoopExprsForTree(GenTree* tree,
5753 LoopHoistContext* hoistCtxt,
5754 bool* firstBlockAndBeforeSideEffect,
5756 bool* pCctorDependent);
5758 // Performs the hoisting 'tree' into the PreHeader for loop 'lnum'
5759 void optHoistCandidate(GenTree* tree, unsigned lnum, LoopHoistContext* hoistCtxt);
5761 // Returns true iff the ValueNum "vn" represents a value that is loop-invariant in "lnum".
5762 // Constants and init values are always loop invariant.
5763 // VNPhi's connect VN's to the SSA definition, so we can know if the SSA def occurs in the loop.
5764 bool optVNIsLoopInvariant(ValueNum vn, unsigned lnum, VNToBoolMap* recordedVNs);
5766 // Returns "true" iff "tree" is valid at the head of loop "lnum", in the context of the hoist substitution
5767 // "subst". If "tree" is a local SSA var, it is valid if its SSA definition occurs outside of the loop, or
5768 // if it is in the domain of "subst" (meaning that it's definition has been previously hoisted, with a "standin"
5769 // local.) If tree is a constant, it is valid. Otherwise, if it is an operator, it is valid iff its children are.
5770 bool optTreeIsValidAtLoopHead(GenTree* tree, unsigned lnum);
5772 // If "blk" is the entry block of a natural loop, returns true and sets "*pLnum" to the index of the loop
5773 // in the loop table.
5774 bool optBlockIsLoopEntry(BasicBlock* blk, unsigned* pLnum);
5776 // Records the set of "side effects" of all loops: fields (object instance and static)
5777 // written to, and SZ-array element type equivalence classes updated.
5778 void optComputeLoopSideEffects();
5781 // Requires "lnum" to be the index of an outermost loop in the loop table. Traverses the body of that loop,
5782 // including all nested loops, and records the set of "side effects" of the loop: fields (object instance and
5783 // static) written to, and SZ-array element type equivalence classes updated.
5784 void optComputeLoopNestSideEffects(unsigned lnum);
5786 // Add the side effects of "blk" (which is required to be within a loop) to all loops of which it is a part.
5787 void optComputeLoopSideEffectsOfBlock(BasicBlock* blk);
5789 // Hoist the expression "expr" out of loop "lnum".
5790 void optPerformHoistExpr(GenTree* expr, unsigned lnum);
5793 void optOptimizeBools();
5796 GenTree* optIsBoolCond(GenTree* condBranch, GenTree** compPtr, bool* boolPtr);
5798 void optOptimizeBoolsGcStress(BasicBlock* condBlock);
5801 void optOptimizeLayout(); // Optimize the BasicBlock layout of the method
5803 void optOptimizeLoops(); // for "while-do" loops duplicates simple loop conditions and transforms
5804 // the loop into a "do-while" loop
5805 // Also finds all natural loops and records them in the loop table
5807 // Optionally clone loops in the loop table.
5808 void optCloneLoops();
5810 // Clone loop "loopInd" in the loop table.
5811 void optCloneLoop(unsigned loopInd, LoopCloneContext* context);
5813 // Ensure that loop "loopInd" has a unique head block. (If the existing entry has
5814 // non-loop predecessors other than the head entry, create a new, empty block that goes (only) to the entry,
5815 // and redirects the preds of the entry to this new block.) Sets the weight of the newly created block to
5817 void optEnsureUniqueHead(unsigned loopInd, unsigned ambientWeight);
5819 void optUnrollLoops(); // Unrolls loops (needs to have cost info)
5822 // This enumeration describes what is killed by a call.
5826 CALLINT_NONE, // no interference (most helpers)
5827 CALLINT_REF_INDIRS, // kills GC ref indirections (SETFIELD OBJ)
5828 CALLINT_SCL_INDIRS, // kills non GC ref indirections (SETFIELD non-OBJ)
5829 CALLINT_ALL_INDIRS, // kills both GC ref and non GC ref indirections (SETFIELD STRUCT)
5830 CALLINT_ALL, // kills everything (normal method call)
5834 // A "LoopDsc" describes a ("natural") loop. We (currently) require the body of a loop to be a contiguous (in
5835 // bbNext order) sequence of basic blocks. (At times, we may require the blocks in a loop to be "properly numbered"
5836 // in bbNext order; we use comparisons on the bbNum to decide order.)
5837 // The blocks that define the body are
5838 // first <= top <= entry <= bottom .
5839 // The "head" of the loop is a block outside the loop that has "entry" as a successor. We only support loops with a
5840 // single 'head' block. The meanings of these blocks are given in the definitions below. Also see the picture at
5841 // Compiler::optFindNaturalLoops().
5844 BasicBlock* lpHead; // HEAD of the loop (not part of the looping of the loop) -- has ENTRY as a successor.
5845 BasicBlock* lpFirst; // FIRST block (in bbNext order) reachable within this loop. (May be part of a nested
5846 // loop, but not the outer loop.)
5847 BasicBlock* lpTop; // loop TOP (the back edge from lpBottom reaches here) (in most cases FIRST and TOP are the
5849 BasicBlock* lpEntry; // the ENTRY in the loop (in most cases TOP or BOTTOM)
5850 BasicBlock* lpBottom; // loop BOTTOM (from here we have a back edge to the TOP)
5851 BasicBlock* lpExit; // if a single exit loop this is the EXIT (in most cases BOTTOM)
5853 callInterf lpAsgCall; // "callInterf" for calls in the loop
5854 ALLVARSET_TP lpAsgVars; // set of vars assigned within the loop (all vars, not just tracked)
5855 varRefKinds lpAsgInds : 8; // set of inds modified within the loop
5857 unsigned short lpFlags; // Mask of the LPFLG_* constants
5859 unsigned char lpExitCnt; // number of exits from the loop
5861 unsigned char lpParent; // The index of the most-nested loop that completely contains this one,
5862 // or else BasicBlock::NOT_IN_LOOP if no such loop exists.
5863 unsigned char lpChild; // The index of a nested loop, or else BasicBlock::NOT_IN_LOOP if no child exists.
5864 // (Actually, an "immediately" nested loop --
5865 // no other child of this loop is a parent of lpChild.)
5866 unsigned char lpSibling; // The index of another loop that is an immediate child of lpParent,
5867 // or else BasicBlock::NOT_IN_LOOP. One can enumerate all the children of a loop
5868 // by following "lpChild" then "lpSibling" links.
5870 #define LPFLG_DO_WHILE 0x0001 // it's a do-while loop (i.e ENTRY is at the TOP)
5871 #define LPFLG_ONE_EXIT 0x0002 // the loop has only one exit
5873 #define LPFLG_ITER 0x0004 // for (i = icon or lclVar; test_condition(); i++)
5874 #define LPFLG_HOISTABLE 0x0008 // the loop is in a form that is suitable for hoisting expressions
5875 #define LPFLG_CONST 0x0010 // for (i=icon;i<icon;i++){ ... } - constant loop
5877 #define LPFLG_VAR_INIT 0x0020 // iterator is initialized with a local var (var # found in lpVarInit)
5878 #define LPFLG_CONST_INIT 0x0040 // iterator is initialized with a constant (found in lpConstInit)
5880 #define LPFLG_VAR_LIMIT 0x0100 // iterator is compared with a local var (var # found in lpVarLimit)
5881 #define LPFLG_CONST_LIMIT 0x0200 // iterator is compared with a constant (found in lpConstLimit)
5882 #define LPFLG_ARRLEN_LIMIT 0x0400 // iterator is compared with a.len or a[i].len (found in lpArrLenLimit)
5883 #define LPFLG_SIMD_LIMIT 0x0080 // iterator is compared with Vector<T>.Count (found in lpConstLimit)
5885 #define LPFLG_HAS_PREHEAD 0x0800 // lpHead is known to be a preHead for this loop
5886 #define LPFLG_REMOVED 0x1000 // has been removed from the loop table (unrolled or optimized away)
5887 #define LPFLG_DONT_UNROLL 0x2000 // do not unroll this loop
5889 #define LPFLG_ASGVARS_YES 0x4000 // "lpAsgVars" has been computed
5890 #define LPFLG_ASGVARS_INC 0x8000 // "lpAsgVars" is incomplete -- vars beyond those representable in an AllVarSet
5891 // type are assigned to.
5893 bool lpLoopHasMemoryHavoc[MemoryKindCount]; // The loop contains an operation that we assume has arbitrary
5894 // memory side effects. If this is set, the fields below
5895 // may not be accurate (since they become irrelevant.)
5896 bool lpContainsCall; // True if executing the loop body *may* execute a call
5898 VARSET_TP lpVarInOut; // The set of variables that are IN or OUT during the execution of this loop
5899 VARSET_TP lpVarUseDef; // The set of variables that are USE or DEF during the execution of this loop
5901 int lpHoistedExprCount; // The register count for the non-FP expressions from inside this loop that have been
5903 int lpLoopVarCount; // The register count for the non-FP LclVars that are read/written inside this loop
5904 int lpVarInOutCount; // The register count for the non-FP LclVars that are alive inside or accross this loop
5906 int lpHoistedFPExprCount; // The register count for the FP expressions from inside this loop that have been
5908 int lpLoopVarFPCount; // The register count for the FP LclVars that are read/written inside this loop
5909 int lpVarInOutFPCount; // The register count for the FP LclVars that are alive inside or accross this loop
5911 typedef JitHashTable<CORINFO_FIELD_HANDLE, JitPtrKeyFuncs<struct CORINFO_FIELD_STRUCT_>, bool> FieldHandleSet;
5912 FieldHandleSet* lpFieldsModified; // This has entries (mappings to "true") for all static field and object
5913 // instance fields modified
5916 typedef JitHashTable<CORINFO_CLASS_HANDLE, JitPtrKeyFuncs<struct CORINFO_CLASS_STRUCT_>, bool> ClassHandleSet;
5917 ClassHandleSet* lpArrayElemTypesModified; // Bits set indicate the set of sz array element types such that
5918 // arrays of that type are modified
5921 // Adds the variable liveness information for 'blk' to 'this' LoopDsc
5922 void AddVariableLiveness(Compiler* comp, BasicBlock* blk);
5924 inline void AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd);
5925 // This doesn't *always* take a class handle -- it can also take primitive types, encoded as class handles
5926 // (shifted left, with a low-order bit set to distinguish.)
5927 // Use the {Encode/Decode}ElemType methods to construct/destruct these.
5928 inline void AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd);
5930 /* The following values are set only for iterator loops, i.e. has the flag LPFLG_ITER set */
5932 GenTree* lpIterTree; // The "i = i <op> const" tree
5933 unsigned lpIterVar(); // iterator variable #
5934 int lpIterConst(); // the constant with which the iterator is incremented
5935 genTreeOps lpIterOper(); // the type of the operation on the iterator (ASG_ADD, ASG_SUB, etc.)
5936 void VERIFY_lpIterTree();
5938 var_types lpIterOperType(); // For overflow instructions
5941 int lpConstInit; // initial constant value of iterator : Valid if LPFLG_CONST_INIT
5942 unsigned lpVarInit; // initial local var number to which we initialize the iterator : Valid if
5946 /* The following is for LPFLG_ITER loops only (i.e. the loop condition is "i RELOP const or var" */
5948 GenTree* lpTestTree; // pointer to the node containing the loop test
5949 genTreeOps lpTestOper(); // the type of the comparison between the iterator and the limit (GT_LE, GT_GE, etc.)
5950 void VERIFY_lpTestTree();
5952 bool lpIsReversed(); // true if the iterator node is the second operand in the loop condition
5953 GenTree* lpIterator(); // the iterator node in the loop test
5954 GenTree* lpLimit(); // the limit node in the loop test
5956 int lpConstLimit(); // limit constant value of iterator - loop condition is "i RELOP const" : Valid if
5957 // LPFLG_CONST_LIMIT
5958 unsigned lpVarLimit(); // the lclVar # in the loop condition ( "i RELOP lclVar" ) : Valid if
5960 bool lpArrLenLimit(Compiler* comp, ArrIndex* index); // The array length in the loop condition ( "i RELOP
5961 // arr.len" or "i RELOP arr[i][j].len" ) : Valid if
5962 // LPFLG_ARRLEN_LIMIT
5964 // Returns "true" iff "*this" contains the blk.
5965 bool lpContains(BasicBlock* blk)
5967 return lpFirst->bbNum <= blk->bbNum && blk->bbNum <= lpBottom->bbNum;
5969 // Returns "true" iff "*this" (properly) contains the range [first, bottom] (allowing firsts
5970 // to be equal, but requiring bottoms to be different.)
5971 bool lpContains(BasicBlock* first, BasicBlock* bottom)
5973 return lpFirst->bbNum <= first->bbNum && bottom->bbNum < lpBottom->bbNum;
5976 // Returns "true" iff "*this" (properly) contains "lp2" (allowing firsts to be equal, but requiring
5977 // bottoms to be different.)
5978 bool lpContains(const LoopDsc& lp2)
5980 return lpContains(lp2.lpFirst, lp2.lpBottom);
5983 // Returns "true" iff "*this" is (properly) contained by the range [first, bottom]
5984 // (allowing firsts to be equal, but requiring bottoms to be different.)
5985 bool lpContainedBy(BasicBlock* first, BasicBlock* bottom)
5987 return first->bbNum <= lpFirst->bbNum && lpBottom->bbNum < bottom->bbNum;
5990 // Returns "true" iff "*this" is (properly) contained by "lp2"
5991 // (allowing firsts to be equal, but requiring bottoms to be different.)
5992 bool lpContainedBy(const LoopDsc& lp2)
5994 return lpContains(lp2.lpFirst, lp2.lpBottom);
5997 // Returns "true" iff "*this" is disjoint from the range [top, bottom].
5998 bool lpDisjoint(BasicBlock* first, BasicBlock* bottom)
6000 return bottom->bbNum < lpFirst->bbNum || lpBottom->bbNum < first->bbNum;
6002 // Returns "true" iff "*this" is disjoint from "lp2".
6003 bool lpDisjoint(const LoopDsc& lp2)
6005 return lpDisjoint(lp2.lpFirst, lp2.lpBottom);
6007 // Returns "true" iff the loop is well-formed (see code for defn).
6010 return lpFirst->bbNum <= lpTop->bbNum && lpTop->bbNum <= lpEntry->bbNum &&
6011 lpEntry->bbNum <= lpBottom->bbNum &&
6012 (lpHead->bbNum < lpTop->bbNum || lpHead->bbNum > lpBottom->bbNum);
6017 bool fgMightHaveLoop(); // returns true if there are any backedges
6018 bool fgHasLoops; // True if this method has any loops, set in fgComputeReachability
6021 LoopDsc* optLoopTable; // loop descriptor table
6022 unsigned char optLoopCount; // number of tracked loops
6024 bool optRecordLoop(BasicBlock* head,
6030 unsigned char exitCnt);
6033 unsigned optCallCount; // number of calls made in the method
6034 unsigned optIndirectCallCount; // number of virtual, interface and indirect calls made in the method
6035 unsigned optNativeCallCount; // number of Pinvoke/Native calls made in the method
6036 unsigned optLoopsCloned; // number of loops cloned in the current method.
6039 unsigned optFindLoopNumberFromBeginBlock(BasicBlock* begBlk);
6040 void optPrintLoopInfo(unsigned loopNum,
6042 BasicBlock* lpFirst,
6044 BasicBlock* lpEntry,
6045 BasicBlock* lpBottom,
6046 unsigned char lpExitCnt,
6048 unsigned parentLoop = BasicBlock::NOT_IN_LOOP);
6049 void optPrintLoopInfo(unsigned lnum);
6050 void optPrintLoopRecording(unsigned lnum);
6052 void optCheckPreds();
6055 void optSetBlockWeights();
6057 void optMarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk, bool excludeEndBlk);
6059 void optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk);
6061 void optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmarkLoop = false);
6063 bool optIsLoopTestEvalIntoTemp(GenTreeStmt* testStmt, GenTreeStmt** newTestStmt);
6064 unsigned optIsLoopIncrTree(GenTree* incr);
6065 bool optCheckIterInLoopTest(unsigned loopInd, GenTree* test, BasicBlock* from, BasicBlock* to, unsigned iterVar);
6066 bool optComputeIterInfo(GenTree* incr, BasicBlock* from, BasicBlock* to, unsigned* pIterVar);
6067 bool optPopulateInitInfo(unsigned loopInd, GenTree* init, unsigned iterVar);
6068 bool optExtractInitTestIncr(
6069 BasicBlock* head, BasicBlock* bottom, BasicBlock* exit, GenTree** ppInit, GenTree** ppTest, GenTree** ppIncr);
6071 void optFindNaturalLoops();
6073 // Ensures that all the loops in the loop nest rooted at "loopInd" (an index into the loop table) are 'canonical' --
6074 // each loop has a unique "top." Returns "true" iff the flowgraph has been modified.
6075 bool optCanonicalizeLoopNest(unsigned char loopInd);
6077 // Ensures that the loop "loopInd" (an index into the loop table) is 'canonical' -- it has a unique "top,"
6078 // unshared with any other loop. Returns "true" iff the flowgraph has been modified
6079 bool optCanonicalizeLoop(unsigned char loopInd);
6081 // Requires "l1" to be a valid loop table index, and not "BasicBlock::NOT_IN_LOOP". Requires "l2" to be
6082 // a valid loop table index, or else "BasicBlock::NOT_IN_LOOP". Returns true
6083 // iff "l2" is not NOT_IN_LOOP, and "l1" contains "l2".
6084 bool optLoopContains(unsigned l1, unsigned l2);
6086 // Requires "loopInd" to be a valid index into the loop table.
6087 // Updates the loop table by changing loop "loopInd", whose head is required
6088 // to be "from", to be "to". Also performs this transformation for any
6089 // loop nested in "loopInd" that shares the same head as "loopInd".
6090 void optUpdateLoopHead(unsigned loopInd, BasicBlock* from, BasicBlock* to);
6092 // Updates the successors of "blk": if "blk2" is a successor of "blk", and there is a mapping for "blk2->blk3" in
6093 // "redirectMap", change "blk" so that "blk3" is this successor. Note that the predecessor lists are not updated.
6094 void optRedirectBlock(BasicBlock* blk, BlockToBlockMap* redirectMap);
6096 // Marks the containsCall information to "lnum" and any parent loops.
6097 void AddContainsCallAllContainingLoops(unsigned lnum);
6098 // Adds the variable liveness information from 'blk' to "lnum" and any parent loops.
6099 void AddVariableLivenessAllContainingLoops(unsigned lnum, BasicBlock* blk);
6100 // Adds "fldHnd" to the set of modified fields of "lnum" and any parent loops.
6101 void AddModifiedFieldAllContainingLoops(unsigned lnum, CORINFO_FIELD_HANDLE fldHnd);
6102 // Adds "elemType" to the set of modified array element types of "lnum" and any parent loops.
6103 void AddModifiedElemTypeAllContainingLoops(unsigned lnum, CORINFO_CLASS_HANDLE elemType);
6105 // Requires that "from" and "to" have the same "bbJumpKind" (perhaps because "to" is a clone
6106 // of "from".) Copies the jump destination from "from" to "to".
6107 void optCopyBlkDest(BasicBlock* from, BasicBlock* to);
6109 // The depth of the loop described by "lnum" (an index into the loop table.) (0 == top level)
6110 unsigned optLoopDepth(unsigned lnum)
6112 unsigned par = optLoopTable[lnum].lpParent;
6113 if (par == BasicBlock::NOT_IN_LOOP)
6119 return 1 + optLoopDepth(par);
6123 void fgOptWhileLoop(BasicBlock* block);
6125 bool optComputeLoopRep(int constInit,
6128 genTreeOps iterOper,
6130 genTreeOps testOper,
6133 unsigned* iterCount);
6136 static fgWalkPreFn optIsVarAssgCB;
6139 bool optIsVarAssigned(BasicBlock* beg, BasicBlock* end, GenTree* skip, unsigned var);
6141 bool optIsVarAssgLoop(unsigned lnum, unsigned var);
6143 int optIsSetAssgLoop(unsigned lnum, ALLVARSET_VALARG_TP vars, varRefKinds inds = VR_NONE);
6145 bool optNarrowTree(GenTree* tree, var_types srct, var_types dstt, ValueNumPair vnpNarrow, bool doit);
6147 /**************************************************************************
6148 * Optimization conditions
6149 *************************************************************************/
6151 bool optFastCodeOrBlendedLoop(BasicBlock::weight_t bbWeight);
6152 bool optPentium4(void);
6153 bool optAvoidIncDec(BasicBlock::weight_t bbWeight);
6154 bool optAvoidIntMult(void);
6159 // The following is the upper limit on how many expressions we'll keep track
6160 // of for the CSE analysis.
6162 static const unsigned MAX_CSE_CNT = EXPSET_SZ;
6164 static const int MIN_CSE_COST = 2;
6166 // Keeps tracked cse indices
6167 BitVecTraits* cseTraits;
6170 /* Generic list of nodes - used by the CSE logic */
6180 treeStmtLst* tslNext;
6181 GenTree* tslTree; // tree node
6182 GenTreeStmt* tslStmt; // statement containing the tree
6183 BasicBlock* tslBlock; // block containing the statement
6186 // The following logic keeps track of expressions via a simple hash table.
6190 CSEdsc* csdNextInBucket; // used by the hash table
6192 unsigned csdHashKey; // the orginal hashkey
6194 unsigned csdIndex; // 1..optCSECandidateCount
6195 char csdLiveAcrossCall; // 0 or 1
6197 unsigned short csdDefCount; // definition count
6198 unsigned short csdUseCount; // use count (excluding the implicit uses at defs)
6200 unsigned csdDefWtCnt; // weighted def count
6201 unsigned csdUseWtCnt; // weighted use count (excluding the implicit uses at defs)
6203 GenTree* csdTree; // treenode containing the 1st occurance
6204 GenTreeStmt* csdStmt; // stmt containing the 1st occurance
6205 BasicBlock* csdBlock; // block containing the 1st occurance
6207 treeStmtLst* csdTreeList; // list of matching tree nodes: head
6208 treeStmtLst* csdTreeLast; // list of matching tree nodes: tail
6210 ValueNum defExcSetPromise; // The exception set that is now required for all defs of this CSE.
6211 // This will be set to NoVN if we decide to abandon this CSE
6213 ValueNum defExcSetCurrent; // The set of exceptions we currently can use for CSE uses.
6215 ValueNum defConservNormVN; // if all def occurrences share the same conservative normal value
6216 // number, this will reflect it; otherwise, NoVN.
6219 static const size_t s_optCSEhashSize;
6220 CSEdsc** optCSEhash;
6223 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, GenTree*> NodeToNodeMap;
6225 NodeToNodeMap* optCseCheckedBoundMap; // Maps bound nodes to ancestor compares that should be
6226 // re-numbered with the bound to improve range check elimination
6228 // Given a compare, look for a cse candidate checked bound feeding it and add a map entry if found.
6229 void optCseUpdateCheckedBoundMap(GenTree* compare);
6233 CSEdsc* optCSEfindDsc(unsigned index);
6234 bool optUnmarkCSE(GenTree* tree);
6236 // user defined callback data for the tree walk function optCSE_MaskHelper()
6237 struct optCSE_MaskData
6239 EXPSET_TP CSE_defMask;
6240 EXPSET_TP CSE_useMask;
6243 // Treewalk helper for optCSE_DefMask and optCSE_UseMask
6244 static fgWalkPreFn optCSE_MaskHelper;
6246 // This function walks all the node for an given tree
6247 // and return the mask of CSE definitions and uses for the tree
6249 void optCSE_GetMaskData(GenTree* tree, optCSE_MaskData* pMaskData);
6251 // Given a binary tree node return true if it is safe to swap the order of evaluation for op1 and op2.
6252 bool optCSE_canSwap(GenTree* firstNode, GenTree* secondNode);
6253 bool optCSE_canSwap(GenTree* tree);
6255 static int __cdecl optCSEcostCmpEx(const void* op1, const void* op2);
6256 static int __cdecl optCSEcostCmpSz(const void* op1, const void* op2);
6258 void optCleanupCSEs();
6261 void optEnsureClearCSEInfo();
6264 #endif // FEATURE_ANYCSE
6266 #if FEATURE_VALNUM_CSE
6267 /**************************************************************************
6268 * Value Number based CSEs
6269 *************************************************************************/
6272 void optOptimizeValnumCSEs();
6275 void optValnumCSE_Init();
6276 unsigned optValnumCSE_Index(GenTree* tree, GenTreeStmt* stmt);
6277 unsigned optValnumCSE_Locate();
6278 void optValnumCSE_InitDataFlow();
6279 void optValnumCSE_DataFlow();
6280 void optValnumCSE_Availablity();
6281 void optValnumCSE_Heuristic();
6283 #endif // FEATURE_VALNUM_CSE
6286 bool optDoCSE; // True when we have found a duplicate CSE tree
6287 bool optValnumCSE_phase; // True when we are executing the optValnumCSE_phase
6288 unsigned optCSECandidateTotal; // Grand total of CSE candidates for both Lexical and ValNum
6289 unsigned optCSECandidateCount; // Count of CSE's candidates, reset for Lexical and ValNum CSE's
6290 unsigned optCSEstart; // The first local variable number that is a CSE
6291 unsigned optCSEcount; // The total count of CSE's introduced.
6292 unsigned optCSEweight; // The weight of the current block when we are
6293 // scanning for CSE expressions
6295 bool optIsCSEcandidate(GenTree* tree);
6297 // lclNumIsTrueCSE returns true if the LclVar was introduced by the CSE phase of the compiler
6299 bool lclNumIsTrueCSE(unsigned lclNum) const
6301 return ((optCSEcount > 0) && (lclNum >= optCSEstart) && (lclNum < optCSEstart + optCSEcount));
6304 // lclNumIsCSE returns true if the LclVar should be treated like a CSE with regards to constant prop.
6306 bool lclNumIsCSE(unsigned lclNum) const
6308 return lvaTable[lclNum].lvIsCSE;
6312 bool optConfigDisableCSE();
6313 bool optConfigDisableCSE2();
6315 void optOptimizeCSEs();
6317 #endif // FEATURE_ANYCSE
6325 unsigned ivaVar; // Variable we are interested in, or -1
6326 ALLVARSET_TP ivaMaskVal; // Set of variables assigned to. This is a set of all vars, not tracked vars.
6327 bool ivaMaskIncomplete; // Variables not representable in ivaMaskVal were assigned to.
6328 varRefKinds ivaMaskInd; // What kind of indirect assignments are there?
6329 callInterf ivaMaskCall; // What kind of calls are there?
6332 static callInterf optCallInterf(GenTreeCall* call);
6335 // VN based copy propagation.
6336 typedef ArrayStack<GenTree*> GenTreePtrStack;
6337 typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, GenTreePtrStack*> LclNumToGenTreePtrStack;
6339 // Kill set to track variables with intervening definitions.
6340 VARSET_TP optCopyPropKillSet;
6342 // Copy propagation functions.
6343 void optCopyProp(BasicBlock* block, GenTreeStmt* stmt, GenTree* tree, LclNumToGenTreePtrStack* curSsaName);
6344 void optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
6345 void optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
6346 bool optIsSsaLocal(GenTree* tree);
6347 int optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2);
6348 void optVnCopyProp();
6349 INDEBUG(void optDumpCopyPropStack(LclNumToGenTreePtrStack* curSsaName));
6351 /**************************************************************************
6352 * Early value propagation
6353 *************************************************************************/
6359 SSAName(unsigned lvNum, unsigned ssaNum) : m_lvNum(lvNum), m_ssaNum(ssaNum)
6363 static unsigned GetHashCode(SSAName ssaNm)
6365 return (ssaNm.m_lvNum << 16) | (ssaNm.m_ssaNum);
6368 static bool Equals(SSAName ssaNm1, SSAName ssaNm2)
6370 return (ssaNm1.m_lvNum == ssaNm2.m_lvNum) && (ssaNm1.m_ssaNum == ssaNm2.m_ssaNum);
6374 #define OMF_HAS_NEWARRAY 0x00000001 // Method contains 'new' of an array
6375 #define OMF_HAS_NEWOBJ 0x00000002 // Method contains 'new' of an object type.
6376 #define OMF_HAS_ARRAYREF 0x00000004 // Method contains array element loads or stores.
6377 #define OMF_HAS_VTABLEREF 0x00000008 // Method contains method table reference.
6378 #define OMF_HAS_NULLCHECK 0x00000010 // Method contains null check.
6379 #define OMF_HAS_FATPOINTER 0x00000020 // Method contains call, that needs fat pointer transformation.
6380 #define OMF_HAS_OBJSTACKALLOC 0x00000040 // Method contains an object allocated on the stack.
6381 #define OMF_HAS_GUARDEDDEVIRT 0x00000080 // Method contains guarded devirtualization candidate
6383 bool doesMethodHaveFatPointer()
6385 return (optMethodFlags & OMF_HAS_FATPOINTER) != 0;
6388 void setMethodHasFatPointer()
6390 optMethodFlags |= OMF_HAS_FATPOINTER;
6393 void clearMethodHasFatPointer()
6395 optMethodFlags &= ~OMF_HAS_FATPOINTER;
6398 void addFatPointerCandidate(GenTreeCall* call);
6400 bool doesMethodHaveGuardedDevirtualization()
6402 return (optMethodFlags & OMF_HAS_GUARDEDDEVIRT) != 0;
6405 void setMethodHasGuardedDevirtualization()
6407 optMethodFlags |= OMF_HAS_GUARDEDDEVIRT;
6410 void clearMethodHasGuardedDevirtualization()
6412 optMethodFlags &= ~OMF_HAS_GUARDEDDEVIRT;
6415 void addGuardedDevirtualizationCandidate(GenTreeCall* call,
6416 CORINFO_METHOD_HANDLE methodHandle,
6417 CORINFO_CLASS_HANDLE classHandle,
6418 unsigned methodAttr,
6419 unsigned classAttr);
6421 unsigned optMethodFlags;
6423 // Recursion bound controls how far we can go backwards tracking for a SSA value.
6424 // No throughput diff was found with backward walk bound between 3-8.
6425 static const int optEarlyPropRecurBound = 5;
6427 enum class optPropKind
6435 bool gtIsVtableRef(GenTree* tree);
6436 GenTree* getArrayLengthFromAllocation(GenTree* tree);
6437 GenTree* getObjectHandleNodeFromAllocation(GenTree* tree);
6438 GenTree* optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropKind valueKind, int walkDepth);
6439 GenTree* optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind);
6440 GenTree* optEarlyPropRewriteTree(GenTree* tree);
6441 bool optDoEarlyPropForBlock(BasicBlock* block);
6442 bool optDoEarlyPropForFunc();
6443 void optEarlyProp();
6444 void optFoldNullCheck(GenTree* tree);
6445 bool optCanMoveNullCheckPastTree(GenTree* tree, bool isInsideTry);
6448 /**************************************************************************
6449 * Value/Assertion propagation
6450 *************************************************************************/
6452 // Data structures for assertion prop
6453 BitVecTraits* apTraits;
6456 enum optAssertionKind
6473 O1K_CONSTANT_LOOP_BND,
6494 optAssertionKind assertionKind;
6497 unsigned lclNum; // assigned to or property of this local var number
6505 struct AssertionDscOp1
6507 optOp1Kind kind; // a normal LclVar, or Exact-type or Subtype
6514 struct AssertionDscOp2
6516 optOp2Kind kind; // a const or copy assignment
6520 ssize_t iconVal; // integer
6521 unsigned iconFlags; // gtFlags
6523 struct Range // integer subrange
6537 bool IsCheckedBoundArithBound()
6539 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_BOUND_OPER_BND);
6541 bool IsCheckedBoundBound()
6543 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) && op1.kind == O1K_BOUND_LOOP_BND);
6545 bool IsConstantBound()
6547 return ((assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL) &&
6548 op1.kind == O1K_CONSTANT_LOOP_BND);
6550 bool IsBoundsCheckNoThrow()
6552 return ((assertionKind == OAK_NO_THROW) && (op1.kind == O1K_ARR_BND));
6555 bool IsCopyAssertion()
6557 return ((assertionKind == OAK_EQUAL) && (op1.kind == O1K_LCLVAR) && (op2.kind == O2K_LCLVAR_COPY));
6560 static bool SameKind(AssertionDsc* a1, AssertionDsc* a2)
6562 return a1->assertionKind == a2->assertionKind && a1->op1.kind == a2->op1.kind &&
6563 a1->op2.kind == a2->op2.kind;
6566 static bool ComplementaryKind(optAssertionKind kind, optAssertionKind kind2)
6568 if (kind == OAK_EQUAL)
6570 return kind2 == OAK_NOT_EQUAL;
6572 else if (kind == OAK_NOT_EQUAL)
6574 return kind2 == OAK_EQUAL;
6579 static ssize_t GetLowerBoundForIntegralType(var_types type)
6598 static ssize_t GetUpperBoundForIntegralType(var_types type)
6621 bool HasSameOp1(AssertionDsc* that, bool vnBased)
6623 if (op1.kind != that->op1.kind)
6627 else if (op1.kind == O1K_ARR_BND)
6630 return (op1.bnd.vnIdx == that->op1.bnd.vnIdx) && (op1.bnd.vnLen == that->op1.bnd.vnLen);
6634 return ((vnBased && (op1.vn == that->op1.vn)) ||
6635 (!vnBased && (op1.lcl.lclNum == that->op1.lcl.lclNum)));
6639 bool HasSameOp2(AssertionDsc* that, bool vnBased)
6641 if (op2.kind != that->op2.kind)
6647 case O2K_IND_CNS_INT:
6649 return ((op2.u1.iconVal == that->op2.u1.iconVal) && (op2.u1.iconFlags == that->op2.u1.iconFlags));
6651 case O2K_CONST_LONG:
6652 return (op2.lconVal == that->op2.lconVal);
6654 case O2K_CONST_DOUBLE:
6655 // exact match because of positive and negative zero.
6656 return (memcmp(&op2.dconVal, &that->op2.dconVal, sizeof(double)) == 0);
6658 case O2K_LCLVAR_COPY:
6660 return (op2.lcl.lclNum == that->op2.lcl.lclNum) &&
6661 (!vnBased || op2.lcl.ssaNum == that->op2.lcl.ssaNum);
6664 return ((op2.u2.loBound == that->op2.u2.loBound) && (op2.u2.hiBound == that->op2.u2.hiBound));
6667 // we will return false
6671 assert(!"Unexpected value for op2.kind in AssertionDsc.");
6677 bool Complementary(AssertionDsc* that, bool vnBased)
6679 return ComplementaryKind(assertionKind, that->assertionKind) && HasSameOp1(that, vnBased) &&
6680 HasSameOp2(that, vnBased);
6683 bool Equals(AssertionDsc* that, bool vnBased)
6685 if (assertionKind != that->assertionKind)
6689 else if (assertionKind == OAK_NO_THROW)
6691 assert(op2.kind == O2K_INVALID);
6692 return HasSameOp1(that, vnBased);
6696 return HasSameOp1(that, vnBased) && HasSameOp2(that, vnBased);
6702 static fgWalkPreFn optAddCopiesCallback;
6703 static fgWalkPreFn optVNAssertionPropCurStmtVisitor;
6704 unsigned optAddCopyLclNum;
6705 GenTree* optAddCopyAsgnNode;
6707 bool optLocalAssertionProp; // indicates that we are performing local assertion prop
6708 bool optAssertionPropagated; // set to true if we modified the trees
6709 bool optAssertionPropagatedCurrentStmt;
6711 GenTree* optAssertionPropCurrentTree;
6713 AssertionIndex* optComplementaryAssertionMap;
6714 JitExpandArray<ASSERT_TP>* optAssertionDep; // table that holds dependent assertions (assertions
6715 // using the value of a local var) for each local var
6716 AssertionDsc* optAssertionTabPrivate; // table that holds info about value assignments
6717 AssertionIndex optAssertionCount; // total number of assertions in the assertion table
6718 AssertionIndex optMaxAssertionCount;
6721 void optVnNonNullPropCurStmt(BasicBlock* block, GenTreeStmt* stmt, GenTree* tree);
6722 fgWalkResult optVNConstantPropCurStmt(BasicBlock* block, GenTreeStmt* stmt, GenTree* tree);
6723 GenTree* optVNConstantPropOnJTrue(BasicBlock* block, GenTree* test);
6724 GenTree* optVNConstantPropOnTree(BasicBlock* block, GenTree* tree);
6725 GenTree* optPrepareTreeForReplacement(GenTree* extractTree, GenTree* replaceTree);
6727 AssertionIndex GetAssertionCount()
6729 return optAssertionCount;
6731 ASSERT_TP* bbJtrueAssertionOut;
6732 typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, ASSERT_TP> ValueNumToAssertsMap;
6733 ValueNumToAssertsMap* optValueNumToAsserts;
6735 // Assertion prop helpers.
6736 ASSERT_TP& GetAssertionDep(unsigned lclNum);
6737 AssertionDsc* optGetAssertion(AssertionIndex assertIndex);
6738 void optAssertionInit(bool isLocalProp);
6739 void optAssertionTraitsInit(AssertionIndex assertionCount);
6740 #if LOCAL_ASSERTION_PROP
6741 void optAssertionReset(AssertionIndex limit);
6742 void optAssertionRemove(AssertionIndex index);
6745 // Assertion prop data flow functions.
6746 void optAssertionPropMain();
6747 GenTreeStmt* optVNAssertionPropCurStmt(BasicBlock* block, GenTreeStmt* stmt);
6748 bool optIsTreeKnownIntValue(bool vnBased, GenTree* tree, ssize_t* pConstant, unsigned* pIconFlags);
6749 ASSERT_TP* optInitAssertionDataflowFlags();
6750 ASSERT_TP* optComputeAssertionGen();
6752 // Assertion Gen functions.
6753 void optAssertionGen(GenTree* tree);
6754 AssertionIndex optAssertionGenPhiDefn(GenTree* tree);
6755 AssertionInfo optCreateJTrueBoundsAssertion(GenTree* tree);
6756 AssertionInfo optAssertionGenJtrue(GenTree* tree);
6757 AssertionIndex optCreateJtrueAssertions(GenTree* op1, GenTree* op2, Compiler::optAssertionKind assertionKind);
6758 AssertionIndex optFindComplementary(AssertionIndex assertionIndex);
6759 void optMapComplementary(AssertionIndex assertionIndex, AssertionIndex index);
6761 // Assertion creation functions.
6762 AssertionIndex optCreateAssertion(GenTree* op1, GenTree* op2, optAssertionKind assertionKind);
6763 AssertionIndex optCreateAssertion(GenTree* op1,
6765 optAssertionKind assertionKind,
6766 AssertionDsc* assertion);
6767 void optCreateComplementaryAssertion(AssertionIndex assertionIndex, GenTree* op1, GenTree* op2);
6769 bool optAssertionVnInvolvesNan(AssertionDsc* assertion);
6770 AssertionIndex optAddAssertion(AssertionDsc* assertion);
6771 void optAddVnAssertionMapping(ValueNum vn, AssertionIndex index);
6773 void optPrintVnAssertionMapping();
6775 ASSERT_TP optGetVnMappedAssertions(ValueNum vn);
6777 // Used for respective assertion propagations.
6778 AssertionIndex optAssertionIsSubrange(GenTree* tree, var_types toType, ASSERT_VALARG_TP assertions);
6779 AssertionIndex optAssertionIsSubtype(GenTree* tree, GenTree* methodTableArg, ASSERT_VALARG_TP assertions);
6780 AssertionIndex optAssertionIsNonNullInternal(GenTree* op, ASSERT_VALARG_TP assertions);
6781 bool optAssertionIsNonNull(GenTree* op,
6782 ASSERT_VALARG_TP assertions DEBUGARG(bool* pVnBased) DEBUGARG(AssertionIndex* pIndex));
6784 // Used for Relop propagation.
6785 AssertionIndex optGlobalAssertionIsEqualOrNotEqual(ASSERT_VALARG_TP assertions, GenTree* op1, GenTree* op2);
6786 AssertionIndex optGlobalAssertionIsEqualOrNotEqualZero(ASSERT_VALARG_TP assertions, GenTree* op1);
6787 AssertionIndex optLocalAssertionIsEqualOrNotEqual(
6788 optOp1Kind op1Kind, unsigned lclNum, optOp2Kind op2Kind, ssize_t cnsVal, ASSERT_VALARG_TP assertions);
6790 // Assertion prop for lcl var functions.
6791 bool optAssertionProp_LclVarTypeCheck(GenTree* tree, LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc);
6792 GenTree* optCopyAssertionProp(AssertionDsc* curAssertion,
6794 GenTreeStmt* stmt DEBUGARG(AssertionIndex index));
6795 GenTree* optConstantAssertionProp(AssertionDsc* curAssertion,
6797 GenTreeStmt* stmt DEBUGARG(AssertionIndex index));
6799 // Assertion propagation functions.
6800 GenTree* optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTreeStmt* stmt);
6801 GenTree* optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, GenTree* tree, GenTreeStmt* stmt);
6802 GenTree* optAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* tree, GenTreeStmt* stmt);
6803 GenTree* optAssertionProp_Cast(ASSERT_VALARG_TP assertions, GenTree* tree, GenTreeStmt* stmt);
6804 GenTree* optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, GenTreeStmt* stmt);
6805 GenTree* optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTreeStmt* stmt);
6806 GenTree* optAssertionProp_Comma(ASSERT_VALARG_TP assertions, GenTree* tree, GenTreeStmt* stmt);
6807 GenTree* optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree* tree);
6808 GenTree* optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTreeStmt* stmt);
6809 GenTree* optAssertionPropLocal_RelOp(ASSERT_VALARG_TP assertions, GenTree* tree, GenTreeStmt* stmt);
6810 GenTree* optAssertionProp_Update(GenTree* newTree, GenTree* tree, GenTreeStmt* stmt);
6811 GenTree* optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call);
6813 // Implied assertion functions.
6814 void optImpliedAssertions(AssertionIndex assertionIndex, ASSERT_TP& activeAssertions);
6815 void optImpliedByTypeOfAssertions(ASSERT_TP& activeAssertions);
6816 void optImpliedByCopyAssertion(AssertionDsc* copyAssertion, AssertionDsc* depAssertion, ASSERT_TP& result);
6817 void optImpliedByConstAssertion(AssertionDsc* curAssertion, ASSERT_TP& result);
6820 void optPrintAssertion(AssertionDsc* newAssertion, AssertionIndex assertionIndex = 0);
6821 void optDebugCheckAssertion(AssertionDsc* assertion);
6822 void optDebugCheckAssertions(AssertionIndex AssertionIndex);
6824 void optAddCopies();
6825 #endif // ASSERTION_PROP
6827 /**************************************************************************
6829 *************************************************************************/
6832 struct LoopCloneVisitorInfo
6834 LoopCloneContext* context;
6837 LoopCloneVisitorInfo(LoopCloneContext* context, unsigned loopNum, GenTreeStmt* stmt)
6838 : context(context), loopNum(loopNum), stmt(nullptr)
6843 bool optIsStackLocalInvariant(unsigned loopNum, unsigned lclNum);
6844 bool optExtractArrIndex(GenTree* tree, ArrIndex* result, unsigned lhsNum);
6845 bool optReconstructArrIndex(GenTree* tree, ArrIndex* result, unsigned lhsNum);
6846 bool optIdentifyLoopOptInfo(unsigned loopNum, LoopCloneContext* context);
6847 static fgWalkPreFn optCanOptimizeByLoopCloningVisitor;
6848 fgWalkResult optCanOptimizeByLoopCloning(GenTree* tree, LoopCloneVisitorInfo* info);
6849 void optObtainLoopCloningOpts(LoopCloneContext* context);
6850 bool optIsLoopClonable(unsigned loopInd);
6852 bool optCanCloneLoops();
6855 void optDebugLogLoopCloning(BasicBlock* block, GenTreeStmt* insertBefore);
6857 void optPerformStaticOptimizations(unsigned loopNum, LoopCloneContext* context DEBUGARG(bool fastPath));
6858 bool optComputeDerefConditions(unsigned loopNum, LoopCloneContext* context);
6859 bool optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext* context);
6860 BasicBlock* optInsertLoopChoiceConditions(LoopCloneContext* context,
6866 ssize_t optGetArrayRefScaleAndIndex(GenTree* mul, GenTree** pIndex DEBUGARG(bool bRngChk));
6868 bool optReachWithoutCall(BasicBlock* srcBB, BasicBlock* dstBB);
6871 bool optLoopsMarked;
6874 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6875 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6879 XX Does the register allocation and puts the remaining lclVars on the stack XX
6881 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6882 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6886 regNumber raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc);
6888 void raMarkStkVars();
6891 // Some things are used by both LSRA and regpredict allocators.
6893 FrameType rpFrameType;
6894 bool rpMustCreateEBPCalled; // Set to true after we have called rpMustCreateEBPFrame once
6896 bool rpMustCreateEBPFrame(INDEBUG(const char** wbReason));
6899 Lowering* m_pLowering; // Lowering; needed to Lower IR that's added or modified after Lowering.
6900 LinearScanInterface* m_pLinearScan; // Linear Scan allocator
6902 /* raIsVarargsStackArg is called by raMaskStkVars and by
6903 lvaSortByRefCount. It identifies the special case
6904 where a varargs function has a parameter passed on the
6905 stack, other than the special varargs handle. Such parameters
6906 require special treatment, because they cannot be tracked
6907 by the GC (their offsets in the stack are not known
6911 bool raIsVarargsStackArg(unsigned lclNum)
6915 LclVarDsc* varDsc = &lvaTable[lclNum];
6917 assert(varDsc->lvIsParam);
6919 return (info.compIsVarArgs && !varDsc->lvIsRegArg && (lclNum != lvaVarargsHandleArg));
6921 #else // _TARGET_X86_
6925 #endif // _TARGET_X86_
6929 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6930 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6934 XX Get to the class and method info from the Execution Engine given XX
6935 XX tokens for the class and method XX
6937 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6938 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6944 void eeGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6945 CORINFO_RESOLVED_TOKEN* pConstrainedToken,
6946 CORINFO_CALLINFO_FLAGS flags,
6947 CORINFO_CALL_INFO* pResult);
6948 inline CORINFO_CALLINFO_FLAGS addVerifyFlag(CORINFO_CALLINFO_FLAGS flags);
6950 void eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
6951 CORINFO_ACCESS_FLAGS flags,
6952 CORINFO_FIELD_INFO* pResult);
6956 BOOL eeIsValueClass(CORINFO_CLASS_HANDLE clsHnd);
6958 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(TRACK_LSRA_STATS)
6960 bool IsSuperPMIException(unsigned code)
6962 // Copied from NDP\clr\src\ToolBox\SuperPMI\SuperPMI-Shared\ErrorHandling.h
6964 const unsigned EXCEPTIONCODE_DebugBreakorAV = 0xe0421000;
6965 const unsigned EXCEPTIONCODE_MC = 0xe0422000;
6966 const unsigned EXCEPTIONCODE_LWM = 0xe0423000;
6967 const unsigned EXCEPTIONCODE_SASM = 0xe0424000;
6968 const unsigned EXCEPTIONCODE_SSYM = 0xe0425000;
6969 const unsigned EXCEPTIONCODE_CALLUTILS = 0xe0426000;
6970 const unsigned EXCEPTIONCODE_TYPEUTILS = 0xe0427000;
6971 const unsigned EXCEPTIONCODE_ASSERT = 0xe0440000;
6975 case EXCEPTIONCODE_DebugBreakorAV:
6976 case EXCEPTIONCODE_MC:
6977 case EXCEPTIONCODE_LWM:
6978 case EXCEPTIONCODE_SASM:
6979 case EXCEPTIONCODE_SSYM:
6980 case EXCEPTIONCODE_CALLUTILS:
6981 case EXCEPTIONCODE_TYPEUTILS:
6982 case EXCEPTIONCODE_ASSERT:
6989 const char* eeGetMethodName(CORINFO_METHOD_HANDLE hnd, const char** className);
6990 const char* eeGetMethodFullName(CORINFO_METHOD_HANDLE hnd);
6992 bool eeIsNativeMethod(CORINFO_METHOD_HANDLE method);
6993 CORINFO_METHOD_HANDLE eeGetMethodHandleForNative(CORINFO_METHOD_HANDLE method);
6996 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
6997 var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig, bool* isPinned);
6998 unsigned eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig);
7000 // VOM info, method sigs
7002 void eeGetSig(unsigned sigTok,
7003 CORINFO_MODULE_HANDLE scope,
7004 CORINFO_CONTEXT_HANDLE context,
7005 CORINFO_SIG_INFO* retSig);
7007 void eeGetCallSiteSig(unsigned sigTok,
7008 CORINFO_MODULE_HANDLE scope,
7009 CORINFO_CONTEXT_HANDLE context,
7010 CORINFO_SIG_INFO* retSig);
7012 void eeGetMethodSig(CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* retSig, CORINFO_CLASS_HANDLE owner = nullptr);
7014 // Method entry-points, instrs
7016 CORINFO_METHOD_HANDLE eeMarkNativeTarget(CORINFO_METHOD_HANDLE method);
7018 CORINFO_EE_INFO eeInfo;
7019 bool eeInfoInitialized;
7021 CORINFO_EE_INFO* eeGetEEInfo();
7023 // Gets the offset of a SDArray's first element
7024 unsigned eeGetArrayDataOffset(var_types type);
7025 // Gets the offset of a MDArray's first element
7026 unsigned eeGetMDArrayDataOffset(var_types type, unsigned rank);
7028 GenTree* eeGetPInvokeCookie(CORINFO_SIG_INFO* szMetaSig);
7030 // Returns the page size for the target machine as reported by the EE.
7031 target_size_t eeGetPageSize()
7033 return (target_size_t)eeGetEEInfo()->osPageSize;
7036 // Returns the frame size at which we will generate a loop to probe the stack.
7037 target_size_t getVeryLargeFrameSize()
7040 // The looping probe code is 40 bytes, whereas the straight-line probing for
7041 // the (0x2000..0x3000) case is 44, so use looping for anything 0x2000 bytes
7042 // or greater, to generate smaller code.
7043 return 2 * eeGetPageSize();
7045 return 3 * eeGetPageSize();
7049 //------------------------------------------------------------------------
7050 // VirtualStubParam: virtual stub dispatch extra parameter (slot address).
7052 // It represents Abi and target specific registers for the parameter.
7054 class VirtualStubParamInfo
7057 VirtualStubParamInfo(bool isCoreRTABI)
7059 #if defined(_TARGET_X86_)
7062 #elif defined(_TARGET_AMD64_)
7073 #elif defined(_TARGET_ARM_)
7084 #elif defined(_TARGET_ARM64_)
7088 #error Unsupported or unset target architecture
7092 regNumber GetReg() const
7097 _regMask_enum GetRegMask() const
7104 _regMask_enum regMask;
7107 VirtualStubParamInfo* virtualStubParamInfo;
7109 bool IsTargetAbi(CORINFO_RUNTIME_ABI abi)
7111 return eeGetEEInfo()->targetAbi == abi;
7114 bool generateCFIUnwindCodes()
7116 #if defined(_TARGET_UNIX_)
7117 return IsTargetAbi(CORINFO_CORERT_ABI);
7123 // Debugging support - Line number info
7125 void eeGetStmtOffsets();
7127 unsigned eeBoundariesCount;
7129 struct boundariesDsc
7131 UNATIVE_OFFSET nativeIP;
7133 unsigned sourceReason;
7134 } * eeBoundaries; // Boundaries to report to EE
7135 void eeSetLIcount(unsigned count);
7136 void eeSetLIinfo(unsigned which, UNATIVE_OFFSET offs, unsigned srcIP, bool stkEmpty, bool callInstruction);
7140 static void eeDispILOffs(IL_OFFSET offs);
7141 static void eeDispLineInfo(const boundariesDsc* line);
7142 void eeDispLineInfos();
7145 // Debugging support - Local var info
7149 unsigned eeVarsCount;
7151 struct VarResultInfo
7153 UNATIVE_OFFSET startOffset;
7154 UNATIVE_OFFSET endOffset;
7156 CodeGenInterface::siVarLoc loc;
7158 void eeSetLVcount(unsigned count);
7159 void eeSetLVinfo(unsigned which,
7160 UNATIVE_OFFSET startOffs,
7161 UNATIVE_OFFSET length,
7163 const CodeGenInterface::siVarLoc& loc);
7167 void eeDispVar(ICorDebugInfo::NativeVarInfo* var);
7168 void eeDispVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars);
7171 // ICorJitInfo wrappers
7173 void eeReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize);
7175 void eeAllocUnwindInfo(BYTE* pHotCode,
7181 CorJitFuncKind funcKind);
7183 void eeSetEHcount(unsigned cEH);
7185 void eeSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause);
7187 WORD eeGetRelocTypeHint(void* target);
7189 // ICorStaticInfo wrapper functions
7191 bool eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken);
7193 #if defined(UNIX_AMD64_ABI)
7195 static void dumpSystemVClassificationType(SystemVClassificationType ct);
7198 void eeGetSystemVAmd64PassStructInRegisterDescriptor(
7199 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
7200 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr);
7201 #endif // UNIX_AMD64_ABI
7203 template <typename ParamType>
7204 bool eeRunWithErrorTrap(void (*function)(ParamType*), ParamType* param)
7206 return eeRunWithErrorTrapImp(reinterpret_cast<void (*)(void*)>(function), reinterpret_cast<void*>(param));
7209 bool eeRunWithErrorTrapImp(void (*function)(void*), void* param);
7211 // Utility functions
7213 const char* eeGetFieldName(CORINFO_FIELD_HANDLE fieldHnd, const char** classNamePtr = nullptr);
7216 const wchar_t* eeGetCPString(size_t stringHandle);
7219 const char* eeGetClassName(CORINFO_CLASS_HANDLE clsHnd);
7221 static CORINFO_METHOD_HANDLE eeFindHelper(unsigned helper);
7222 static CorInfoHelpFunc eeGetHelperNum(CORINFO_METHOD_HANDLE method);
7224 static fgWalkPreFn CountSharedStaticHelper;
7225 static bool IsSharedStaticHelper(GenTree* tree);
7226 static bool IsTreeAlwaysHoistable(GenTree* tree);
7227 static bool IsGcSafePoint(GenTree* tree);
7229 static CORINFO_FIELD_HANDLE eeFindJitDataOffs(unsigned jitDataOffs);
7230 // returns true/false if 'field' is a Jit Data offset
7231 static bool eeIsJitDataOffs(CORINFO_FIELD_HANDLE field);
7232 // returns a number < 0 if 'field' is not a Jit Data offset, otherwise the data offset (limited to 2GB)
7233 static int eeGetJitDataOffs(CORINFO_FIELD_HANDLE field);
7235 /*****************************************************************************/
7238 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7239 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7243 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7244 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7248 CodeGenInterface* codeGen;
7250 // The following holds information about instr offsets in terms of generated code.
7254 IPmappingDsc* ipmdNext; // next line# record
7255 IL_OFFSETX ipmdILoffsx; // the instr offset
7256 emitLocation ipmdNativeLoc; // the emitter location of the native code corresponding to the IL offset
7257 bool ipmdIsLabel; // Can this code be a branch label?
7260 // Record the instr offset mapping to the generated code
7262 IPmappingDsc* genIPmappingList;
7263 IPmappingDsc* genIPmappingLast;
7265 // Managed RetVal - A side hash table meant to record the mapping from a
7266 // GT_CALL node to its IL offset. This info is used to emit sequence points
7267 // that can be used by debugger to determine the native offset at which the
7268 // managed RetVal will be available.
7270 // In fact we can store IL offset in a GT_CALL node. This was ruled out in
7271 // favor of a side table for two reasons: 1) We need IL offset for only those
7272 // GT_CALL nodes (created during importation) that correspond to an IL call and
7273 // whose return type is other than TYP_VOID. 2) GT_CALL node is a frequently used
7274 // structure and IL offset is needed only when generating debuggable code. Therefore
7275 // it is desirable to avoid memory size penalty in retail scenarios.
7276 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, IL_OFFSETX> CallSiteILOffsetTable;
7277 CallSiteILOffsetTable* genCallSite2ILOffsetMap;
7279 unsigned genReturnLocal; // Local number for the return value when applicable.
7280 BasicBlock* genReturnBB; // jumped to when not optimizing for speed.
7282 // The following properties are part of CodeGenContext. Getters are provided here for
7283 // convenience and backward compatibility, but the properties can only be set by invoking
7284 // the setter on CodeGenContext directly.
7286 __declspec(property(get = getEmitter)) emitter* genEmitter;
7287 emitter* getEmitter() const
7289 return codeGen->getEmitter();
7292 bool isFramePointerUsed() const
7294 return codeGen->isFramePointerUsed();
7297 __declspec(property(get = getInterruptible, put = setInterruptible)) bool genInterruptible;
7298 bool getInterruptible()
7300 return codeGen->genInterruptible;
7302 void setInterruptible(bool value)
7304 codeGen->setInterruptible(value);
7307 #ifdef _TARGET_ARMARCH_
7308 __declspec(property(get = getHasTailCalls, put = setHasTailCalls)) bool hasTailCalls;
7309 bool getHasTailCalls()
7311 return codeGen->hasTailCalls;
7313 void setHasTailCalls(bool value)
7315 codeGen->setHasTailCalls(value);
7317 #endif // _TARGET_ARMARCH_
7320 const bool genDoubleAlign()
7322 return codeGen->doDoubleAlign();
7324 DWORD getCanDoubleAlign();
7325 bool shouldDoubleAlign(unsigned refCntStk,
7327 unsigned refCntWtdReg,
7328 unsigned refCntStkParam,
7329 unsigned refCntWtdStkDbl);
7330 #endif // DOUBLE_ALIGN
7332 __declspec(property(get = getFullPtrRegMap, put = setFullPtrRegMap)) bool genFullPtrRegMap;
7333 bool getFullPtrRegMap()
7335 return codeGen->genFullPtrRegMap;
7337 void setFullPtrRegMap(bool value)
7339 codeGen->setFullPtrRegMap(value);
7342 // Things that MAY belong either in CodeGen or CodeGenContext
7344 #if FEATURE_EH_FUNCLETS
7345 FuncInfoDsc* compFuncInfos;
7346 unsigned short compCurrFuncIdx;
7347 unsigned short compFuncInfoCount;
7349 unsigned short compFuncCount()
7351 assert(fgFuncletsCreated);
7352 return compFuncInfoCount;
7355 #else // !FEATURE_EH_FUNCLETS
7357 // This is a no-op when there are no funclets!
7358 void genUpdateCurrentFunclet(BasicBlock* block)
7363 FuncInfoDsc compFuncInfoRoot;
7365 static const unsigned compCurrFuncIdx = 0;
7367 unsigned short compFuncCount()
7372 #endif // !FEATURE_EH_FUNCLETS
7374 FuncInfoDsc* funCurrentFunc();
7375 void funSetCurrentFunc(unsigned funcIdx);
7376 FuncInfoDsc* funGetFunc(unsigned funcIdx);
7377 unsigned int funGetFuncIdx(BasicBlock* block);
7381 VARSET_TP compCurLife; // current live variables
7382 GenTree* compCurLifeTree; // node after which compCurLife has been computed
7384 template <bool ForCodeGen>
7385 void compChangeLife(VARSET_VALARG_TP newLife);
7387 template <bool ForCodeGen>
7388 inline void compUpdateLife(VARSET_VALARG_TP newLife);
7390 // Gets a register mask that represent the kill set for a helper call since
7391 // not all JIT Helper calls follow the standard ABI on the target architecture.
7392 regMaskTP compHelperCallKillSet(CorInfoHelpFunc helper);
7395 // Requires that "varDsc" be a promoted struct local variable being passed as an argument, beginning at
7396 // "firstArgRegNum", which is assumed to have already been aligned to the register alignment restriction of the
7397 // struct type. Adds bits to "*pArgSkippedRegMask" for any argument registers *not* used in passing "varDsc" --
7398 // i.e., internal "holes" caused by internal alignment constraints. For example, if the struct contained an int and
7399 // a double, and we at R0 (on ARM), then R1 would be skipped, and the bit for R1 would be added to the mask.
7400 void fgAddSkippedRegsInPromotedStructArg(LclVarDsc* varDsc, unsigned firstArgRegNum, regMaskTP* pArgSkippedRegMask);
7401 #endif // _TARGET_ARM_
7403 // 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
7405 static GenTree* fgIsIndirOfAddrOfLocal(GenTree* tree);
7407 // This map is indexed by GT_OBJ nodes that are address of promoted struct variables, which
7408 // have been annotated with the GTF_VAR_DEATH flag. If such a node is *not* mapped in this
7409 // table, one may assume that all the (tracked) field vars die at this GT_OBJ. Otherwise,
7410 // the node maps to a pointer to a VARSET_TP, containing set bits for each of the tracked field
7411 // vars of the promoted struct local that go dead at the given node (the set bits are the bits
7412 // for the tracked var indices of the field vars, as in a live var set).
7414 // The map is allocated on demand so all map operations should use one of the following three
7417 NodeToVarsetPtrMap* m_promotedStructDeathVars;
7419 NodeToVarsetPtrMap* GetPromotedStructDeathVars()
7421 if (m_promotedStructDeathVars == nullptr)
7423 m_promotedStructDeathVars = new (getAllocator()) NodeToVarsetPtrMap(getAllocator());
7425 return m_promotedStructDeathVars;
7428 void ClearPromotedStructDeathVars()
7430 if (m_promotedStructDeathVars != nullptr)
7432 m_promotedStructDeathVars->RemoveAll();
7436 bool LookupPromotedStructDeathVars(GenTree* tree, VARSET_TP** bits)
7439 bool result = false;
7441 if (m_promotedStructDeathVars != nullptr)
7443 result = m_promotedStructDeathVars->Lookup(tree, bits);
7450 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7451 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7455 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7456 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7459 #if !defined(__GNUC__)
7460 #pragma region Unwind information
7465 // Infrastructure functions: start/stop/reserve/emit.
7468 void unwindBegProlog();
7469 void unwindEndProlog();
7470 void unwindBegEpilog();
7471 void unwindEndEpilog();
7472 void unwindReserve();
7473 void unwindEmit(void* pHotCode, void* pColdCode);
7476 // Specific unwind information functions: called by code generation to indicate a particular
7477 // prolog or epilog unwindable instruction has been generated.
7480 void unwindPush(regNumber reg);
7481 void unwindAllocStack(unsigned size);
7482 void unwindSetFrameReg(regNumber reg, unsigned offset);
7483 void unwindSaveReg(regNumber reg, unsigned offset);
7485 #if defined(_TARGET_ARM_)
7486 void unwindPushMaskInt(regMaskTP mask);
7487 void unwindPushMaskFloat(regMaskTP mask);
7488 void unwindPopMaskInt(regMaskTP mask);
7489 void unwindPopMaskFloat(regMaskTP mask);
7490 void unwindBranch16(); // The epilog terminates with a 16-bit branch (e.g., "bx lr")
7491 void unwindNop(unsigned codeSizeInBytes); // Generate unwind NOP code. 'codeSizeInBytes' is 2 or 4 bytes. Only
7492 // called via unwindPadding().
7493 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7494 // instruction and the current location.
7495 #endif // _TARGET_ARM_
7497 #if defined(_TARGET_ARM64_)
7499 void unwindPadding(); // Generate a sequence of unwind NOP codes representing instructions between the last
7500 // instruction and the current location.
7501 void unwindSaveReg(regNumber reg, int offset); // str reg, [sp, #offset]
7502 void unwindSaveRegPreindexed(regNumber reg, int offset); // str reg, [sp, #offset]!
7503 void unwindSaveRegPair(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]
7504 void unwindSaveRegPairPreindexed(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]!
7505 void unwindSaveNext(); // unwind code: save_next
7506 void unwindReturn(regNumber reg); // ret lr
7507 #endif // defined(_TARGET_ARM64_)
7510 // Private "helper" functions for the unwind implementation.
7514 #if FEATURE_EH_FUNCLETS
7515 void unwindGetFuncLocations(FuncInfoDsc* func,
7516 bool getHotSectionData,
7517 /* OUT */ emitLocation** ppStartLoc,
7518 /* OUT */ emitLocation** ppEndLoc);
7519 #endif // FEATURE_EH_FUNCLETS
7521 void unwindReserveFunc(FuncInfoDsc* func);
7522 void unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
7524 #if defined(_TARGET_AMD64_) || (defined(_TARGET_X86_) && FEATURE_EH_FUNCLETS)
7526 void unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode);
7527 void unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode);
7529 #endif // _TARGET_AMD64_ || (_TARGET_X86_ && FEATURE_EH_FUNCLETS)
7531 UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func);
7533 #if defined(_TARGET_AMD64_)
7535 void unwindBegPrologWindows();
7536 void unwindPushWindows(regNumber reg);
7537 void unwindAllocStackWindows(unsigned size);
7538 void unwindSetFrameRegWindows(regNumber reg, unsigned offset);
7539 void unwindSaveRegWindows(regNumber reg, unsigned offset);
7541 #ifdef UNIX_AMD64_ABI
7542 void unwindSaveRegCFI(regNumber reg, unsigned offset);
7543 #endif // UNIX_AMD64_ABI
7544 #elif defined(_TARGET_ARM_)
7546 void unwindPushPopMaskInt(regMaskTP mask, bool useOpsize16);
7547 void unwindPushPopMaskFloat(regMaskTP mask);
7549 #endif // _TARGET_ARM_
7551 #if defined(_TARGET_UNIX_)
7552 int mapRegNumToDwarfReg(regNumber reg);
7553 void createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR opcode, USHORT dwarfReg, INT offset = 0);
7554 void unwindPushPopCFI(regNumber reg);
7555 void unwindBegPrologCFI();
7556 void unwindPushPopMaskCFI(regMaskTP regMask, bool isFloat);
7557 void unwindAllocStackCFI(unsigned size);
7558 void unwindSetFrameRegCFI(regNumber reg, unsigned offset);
7559 void unwindEmitFuncCFI(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
7561 void DumpCfiInfo(bool isHotCode,
7562 UNATIVE_OFFSET startOffset,
7563 UNATIVE_OFFSET endOffset,
7565 const CFI_CODE* const pCfiCode);
7568 #endif // _TARGET_UNIX_
7570 #if !defined(__GNUC__)
7571 #pragma endregion // Note: region is NOT under !defined(__GNUC__)
7575 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7576 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7580 XX Info about SIMD types, methods and the SIMD assembly (i.e. the assembly XX
7581 XX that contains the distinguished, well-known SIMD type definitions). XX
7583 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7584 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7587 // Get highest available level for SIMD codegen
7588 SIMDLevel getSIMDSupportLevel()
7590 #if defined(_TARGET_XARCH_)
7591 if (compSupports(InstructionSet_AVX2))
7593 return SIMD_AVX2_Supported;
7596 if (compSupports(InstructionSet_SSE42))
7598 return SIMD_SSE4_Supported;
7602 return SIMD_SSE2_Supported;
7604 assert(!"Available instruction set(s) for SIMD codegen is not defined for target arch");
7606 return SIMD_Not_Supported;
7612 // Should we support SIMD intrinsics?
7615 // Have we identified any SIMD types?
7616 // This is currently used by struct promotion to avoid getting type information for a struct
7617 // field to see if it is a SIMD type, if we haven't seen any SIMD types or operations in
7619 bool _usesSIMDTypes;
7620 bool usesSIMDTypes()
7622 return _usesSIMDTypes;
7624 void setUsesSIMDTypes(bool value)
7626 _usesSIMDTypes = value;
7629 // This is a temp lclVar allocated on the stack as TYP_SIMD. It is used to implement intrinsics
7630 // that require indexed access to the individual fields of the vector, which is not well supported
7631 // by the hardware. It is allocated when/if such situations are encountered during Lowering.
7632 unsigned lvaSIMDInitTempVarNum;
7634 struct SIMDHandlesCache
7637 CORINFO_CLASS_HANDLE SIMDFloatHandle;
7638 CORINFO_CLASS_HANDLE SIMDDoubleHandle;
7639 CORINFO_CLASS_HANDLE SIMDIntHandle;
7640 CORINFO_CLASS_HANDLE SIMDUShortHandle;
7641 CORINFO_CLASS_HANDLE SIMDUByteHandle;
7642 CORINFO_CLASS_HANDLE SIMDShortHandle;
7643 CORINFO_CLASS_HANDLE SIMDByteHandle;
7644 CORINFO_CLASS_HANDLE SIMDLongHandle;
7645 CORINFO_CLASS_HANDLE SIMDUIntHandle;
7646 CORINFO_CLASS_HANDLE SIMDULongHandle;
7647 CORINFO_CLASS_HANDLE SIMDVector2Handle;
7648 CORINFO_CLASS_HANDLE SIMDVector3Handle;
7649 CORINFO_CLASS_HANDLE SIMDVector4Handle;
7650 CORINFO_CLASS_HANDLE SIMDVectorHandle;
7652 #ifdef FEATURE_HW_INTRINSICS
7653 #if defined(_TARGET_ARM64_)
7654 CORINFO_CLASS_HANDLE Vector64FloatHandle;
7655 CORINFO_CLASS_HANDLE Vector64IntHandle;
7656 CORINFO_CLASS_HANDLE Vector64UShortHandle;
7657 CORINFO_CLASS_HANDLE Vector64UByteHandle;
7658 CORINFO_CLASS_HANDLE Vector64ShortHandle;
7659 CORINFO_CLASS_HANDLE Vector64ByteHandle;
7660 CORINFO_CLASS_HANDLE Vector64UIntHandle;
7661 #endif // defined(_TARGET_ARM64_)
7662 CORINFO_CLASS_HANDLE Vector128FloatHandle;
7663 CORINFO_CLASS_HANDLE Vector128DoubleHandle;
7664 CORINFO_CLASS_HANDLE Vector128IntHandle;
7665 CORINFO_CLASS_HANDLE Vector128UShortHandle;
7666 CORINFO_CLASS_HANDLE Vector128UByteHandle;
7667 CORINFO_CLASS_HANDLE Vector128ShortHandle;
7668 CORINFO_CLASS_HANDLE Vector128ByteHandle;
7669 CORINFO_CLASS_HANDLE Vector128LongHandle;
7670 CORINFO_CLASS_HANDLE Vector128UIntHandle;
7671 CORINFO_CLASS_HANDLE Vector128ULongHandle;
7672 #if defined(_TARGET_XARCH_)
7673 CORINFO_CLASS_HANDLE Vector256FloatHandle;
7674 CORINFO_CLASS_HANDLE Vector256DoubleHandle;
7675 CORINFO_CLASS_HANDLE Vector256IntHandle;
7676 CORINFO_CLASS_HANDLE Vector256UShortHandle;
7677 CORINFO_CLASS_HANDLE Vector256UByteHandle;
7678 CORINFO_CLASS_HANDLE Vector256ShortHandle;
7679 CORINFO_CLASS_HANDLE Vector256ByteHandle;
7680 CORINFO_CLASS_HANDLE Vector256LongHandle;
7681 CORINFO_CLASS_HANDLE Vector256UIntHandle;
7682 CORINFO_CLASS_HANDLE Vector256ULongHandle;
7683 #endif // defined(_TARGET_XARCH_)
7684 #endif // FEATURE_HW_INTRINSICS
7688 memset(this, 0, sizeof(*this));
7692 SIMDHandlesCache* m_simdHandleCache;
7694 // Get an appropriate "zero" for the given type and class handle.
7695 GenTree* gtGetSIMDZero(var_types simdType, var_types baseType, CORINFO_CLASS_HANDLE simdHandle);
7697 // Get the handle for a SIMD type.
7698 CORINFO_CLASS_HANDLE gtGetStructHandleForSIMD(var_types simdType, var_types simdBaseType)
7700 if (m_simdHandleCache == nullptr)
7702 // This may happen if the JIT generates SIMD node on its own, without importing them.
7703 // Otherwise getBaseTypeAndSizeOfSIMDType should have created the cache.
7704 return NO_CLASS_HANDLE;
7707 if (simdBaseType == TYP_FLOAT)
7712 return m_simdHandleCache->SIMDVector2Handle;
7714 return m_simdHandleCache->SIMDVector3Handle;
7716 if ((getSIMDVectorType() == TYP_SIMD32) ||
7717 (m_simdHandleCache->SIMDVector4Handle != NO_CLASS_HANDLE))
7719 return m_simdHandleCache->SIMDVector4Handle;
7728 assert(emitTypeSize(simdType) <= maxSIMDStructBytes());
7729 switch (simdBaseType)
7732 return m_simdHandleCache->SIMDFloatHandle;
7734 return m_simdHandleCache->SIMDDoubleHandle;
7736 return m_simdHandleCache->SIMDIntHandle;
7738 return m_simdHandleCache->SIMDUShortHandle;
7740 return m_simdHandleCache->SIMDUByteHandle;
7742 return m_simdHandleCache->SIMDShortHandle;
7744 return m_simdHandleCache->SIMDByteHandle;
7746 return m_simdHandleCache->SIMDLongHandle;
7748 return m_simdHandleCache->SIMDUIntHandle;
7750 return m_simdHandleCache->SIMDULongHandle;
7752 assert(!"Didn't find a class handle for simdType");
7754 return NO_CLASS_HANDLE;
7757 // Returns true if this is a SIMD type that should be considered an opaque
7758 // vector type (i.e. do not analyze or promote its fields).
7759 // Note that all but the fixed vector types are opaque, even though they may
7760 // actually be declared as having fields.
7761 bool isOpaqueSIMDType(CORINFO_CLASS_HANDLE structHandle)
7763 return ((m_simdHandleCache != nullptr) && (structHandle != m_simdHandleCache->SIMDVector2Handle) &&
7764 (structHandle != m_simdHandleCache->SIMDVector3Handle) &&
7765 (structHandle != m_simdHandleCache->SIMDVector4Handle));
7768 // Returns true if the tree corresponds to a TYP_SIMD lcl var.
7769 // Note that both SIMD vector args and locals are mared as lvSIMDType = true, but
7770 // type of an arg node is TYP_BYREF and a local node is TYP_SIMD or TYP_STRUCT.
7771 bool isSIMDTypeLocal(GenTree* tree)
7773 return tree->OperIsLocal() && lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7776 // Returns true if the lclVar is an opaque SIMD type.
7777 bool isOpaqueSIMDLclVar(LclVarDsc* varDsc)
7779 if (!varDsc->lvSIMDType)
7783 return isOpaqueSIMDType(varDsc->lvVerTypeInfo.GetClassHandle());
7786 // Returns true if the type of the tree is a byref of TYP_SIMD
7787 bool isAddrOfSIMDType(GenTree* tree)
7789 if (tree->TypeGet() == TYP_BYREF || tree->TypeGet() == TYP_I_IMPL)
7791 switch (tree->OperGet())
7794 return varTypeIsSIMD(tree->gtGetOp1());
7796 case GT_LCL_VAR_ADDR:
7797 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvSIMDType;
7800 return isSIMDTypeLocal(tree);
7807 static bool isRelOpSIMDIntrinsic(SIMDIntrinsicID intrinsicId)
7809 return (intrinsicId == SIMDIntrinsicEqual || intrinsicId == SIMDIntrinsicLessThan ||
7810 intrinsicId == SIMDIntrinsicLessThanOrEqual || intrinsicId == SIMDIntrinsicGreaterThan ||
7811 intrinsicId == SIMDIntrinsicGreaterThanOrEqual);
7814 // Returns base type of a TYP_SIMD local.
7815 // Returns TYP_UNKNOWN if the local is not TYP_SIMD.
7816 var_types getBaseTypeOfSIMDLocal(GenTree* tree)
7818 if (isSIMDTypeLocal(tree))
7820 return lvaTable[tree->AsLclVarCommon()->gtLclNum].lvBaseType;
7826 bool isSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7828 return info.compCompHnd->isInSIMDModule(clsHnd);
7831 bool isIntrinsicType(CORINFO_CLASS_HANDLE clsHnd)
7833 return (info.compCompHnd->getClassAttribs(clsHnd) & CORINFO_FLG_INTRINSIC_TYPE) != 0;
7836 const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName)
7838 return info.compCompHnd->getClassNameFromMetadata(cls, namespaceName);
7841 CORINFO_CLASS_HANDLE getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index)
7843 return info.compCompHnd->getTypeInstantiationArgument(cls, index);
7846 bool isSIMDClass(typeInfo* pTypeInfo)
7848 return pTypeInfo->IsStruct() && isSIMDClass(pTypeInfo->GetClassHandleForValueClass());
7851 bool isHWSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7853 #ifdef FEATURE_HW_INTRINSICS
7854 if (isIntrinsicType(clsHnd))
7856 const char* namespaceName = nullptr;
7857 (void)getClassNameFromMetadata(clsHnd, &namespaceName);
7858 return strcmp(namespaceName, "System.Runtime.Intrinsics") == 0;
7860 #endif // FEATURE_HW_INTRINSICS
7864 bool isHWSIMDClass(typeInfo* pTypeInfo)
7866 #ifdef FEATURE_HW_INTRINSICS
7867 return pTypeInfo->IsStruct() && isHWSIMDClass(pTypeInfo->GetClassHandleForValueClass());
7873 bool isSIMDorHWSIMDClass(CORINFO_CLASS_HANDLE clsHnd)
7875 return isSIMDClass(clsHnd) || isHWSIMDClass(clsHnd);
7878 bool isSIMDorHWSIMDClass(typeInfo* pTypeInfo)
7880 return isSIMDClass(pTypeInfo) || isHWSIMDClass(pTypeInfo);
7883 // Get the base (element) type and size in bytes for a SIMD type. Returns TYP_UNKNOWN
7884 // if it is not a SIMD type or is an unsupported base type.
7885 var_types getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, unsigned* sizeBytes = nullptr);
7887 var_types getBaseTypeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7889 return getBaseTypeAndSizeOfSIMDType(typeHnd, nullptr);
7892 // Get SIMD Intrinsic info given the method handle.
7893 // Also sets typeHnd, argCount, baseType and sizeBytes out params.
7894 const SIMDIntrinsicInfo* getSIMDIntrinsicInfo(CORINFO_CLASS_HANDLE* typeHnd,
7895 CORINFO_METHOD_HANDLE methodHnd,
7896 CORINFO_SIG_INFO* sig,
7899 var_types* baseType,
7900 unsigned* sizeBytes);
7902 // Pops and returns GenTree node from importers type stack.
7903 // Normalizes TYP_STRUCT value in case of GT_CALL, GT_RET_EXPR and arg nodes.
7904 GenTree* impSIMDPopStack(var_types type, bool expectAddr = false, CORINFO_CLASS_HANDLE structType = nullptr);
7906 // Create a GT_SIMD tree for a Get property of SIMD vector with a fixed index.
7907 GenTreeSIMD* impSIMDGetFixed(var_types simdType, var_types baseType, unsigned simdSize, int index);
7909 // Creates a GT_SIMD tree for Select operation
7910 GenTree* impSIMDSelect(CORINFO_CLASS_HANDLE typeHnd,
7912 unsigned simdVectorSize,
7917 // Creates a GT_SIMD tree for Min/Max operation
7918 GenTree* impSIMDMinMax(SIMDIntrinsicID intrinsicId,
7919 CORINFO_CLASS_HANDLE typeHnd,
7921 unsigned simdVectorSize,
7925 // Transforms operands and returns the SIMD intrinsic to be applied on
7926 // transformed operands to obtain given relop result.
7927 SIMDIntrinsicID impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId,
7928 CORINFO_CLASS_HANDLE typeHnd,
7929 unsigned simdVectorSize,
7930 var_types* baseType,
7934 // Creates a GT_SIMD tree for Abs intrinsic.
7935 GenTree* impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType, unsigned simdVectorSize, GenTree* op1);
7937 #if defined(_TARGET_XARCH_)
7939 // Transforms operands and returns the SIMD intrinsic to be applied on
7940 // transformed operands to obtain == comparison result.
7941 SIMDIntrinsicID impSIMDLongRelOpEqual(CORINFO_CLASS_HANDLE typeHnd,
7942 unsigned simdVectorSize,
7946 // Transforms operands and returns the SIMD intrinsic to be applied on
7947 // transformed operands to obtain > comparison result.
7948 SIMDIntrinsicID impSIMDLongRelOpGreaterThan(CORINFO_CLASS_HANDLE typeHnd,
7949 unsigned simdVectorSize,
7953 // Transforms operands and returns the SIMD intrinsic to be applied on
7954 // transformed operands to obtain >= comparison result.
7955 SIMDIntrinsicID impSIMDLongRelOpGreaterThanOrEqual(CORINFO_CLASS_HANDLE typeHnd,
7956 unsigned simdVectorSize,
7960 // Transforms operands and returns the SIMD intrinsic to be applied on
7961 // transformed operands to obtain >= comparison result in case of int32
7962 // and small int base type vectors.
7963 SIMDIntrinsicID impSIMDIntegralRelOpGreaterThanOrEqual(
7964 CORINFO_CLASS_HANDLE typeHnd, unsigned simdVectorSize, var_types baseType, GenTree** op1, GenTree** op2);
7966 #endif // defined(_TARGET_XARCH_)
7968 void setLclRelatedToSIMDIntrinsic(GenTree* tree);
7969 bool areFieldsContiguous(GenTree* op1, GenTree* op2);
7970 bool areArrayElementsContiguous(GenTree* op1, GenTree* op2);
7971 bool areArgumentsContiguous(GenTree* op1, GenTree* op2);
7972 GenTree* createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize);
7974 // check methodHnd to see if it is a SIMD method that is expanded as an intrinsic in the JIT.
7975 GenTree* impSIMDIntrinsic(OPCODE opcode,
7976 GenTree* newobjThis,
7977 CORINFO_CLASS_HANDLE clsHnd,
7978 CORINFO_METHOD_HANDLE method,
7979 CORINFO_SIG_INFO* sig,
7980 unsigned methodFlags,
7983 GenTree* getOp1ForConstructor(OPCODE opcode, GenTree* newobjThis, CORINFO_CLASS_HANDLE clsHnd);
7985 // Whether SIMD vector occupies part of SIMD register.
7986 // SSE2: vector2f/3f are considered sub register SIMD types.
7987 // AVX: vector2f, 3f and 4f are all considered sub register SIMD types.
7988 bool isSubRegisterSIMDType(CORINFO_CLASS_HANDLE typeHnd)
7990 unsigned sizeBytes = 0;
7991 var_types baseType = getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
7992 return (baseType == TYP_FLOAT) && (sizeBytes < getSIMDVectorRegisterByteLength());
7995 bool isSubRegisterSIMDType(GenTreeSIMD* simdNode)
7997 return (simdNode->gtSIMDSize < getSIMDVectorRegisterByteLength());
8000 // Get the type for the hardware SIMD vector.
8001 // This is the maximum SIMD type supported for this target.
8002 var_types getSIMDVectorType()
8004 #if defined(_TARGET_XARCH_)
8005 if (getSIMDSupportLevel() == SIMD_AVX2_Supported)
8011 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
8014 #elif defined(_TARGET_ARM64_)
8017 assert(!"getSIMDVectorType() unimplemented on target arch");
8022 // Get the size of the SIMD type in bytes
8023 int getSIMDTypeSizeInBytes(CORINFO_CLASS_HANDLE typeHnd)
8025 unsigned sizeBytes = 0;
8026 (void)getBaseTypeAndSizeOfSIMDType(typeHnd, &sizeBytes);
8030 // Get the the number of elements of basetype of SIMD vector given by its size and baseType
8031 static int getSIMDVectorLength(unsigned simdSize, var_types baseType);
8033 // Get the the number of elements of basetype of SIMD vector given by its type handle
8034 int getSIMDVectorLength(CORINFO_CLASS_HANDLE typeHnd);
8036 // Get preferred alignment of SIMD type.
8037 int getSIMDTypeAlignment(var_types simdType);
8039 // Get the number of bytes in a System.Numeric.Vector<T> for the current compilation.
8040 // Note - cannot be used for System.Runtime.Intrinsic
8041 unsigned getSIMDVectorRegisterByteLength()
8043 #if defined(_TARGET_XARCH_)
8044 if (getSIMDSupportLevel() == SIMD_AVX2_Supported)
8046 return YMM_REGSIZE_BYTES;
8050 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
8051 return XMM_REGSIZE_BYTES;
8053 #elif defined(_TARGET_ARM64_)
8054 return FP_REGSIZE_BYTES;
8056 assert(!"getSIMDVectorRegisterByteLength() unimplemented on target arch");
8061 // The minimum and maximum possible number of bytes in a SIMD vector.
8063 // maxSIMDStructBytes
8064 // The minimum SIMD size supported by System.Numeric.Vectors or System.Runtime.Intrinsic
8065 // SSE: 16-byte Vector<T> and Vector128<T>
8066 // AVX: 32-byte Vector256<T> (Vector<T> is 16-byte)
8067 // AVX2: 32-byte Vector<T> and Vector256<T>
8068 unsigned int maxSIMDStructBytes()
8070 #if defined(FEATURE_HW_INTRINSICS) && defined(_TARGET_XARCH_)
8071 if (compSupports(InstructionSet_AVX))
8073 return YMM_REGSIZE_BYTES;
8077 assert(getSIMDSupportLevel() >= SIMD_SSE2_Supported);
8078 return XMM_REGSIZE_BYTES;
8081 return getSIMDVectorRegisterByteLength();
8084 unsigned int minSIMDStructBytes()
8086 return emitTypeSize(TYP_SIMD8);
8089 // Returns the codegen type for a given SIMD size.
8090 var_types getSIMDTypeForSize(unsigned size)
8092 var_types simdType = TYP_UNDEF;
8095 simdType = TYP_SIMD8;
8097 else if (size == 12)
8099 simdType = TYP_SIMD12;
8101 else if (size == 16)
8103 simdType = TYP_SIMD16;
8105 else if (size == 32)
8107 simdType = TYP_SIMD32;
8111 noway_assert(!"Unexpected size for SIMD type");
8116 unsigned getSIMDInitTempVarNum()
8118 if (lvaSIMDInitTempVarNum == BAD_VAR_NUM)
8120 lvaSIMDInitTempVarNum = lvaGrabTempWithImplicitUse(false DEBUGARG("SIMDInitTempVar"));
8121 lvaTable[lvaSIMDInitTempVarNum].lvType = getSIMDVectorType();
8123 return lvaSIMDInitTempVarNum;
8126 #else // !FEATURE_SIMD
8127 bool isOpaqueSIMDLclVar(LclVarDsc* varDsc)
8131 #endif // FEATURE_SIMD
8134 //------------------------------------------------------------------------
8135 // largestEnregisterableStruct: The size in bytes of the largest struct that can be enregistered.
8137 // Notes: It is not guaranteed that the struct of this size or smaller WILL be a
8138 // candidate for enregistration.
8140 unsigned largestEnregisterableStructSize()
8143 unsigned vectorRegSize = getSIMDVectorRegisterByteLength();
8144 if (vectorRegSize > TARGET_POINTER_SIZE)
8146 return vectorRegSize;
8149 #endif // FEATURE_SIMD
8151 return TARGET_POINTER_SIZE;
8156 // These routines need not be enclosed under FEATURE_SIMD since lvIsSIMDType()
8157 // is defined for both FEATURE_SIMD and !FEATURE_SIMD apropriately. The use
8158 // of this routines also avoids the need of #ifdef FEATURE_SIMD specific code.
8160 // Is this var is of type simd struct?
8161 bool lclVarIsSIMDType(unsigned varNum)
8163 LclVarDsc* varDsc = lvaTable + varNum;
8164 return varDsc->lvIsSIMDType();
8167 // Is this Local node a SIMD local?
8168 bool lclVarIsSIMDType(GenTreeLclVarCommon* lclVarTree)
8170 return lclVarIsSIMDType(lclVarTree->gtLclNum);
8173 // Returns true if the TYP_SIMD locals on stack are aligned at their
8174 // preferred byte boundary specified by getSIMDTypeAlignment().
8176 // As per the Intel manual, the preferred alignment for AVX vectors is 32-bytes. On Amd64,
8177 // RSP/EBP is aligned at 16-bytes, therefore to align SIMD types at 32-bytes we need even
8178 // RSP/EBP to be 32-byte aligned. It is not clear whether additional stack space used in
8179 // aligning stack is worth the benefit and for now will use 16-byte alignment for AVX
8180 // 256-bit vectors with unaligned load/stores to/from memory. On x86, the stack frame
8181 // is aligned to 4 bytes. We need to extend existing support for double (8-byte) alignment
8182 // to 16 or 32 byte alignment for frames with local SIMD vars, if that is determined to be
8185 bool isSIMDTypeLocalAligned(unsigned varNum)
8187 #if defined(FEATURE_SIMD) && ALIGN_SIMD_TYPES
8188 if (lclVarIsSIMDType(varNum) && lvaTable[varNum].lvType != TYP_BYREF)
8191 int off = lvaFrameAddress(varNum, &ebpBased);
8192 // TODO-Cleanup: Can't this use the lvExactSize on the varDsc?
8193 int alignment = getSIMDTypeAlignment(lvaTable[varNum].lvType);
8194 bool isAligned = (alignment <= STACK_ALIGN) && ((off % alignment) == 0);
8197 #endif // FEATURE_SIMD
8202 bool compSupports(InstructionSet isa) const
8204 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
8205 return (opts.compSupportsISA & (1ULL << isa)) != 0;
8211 bool canUseVexEncoding() const
8213 #ifdef _TARGET_XARCH_
8214 return compSupports(InstructionSet_AVX);
8221 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8222 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8226 XX Generic info about the compilation and the method being compiled. XX
8227 XX It is responsible for driving the other phases. XX
8228 XX It is also responsible for all the memory management. XX
8230 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8231 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8235 Compiler* InlineeCompiler; // The Compiler instance for the inlinee
8237 InlineResult* compInlineResult; // The result of importing the inlinee method.
8239 bool compDoAggressiveInlining; // If true, mark every method as CORINFO_FLG_FORCEINLINE
8240 bool compJmpOpUsed; // Does the method do a JMP
8241 bool compLongUsed; // Does the method use TYP_LONG
8242 bool compFloatingPointUsed; // Does the method use TYP_FLOAT or TYP_DOUBLE
8243 bool compTailCallUsed; // Does the method do a tailcall
8244 bool compLocallocUsed; // Does the method use localloc.
8245 bool compLocallocOptimized; // Does the method have an optimized localloc
8246 bool compQmarkUsed; // Does the method use GT_QMARK/GT_COLON
8247 bool compQmarkRationalized; // Is it allowed to use a GT_QMARK/GT_COLON node.
8248 bool compUnsafeCastUsed; // Does the method use LDIND/STIND to cast between scalar/refernce types
8250 // NOTE: These values are only reliable after
8251 // the importing is completely finished.
8254 // State information - which phases have completed?
8255 // These are kept together for easy discoverability
8257 bool bRangeAllowStress;
8258 bool compCodeGenDone;
8259 int64_t compNumStatementLinksTraversed; // # of links traversed while doing debug checks
8260 bool fgNormalizeEHDone; // Has the flowgraph EH normalization phase been done?
8261 size_t compSizeEstimate; // The estimated size of the method as per `gtSetEvalOrder`.
8262 size_t compCycleEstimate; // The estimated cycle count of the method as per `gtSetEvalOrder`
8265 bool fgLocalVarLivenessDone; // Note that this one is used outside of debug.
8266 bool fgLocalVarLivenessChanged;
8268 bool compRationalIRForm;
8270 bool compUsesThrowHelper; // There is a call to a THOROW_HELPER for the compiled method.
8272 bool compGeneratingProlog;
8273 bool compGeneratingEpilog;
8274 bool compNeedsGSSecurityCookie; // There is an unsafe buffer (or localloc) on the stack.
8275 // Insert cookie on frame and code to check the cookie, like VC++ -GS.
8276 bool compGSReorderStackLayout; // There is an unsafe buffer on the stack, reorder locals and make local
8277 // copies of susceptible parameters to avoid buffer overrun attacks through locals/params
8278 bool getNeedsGSSecurityCookie() const
8280 return compNeedsGSSecurityCookie;
8282 void setNeedsGSSecurityCookie()
8284 compNeedsGSSecurityCookie = true;
8287 FrameLayoutState lvaDoneFrameLayout; // The highest frame layout state that we've completed. During
8288 // frame layout calculations, this is the level we are currently
8291 //---------------------------- JITing options -----------------------------
8304 JitFlags* jitFlags; // all flags passed from the EE
8305 unsigned compFlags; // method attributes
8307 codeOptimize compCodeOpt; // what type of code optimizations
8312 #if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
8313 uint64_t compSupportsISA;
8314 void setSupportedISA(InstructionSet isa)
8316 compSupportsISA |= 1ULL << isa;
8320 // optimize maximally and/or favor speed over size?
8322 #define DEFAULT_MIN_OPTS_CODE_SIZE 60000
8323 #define DEFAULT_MIN_OPTS_INSTR_COUNT 20000
8324 #define DEFAULT_MIN_OPTS_BB_COUNT 2000
8325 #define DEFAULT_MIN_OPTS_LV_NUM_COUNT 2000
8326 #define DEFAULT_MIN_OPTS_LV_REF_COUNT 8000
8328 // Maximun number of locals before turning off the inlining
8329 #define MAX_LV_NUM_COUNT_FOR_INLINING 512
8332 unsigned instrCount;
8333 unsigned lvRefCount;
8334 bool compMinOptsIsSet;
8336 bool compMinOptsIsUsed;
8340 assert(compMinOptsIsSet);
8341 compMinOptsIsUsed = true;
8346 return compMinOptsIsSet;
8355 return compMinOptsIsSet;
8359 bool OptimizationDisabled()
8361 return MinOpts() || compDbgCode;
8363 bool OptimizationEnabled()
8365 return !OptimizationDisabled();
8368 void SetMinOpts(bool val)
8370 assert(!compMinOptsIsUsed);
8371 assert(!compMinOptsIsSet || (compMinOpts == val));
8373 compMinOptsIsSet = true;
8376 // true if the CLFLG_* for an optimization is set.
8377 bool OptEnabled(unsigned optFlag)
8379 return !!(compFlags & optFlag);
8382 #ifdef FEATURE_READYTORUN_COMPILER
8385 return jitFlags->IsSet(JitFlags::JIT_FLAG_READYTORUN);
8394 // true if we should use the PINVOKE_{BEGIN,END} helpers instead of generating
8395 // PInvoke transitions inline (e.g. when targeting CoreRT).
8396 bool ShouldUsePInvokeHelpers()
8398 return jitFlags->IsSet(JitFlags::JIT_FLAG_USE_PINVOKE_HELPERS);
8401 // true if we should use insert the REVERSE_PINVOKE_{ENTER,EXIT} helpers in the method
8403 bool IsReversePInvoke()
8405 return jitFlags->IsSet(JitFlags::JIT_FLAG_REVERSE_PINVOKE);
8408 // true if we must generate code compatible with JIT32 quirks
8409 bool IsJit32Compat()
8411 #if defined(_TARGET_X86_)
8412 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
8418 // true if we must generate code compatible with Jit64 quirks
8419 bool IsJit64Compat()
8421 #if defined(_TARGET_AMD64_)
8422 return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
8423 #elif !defined(FEATURE_CORECLR)
8430 bool compScopeInfo; // Generate the LocalVar info ?
8431 bool compDbgCode; // Generate debugger-friendly code?
8432 bool compDbgInfo; // Gather debugging info?
8435 #ifdef PROFILING_SUPPORTED
8436 bool compNoPInvokeInlineCB;
8438 static const bool compNoPInvokeInlineCB;
8442 bool compGcChecks; // Check arguments and return values to ensure they are sane
8445 #if defined(DEBUG) && defined(_TARGET_XARCH_)
8447 bool compStackCheckOnRet; // Check stack pointer on return to ensure it is correct.
8449 #endif // defined(DEBUG) && defined(_TARGET_XARCH_)
8451 #if defined(DEBUG) && defined(_TARGET_X86_)
8453 bool compStackCheckOnCall; // Check stack pointer after call to ensure it is correct. Only for x86.
8455 #endif // defined(DEBUG) && defined(_TARGET_X86_)
8457 bool compNeedSecurityCheck; // This flag really means where or not a security object needs
8458 // to be allocated on the stack.
8459 // It will be set to true in the following cases:
8460 // 1. When the method being compiled has a declarative security
8461 // (i.e. when CORINFO_FLG_NOSECURITYWRAP is reset for the current method).
8462 // This is also the case when we inject a prolog and epilog in the method.
8464 // 2. When the method being compiled has imperative security (i.e. the method
8465 // calls into another method that has CORINFO_FLG_SECURITYCHECK flag set).
8467 // 3. When opts.compDbgEnC is true. (See also Compiler::compCompile).
8469 // When this flag is set, jit will allocate a gc-reference local variable (lvaSecurityObject),
8470 // which gets reported as a GC root to stackwalker.
8471 // (See also ICodeManager::GetAddrOfSecurityObject.)
8473 bool compReloc; // Generate relocs for pointers in code, true for all ngen/prejit codegen
8476 #if defined(_TARGET_XARCH_)
8477 bool compEnablePCRelAddr; // Whether absolute addr be encoded as PC-rel offset by RyuJIT where possible
8481 #ifdef UNIX_AMD64_ABI
8482 // This flag is indicating if there is a need to align the frame.
8483 // On AMD64-Windows, if there are calls, 4 slots for the outgoing ars are allocated, except for
8484 // FastTailCall. This slots makes the frame size non-zero, so alignment logic will be called.
8485 // On AMD64-Unix, there are no such slots. There is a possibility to have calls in the method with frame size of
8486 // 0. The frame alignment logic won't kick in. This flags takes care of the AMD64-Unix case by remembering that
8487 // there are calls and making sure the frame alignment logic is executed.
8488 bool compNeedToAlignFrame;
8489 #endif // UNIX_AMD64_ABI
8491 bool compProcedureSplitting; // Separate cold code from hot code
8493 bool genFPorder; // Preserve FP order (operations are non-commutative)
8494 bool genFPopt; // Can we do frame-pointer-omission optimization?
8495 bool altJit; // True if we are an altjit and are compiling this method
8498 bool optRepeat; // Repeat optimizer phases k times
8502 bool compProcedureSplittingEH; // Separate cold code from hot code for functions with EH
8503 bool dspCode; // Display native code generated
8504 bool dspEHTable; // Display the EH table reported to the VM
8505 bool dspDebugInfo; // Display the Debug info reported to the VM
8506 bool dspInstrs; // Display the IL instructions intermixed with the native code output
8507 bool dspEmit; // Display emitter output
8508 bool dspLines; // Display source-code lines intermixed with native code output
8509 bool dmpHex; // Display raw bytes in hex of native code output
8510 bool varNames; // Display variables names in native code output
8511 bool disAsm; // Display native code as it is generated
8512 bool disAsmSpilled; // Display native code when any register spilling occurs
8513 bool disDiffable; // Makes the Disassembly code 'diff-able'
8514 bool disAsm2; // Display native code after it is generated using external disassembler
8515 bool dspOrder; // Display names of each of the methods that we ngen/jit
8516 bool dspUnwind; // Display the unwind info output
8517 bool dspDiffable; // Makes the Jit Dump 'diff-able' (currently uses same COMPlus_* flag as disDiffable)
8518 bool compLongAddress; // Force using large pseudo instructions for long address
8519 // (IF_LARGEJMP/IF_LARGEADR/IF_LARGLDC)
8520 bool dspGCtbls; // Display the GC tables
8524 bool doLateDisasm; // Run the late disassembler
8525 #endif // LATE_DISASM
8527 #if DUMP_GC_TABLES && !defined(DEBUG) && defined(JIT32_GCENCODER)
8528 // Only the JIT32_GCENCODER implements GC dumping in non-DEBUG code.
8529 #pragma message("NOTE: this non-debug build has GC ptr table dumping always enabled!")
8530 static const bool dspGCtbls = true;
8533 #ifdef PROFILING_SUPPORTED
8534 // Whether to emit Enter/Leave/TailCall hooks using a dummy stub (DummyProfilerELTStub()).
8535 // This option helps make the JIT behave as if it is running under a profiler.
8536 bool compJitELTHookEnabled;
8537 #endif // PROFILING_SUPPORTED
8539 #if FEATURE_TAILCALL_OPT
8540 // Whether opportunistic or implicit tail call optimization is enabled.
8541 bool compTailCallOpt;
8542 // Whether optimization of transforming a recursive tail call into a loop is enabled.
8543 bool compTailCallLoopOpt;
8546 #if defined(_TARGET_ARM64_)
8547 // Decision about whether to save FP/LR registers with callee-saved registers (see
8548 // COMPlus_JitSaveFpLrWithCalleSavedRegisters).
8549 int compJitSaveFpLrWithCalleeSavedRegisters;
8550 #endif // defined(_TARGET_ARM64_)
8553 static const bool compUseSoftFP = true;
8554 #else // !ARM_SOFTFP
8555 static const bool compUseSoftFP = false;
8558 GCPollType compGCPollType;
8562 static bool s_pAltJitExcludeAssembliesListInitialized;
8563 static AssemblyNamesList2* s_pAltJitExcludeAssembliesList;
8567 static bool s_pJitDisasmIncludeAssembliesListInitialized;
8568 static AssemblyNamesList2* s_pJitDisasmIncludeAssembliesList;
8570 static bool s_pJitFunctionFileInitialized;
8571 static MethodSet* s_pJitMethodSet;
8575 // silence warning of cast to greater size. It is easier to silence than construct code the compiler is happy with, and
8576 // it is safe in this case
8577 #pragma warning(push)
8578 #pragma warning(disable : 4312)
8580 template <typename T>
8583 return (p == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : p);
8586 template <typename T>
8589 return (o == ZERO) ? ZERO : (opts.dspDiffable ? T(0xD1FFAB1E) : o);
8591 #pragma warning(pop)
8593 static int dspTreeID(GenTree* tree)
8595 return tree->gtTreeID;
8597 static void printTreeID(GenTree* tree)
8599 if (tree == nullptr)
8605 printf("[%06d]", dspTreeID(tree));
8612 #define STRESS_MODES \
8616 /* "Variations" stress areas which we try to mix up with each other. */ \
8617 /* These should not be exhaustively used as they might */ \
8618 /* hide/trivialize other areas */ \
8621 STRESS_MODE(DBL_ALN) \
8622 STRESS_MODE(LCL_FLDS) \
8623 STRESS_MODE(UNROLL_LOOPS) \
8624 STRESS_MODE(MAKE_CSE) \
8625 STRESS_MODE(LEGACY_INLINE) \
8626 STRESS_MODE(CLONE_EXPR) \
8627 STRESS_MODE(USE_FCOMI) \
8628 STRESS_MODE(USE_CMOV) \
8630 STRESS_MODE(BB_PROFILE) \
8631 STRESS_MODE(OPT_BOOLS_GC) \
8632 STRESS_MODE(REMORPH_TREES) \
8633 STRESS_MODE(64RSLT_MUL) \
8634 STRESS_MODE(DO_WHILE_LOOPS) \
8635 STRESS_MODE(MIN_OPTS) \
8636 STRESS_MODE(REVERSE_FLAG) /* Will set GTF_REVERSE_OPS whenever we can */ \
8637 STRESS_MODE(REVERSE_COMMA) /* Will reverse commas created with gtNewCommaNode */ \
8638 STRESS_MODE(TAILCALL) /* Will make the call as a tailcall whenever legal */ \
8639 STRESS_MODE(CATCH_ARG) /* Will spill catch arg */ \
8640 STRESS_MODE(UNSAFE_BUFFER_CHECKS) \
8641 STRESS_MODE(NULL_OBJECT_CHECK) \
8642 STRESS_MODE(PINVOKE_RESTORE_ESP) \
8643 STRESS_MODE(RANDOM_INLINE) \
8644 STRESS_MODE(SWITCH_CMP_BR_EXPANSION) \
8645 STRESS_MODE(GENERIC_VARN) \
8647 /* After COUNT_VARN, stress level 2 does all of these all the time */ \
8649 STRESS_MODE(COUNT_VARN) \
8651 /* "Check" stress areas that can be exhaustively used if we */ \
8652 /* dont care about performance at all */ \
8654 STRESS_MODE(FORCE_INLINE) /* Treat every method as AggressiveInlining */ \
8655 STRESS_MODE(CHK_FLOW_UPDATE) \
8656 STRESS_MODE(EMITTER) \
8657 STRESS_MODE(CHK_REIMPORT) \
8658 STRESS_MODE(FLATFP) \
8659 STRESS_MODE(GENERIC_CHECK) \
8664 #define STRESS_MODE(mode) STRESS_##mode,
8671 static const LPCWSTR s_compStressModeNames[STRESS_COUNT + 1];
8672 BYTE compActiveStressModes[STRESS_COUNT];
8675 #define MAX_STRESS_WEIGHT 100
8677 bool compStressCompile(compStressArea stressArea, unsigned weightPercentage);
8681 bool compInlineStress()
8683 return compStressCompile(STRESS_LEGACY_INLINE, 50);
8686 bool compRandomInlineStress()
8688 return compStressCompile(STRESS_RANDOM_INLINE, 50);
8693 bool compTailCallStress()
8696 return (JitConfig.TailcallStress() != 0 || compStressCompile(STRESS_TAILCALL, 5));
8702 codeOptimize compCodeOpt()
8705 // Switching between size & speed has measurable throughput impact
8706 // (3.5% on NGen mscorlib when measured). It used to be enabled for
8707 // DEBUG, but should generate identical code between CHK & RET builds,
8708 // so that's not acceptable.
8709 // TODO-Throughput: Figure out what to do about size vs. speed & throughput.
8710 // Investigate the cause of the throughput regression.
8712 return opts.compCodeOpt;
8714 return BLENDED_CODE;
8718 //--------------------- Info about the procedure --------------------------
8722 COMP_HANDLE compCompHnd;
8723 CORINFO_MODULE_HANDLE compScopeHnd;
8724 CORINFO_CLASS_HANDLE compClassHnd;
8725 CORINFO_METHOD_HANDLE compMethodHnd;
8726 CORINFO_METHOD_INFO* compMethodInfo;
8728 BOOL hasCircularClassConstraints;
8729 BOOL hasCircularMethodConstraints;
8731 #if defined(DEBUG) || defined(LATE_DISASM)
8732 const char* compMethodName;
8733 const char* compClassName;
8734 const char* compFullName;
8735 #endif // defined(DEBUG) || defined(LATE_DISASM)
8737 #if defined(DEBUG) || defined(INLINE_DATA)
8738 // Method hash is logcally const, but computed
8740 mutable unsigned compMethodHashPrivate;
8741 unsigned compMethodHash() const;
8742 #endif // defined(DEBUG) || defined(INLINE_DATA)
8744 #ifdef PSEUDORANDOM_NOP_INSERTION
8745 // things for pseudorandom nop insertion
8746 unsigned compChecksum;
8750 // The following holds the FLG_xxxx flags for the method we're compiling.
8753 // The following holds the class attributes for the method we're compiling.
8754 unsigned compClassAttr;
8756 const BYTE* compCode;
8757 IL_OFFSET compILCodeSize; // The IL code size
8758 IL_OFFSET compILImportSize; // Estimated amount of IL actually imported
8759 UNATIVE_OFFSET compNativeCodeSize; // The native code size, after instructions are issued. This
8760 // is less than (compTotalHotCodeSize + compTotalColdCodeSize) only if:
8761 // (1) the code is not hot/cold split, and we issued less code than we expected, or
8762 // (2) the code is hot/cold split, and we issued less code than we expected
8763 // in the cold section (the hot section will always be padded out to compTotalHotCodeSize).
8765 bool compIsStatic : 1; // Is the method static (no 'this' pointer)?
8766 bool compIsVarArgs : 1; // Does the method have varargs parameters?
8767 bool compIsContextful : 1; // contextful method
8768 bool compInitMem : 1; // Is the CORINFO_OPT_INIT_LOCALS bit set in the method info options?
8769 bool compUnwrapContextful : 1; // JIT should unwrap proxies when possible
8770 bool compProfilerCallback : 1; // JIT inserted a profiler Enter callback
8771 bool compPublishStubParam : 1; // EAX captured in prolog will be available through an instrinsic
8772 bool compRetBuffDefStack : 1; // The ret buff argument definitely points into the stack.
8774 var_types compRetType; // Return type of the method as declared in IL
8775 var_types compRetNativeType; // Normalized return type as per target arch ABI
8776 unsigned compILargsCount; // Number of arguments (incl. implicit but not hidden)
8777 unsigned compArgsCount; // Number of arguments (incl. implicit and hidden)
8779 #if FEATURE_FASTTAILCALL
8780 size_t compArgStackSize; // Incoming argument stack size in bytes
8781 bool compHasMultiSlotArgs; // Caller has >8 byte sized struct parameter
8782 #endif // FEATURE_FASTTAILCALL
8784 unsigned compRetBuffArg; // position of hidden return param var (0, 1) (BAD_VAR_NUM means not present);
8785 int compTypeCtxtArg; // position of hidden param for type context for generic code (CORINFO_CALLCONV_PARAMTYPE)
8786 unsigned compThisArg; // position of implicit this pointer param (not to be confused with lvaArg0Var)
8787 unsigned compILlocalsCount; // Number of vars : args + locals (incl. implicit but not hidden)
8788 unsigned compLocalsCount; // Number of vars : args + locals (incl. implicit and hidden)
8789 unsigned compMaxStack;
8790 UNATIVE_OFFSET compTotalHotCodeSize; // Total number of bytes of Hot Code in the method
8791 UNATIVE_OFFSET compTotalColdCodeSize; // Total number of bytes of Cold Code in the method
8793 unsigned compCallUnmanaged; // count of unmanaged calls
8794 unsigned compLvFrameListRoot; // lclNum for the Frame root
8795 unsigned compXcptnsCount; // Number of exception-handling clauses read in the method's IL.
8796 // You should generally use compHndBBtabCount instead: it is the
8797 // current number of EH clauses (after additions like synchronized
8798 // methods and funclets, and removals like unreachable code deletion).
8800 bool compMatchedVM; // true if the VM is "matched": either the JIT is a cross-compiler
8801 // and the VM expects that, or the JIT is a "self-host" compiler
8802 // (e.g., x86 hosted targeting x86) and the VM expects that.
8804 /* The following holds IL scope information about local variables.
8807 unsigned compVarScopesCount;
8808 VarScopeDsc* compVarScopes;
8810 /* The following holds information about instr offsets for
8811 * which we need to report IP-mappings
8814 IL_OFFSET* compStmtOffsets; // sorted
8815 unsigned compStmtOffsetsCount;
8816 ICorDebugInfo::BoundaryTypes compStmtOffsetsImplicit;
8818 #define CPU_X86 0x0100 // The generic X86 CPU
8819 #define CPU_X86_PENTIUM_4 0x0110
8821 #define CPU_X64 0x0200 // The generic x64 CPU
8822 #define CPU_AMD_X64 0x0210 // AMD x64 CPU
8823 #define CPU_INTEL_X64 0x0240 // Intel x64 CPU
8825 #define CPU_ARM 0x0300 // The generic ARM CPU
8826 #define CPU_ARM64 0x0400 // The generic ARM64 CPU
8828 unsigned genCPU; // What CPU are we running on
8831 // Returns true if the method being compiled returns a non-void and non-struct value.
8832 // Note that lvaInitTypeRef() normalizes compRetNativeType for struct returns in a
8833 // single register as per target arch ABI (e.g on Amd64 Windows structs of size 1, 2,
8834 // 4 or 8 gets normalized to TYP_BYTE/TYP_SHORT/TYP_INT/TYP_LONG; On Arm HFA structs).
8835 // Methods returning such structs are considered to return non-struct return value and
8836 // this method returns true in that case.
8837 bool compMethodReturnsNativeScalarType()
8839 return (info.compRetType != TYP_VOID) && !varTypeIsStruct(info.compRetNativeType);
8842 // Returns true if the method being compiled returns RetBuf addr as its return value
8843 bool compMethodReturnsRetBufAddr()
8845 // There are cases where implicit RetBuf argument should be explicitly returned in a register.
8846 // In such cases the return type is changed to TYP_BYREF and appropriate IR is generated.
8848 // 1. Profiler Leave calllback expects the address of retbuf as return value for
8849 // methods with hidden RetBuf argument. impReturnInstruction() when profiler
8850 // callbacks are needed creates GT_RETURN(TYP_BYREF, op1 = Addr of RetBuf) for
8851 // methods with hidden RetBufArg.
8853 // 2. As per the System V ABI, the address of RetBuf needs to be returned by
8854 // methods with hidden RetBufArg in RAX. In such case GT_RETURN is of TYP_BYREF,
8855 // returning the address of RetBuf.
8857 // 3. Windows 64-bit native calling convention also requires the address of RetBuff
8858 // to be returned in RAX.
8859 CLANG_FORMAT_COMMENT_ANCHOR;
8861 #ifdef _TARGET_AMD64_
8862 return (info.compRetBuffArg != BAD_VAR_NUM);
8863 #else // !_TARGET_AMD64_
8864 return (compIsProfilerHookNeeded()) && (info.compRetBuffArg != BAD_VAR_NUM);
8865 #endif // !_TARGET_AMD64_
8868 // Returns true if the method returns a value in more than one return register
8869 // TODO-ARM-Bug: Deal with multi-register genReturnLocaled structs?
8870 // TODO-ARM64: Does this apply for ARM64 too?
8871 bool compMethodReturnsMultiRegRetType()
8873 #if FEATURE_MULTIREG_RET
8874 #if defined(_TARGET_X86_)
8875 // On x86 only 64-bit longs are returned in multiple registers
8876 return varTypeIsLong(info.compRetNativeType);
8877 #else // targets: X64-UNIX, ARM64 or ARM32
8878 // On all other targets that support multireg return values:
8879 // Methods returning a struct in multiple registers have a return value of TYP_STRUCT.
8880 // Such method's compRetNativeType is TYP_STRUCT without a hidden RetBufArg
8881 return varTypeIsStruct(info.compRetNativeType) && (info.compRetBuffArg == BAD_VAR_NUM);
8882 #endif // TARGET_XXX
8884 #else // not FEATURE_MULTIREG_RET
8886 // For this architecture there are no multireg returns
8889 #endif // FEATURE_MULTIREG_RET
8892 #if FEATURE_MULTIREG_ARGS
8893 // Given a GenTree node of TYP_STRUCT that represents a pass by value argument
8894 // return the gcPtr layout for the pointers sized fields
8895 void getStructGcPtrsFromOp(GenTree* op, BYTE* gcPtrsOut);
8896 #endif // FEATURE_MULTIREG_ARGS
8898 // Returns true if the method being compiled returns a value
8899 bool compMethodHasRetVal()
8901 return compMethodReturnsNativeScalarType() || compMethodReturnsRetBufAddr() ||
8902 compMethodReturnsMultiRegRetType();
8907 void compDispLocalVars();
8911 //-------------------------- Global Compiler Data ------------------------------------
8914 static unsigned s_compMethodsCount; // to produce unique label names
8915 unsigned compGenTreeID;
8916 unsigned compBasicBlockID;
8919 BasicBlock* compCurBB; // the current basic block in process
8920 GenTreeStmt* compCurStmt; // the current statement in process
8922 unsigned compCurStmtNum; // to give all statements an increasing StmtNum when printing dumps
8925 // The following is used to create the 'method JIT info' block.
8926 size_t compInfoBlkSize;
8927 BYTE* compInfoBlkAddr;
8929 EHblkDsc* compHndBBtab; // array of EH data
8930 unsigned compHndBBtabCount; // element count of used elements in EH data array
8931 unsigned compHndBBtabAllocCount; // element count of allocated elements in EH data array
8933 #if defined(_TARGET_X86_)
8935 //-------------------------------------------------------------------------
8936 // Tracking of region covered by the monitor in synchronized methods
8937 void* syncStartEmitCookie; // the emitter cookie for first instruction after the call to MON_ENTER
8938 void* syncEndEmitCookie; // the emitter cookie for first instruction after the call to MON_EXIT
8940 #endif // !_TARGET_X86_
8942 Phases previousCompletedPhase; // the most recently completed phase
8944 //-------------------------------------------------------------------------
8945 // The following keeps track of how many bytes of local frame space we've
8946 // grabbed so far in the current function, and how many argument bytes we
8947 // need to pop when we return.
8950 unsigned compLclFrameSize; // secObject+lclBlk+locals+temps
8952 // Count of callee-saved regs we pushed in the prolog.
8953 // Does not include EBP for isFramePointerUsed() and double-aligned frames.
8954 // In case of Amd64 this doesn't include float regs saved on stack.
8955 unsigned compCalleeRegsPushed;
8957 #if defined(_TARGET_XARCH_)
8958 // Mask of callee saved float regs on stack.
8959 regMaskTP compCalleeFPRegsSavedMask;
8961 #ifdef _TARGET_AMD64_
8962 // Quirk for VS debug-launch scenario to work:
8963 // Bytes of padding between save-reg area and locals.
8964 #define VSQUIRK_STACK_PAD (2 * REGSIZE_BYTES)
8965 unsigned compVSQuirkStackPaddingNeeded;
8966 bool compQuirkForPPPflag;
8969 unsigned compArgSize; // total size of arguments in bytes (including register args (lvIsRegArg))
8971 unsigned compMapILargNum(unsigned ILargNum); // map accounting for hidden args
8972 unsigned compMapILvarNum(unsigned ILvarNum); // map accounting for hidden args
8973 unsigned compMap2ILvarNum(unsigned varNum) const; // map accounting for hidden args
8975 //-------------------------------------------------------------------------
8977 static void compStartup(); // One-time initialization
8978 static void compShutdown(); // One-time finalization
8980 void compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo);
8983 static void compDisplayStaticSizes(FILE* fout);
8985 //------------ Some utility functions --------------
8987 void* compGetHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
8988 void** ppIndirection); /* OUT */
8990 // Several JIT/EE interface functions return a CorInfoType, and also return a
8991 // class handle as an out parameter if the type is a value class. Returns the
8992 // size of the type these describe.
8993 unsigned compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd);
8996 // Components used by the compiler may write unit test suites, and
8997 // have them run within this method. They will be run only once per process, and only
8998 // in debug. (Perhaps should be under the control of a COMPlus_ flag.)
8999 // These should fail by asserting.
9000 void compDoComponentUnitTestsOnce();
9003 int compCompile(CORINFO_METHOD_HANDLE methodHnd,
9004 CORINFO_MODULE_HANDLE classPtr,
9005 COMP_HANDLE compHnd,
9006 CORINFO_METHOD_INFO* methodInfo,
9007 void** methodCodePtr,
9008 ULONG* methodCodeSize,
9009 JitFlags* compileFlags);
9010 void compCompileFinish();
9011 int compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
9012 COMP_HANDLE compHnd,
9013 CORINFO_METHOD_INFO* methodInfo,
9014 void** methodCodePtr,
9015 ULONG* methodCodeSize,
9016 JitFlags* compileFlags,
9017 CorInfoInstantiationVerification instVerInfo);
9019 ArenaAllocator* compGetArenaAllocator();
9021 #if MEASURE_MEM_ALLOC
9022 static bool s_dspMemStats; // Display per-phase memory statistics for every function
9023 #endif // MEASURE_MEM_ALLOC
9025 #if LOOP_HOIST_STATS
9026 unsigned m_loopsConsidered;
9027 bool m_curLoopHasHoistedExpression;
9028 unsigned m_loopsWithHoistedExpressions;
9029 unsigned m_totalHoistedExpressions;
9031 void AddLoopHoistStats();
9032 void PrintPerMethodLoopHoistStats();
9034 static CritSecObject s_loopHoistStatsLock; // This lock protects the data structures below.
9035 static unsigned s_loopsConsidered;
9036 static unsigned s_loopsWithHoistedExpressions;
9037 static unsigned s_totalHoistedExpressions;
9039 static void PrintAggregateLoopHoistStats(FILE* f);
9040 #endif // LOOP_HOIST_STATS
9042 bool compIsForImportOnly();
9043 bool compIsForInlining() const;
9044 bool compDonotInline();
9047 // Get the default fill char value we randomize this value when JitStress is enabled.
9048 static unsigned char compGetJitDefaultFill(Compiler* comp);
9050 const char* compLocalVarName(unsigned varNum, unsigned offs);
9051 VarName compVarName(regNumber reg, bool isFloatReg = false);
9052 const char* compRegVarName(regNumber reg, bool displayVar = false, bool isFloatReg = false);
9053 const char* compRegNameForSize(regNumber reg, size_t size);
9054 const char* compFPregVarName(unsigned fpReg, bool displayVar = false);
9055 void compDspSrcLinesByNativeIP(UNATIVE_OFFSET curIP);
9056 void compDspSrcLinesByLineNum(unsigned line, bool seek = false);
9059 //-------------------------------------------------------------------------
9061 struct VarScopeListNode
9064 VarScopeListNode* next;
9065 static VarScopeListNode* Create(VarScopeDsc* value, CompAllocator alloc)
9067 VarScopeListNode* node = new (alloc) VarScopeListNode;
9069 node->next = nullptr;
9074 struct VarScopeMapInfo
9076 VarScopeListNode* head;
9077 VarScopeListNode* tail;
9078 static VarScopeMapInfo* Create(VarScopeListNode* node, CompAllocator alloc)
9080 VarScopeMapInfo* info = new (alloc) VarScopeMapInfo;
9087 // Max value of scope count for which we would use linear search; for larger values we would use hashtable lookup.
9088 static const unsigned MAX_LINEAR_FIND_LCL_SCOPELIST = 32;
9090 typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, VarScopeMapInfo*> VarNumToScopeDscMap;
9092 // Map to keep variables' scope indexed by varNum containing it's scope dscs at the index.
9093 VarNumToScopeDscMap* compVarScopeMap;
9095 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned lifeBeg, unsigned lifeEnd);
9097 VarScopeDsc* compFindLocalVar(unsigned varNum, unsigned offs);
9099 VarScopeDsc* compFindLocalVarLinear(unsigned varNum, unsigned offs);
9101 void compInitVarScopeMap();
9103 VarScopeDsc** compEnterScopeList; // List has the offsets where variables
9104 // enter scope, sorted by instr offset
9105 unsigned compNextEnterScope;
9107 VarScopeDsc** compExitScopeList; // List has the offsets where variables
9108 // go out of scope, sorted by instr offset
9109 unsigned compNextExitScope;
9111 void compInitScopeLists();
9113 void compResetScopeLists();
9115 VarScopeDsc* compGetNextEnterScope(unsigned offs, bool scan = false);
9117 VarScopeDsc* compGetNextExitScope(unsigned offs, bool scan = false);
9119 void compProcessScopesUntil(unsigned offset,
9121 void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*),
9122 void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*));
9125 void compDispScopeLists();
9128 bool compIsProfilerHookNeeded();
9130 //-------------------------------------------------------------------------
9131 /* Statistical Data Gathering */
9133 void compJitStats(); // call this function and enable
9134 // various ifdef's below for statistical data
9137 void compCallArgStats();
9138 static void compDispCallArgStats(FILE* fout);
9141 //-------------------------------------------------------------------------
9148 ArenaAllocator* compArenaAllocator;
9151 void compFunctionTraceStart();
9152 void compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, bool isNYI);
9155 size_t compMaxUncheckedOffsetForNullObject;
9157 void compInitOptions(JitFlags* compileFlags);
9159 void compSetProcessor();
9160 void compInitDebuggingInfo();
9161 void compSetOptimizationLevel();
9162 #ifdef _TARGET_ARMARCH_
9163 bool compRsvdRegCheck(FrameLayoutState curState);
9165 void compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags);
9167 // Clear annotations produced during optimizations; to be used between iterations when repeating opts.
9168 void ResetOptAnnotations();
9170 // Regenerate loop descriptors; to be used between iterations when repeating opts.
9171 void RecomputeLoopInfo();
9173 #ifdef PROFILING_SUPPORTED
9174 // Data required for generating profiler Enter/Leave/TailCall hooks
9176 bool compProfilerHookNeeded; // Whether profiler Enter/Leave/TailCall hook needs to be generated for the method
9177 void* compProfilerMethHnd; // Profiler handle of the method being compiled. Passed as param to ELT callbacks
9178 bool compProfilerMethHndIndirected; // Whether compProfilerHandle is pointer to the handle or is an actual handle
9181 #ifdef _TARGET_AMD64_
9182 bool compQuirkForPPP(); // Check if this method should be Quirked for the PPP issue
9185 // Assumes called as part of process shutdown; does any compiler-specific work associated with that.
9186 static void ProcessShutdownWork(ICorStaticInfo* statInfo);
9188 CompAllocator getAllocator(CompMemKind cmk = CMK_Generic)
9190 return CompAllocator(compArenaAllocator, cmk);
9193 CompAllocator getAllocatorGC()
9195 return getAllocator(CMK_GC);
9198 CompAllocator getAllocatorLoopHoist()
9200 return getAllocator(CMK_LoopHoist);
9204 CompAllocator getAllocatorDebugOnly()
9206 return getAllocator(CMK_DebugOnly);
9211 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9212 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9216 XX Checks for type compatibility and merges types XX
9218 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9219 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9223 // Set to TRUE if verification cannot be skipped for this method
9224 // If we detect unverifiable code, we will lazily check
9225 // canSkipMethodVerification() to see if verification is REALLY needed.
9226 BOOL tiVerificationNeeded;
9228 // It it initially TRUE, and it gets set to FALSE if we run into unverifiable code
9229 // Note that this is valid only if tiVerificationNeeded was ever TRUE.
9230 BOOL tiIsVerifiableCode;
9232 // Set to TRUE if runtime callout is needed for this method
9233 BOOL tiRuntimeCalloutNeeded;
9235 // Set to TRUE if security prolog/epilog callout is needed for this method
9236 // Note: This flag is different than compNeedSecurityCheck.
9237 // compNeedSecurityCheck means whether or not a security object needs
9238 // to be allocated on the stack, which is currently true for EnC as well.
9239 // tiSecurityCalloutNeeded means whether or not security callouts need
9240 // to be inserted in the jitted code.
9241 BOOL tiSecurityCalloutNeeded;
9243 // Returns TRUE if child is equal to or a subtype of parent for merge purposes
9244 // This support is necessary to suport attributes that are not described in
9245 // for example, signatures. For example, the permanent home byref (byref that
9246 // points to the gc heap), isn't a property of method signatures, therefore,
9247 // it is safe to have mismatches here (that tiCompatibleWith will not flag),
9248 // but when deciding if we need to reimport a block, we need to take these
9250 BOOL tiMergeCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
9252 // Returns TRUE if child is equal to or a subtype of parent.
9253 // normalisedForStack indicates that both types are normalised for the stack
9254 BOOL tiCompatibleWith(const typeInfo& pChild, const typeInfo& pParent, bool normalisedForStack) const;
9256 // Merges pDest and pSrc. Returns FALSE if merge is undefined.
9257 // *pDest is modified to represent the merged type. Sets "*changed" to true
9258 // if this changes "*pDest".
9259 BOOL tiMergeToCommonParent(typeInfo* pDest, const typeInfo* pSrc, bool* changed) const;
9262 // <BUGNUM> VSW 471305
9263 // IJW allows assigning REF to BYREF. The following allows us to temporarily
9264 // bypass the assert check in gcMarkRegSetGCref and gcMarkRegSetByref
9265 // We use a "short" as we need to push/pop this scope.
9267 short compRegSetCheckLevel;
9271 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9272 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9274 XX IL verification stuff XX
9277 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9278 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9282 // The following is used to track liveness of local variables, initialization
9283 // of valueclass constructors, and type safe use of IL instructions.
9285 // dynamic state info needed for verification
9286 EntryState verCurrentState;
9288 // this ptr of object type .ctors are considered intited only after
9289 // the base class ctor is called, or an alternate ctor is called.
9290 // An uninited this ptr can be used to access fields, but cannot
9291 // be used to call a member function.
9292 BOOL verTrackObjCtorInitState;
9294 void verInitBBEntryState(BasicBlock* block, EntryState* currentState);
9296 // Requires that "tis" is not TIS_Bottom -- it's a definite init/uninit state.
9297 void verSetThisInit(BasicBlock* block, ThisInitState tis);
9298 void verInitCurrentState();
9299 void verResetCurrentState(BasicBlock* block, EntryState* currentState);
9301 // Merges the current verification state into the entry state of "block", return FALSE if that merge fails,
9302 // TRUE if it succeeds. Further sets "*changed" to true if this changes the entry state of "block".
9303 BOOL verMergeEntryStates(BasicBlock* block, bool* changed);
9305 void verConvertBBToThrowVerificationException(BasicBlock* block DEBUGARG(bool logMsg));
9306 void verHandleVerificationFailure(BasicBlock* block DEBUGARG(bool logMsg));
9307 typeInfo verMakeTypeInfo(CORINFO_CLASS_HANDLE clsHnd,
9308 bool bashStructToRef = false); // converts from jit type representation to typeInfo
9309 typeInfo verMakeTypeInfo(CorInfoType ciType,
9310 CORINFO_CLASS_HANDLE clsHnd); // converts from jit type representation to typeInfo
9311 BOOL verIsSDArray(typeInfo ti);
9312 typeInfo verGetArrayElemType(typeInfo ti);
9314 typeInfo verParseArgSigToTypeInfo(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args);
9315 BOOL verNeedsVerification();
9316 BOOL verIsByRefLike(const typeInfo& ti);
9317 BOOL verIsSafeToReturnByRef(const typeInfo& ti);
9319 // generic type variables range over types that satisfy IsBoxable
9320 BOOL verIsBoxable(const typeInfo& ti);
9322 void DECLSPEC_NORETURN verRaiseVerifyException(INDEBUG(const char* reason) DEBUGARG(const char* file)
9323 DEBUGARG(unsigned line));
9324 void verRaiseVerifyExceptionIfNeeded(INDEBUG(const char* reason) DEBUGARG(const char* file)
9325 DEBUGARG(unsigned line));
9326 bool verCheckTailCallConstraint(OPCODE opcode,
9327 CORINFO_RESOLVED_TOKEN* pResolvedToken,
9328 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call
9329 // on a type parameter?
9330 bool speculative // If true, won't throw if verificatoin fails. Instead it will
9331 // return false to the caller.
9332 // If false, it will throw.
9334 bool verIsBoxedValueType(typeInfo ti);
9336 void verVerifyCall(OPCODE opcode,
9337 CORINFO_RESOLVED_TOKEN* pResolvedToken,
9338 CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
9340 bool readonlyCall, // is this a "readonly." call?
9341 const BYTE* delegateCreateStart,
9342 const BYTE* codeAddr,
9343 CORINFO_CALL_INFO* callInfo DEBUGARG(const char* methodName));
9345 BOOL verCheckDelegateCreation(const BYTE* delegateCreateStart, const BYTE* codeAddr, mdMemberRef& targetMemberRef);
9347 typeInfo verVerifySTIND(const typeInfo& ptr, const typeInfo& value, const typeInfo& instrType);
9348 typeInfo verVerifyLDIND(const typeInfo& ptr, const typeInfo& instrType);
9349 void verVerifyField(CORINFO_RESOLVED_TOKEN* pResolvedToken,
9350 const CORINFO_FIELD_INFO& fieldInfo,
9351 const typeInfo* tiThis,
9353 BOOL allowPlainStructAsThis = FALSE);
9354 void verVerifyCond(const typeInfo& tiOp1, const typeInfo& tiOp2, unsigned opcode);
9355 void verVerifyThisPtrInitialised();
9356 BOOL verIsCallToInitThisPtr(CORINFO_CLASS_HANDLE context, CORINFO_CLASS_HANDLE target);
9360 // One line log function. Default level is 0. Increasing it gives you
9361 // more log information
9363 // levels are currently unused: #define JITDUMP(level,...) ();
9364 void JitLogEE(unsigned level, const char* fmt, ...);
9366 bool compDebugBreak;
9368 bool compJitHaltMethod();
9373 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9374 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9376 XX GS Security checks for unsafe buffers XX
9378 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9379 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9382 struct ShadowParamVarInfo
9384 FixedBitVect* assignGroup; // the closure set of variables whose values depend on each other
9385 unsigned shadowCopy; // Lcl var num, valid only if not set to NO_SHADOW_COPY
9387 static bool mayNeedShadowCopy(LclVarDsc* varDsc)
9389 #if defined(_TARGET_AMD64_)
9390 // GS cookie logic to create shadow slots, create trees to copy reg args to shadow
9391 // slots and update all trees to refer to shadow slots is done immediately after
9392 // fgMorph(). Lsra could potentially mark a param as DoNotEnregister after JIT determines
9393 // not to shadow a parameter. Also, LSRA could potentially spill a param which is passed
9394 // in register. Therefore, conservatively all params may need a shadow copy. Note that
9395 // GS cookie logic further checks whether the param is a ptr or an unsafe buffer before
9396 // creating a shadow slot even though this routine returns true.
9398 // TODO-AMD64-CQ: Revisit this conservative approach as it could create more shadow slots than
9399 // required. There are two cases under which a reg arg could potentially be used from its
9401 // a) LSRA marks it as DoNotEnregister (see LinearScan::identifyCandidates())
9402 // b) LSRA spills it
9404 // Possible solution to address case (a)
9405 // - The conditions under which LSRA marks a varDsc as DoNotEnregister could be checked
9406 // in this routine. Note that live out of exception handler is something we may not be
9407 // able to do it here since GS cookie logic is invoked ahead of liveness computation.
9408 // Therefore, for methods with exception handling and need GS cookie check we might have
9409 // to take conservative approach.
9411 // Possible solution to address case (b)
9412 // - Whenver a parameter passed in an argument register needs to be spilled by LSRA, we
9413 // create a new spill temp if the method needs GS cookie check.
9414 return varDsc->lvIsParam;
9415 #else // !defined(_TARGET_AMD64_)
9416 return varDsc->lvIsParam && !varDsc->lvIsRegArg;
9423 printf("assignGroup [%p]; shadowCopy: [%d];\n", assignGroup, shadowCopy);
9428 GSCookie* gsGlobalSecurityCookieAddr; // Address of global cookie for unsafe buffer checks
9429 GSCookie gsGlobalSecurityCookieVal; // Value of global cookie if addr is NULL
9430 ShadowParamVarInfo* gsShadowVarInfo; // Table used by shadow param analysis code
9432 void gsGSChecksInitCookie(); // Grabs cookie variable
9433 void gsCopyShadowParams(); // Identify vulnerable params and create dhadow copies
9434 bool gsFindVulnerableParams(); // Shadow param analysis code
9435 void gsParamsToShadows(); // Insert copy code and replave param uses by shadow
9437 static fgWalkPreFn gsMarkPtrsAndAssignGroups; // Shadow param analysis tree-walk
9438 static fgWalkPreFn gsReplaceShadowParams; // Shadow param replacement tree-walk
9440 #define DEFAULT_MAX_INLINE_SIZE 100 // Methods with > DEFAULT_MAX_INLINE_SIZE IL bytes will never be inlined.
9441 // This can be overwritten by setting complus_JITInlineSize env variable.
9443 #define DEFAULT_MAX_INLINE_DEPTH 20 // Methods at more than this level deep will not be inlined
9445 #define DEFAULT_MAX_LOCALLOC_TO_LOCAL_SIZE 32 // fixed locallocs of this size or smaller will convert to local buffers
9448 #ifdef FEATURE_JIT_METHOD_PERF
9449 JitTimer* pCompJitTimer; // Timer data structure (by phases) for current compilation.
9450 static CompTimeSummaryInfo s_compJitTimerSummary; // Summary of the Timer information for the whole run.
9452 static LPCWSTR JitTimeLogCsv(); // Retrieve the file name for CSV from ConfigDWORD.
9453 static LPCWSTR compJitTimeLogFilename; // If a log file for JIT time is desired, filename to write it to.
9455 inline void EndPhase(Phases phase); // Indicate the end of the given phase.
9457 #if MEASURE_CLRAPI_CALLS
9458 // Thin wrappers that call into JitTimer (if present).
9459 inline void CLRApiCallEnter(unsigned apix);
9460 inline void CLRApiCallLeave(unsigned apix);
9463 inline void CLR_API_Enter(API_ICorJitInfo_Names ename);
9464 inline void CLR_API_Leave(API_ICorJitInfo_Names ename);
9469 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9470 // These variables are associated with maintaining SQM data about compile time.
9471 unsigned __int64 m_compCyclesAtEndOfInlining; // The thread-virtualized cycle count at the end of the inlining phase
9472 // in the current compilation.
9473 unsigned __int64 m_compCycles; // Net cycle count for current compilation
9474 DWORD m_compTickCountAtEndOfInlining; // The result of GetTickCount() (# ms since some epoch marker) at the end of
9475 // the inlining phase in the current compilation.
9476 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
9478 // Records the SQM-relevant (cycles and tick count). Should be called after inlining is complete.
9479 // (We do this after inlining because this marks the last point at which the JIT is likely to cause
9480 // type-loading and class initialization).
9481 void RecordStateAtEndOfInlining();
9482 // Assumes being called at the end of compilation. Update the SQM state.
9483 void RecordStateAtEndOfCompilation();
9485 #ifdef FEATURE_CLRSQM
9486 // Does anything SQM related necessary at process shutdown time.
9487 static void ProcessShutdownSQMWork(ICorStaticInfo* statInfo);
9488 #endif // FEATURE_CLRSQM
9491 #if FUNC_INFO_LOGGING
9492 static LPCWSTR compJitFuncInfoFilename; // If a log file for per-function information is required, this is the
9493 // filename to write it to.
9494 static FILE* compJitFuncInfoFile; // And this is the actual FILE* to write to.
9495 #endif // FUNC_INFO_LOGGING
9497 Compiler* prevCompiler; // Previous compiler on stack for TLS Compiler* linked list for reentrant compilers.
9499 // Is the compilation in a full trust context?
9500 bool compIsFullTrust();
9503 void RecordNowayAssert(const char* filename, unsigned line, const char* condStr);
9504 #endif // MEASURE_NOWAY
9506 #ifndef FEATURE_TRACELOGGING
9507 // Should we actually fire the noway assert body and the exception handler?
9508 bool compShouldThrowOnNoway();
9509 #else // FEATURE_TRACELOGGING
9510 // Should we actually fire the noway assert body and the exception handler?
9511 bool compShouldThrowOnNoway(const char* filename, unsigned line);
9513 // Telemetry instance to use per method compilation.
9514 JitTelemetry compJitTelemetry;
9516 // Get common parameters that have to be logged with most telemetry data.
9517 void compGetTelemetryDefaults(const char** assemblyName,
9518 const char** scopeName,
9519 const char** methodName,
9520 unsigned* methodHash);
9521 #endif // !FEATURE_TRACELOGGING
9525 NodeToTestDataMap* m_nodeTestData;
9527 static const unsigned FIRST_LOOP_HOIST_CSE_CLASS = 1000;
9528 unsigned m_loopHoistCSEClass; // LoopHoist test annotations turn into CSE requirements; we
9529 // label them with CSE Class #'s starting at FIRST_LOOP_HOIST_CSE_CLASS.
9530 // Current kept in this.
9532 NodeToTestDataMap* GetNodeTestData()
9534 Compiler* compRoot = impInlineRoot();
9535 if (compRoot->m_nodeTestData == nullptr)
9537 compRoot->m_nodeTestData = new (getAllocatorDebugOnly()) NodeToTestDataMap(getAllocatorDebugOnly());
9539 return compRoot->m_nodeTestData;
9542 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, int> NodeToIntMap;
9544 // Returns the set (i.e., the domain of the result map) of nodes that are keys in m_nodeTestData, and
9545 // currently occur in the AST graph.
9546 NodeToIntMap* FindReachableNodesInNodeTestData();
9548 // Node "from" is being eliminated, and being replaced by node "to". If "from" had any associated
9549 // test data, associate that data with "to".
9550 void TransferTestDataToNode(GenTree* from, GenTree* to);
9552 // Requires that "to" is a clone of "from". If any nodes in the "from" tree
9553 // have annotations, attach similar annotations to the corresponding nodes in "to".
9554 void CopyTestDataToCloneTree(GenTree* from, GenTree* to);
9556 // These are the methods that test that the various conditions implied by the
9557 // test attributes are satisfied.
9558 void JitTestCheckSSA(); // SSA builder tests.
9559 void JitTestCheckVN(); // Value numbering tests.
9562 // The "FieldSeqStore", for canonicalizing field sequences. See the definition of FieldSeqStore for
9564 FieldSeqStore* m_fieldSeqStore;
9566 FieldSeqStore* GetFieldSeqStore()
9568 Compiler* compRoot = impInlineRoot();
9569 if (compRoot->m_fieldSeqStore == nullptr)
9571 // Create a CompAllocator that labels sub-structure with CMK_FieldSeqStore, and use that for allocation.
9572 CompAllocator ialloc(getAllocator(CMK_FieldSeqStore));
9573 compRoot->m_fieldSeqStore = new (ialloc) FieldSeqStore(ialloc);
9575 return compRoot->m_fieldSeqStore;
9578 typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, FieldSeqNode*> NodeToFieldSeqMap;
9580 // Some nodes of "TYP_BYREF" or "TYP_I_IMPL" actually represent the address of a field within a struct, but since
9581 // the offset of the field is zero, there's no "GT_ADD" node. We normally attach a field sequence to the constant
9582 // that is added, but what do we do when that constant is zero, and is thus not present? We use this mechanism to
9583 // attach the field sequence directly to the address node.
9584 NodeToFieldSeqMap* m_zeroOffsetFieldMap;
9586 NodeToFieldSeqMap* GetZeroOffsetFieldMap()
9588 // Don't need to worry about inlining here
9589 if (m_zeroOffsetFieldMap == nullptr)
9591 // Create a CompAllocator that labels sub-structure with CMK_ZeroOffsetFieldMap, and use that for
9593 CompAllocator ialloc(getAllocator(CMK_ZeroOffsetFieldMap));
9594 m_zeroOffsetFieldMap = new (ialloc) NodeToFieldSeqMap(ialloc);
9596 return m_zeroOffsetFieldMap;
9599 // Requires that "op1" is a node of type "TYP_BYREF" or "TYP_I_IMPL". We are dereferencing this with the fields in
9600 // "fieldSeq", whose offsets are required all to be zero. Ensures that any field sequence annotation currently on
9601 // "op1" or its components is augmented by appending "fieldSeq". In practice, if "op1" is a GT_LCL_FLD, it has
9602 // a field sequence as a member; otherwise, it may be the addition of an a byref and a constant, where the const
9603 // has a field sequence -- in this case "fieldSeq" is appended to that of the constant; otherwise, we
9604 // record the the field sequence using the ZeroOffsetFieldMap described above.
9606 // One exception above is that "op1" is a node of type "TYP_REF" where "op1" is a GT_LCL_VAR.
9607 // This happens when System.Object vtable pointer is a regular field at offset 0 in System.Private.CoreLib in
9608 // CoreRT. Such case is handled same as the default case.
9609 void fgAddFieldSeqForZeroOffset(GenTree* op1, FieldSeqNode* fieldSeq);
9611 typedef JitHashTable<const GenTree*, JitPtrKeyFuncs<GenTree>, ArrayInfo> NodeToArrayInfoMap;
9612 NodeToArrayInfoMap* m_arrayInfoMap;
9614 NodeToArrayInfoMap* GetArrayInfoMap()
9616 Compiler* compRoot = impInlineRoot();
9617 if (compRoot->m_arrayInfoMap == nullptr)
9619 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9620 CompAllocator ialloc(getAllocator(CMK_ArrayInfoMap));
9621 compRoot->m_arrayInfoMap = new (ialloc) NodeToArrayInfoMap(ialloc);
9623 return compRoot->m_arrayInfoMap;
9626 //-----------------------------------------------------------------------------------------------------------------
9627 // Compiler::TryGetArrayInfo:
9628 // Given an indirection node, checks to see whether or not that indirection represents an array access, and
9629 // if so returns information about the array.
9632 // indir - The `GT_IND` node.
9633 // arrayInfo (out) - Information about the accessed array if this function returns true. Undefined otherwise.
9636 // True if the `GT_IND` node represents an array access; false otherwise.
9637 bool TryGetArrayInfo(GenTreeIndir* indir, ArrayInfo* arrayInfo)
9639 if ((indir->gtFlags & GTF_IND_ARR_INDEX) == 0)
9644 if (indir->gtOp1->OperIs(GT_INDEX_ADDR))
9646 GenTreeIndexAddr* const indexAddr = indir->gtOp1->AsIndexAddr();
9647 *arrayInfo = ArrayInfo(indexAddr->gtElemType, indexAddr->gtElemSize, indexAddr->gtElemOffset,
9648 indexAddr->gtStructElemClass);
9652 bool found = GetArrayInfoMap()->Lookup(indir, arrayInfo);
9657 NodeToUnsignedMap* m_memorySsaMap[MemoryKindCount];
9659 // In some cases, we want to assign intermediate SSA #'s to memory states, and know what nodes create those memory
9660 // states. (We do this for try blocks, where, if the try block doesn't do a call that loses track of the memory
9661 // state, all the possible memory states are possible initial states of the corresponding catch block(s).)
9662 NodeToUnsignedMap* GetMemorySsaMap(MemoryKind memoryKind)
9664 if (memoryKind == GcHeap && byrefStatesMatchGcHeapStates)
9666 // Use the same map for GCHeap and ByrefExposed when their states match.
9667 memoryKind = ByrefExposed;
9670 assert(memoryKind < MemoryKindCount);
9671 Compiler* compRoot = impInlineRoot();
9672 if (compRoot->m_memorySsaMap[memoryKind] == nullptr)
9674 // Create a CompAllocator that labels sub-structure with CMK_ArrayInfoMap, and use that for allocation.
9675 CompAllocator ialloc(getAllocator(CMK_ArrayInfoMap));
9676 compRoot->m_memorySsaMap[memoryKind] = new (ialloc) NodeToUnsignedMap(ialloc);
9678 return compRoot->m_memorySsaMap[memoryKind];
9681 // The Refany type is the only struct type whose structure is implicitly assumed by IL. We need its fields.
9682 CORINFO_CLASS_HANDLE m_refAnyClass;
9683 CORINFO_FIELD_HANDLE GetRefanyDataField()
9685 if (m_refAnyClass == nullptr)
9687 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9689 return info.compCompHnd->getFieldInClass(m_refAnyClass, 0);
9691 CORINFO_FIELD_HANDLE GetRefanyTypeField()
9693 if (m_refAnyClass == nullptr)
9695 m_refAnyClass = info.compCompHnd->getBuiltinClass(CLASSID_TYPED_BYREF);
9697 return info.compCompHnd->getFieldInClass(m_refAnyClass, 1);
9701 static BitSetSupport::BitSetOpCounter m_varsetOpCounter;
9703 #if ALLVARSET_COUNTOPS
9704 static BitSetSupport::BitSetOpCounter m_allvarsetOpCounter;
9707 static HelperCallProperties s_helperCallProperties;
9709 #ifdef UNIX_AMD64_ABI
9710 static var_types GetTypeFromClassificationAndSizes(SystemVClassificationType classType, int size);
9711 static var_types GetEightByteType(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9714 static void GetStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
9717 unsigned __int8* offset0,
9718 unsigned __int8* offset1);
9720 void GetStructTypeOffset(CORINFO_CLASS_HANDLE typeHnd,
9723 unsigned __int8* offset0,
9724 unsigned __int8* offset1);
9726 #endif // defined(UNIX_AMD64_ABI)
9728 void fgMorphMultiregStructArgs(GenTreeCall* call);
9729 GenTree* fgMorphMultiregStructArg(GenTree* arg, fgArgTabEntry* fgEntryPtr);
9731 bool killGCRefs(GenTree* tree);
9733 }; // end of class Compiler
9735 //---------------------------------------------------------------------------------------------------------------------
9736 // GenTreeVisitor: a flexible tree walker implemented using the curiosly-recurring-template pattern.
9738 // This class implements a configurable walker for IR trees. There are five configuration options (defaults values are
9739 // shown in parentheses):
9741 // - ComputeStack (false): when true, the walker will push each node onto the `m_ancestors` stack. "Ancestors" is a bit
9742 // of a misnomer, as the first entry will always be the current node.
9744 // - DoPreOrder (false): when true, the walker will invoke `TVisitor::PreOrderVisit` with the current node as an
9745 // argument before visiting the node's operands.
9747 // - DoPostOrder (false): when true, the walker will invoke `TVisitor::PostOrderVisit` with the current node as an
9748 // argument after visiting the node's operands.
9750 // - DoLclVarsOnly (false): when true, the walker will only invoke `TVisitor::PreOrderVisit` for lclVar nodes.
9751 // `DoPreOrder` must be true if this option is true.
9753 // - UseExecutionOrder (false): when true, then walker will visit a node's operands in execution order (e.g. if a
9754 // binary operator has the `GTF_REVERSE_OPS` flag set, the second operand will be
9755 // visited before the first).
9757 // At least one of `DoPreOrder` and `DoPostOrder` must be specified.
9759 // A simple pre-order visitor might look something like the following:
9761 // class CountingVisitor final : public GenTreeVisitor<CountingVisitor>
9766 // DoPreOrder = true
9769 // unsigned m_count;
9771 // CountingVisitor(Compiler* compiler)
9772 // : GenTreeVisitor<CountingVisitor>(compiler), m_count(0)
9776 // Compiler::fgWalkResult PreOrderVisit(GenTree* node)
9782 // This visitor would then be used like so:
9784 // CountingVisitor countingVisitor(compiler);
9785 // countingVisitor.WalkTree(root);
9787 template <typename TVisitor>
9788 class GenTreeVisitor
9791 typedef Compiler::fgWalkResult fgWalkResult;
9795 ComputeStack = false,
9797 DoPostOrder = false,
9798 DoLclVarsOnly = false,
9799 UseExecutionOrder = false,
9802 Compiler* m_compiler;
9803 ArrayStack<GenTree*> m_ancestors;
9805 GenTreeVisitor(Compiler* compiler) : m_compiler(compiler), m_ancestors(compiler->getAllocator(CMK_ArrayStack))
9807 assert(compiler != nullptr);
9809 static_assert_no_msg(TVisitor::DoPreOrder || TVisitor::DoPostOrder);
9810 static_assert_no_msg(!TVisitor::DoLclVarsOnly || TVisitor::DoPreOrder);
9813 fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
9815 return fgWalkResult::WALK_CONTINUE;
9818 fgWalkResult PostOrderVisit(GenTree** use, GenTree* user)
9820 return fgWalkResult::WALK_CONTINUE;
9824 fgWalkResult WalkTree(GenTree** use, GenTree* user)
9826 assert(use != nullptr);
9828 GenTree* node = *use;
9830 if (TVisitor::ComputeStack)
9832 m_ancestors.Push(node);
9835 fgWalkResult result = fgWalkResult::WALK_CONTINUE;
9836 if (TVisitor::DoPreOrder && !TVisitor::DoLclVarsOnly)
9838 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9839 if (result == fgWalkResult::WALK_ABORT)
9845 if ((node == nullptr) || (result == fgWalkResult::WALK_SKIP_SUBTREES))
9851 switch (node->OperGet())
9856 case GT_LCL_VAR_ADDR:
9857 case GT_LCL_FLD_ADDR:
9858 if (TVisitor::DoLclVarsOnly)
9860 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9861 if (result == fgWalkResult::WALK_ABORT)
9877 case GT_MEMORYBARRIER:
9882 case GT_START_NONGC:
9883 case GT_START_PREEMPTGC:
9885 #if !FEATURE_EH_FUNCLETS
9887 #endif // !FEATURE_EH_FUNCLETS
9891 case GT_CLS_VAR_ADDR:
9895 case GT_PINVOKE_PROLOG:
9896 case GT_PINVOKE_EPILOG:
9900 // Lclvar unary operators
9901 case GT_STORE_LCL_VAR:
9902 case GT_STORE_LCL_FLD:
9903 if (TVisitor::DoLclVarsOnly)
9905 result = reinterpret_cast<TVisitor*>(this)->PreOrderVisit(use, user);
9906 if (result == fgWalkResult::WALK_ABORT)
9913 // Standard unary operators
9942 case GT_RUNTIMELOOKUP:
9944 GenTreeUnOp* const unOp = node->AsUnOp();
9945 if (unOp->gtOp1 != nullptr)
9947 result = WalkTree(&unOp->gtOp1, unOp);
9948 if (result == fgWalkResult::WALK_ABORT)
9959 GenTreeCmpXchg* const cmpXchg = node->AsCmpXchg();
9961 result = WalkTree(&cmpXchg->gtOpLocation, cmpXchg);
9962 if (result == fgWalkResult::WALK_ABORT)
9966 result = WalkTree(&cmpXchg->gtOpValue, cmpXchg);
9967 if (result == fgWalkResult::WALK_ABORT)
9971 result = WalkTree(&cmpXchg->gtOpComparand, cmpXchg);
9972 if (result == fgWalkResult::WALK_ABORT)
9979 case GT_ARR_BOUNDS_CHECK:
9982 #endif // FEATURE_SIMD
9983 #ifdef FEATURE_HW_INTRINSICS
9984 case GT_HW_INTRINSIC_CHK:
9985 #endif // FEATURE_HW_INTRINSICS
9987 GenTreeBoundsChk* const boundsChk = node->AsBoundsChk();
9989 result = WalkTree(&boundsChk->gtIndex, boundsChk);
9990 if (result == fgWalkResult::WALK_ABORT)
9994 result = WalkTree(&boundsChk->gtArrLen, boundsChk);
9995 if (result == fgWalkResult::WALK_ABORT)
10004 GenTreeField* const field = node->AsField();
10006 if (field->gtFldObj != nullptr)
10008 result = WalkTree(&field->gtFldObj, field);
10009 if (result == fgWalkResult::WALK_ABORT)
10019 GenTreeArrElem* const arrElem = node->AsArrElem();
10021 result = WalkTree(&arrElem->gtArrObj, arrElem);
10022 if (result == fgWalkResult::WALK_ABORT)
10027 const unsigned rank = arrElem->gtArrRank;
10028 for (unsigned dim = 0; dim < rank; dim++)
10030 result = WalkTree(&arrElem->gtArrInds[dim], arrElem);
10031 if (result == fgWalkResult::WALK_ABORT)
10039 case GT_ARR_OFFSET:
10041 GenTreeArrOffs* const arrOffs = node->AsArrOffs();
10043 result = WalkTree(&arrOffs->gtOffset, arrOffs);
10044 if (result == fgWalkResult::WALK_ABORT)
10048 result = WalkTree(&arrOffs->gtIndex, arrOffs);
10049 if (result == fgWalkResult::WALK_ABORT)
10053 result = WalkTree(&arrOffs->gtArrObj, arrOffs);
10054 if (result == fgWalkResult::WALK_ABORT)
10063 GenTreeDynBlk* const dynBlock = node->AsDynBlk();
10065 GenTree** op1Use = &dynBlock->gtOp1;
10066 GenTree** op2Use = &dynBlock->gtDynamicSize;
10068 if (TVisitor::UseExecutionOrder && dynBlock->gtEvalSizeFirst)
10070 std::swap(op1Use, op2Use);
10073 result = WalkTree(op1Use, dynBlock);
10074 if (result == fgWalkResult::WALK_ABORT)
10078 result = WalkTree(op2Use, dynBlock);
10079 if (result == fgWalkResult::WALK_ABORT)
10086 case GT_STORE_DYN_BLK:
10088 GenTreeDynBlk* const dynBlock = node->AsDynBlk();
10090 GenTree** op1Use = &dynBlock->gtOp1;
10091 GenTree** op2Use = &dynBlock->gtOp2;
10092 GenTree** op3Use = &dynBlock->gtDynamicSize;
10094 if (TVisitor::UseExecutionOrder)
10096 if (dynBlock->IsReverseOp())
10098 std::swap(op1Use, op2Use);
10100 if (dynBlock->gtEvalSizeFirst)
10102 std::swap(op3Use, op2Use);
10103 std::swap(op2Use, op1Use);
10107 result = WalkTree(op1Use, dynBlock);
10108 if (result == fgWalkResult::WALK_ABORT)
10112 result = WalkTree(op2Use, dynBlock);
10113 if (result == fgWalkResult::WALK_ABORT)
10117 result = WalkTree(op3Use, dynBlock);
10118 if (result == fgWalkResult::WALK_ABORT)
10127 GenTreeCall* const call = node->AsCall();
10129 if (call->gtCallObjp != nullptr)
10131 result = WalkTree(&call->gtCallObjp, call);
10132 if (result == fgWalkResult::WALK_ABORT)
10138 for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
10140 result = WalkTree(args->pCurrent(), call);
10141 if (result == fgWalkResult::WALK_ABORT)
10147 for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
10149 result = WalkTree(args->pCurrent(), call);
10150 if (result == fgWalkResult::WALK_ABORT)
10156 if (call->gtCallType == CT_INDIRECT)
10158 if (call->gtCallCookie != nullptr)
10160 result = WalkTree(&call->gtCallCookie, call);
10161 if (result == fgWalkResult::WALK_ABORT)
10167 result = WalkTree(&call->gtCallAddr, call);
10168 if (result == fgWalkResult::WALK_ABORT)
10174 if (call->gtControlExpr != nullptr)
10176 result = WalkTree(&call->gtControlExpr, call);
10177 if (result == fgWalkResult::WALK_ABORT)
10189 assert(node->OperIsBinary());
10191 GenTreeOp* const op = node->AsOp();
10193 GenTree** op1Use = &op->gtOp1;
10194 GenTree** op2Use = &op->gtOp2;
10196 if (TVisitor::UseExecutionOrder && node->IsReverseOp())
10198 std::swap(op1Use, op2Use);
10201 if (*op1Use != nullptr)
10203 result = WalkTree(op1Use, op);
10204 if (result == fgWalkResult::WALK_ABORT)
10210 if (*op2Use != nullptr)
10212 result = WalkTree(op2Use, op);
10213 if (result == fgWalkResult::WALK_ABORT)
10223 // Finally, visit the current node
10224 if (TVisitor::DoPostOrder)
10226 result = reinterpret_cast<TVisitor*>(this)->PostOrderVisit(use, user);
10229 if (TVisitor::ComputeStack)
10238 template <bool computeStack, bool doPreOrder, bool doPostOrder, bool doLclVarsOnly, bool useExecutionOrder>
10239 class GenericTreeWalker final
10240 : public GenTreeVisitor<GenericTreeWalker<computeStack, doPreOrder, doPostOrder, doLclVarsOnly, useExecutionOrder>>
10245 ComputeStack = computeStack,
10246 DoPreOrder = doPreOrder,
10247 DoPostOrder = doPostOrder,
10248 DoLclVarsOnly = doLclVarsOnly,
10249 UseExecutionOrder = useExecutionOrder,
10253 Compiler::fgWalkData* m_walkData;
10256 GenericTreeWalker(Compiler::fgWalkData* walkData)
10257 : GenTreeVisitor<GenericTreeWalker<computeStack, doPreOrder, doPostOrder, doLclVarsOnly, useExecutionOrder>>(
10258 walkData->compiler)
10259 , m_walkData(walkData)
10261 assert(walkData != nullptr);
10265 walkData->parentStack = &this->m_ancestors;
10269 Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
10271 m_walkData->parent = user;
10272 return m_walkData->wtprVisitorFn(use, m_walkData);
10275 Compiler::fgWalkResult PostOrderVisit(GenTree** use, GenTree* user)
10277 m_walkData->parent = user;
10278 return m_walkData->wtpoVisitorFn(use, m_walkData);
10283 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10284 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10286 XX Miscellaneous Compiler stuff XX
10288 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10289 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10292 // Values used to mark the types a stack slot is used for
10294 const unsigned TYPE_REF_INT = 0x01; // slot used as a 32-bit int
10295 const unsigned TYPE_REF_LNG = 0x02; // slot used as a 64-bit long
10296 const unsigned TYPE_REF_FLT = 0x04; // slot used as a 32-bit float
10297 const unsigned TYPE_REF_DBL = 0x08; // slot used as a 64-bit float
10298 const unsigned TYPE_REF_PTR = 0x10; // slot used as a 32-bit pointer
10299 const unsigned TYPE_REF_BYR = 0x20; // slot used as a byref pointer
10300 const unsigned TYPE_REF_STC = 0x40; // slot used as a struct
10301 const unsigned TYPE_REF_TYPEMASK = 0x7F; // bits that represent the type
10303 // const unsigned TYPE_REF_ADDR_TAKEN = 0x80; // slots address was taken
10305 /*****************************************************************************
10307 * Variables to keep track of total code amounts.
10312 extern size_t grossVMsize;
10313 extern size_t grossNCsize;
10314 extern size_t totalNCsize;
10316 extern unsigned genMethodICnt;
10317 extern unsigned genMethodNCnt;
10318 extern size_t gcHeaderISize;
10319 extern size_t gcPtrMapISize;
10320 extern size_t gcHeaderNSize;
10321 extern size_t gcPtrMapNSize;
10323 #endif // DISPLAY_SIZES
10325 /*****************************************************************************
10327 * Variables to keep track of basic block counts (more data on 1 BB methods)
10330 #if COUNT_BASIC_BLOCKS
10331 extern Histogram bbCntTable;
10332 extern Histogram bbOneBBSizeTable;
10335 /*****************************************************************************
10337 * Used by optFindNaturalLoops to gather statistical information such as
10338 * - total number of natural loops
10339 * - number of loops with 1, 2, ... exit conditions
10340 * - number of loops that have an iterator (for like)
10341 * - number of loops that have a constant iterator
10346 extern unsigned totalLoopMethods; // counts the total number of methods that have natural loops
10347 extern unsigned maxLoopsPerMethod; // counts the maximum number of loops a method has
10348 extern unsigned totalLoopOverflows; // # of methods that identified more loops than we can represent
10349 extern unsigned totalLoopCount; // counts the total number of natural loops
10350 extern unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
10351 extern unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
10352 extern unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
10353 extern unsigned simpleTestLoopCount; // counts the # of loops with an iterator and a simple loop condition (iter <
10355 extern unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
10356 extern bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
10357 extern unsigned loopsThisMethod; // counts the number of loops in the current method
10358 extern bool loopOverflowThisMethod; // True if we exceeded the max # of loops in the method.
10359 extern Histogram loopCountTable; // Histogram of loop counts
10360 extern Histogram loopExitCountTable; // Histogram of loop exit counts
10362 #endif // COUNT_LOOPS
10364 /*****************************************************************************
10365 * variables to keep track of how many iterations we go in a dataflow pass
10370 extern unsigned CSEiterCount; // counts the # of iteration for the CSE dataflow
10371 extern unsigned CFiterCount; // counts the # of iteration for the Const Folding dataflow
10373 #endif // DATAFLOW_ITER
10375 #if MEASURE_BLOCK_SIZE
10376 extern size_t genFlowNodeSize;
10377 extern size_t genFlowNodeCnt;
10378 #endif // MEASURE_BLOCK_SIZE
10380 #if MEASURE_NODE_SIZE
10381 struct NodeSizeStats
10385 genTreeNodeCnt = 0;
10386 genTreeNodeSize = 0;
10387 genTreeNodeActualSize = 0;
10390 // Count of tree nodes allocated.
10391 unsigned __int64 genTreeNodeCnt;
10393 // The size we allocate.
10394 unsigned __int64 genTreeNodeSize;
10396 // The actual size of the node. Note that the actual size will likely be smaller
10397 // than the allocated size, but we sometimes use SetOper()/ChangeOper() to change
10398 // a smaller node to a larger one. TODO-Cleanup: add stats on
10399 // SetOper()/ChangeOper() usage to quantify this.
10400 unsigned __int64 genTreeNodeActualSize;
10402 extern NodeSizeStats genNodeSizeStats; // Total node size stats
10403 extern NodeSizeStats genNodeSizeStatsPerFunc; // Per-function node size stats
10404 extern Histogram genTreeNcntHist;
10405 extern Histogram genTreeNsizHist;
10406 #endif // MEASURE_NODE_SIZE
10408 /*****************************************************************************
10409 * Count fatal errors (including noway_asserts).
10413 extern unsigned fatal_badCode;
10414 extern unsigned fatal_noWay;
10415 extern unsigned fatal_NOMEM;
10416 extern unsigned fatal_noWayAssertBody;
10418 extern unsigned fatal_noWayAssertBodyArgs;
10420 extern unsigned fatal_NYI;
10421 #endif // MEASURE_FATAL
10423 /*****************************************************************************
10427 #ifdef _TARGET_XARCH_
10429 const instruction INS_SHIFT_LEFT_LOGICAL = INS_shl;
10430 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_shr;
10431 const instruction INS_SHIFT_RIGHT_ARITHM = INS_sar;
10433 const instruction INS_AND = INS_and;
10434 const instruction INS_OR = INS_or;
10435 const instruction INS_XOR = INS_xor;
10436 const instruction INS_NEG = INS_neg;
10437 const instruction INS_TEST = INS_test;
10438 const instruction INS_MUL = INS_imul;
10439 const instruction INS_SIGNED_DIVIDE = INS_idiv;
10440 const instruction INS_UNSIGNED_DIVIDE = INS_div;
10441 const instruction INS_BREAKPOINT = INS_int3;
10442 const instruction INS_ADDC = INS_adc;
10443 const instruction INS_SUBC = INS_sbb;
10444 const instruction INS_NOT = INS_not;
10446 #endif // _TARGET_XARCH_
10448 #ifdef _TARGET_ARM_
10450 const instruction INS_SHIFT_LEFT_LOGICAL = INS_lsl;
10451 const instruction INS_SHIFT_RIGHT_LOGICAL = INS_lsr;
10452 const instruction INS_SHIFT_RIGHT_ARITHM = INS_asr;
10454 const instruction INS_AND = INS_and;
10455 const instruction INS_OR = INS_orr;
10456 const instruction INS_XOR = INS_eor;
10457 const instruction INS_NEG = INS_rsb;
10458 const instruction INS_TEST = INS_tst;
10459 const instruction INS_MUL = INS_mul;
10460 const instruction INS_MULADD = INS_mla;
10461 const instruction INS_SIGNED_DIVIDE = INS_sdiv;
10462 const instruction INS_UNSIGNED_DIVIDE = INS_udiv;
10463 const instruction INS_BREAKPOINT = INS_bkpt;
10464 const instruction INS_ADDC = INS_adc;
10465 const instruction INS_SUBC = INS_sbc;
10466 const instruction INS_NOT = INS_mvn;
10468 const instruction INS_ABS = INS_vabs;
10469 const instruction INS_SQRT = INS_vsqrt;
10471 #endif // _TARGET_ARM_
10473 #ifdef _TARGET_ARM64_
10475 const instruction INS_MULADD = INS_madd;
10476 const instruction INS_BREAKPOINT = INS_bkpt;
10478 const instruction INS_ABS = INS_fabs;
10479 const instruction INS_SQRT = INS_fsqrt;
10481 #endif // _TARGET_ARM64_
10483 /*****************************************************************************/
10485 extern const BYTE genTypeSizes[];
10486 extern const BYTE genTypeAlignments[];
10487 extern const BYTE genTypeStSzs[];
10488 extern const BYTE genActualTypes[];
10490 /*****************************************************************************/
10492 // VERY_LARGE_FRAME_SIZE_REG_MASK is the set of registers we need to use for
10493 // the probing loop generated for very large stack frames (see `getVeryLargeFrameSize`).
10494 // We only use this to ensure that if we need to reserve a callee-saved register,
10495 // it will be reserved. For ARM32, only R12 and LR are non-callee-saved, non-argument
10496 // registers, so we save at least one more callee-saved register. For ARM64, however,
10497 // we already know we have at least three non-callee-saved, non-argument integer registers,
10498 // so we don't need to save any more.
10500 #ifdef _TARGET_ARM_
10501 #define VERY_LARGE_FRAME_SIZE_REG_MASK (RBM_R4)
10504 /*****************************************************************************/
10506 extern BasicBlock dummyBB;
10508 /*****************************************************************************/
10509 /*****************************************************************************/
10511 // foreach_block: An iterator over all blocks in the function.
10512 // __compiler: the Compiler* object
10513 // __block : a BasicBlock*, already declared, that gets updated each iteration.
10515 #define foreach_block(__compiler, __block) \
10516 for ((__block) = (__compiler)->fgFirstBB; (__block); (__block) = (__block)->bbNext)
10518 /*****************************************************************************/
10519 /*****************************************************************************/
10523 void dumpConvertedVarSet(Compiler* comp, VARSET_VALARG_TP vars);
10525 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10526 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10528 XX Debugging helpers XX
10530 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10531 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10534 /*****************************************************************************/
10535 /* The following functions are intended to be called from the debugger, to dump
10536 * various data structures. The can be used in the debugger Watch or Quick Watch
10537 * windows. They are designed to be short to type and take as few arguments as
10538 * possible. The 'c' versions take a Compiler*, whereas the 'd' versions use the TlsCompiler.
10539 * See the function definition comment for more details.
10542 void cBlock(Compiler* comp, BasicBlock* block);
10543 void cBlocks(Compiler* comp);
10544 void cBlocksV(Compiler* comp);
10545 void cTree(Compiler* comp, GenTree* tree);
10546 void cTrees(Compiler* comp);
10547 void cEH(Compiler* comp);
10548 void cVar(Compiler* comp, unsigned lclNum);
10549 void cVarDsc(Compiler* comp, LclVarDsc* varDsc);
10550 void cVars(Compiler* comp);
10551 void cVarsFinal(Compiler* comp);
10552 void cBlockPreds(Compiler* comp, BasicBlock* block);
10553 void cReach(Compiler* comp);
10554 void cDoms(Compiler* comp);
10555 void cLiveness(Compiler* comp);
10556 void cCVarSet(Compiler* comp, VARSET_VALARG_TP vars);
10558 void cFuncIR(Compiler* comp);
10559 void cBlockIR(Compiler* comp, BasicBlock* block);
10560 void cLoopIR(Compiler* comp, Compiler::LoopDsc* loop);
10561 void cTreeIR(Compiler* comp, GenTree* tree);
10562 int cTreeTypeIR(Compiler* comp, GenTree* tree);
10563 int cTreeKindsIR(Compiler* comp, GenTree* tree);
10564 int cTreeFlagsIR(Compiler* comp, GenTree* tree);
10565 int cOperandIR(Compiler* comp, GenTree* operand);
10566 int cLeafIR(Compiler* comp, GenTree* tree);
10567 int cIndirIR(Compiler* comp, GenTree* tree);
10568 int cListIR(Compiler* comp, GenTree* list);
10569 int cSsaNumIR(Compiler* comp, GenTree* tree);
10570 int cValNumIR(Compiler* comp, GenTree* tree);
10571 int cDependsIR(Compiler* comp, GenTree* comma, bool* first);
10573 void dBlock(BasicBlock* block);
10576 void dTree(GenTree* tree);
10579 void dVar(unsigned lclNum);
10580 void dVarDsc(LclVarDsc* varDsc);
10583 void dBlockPreds(BasicBlock* block);
10587 void dCVarSet(VARSET_VALARG_TP vars);
10589 void dRegMask(regMaskTP mask);
10592 void dBlockIR(BasicBlock* block);
10593 void dTreeIR(GenTree* tree);
10594 void dLoopIR(Compiler::LoopDsc* loop);
10595 void dLoopNumIR(unsigned loopNum);
10596 int dTabStopIR(int curr, int tabstop);
10597 int dTreeTypeIR(GenTree* tree);
10598 int dTreeKindsIR(GenTree* tree);
10599 int dTreeFlagsIR(GenTree* tree);
10600 int dOperandIR(GenTree* operand);
10601 int dLeafIR(GenTree* tree);
10602 int dIndirIR(GenTree* tree);
10603 int dListIR(GenTree* list);
10604 int dSsaNumIR(GenTree* tree);
10605 int dValNumIR(GenTree* tree);
10606 int dDependsIR(GenTree* comma);
10609 GenTree* dFindTree(GenTree* tree, unsigned id);
10610 GenTree* dFindTree(unsigned id);
10611 GenTreeStmt* dFindStmt(unsigned id);
10612 BasicBlock* dFindBlock(unsigned bbNum);
10616 #include "compiler.hpp" // All the shared inline functions
10618 /*****************************************************************************/
10619 #endif //_COMPILER_H_
10620 /*****************************************************************************/