summaryrefslogtreecommitdiff
path: root/src/jit/compiler.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/compiler.h')
-rw-r--r--src/jit/compiler.h333
1 files changed, 226 insertions, 107 deletions
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index 4239cf613b..9ca0e1a3e1 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -252,8 +252,10 @@ public:
unsigned char lvStackByref : 1; // This is a compiler temporary of TYP_BYREF that is known to point into our local
// stack frame.
- unsigned char lvArgWrite : 1; // variable is a parameter and STARG was used on it
- unsigned char lvIsTemp : 1; // Short-lifetime compiler temp
+ unsigned char lvHasILStoreOp : 1; // there is at least one STLOC or STARG on this local
+ unsigned char lvHasMultipleILStoreOp : 1; // there is more than one STLOC on this local
+
+ unsigned char lvIsTemp : 1; // Short-lifetime compiler temp
#if OPT_BOOL_OPS
unsigned char lvIsBoolean : 1; // set if variable is boolean
#endif
@@ -322,6 +324,12 @@ public:
#endif // FEATURE_SIMD
unsigned char lvRegStruct : 1; // This is a reg-sized non-field-addressed struct.
+ unsigned char lvClassIsExact : 1; // lvClassHandle is the exact type
+
+#ifdef DEBUG
+ unsigned char lvClassInfoUpdated : 1; // true if this var has updated class handle or exactness
+#endif
+
union {
unsigned lvFieldLclStart; // The index of the local var representing the first field in the promoted struct
// local.
@@ -704,6 +712,8 @@ public:
typeInfo lvVerTypeInfo; // type info needed for verification
+ CORINFO_CLASS_HANDLE lvClassHnd; // class handle for the local, or null if not known
+
BYTE* lvGcLayout; // GC layout info for structs
#if ASSERTION_PROP
@@ -917,7 +927,7 @@ struct ArrayInfo
// partition a compilation.
enum Phases
{
-#define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent) enum_nm,
+#define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) enum_nm,
#include "compphases.h"
PHASE_NUMBER_OF
};
@@ -952,6 +962,7 @@ struct CompTimeInfo
static bool PhaseHasChildren[];
static int PhaseParent[];
+ static bool PhaseReportsIRSize[];
unsigned m_byteCodeBytes;
unsigned __int64 m_totalCycles;
@@ -961,6 +972,9 @@ struct CompTimeInfo
unsigned __int64 m_CLRinvokesByPhase[PHASE_NUMBER_OF];
unsigned __int64 m_CLRcyclesByPhase[PHASE_NUMBER_OF];
#endif
+
+ unsigned m_nodeCountAfterPhase[PHASE_NUMBER_OF];
+
// For better documentation, we call EndPhase on
// non-leaf phases. We should also call EndPhase on the
// last leaf subphase; obviously, the elapsed cycles between the EndPhase
@@ -1077,7 +1091,7 @@ public:
static void PrintCsvHeader();
// Ends the current phase (argument is for a redundant check).
- void EndPhase(Phases phase);
+ void EndPhase(Compiler* compiler, Phases phase);
#if MEASURE_CLRAPI_CALLS
// Start and end a timed CLR API call.
@@ -1186,11 +1200,6 @@ struct fgArgTabEntry
unsigned alignment; // 1 or 2 (slots/registers)
unsigned lateArgInx; // index into gtCallLateArgs list
unsigned tmpNum; // the LclVar number if we had to force evaluation of this arg
-#if defined(UNIX_X86_ABI)
- unsigned padStkAlign; // Count of number of padding slots for stack alignment. For each Call, only the first
- // argument may have a value to emit "sub esp, n" to adjust the stack before pushing
- // the argument.
-#endif
bool isSplit : 1; // True when this argument is split between the registers and OutArg area
bool needTmp : 1; // True when we force this argument's evaluation into a temp LclVar
@@ -1263,14 +1272,23 @@ typedef struct fgArgTabEntry* fgArgTabEntryPtr;
class fgArgInfo
{
- Compiler* compiler; // Back pointer to the compiler instance so that we can allocate memory
- GenTreePtr callTree; // Back pointer to the GT_CALL node for this fgArgInfo
- unsigned argCount; // Updatable arg count value
- unsigned nextSlotNum; // Updatable slot count value
- unsigned stkLevel; // Stack depth when we make this call (for x86)
+ Compiler* compiler; // Back pointer to the compiler instance so that we can allocate memory
+ GenTreeCall* callTree; // Back pointer to the GT_CALL node for this fgArgInfo
+ unsigned argCount; // Updatable arg count value
+ unsigned nextSlotNum; // Updatable slot count value
+ unsigned stkLevel; // Stack depth when we make this call (for x86)
+
#if defined(UNIX_X86_ABI)
- unsigned padStkAlign; // Count of number of padding slots for stack alignment. This value is used to turn back
- // stack pointer before it was adjusted after each Call
+ bool alignmentDone; // Updateable flag, set to 'true' after we've done any required alignment.
+ unsigned stkSizeBytes; // Size of stack used by this call, in bytes. Calculated during fgMorphArgs().
+ unsigned padStkAlign; // Stack alignment in bytes required before arguments are pushed for this call.
+ // Computed dynamically during codegen, based on stkSizeBytes and the current
+ // stack level (genStackLevel) when the first stack adjustment is made for
+ // this call.
+#endif
+
+#if FEATURE_FIXED_OUT_ARGS
+ unsigned outArgSize; // Size of the out arg area for the call, will be at least MIN_ARG_AREA_FOR_CALL
#endif
unsigned argTableSize; // size of argTable array (equal to the argCount when done with fgMorphArgs)
@@ -1284,8 +1302,8 @@ private:
void AddArg(fgArgTabEntryPtr curArgTabEntry);
public:
- fgArgInfo(Compiler* comp, GenTreePtr call, unsigned argCount);
- fgArgInfo(GenTreePtr newCall, GenTreePtr oldCall);
+ fgArgInfo(Compiler* comp, GenTreeCall* call, unsigned argCount);
+ fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall);
fgArgTabEntryPtr AddRegArg(
unsigned argNum, GenTreePtr node, GenTreePtr parent, regNumber regNum, unsigned numRegs, unsigned alignment);
@@ -1321,10 +1339,6 @@ public:
void ArgsComplete();
-#if defined(UNIX_X86_ABI)
- void ArgsAlignPadding();
-#endif
-
void SortArgs();
void EvalArgsToTemps();
@@ -1344,12 +1358,6 @@ public:
{
return nextSlotNum;
}
-#if defined(UNIX_X86_ABI)
- unsigned GetPadStackAlign()
- {
- return padStkAlign;
- }
-#endif
bool HasRegArgs()
{
return hasRegArgs;
@@ -1362,6 +1370,49 @@ public:
{
return argsComplete;
}
+#if FEATURE_FIXED_OUT_ARGS
+ unsigned GetOutArgSize() const
+ {
+ return outArgSize;
+ }
+ void SetOutArgSize(unsigned newVal)
+ {
+ outArgSize = newVal;
+ }
+#endif // FEATURE_FIXED_OUT_ARGS
+
+ void ComputeStackAlignment(unsigned curStackLevelInBytes)
+ {
+#if defined(UNIX_X86_ABI)
+ padStkAlign = AlignmentPad(curStackLevelInBytes, STACK_ALIGN);
+#endif // defined(UNIX_X86_ABI)
+ }
+
+ void SetStkSizeBytes(unsigned newStkSizeBytes)
+ {
+#if defined(UNIX_X86_ABI)
+ stkSizeBytes = newStkSizeBytes;
+#endif // defined(UNIX_X86_ABI)
+ }
+
+#if defined(UNIX_X86_ABI)
+ unsigned GetStkAlign()
+ {
+ return padStkAlign;
+ }
+ unsigned GetStkSizeBytes() const
+ {
+ return stkSizeBytes;
+ }
+ bool IsStkAlignmentDone() const
+ {
+ return alignmentDone;
+ }
+ void SetStkAlignmentDone()
+ {
+ alignmentDone = true;
+ }
+#endif // defined(UNIX_X86_ABI)
// Get the late arg for arg at position argIndex. Caller must ensure this position has a late arg.
GenTreePtr GetLateArg(unsigned argIndex);
@@ -2021,9 +2072,9 @@ public:
GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2);
GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2, GenTreePtr op3);
- static fgArgTabEntryPtr gtArgEntryByArgNum(GenTreePtr call, unsigned argNum);
- static fgArgTabEntryPtr gtArgEntryByNode(GenTreePtr call, GenTreePtr node);
- fgArgTabEntryPtr gtArgEntryByLateArgIndex(GenTreePtr call, unsigned lateArgInx);
+ static fgArgTabEntryPtr gtArgEntryByArgNum(GenTreeCall* call, unsigned argNum);
+ static fgArgTabEntryPtr gtArgEntryByNode(GenTreeCall* call, GenTreePtr node);
+ fgArgTabEntryPtr gtArgEntryByLateArgIndex(GenTreeCall* call, unsigned lateArgInx);
bool gtArgIsThisPtr(fgArgTabEntryPtr argEntry);
GenTreePtr gtNewAssignNode(GenTreePtr dst, GenTreePtr src);
@@ -2129,7 +2180,7 @@ public:
unsigned flags = GTF_SIDE_EFFECT,
bool ignoreRoot = false);
- GenTreePtr gtGetThisArg(GenTreePtr call);
+ GenTreePtr gtGetThisArg(GenTreeCall* call);
// Static fields of struct types (and sometimes the types that those are reduced to) are represented by having the
// static field contain an object pointer to the boxed struct. This simplifies the GC implementation...but
@@ -2138,9 +2189,10 @@ public:
bool gtIsStaticFieldPtrToBoxedStruct(var_types fieldNodeType, CORINFO_FIELD_HANDLE fldHnd);
// Return true if call is a recursive call; return false otherwise.
+ // Note when inlining, this looks for calls back to the root method.
bool gtIsRecursiveCall(GenTreeCall* call)
{
- return (call->gtCallMethHnd == info.compMethodHnd);
+ return (call->gtCallMethHnd == impInlineRoot()->info.compMethodHnd);
}
//-------------------------------------------------------------------------
@@ -2166,6 +2218,8 @@ public:
CORINFO_CLASS_HANDLE gtGetStructHandleIfPresent(GenTreePtr tree);
// Get the handle, and assert if not found.
CORINFO_CLASS_HANDLE gtGetStructHandle(GenTreePtr tree);
+ // Get the handle for a ref type.
+ CORINFO_CLASS_HANDLE gtGetClassHandle(GenTreePtr tree, bool* isExact, bool* isNonNull);
//-------------------------------------------------------------------------
// Functions to display the trees
@@ -2204,16 +2258,16 @@ public:
char* gtGetLclVarName(unsigned lclNum);
void gtDispLclVar(unsigned varNum, bool padForBiggestDisp = true);
void gtDispTreeList(GenTreePtr tree, IndentStack* indentStack = nullptr);
- void gtGetArgMsg(GenTreePtr call, GenTreePtr arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength);
- void gtGetLateArgMsg(GenTreePtr call, GenTreePtr arg, int argNum, int listCount, char* bufp, unsigned bufLength);
- void gtDispArgList(GenTreePtr tree, IndentStack* indentStack);
+ void gtGetArgMsg(GenTreeCall* call, GenTreePtr arg, unsigned argNum, int listCount, char* bufp, unsigned bufLength);
+ void gtGetLateArgMsg(GenTreeCall* call, GenTreePtr arg, int argNum, int listCount, char* bufp, unsigned bufLength);
+ void gtDispArgList(GenTreeCall* call, IndentStack* indentStack);
void gtDispFieldSeq(FieldSeqNode* pfsn);
void gtDispRange(LIR::ReadOnlyRange const& range);
void gtDispTreeRange(LIR::Range& containingRange, GenTree* tree);
- void gtDispLIRNode(GenTree* node);
+ void gtDispLIRNode(GenTree* node, const char* prefixMsg = nullptr);
#endif
// For tree walks
@@ -2399,9 +2453,9 @@ public:
// in case there are multiple BBJ_RETURN blocks in the inlinee.
#if FEATURE_FIXED_OUT_ARGS
- unsigned lvaOutgoingArgSpaceVar; // dummy TYP_LCLBLK var for fixed outgoing argument space
- unsigned lvaOutgoingArgSpaceSize; // size of fixed outgoing argument space
-#endif // FEATURE_FIXED_OUT_ARGS
+ unsigned lvaOutgoingArgSpaceVar; // dummy TYP_LCLBLK var for fixed outgoing argument space
+ PhasedVar<unsigned> lvaOutgoingArgSpaceSize; // size of fixed outgoing argument space
+#endif // FEATURE_FIXED_OUT_ARGS
#ifdef _TARGET_ARM_
// On architectures whose ABIs allow structs to be passed in registers, struct promotion will sometimes
@@ -2417,7 +2471,7 @@ public:
unsigned lvaCallEspCheck; // confirms ESP not corrupted after a call
#endif
- bool lvaGenericsContextUsed;
+ unsigned lvaGenericsContextUseCount;
bool lvaKeepAliveAndReportThis(); // Synchronized instance method of a reference type, or
// CORINFO_GENERICS_CTXT_FROM_THIS?
@@ -2564,7 +2618,7 @@ public:
void lvaMarkLocalVars(); // Local variable ref-counting
- void lvaAllocOutgoingArgSpace(); // 'Commit' lvaOutgoingArgSpaceSize and lvaOutgoingArgSpaceVar
+ void lvaAllocOutgoingArgSpaceVar(); // Set up lvaOutgoingArgSpaceVar
VARSET_VALRET_TP lvaStmtLclMask(GenTreePtr stmt);
@@ -2624,11 +2678,16 @@ public:
// Returns true if this local var is a multireg struct
bool lvaIsMultiregStruct(LclVarDsc* varDsc);
- // If the class is a TYP_STRUCT, get/set a class handle describing it
-
+ // If the local is a TYP_STRUCT, get/set a class handle describing it
CORINFO_CLASS_HANDLE lvaGetStruct(unsigned varNum);
void lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool unsafeValueClsCheck, bool setTypeInfo = true);
+ // If the local is TYP_REF, set or update the associated class information.
+ void lvaSetClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
+ void lvaSetClass(unsigned varNum, GenTreePtr tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
+ void lvaUpdateClass(unsigned varNum, CORINFO_CLASS_HANDLE clsHnd, bool isExact = false);
+ void lvaUpdateClass(unsigned varNum, GenTreePtr tree, CORINFO_CLASS_HANDLE stackHandle = nullptr);
+
#define MAX_NumOfFieldsInPromotableStruct 4 // Maximum number of fields in promotable struct
// Info about struct fields
@@ -2664,6 +2723,7 @@ public:
lvaStructPromotionInfo* StructPromotionInfo,
bool sortFields);
void lvaCanPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo);
+ bool lvaShouldPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* structPromotionInfo);
void lvaPromoteStructVar(unsigned lclNum, lvaStructPromotionInfo* StructPromotionInfo);
#if !defined(_TARGET_64BIT_)
void lvaPromoteLongVars();
@@ -2749,6 +2809,9 @@ protected:
static fgWalkPreFn lvaMarkLclRefsCallback;
void lvaMarkLclRefs(GenTreePtr tree);
+ bool IsDominatedByExceptionalEntry(BasicBlock* block);
+ void SetVolatileHint(LclVarDsc* varDsc);
+
// Keeps the mapping from SSA #'s to VN's for the implicit memory variables.
PerSsaArray lvMemoryPerSsaData;
unsigned lvMemoryNumSsaNames;
@@ -2820,6 +2883,7 @@ protected:
StackEntry impPopStack(CORINFO_CLASS_HANDLE& structTypeRet);
GenTreePtr impPopStack(typeInfo& ti);
StackEntry& impStackTop(unsigned n = 0);
+ unsigned impStackHeight();
void impSaveStackState(SavedStack* savePtr, bool copy);
void impRestoreStackState(SavedStack* savePtr);
@@ -2835,18 +2899,14 @@ protected:
bool impCanPInvokeInline();
bool impCanPInvokeInlineCallSite(BasicBlock* block);
void impCheckForPInvokeCall(
- GenTreePtr call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block);
- GenTreePtr impImportIndirectCall(CORINFO_SIG_INFO* sig, IL_OFFSETX ilOffset = BAD_IL_OFFSET);
+ GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block);
+ GenTreeCall* impImportIndirectCall(CORINFO_SIG_INFO* sig, IL_OFFSETX ilOffset = BAD_IL_OFFSET);
void impPopArgsForUnmanagedCall(GenTreePtr call, CORINFO_SIG_INFO* sig);
void impInsertHelperCall(CORINFO_HELPER_DESC* helperCall);
void impHandleAccessAllowed(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
void impHandleAccessAllowedInternal(CorInfoIsAccessAllowedResult result, CORINFO_HELPER_DESC* helperCall);
- void impInsertCalloutForDelegate(CORINFO_METHOD_HANDLE callerMethodHnd,
- CORINFO_METHOD_HANDLE calleeMethodHnd,
- CORINFO_CLASS_HANDLE delegateTypeHnd);
-
var_types impImportCall(OPCODE opcode,
CORINFO_RESOLVED_TOKEN* pResolvedToken,
CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, // Is this a "constrained." call on a
@@ -2856,9 +2916,14 @@ protected:
CORINFO_CALL_INFO* callInfo,
IL_OFFSET rawILOffset);
+ void impDevirtualizeCall(GenTreeCall* call,
+ GenTreePtr obj,
+ CORINFO_CALL_INFO* callInfo,
+ CORINFO_CONTEXT_HANDLE* exactContextHnd);
+
bool impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo);
- GenTreePtr impFixupCallStructReturn(GenTreePtr call, CORINFO_CLASS_HANDLE retClsHnd);
+ GenTreePtr impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HANDLE retClsHnd);
GenTreePtr impFixupStructReturnType(GenTreePtr op, CORINFO_CLASS_HANDLE retClsHnd);
@@ -2995,11 +3060,11 @@ public:
GenTreePtr impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP* pLookup, unsigned flags, void* compileTimeHandle);
- GenTreePtr impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
- CorInfoHelpFunc helper,
- var_types type,
- GenTreeArgList* arg = nullptr,
- CORINFO_LOOKUP_KIND* pGenericLookupKind = nullptr);
+ GenTreeCall* impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
+ CorInfoHelpFunc helper,
+ var_types type,
+ GenTreeArgList* arg = nullptr,
+ CORINFO_LOOKUP_KIND* pGenericLookupKind = nullptr);
GenTreePtr impCastClassOrIsInstToTree(GenTreePtr op1,
GenTreePtr op2,
@@ -3072,6 +3137,11 @@ private:
//---------------- Spilling the importer stack ----------------------------
+ // The maximum number of bytes of IL processed without clean stack state.
+ // It allows to limit the maximum tree size and depth.
+ static const unsigned MAX_TREE_SIZE = 200;
+ bool impCanSpillNow(OPCODE prevOpcode);
+
struct PendingDsc
{
PendingDsc* pdNext;
@@ -3303,7 +3373,10 @@ private:
GenTreePtr variableBeingDereferenced,
InlArgInfo* inlArgInfo);
- void impMarkInlineCandidate(GenTreePtr call, CORINFO_CONTEXT_HANDLE exactContextHnd, CORINFO_CALL_INFO* callInfo);
+ void impMarkInlineCandidate(GenTreePtr call,
+ CORINFO_CONTEXT_HANDLE exactContextHnd,
+ bool exactContextNeedsRuntimeLookup,
+ CORINFO_CALL_INFO* callInfo);
bool impTailCallRetTypeCompatible(var_types callerRetType,
CORINFO_CLASS_HANDLE callerRetTypeClass,
@@ -3320,6 +3393,8 @@ private:
bool impIsImplicitTailCallCandidate(
OPCODE curOpcode, const BYTE* codeAddrOfNextOpcode, const BYTE* codeEnd, int prefixFlags, bool isRecursive);
+ CORINFO_RESOLVED_TOKEN* impAllocateToken(CORINFO_RESOLVED_TOKEN token);
+
/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -3470,6 +3545,8 @@ public:
void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk);
void fgUnlinkBlock(BasicBlock* block);
+ unsigned fgMeasureIR();
+
#if OPT_BOOL_OPS // Used to detect multiple logical "not" assignments.
bool fgMultipleNots;
#endif
@@ -3517,7 +3594,7 @@ public:
bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
bool fgNeedsUpdateFlowGraph; // true if we need to run fgUpdateFlowGraph
- BasicBlock::weight_t fgCalledWeight; // count of the number of times this method was called
+ BasicBlock::weight_t fgCalledCount; // count of the number of times this method was called
// This is derived from the profile data
// or is BB_UNITY_WEIGHT when we don't have profile data
@@ -3555,15 +3632,21 @@ public:
void fgRemoveEmptyFinally();
+ void fgMergeFinallyChains();
+
void fgCloneFinally();
void fgCleanupContinuation(BasicBlock* continuation);
void fgUpdateFinallyTargetFlags();
+ bool fgRetargetBranchesToCanonicalCallFinally(BasicBlock* block,
+ BasicBlock* handler,
+ BlockToBlockMap& continuationMap);
+
GenTreePtr fgGetCritSectOfStaticMethod();
-#if !defined(_TARGET_X86_)
+#if FEATURE_EH_FUNCLETS
void fgAddSyncMethodEnterExit();
@@ -3571,7 +3654,7 @@ public:
void fgConvertSyncReturnToLeave(BasicBlock* block);
-#endif // !_TARGET_X86_
+#endif // FEATURE_EH_FUNCLETS
void fgAddReversePInvokeEnterExit();
@@ -3627,9 +3710,9 @@ public:
GenTreePtr fgInitThisClass();
- GenTreePtr fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper);
+ GenTreeCall* fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper);
- GenTreePtr fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls);
+ GenTreeCall* fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls);
void fgLocalVarLiveness();
@@ -4010,6 +4093,8 @@ protected:
// Based on: A Simple, Fast Dominance Algorithm
// by Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
+ void fgCompDominatedByExceptionalEntryBlocks();
+
BlockSet_ValRet_T fgGetDominatorSet(BasicBlock* block); // Returns a set of blocks that dominate the given block.
// Note: this is relatively slow compared to calling fgDominate(),
// especially if dealing with a single block versus block check.
@@ -4487,12 +4572,22 @@ protected:
bool fgHaveProfileData();
bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weight);
+ void fgInstrumentMethod();
+public:
+ // fgIsUsingProfileWeights - returns true if we have real profile data for this method
+ // or if we have some fake profile data for the stress mode
bool fgIsUsingProfileWeights()
{
return (fgHaveProfileData() || fgStressBBProf());
}
- void fgInstrumentMethod();
+
+ // fgProfileRunsCount - returns total number of scenario runs for the profile data
+ // or BB_UNITY_WEIGHT when we aren't using profile data.
+ unsigned fgProfileRunsCount()
+ {
+ return fgIsUsingProfileWeights() ? fgNumProfileRuns : BB_UNITY_WEIGHT;
+ }
//-------- Insert a statement at the start or end of a basic block --------
@@ -4647,7 +4742,9 @@ private:
void fgNoteNonInlineCandidate(GenTreeStmt* stmt, GenTreeCall* call);
static fgWalkPreFn fgFindNonInlineCandidate;
#endif
- GenTreePtr fgOptimizeDelegateConstructor(GenTreePtr call, CORINFO_CONTEXT_HANDLE* ExactContextHnd);
+ GenTreePtr fgOptimizeDelegateConstructor(GenTreeCall* call,
+ CORINFO_CONTEXT_HANDLE* ExactContextHnd,
+ CORINFO_RESOLVED_TOKEN* ldftnToken);
GenTreePtr fgMorphLeaf(GenTreePtr tree);
void fgAssignSetVarDef(GenTreePtr tree);
GenTreePtr fgMorphOneAsgBlockOp(GenTreePtr tree);
@@ -4789,7 +4886,7 @@ private:
static fgWalkPreFn gtHasLocalsWithAddrOpCB;
bool gtCanOptimizeTypeEquality(GenTreePtr tree);
- bool gtIsTypeHandleToRuntimeTypeHelper(GenTreePtr tree);
+ bool gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call);
bool gtIsActiveCSE_Candidate(GenTreePtr tree);
#ifdef DEBUG
@@ -5343,7 +5440,6 @@ protected:
// Keeps tracked cse indices
BitVecTraits* cseTraits;
EXPSET_TP cseFull;
- EXPSET_TP cseEmpty;
/* Generic list of nodes - used by the CSE logic */
@@ -5397,6 +5493,14 @@ protected:
CSEdsc** optCSEhash;
CSEdsc** optCSEtab;
+ typedef SimplerHashTable<GenTreePtr, PtrKeyFuncs<GenTree>, GenTreePtr, JitSimplerHashBehavior> NodeToNodeMap;
+
+ NodeToNodeMap* optCseArrLenMap; // Maps array length nodes to ancestor compares that should be
+ // re-numbered with the array length to improve range check elimination
+
+ // Given a compare, look for a cse candidate arrlen feeding it and add a map entry if found.
+ void optCseUpdateArrLenMap(GenTreePtr compare);
+
void optCSEstop();
CSEdsc* optCSEfindDsc(unsigned index);
@@ -5504,7 +5608,7 @@ protected:
callInterf ivaMaskCall; // What kind of calls are there?
};
- static callInterf optCallInterf(GenTreePtr call);
+ static callInterf optCallInterf(GenTreeCall* call);
public:
// VN based copy propagation.
@@ -5568,6 +5672,12 @@ public:
optMethodFlags &= ~OMF_HAS_FATPOINTER;
}
+ void addFatPointerCandidate(GenTreeCall* call)
+ {
+ setMethodHasFatPointer();
+ call->SetFatPointerCandidate();
+ }
+
unsigned optMethodFlags;
// Recursion bound controls how far we can go backwards tracking for a SSA value.
@@ -5602,7 +5712,6 @@ public:
// Data structures for assertion prop
BitVecTraits* apTraits;
ASSERT_TP apFull;
- ASSERT_TP apEmpty;
enum optAssertionKind
{
@@ -5773,8 +5882,20 @@ public:
bool HasSameOp1(AssertionDsc* that, bool vnBased)
{
- return (op1.kind == that->op1.kind) &&
- ((vnBased && (op1.vn == that->op1.vn)) || (!vnBased && (op1.lcl.lclNum == that->op1.lcl.lclNum)));
+ if (op1.kind != that->op1.kind)
+ {
+ return false;
+ }
+ else if (op1.kind == O1K_ARR_BND)
+ {
+ assert(vnBased);
+ return (op1.bnd.vnIdx == that->op1.bnd.vnIdx) && (op1.bnd.vnLen == that->op1.bnd.vnLen);
+ }
+ else
+ {
+ return ((vnBased && (op1.vn == that->op1.vn)) ||
+ (!vnBased && (op1.lcl.lclNum == that->op1.lcl.lclNum)));
+ }
}
bool HasSameOp2(AssertionDsc* that, bool vnBased)
@@ -5823,12 +5944,22 @@ public:
bool Equals(AssertionDsc* that, bool vnBased)
{
- return (assertionKind == that->assertionKind) && HasSameOp1(that, vnBased) && HasSameOp2(that, vnBased);
+ if (assertionKind != that->assertionKind)
+ {
+ return false;
+ }
+ else if (assertionKind == OAK_NO_THROW)
+ {
+ assert(op2.kind == O2K_INVALID);
+ return HasSameOp1(that, vnBased);
+ }
+ else
+ {
+ return HasSameOp1(that, vnBased) && HasSameOp2(that, vnBased);
+ }
}
};
- typedef unsigned short AssertionIndex;
-
protected:
static fgWalkPreFn optAddCopiesCallback;
static fgWalkPreFn optVNAssertionPropCurStmtVisitor;
@@ -5865,8 +5996,6 @@ public:
ValueNumToAssertsMap;
ValueNumToAssertsMap* optValueNumToAsserts;
- static const AssertionIndex NO_ASSERTION_INDEX = 0;
-
// Assertion prop helpers.
ASSERT_TP& GetAssertionDep(unsigned lclNum);
AssertionDsc* optGetAssertion(AssertionIndex assertIndex);
@@ -5887,8 +6016,8 @@ public:
// Assertion Gen functions.
void optAssertionGen(GenTreePtr tree);
AssertionIndex optAssertionGenPhiDefn(GenTreePtr tree);
- AssertionIndex optCreateJTrueBoundsAssertion(GenTreePtr tree);
- AssertionIndex optAssertionGenJtrue(GenTreePtr tree);
+ AssertionInfo optCreateJTrueBoundsAssertion(GenTreePtr tree);
+ AssertionInfo optAssertionGenJtrue(GenTreePtr tree);
AssertionIndex optCreateJtrueAssertions(GenTreePtr op1, GenTreePtr op2, Compiler::optAssertionKind assertionKind);
AssertionIndex optFindComplementary(AssertionIndex assertionIndex);
void optMapComplementary(AssertionIndex assertionIndex, AssertionIndex index);
@@ -5936,14 +6065,14 @@ public:
GenTreePtr optAssertionProp_LclVar(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
GenTreePtr optAssertionProp_Ind(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
GenTreePtr optAssertionProp_Cast(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
- GenTreePtr optAssertionProp_Call(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
+ GenTreePtr optAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, const GenTreePtr stmt);
GenTreePtr optAssertionProp_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
GenTreePtr optAssertionProp_Comma(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
GenTreePtr optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
GenTreePtr optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
GenTreePtr optAssertionPropLocal_RelOp(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
GenTreePtr optAssertionProp_Update(const GenTreePtr newTree, const GenTreePtr tree, const GenTreePtr stmt);
- GenTreePtr optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, const GenTreePtr tree, const GenTreePtr stmt);
+ GenTreePtr optNonNullAssertionProp_Call(ASSERT_VALARG_TP assertions, GenTreeCall* call, const GenTreePtr stmt);
// Implied assertion functions.
void optImpliedAssertions(AssertionIndex assertionIndex, ASSERT_TP& activeAssertions);
@@ -5951,9 +6080,6 @@ public:
void optImpliedByCopyAssertion(AssertionDsc* copyAssertion, AssertionDsc* depAssertion, ASSERT_TP& result);
void optImpliedByConstAssertion(AssertionDsc* curAssertion, ASSERT_TP& result);
- ASSERT_VALRET_TP optNewFullAssertSet();
- ASSERT_VALRET_TP optNewEmptyAssertSet();
-
#ifdef DEBUG
void optPrintAssertion(AssertionDsc* newAssertion, AssertionIndex assertionIndex = 0);
void optDebugCheckAssertion(AssertionDsc* assertion);
@@ -6469,11 +6595,7 @@ public:
// Returns the page size for the target machine as reported by the EE.
inline size_t eeGetPageSize()
{
-#if COR_JIT_EE_VERSION > 460
return eeGetEEInfo()->osPageSize;
-#else // COR_JIT_EE_VERSION <= 460
- return CORINFO_PAGE_SIZE;
-#endif // COR_JIT_EE_VERSION > 460
}
// Returns the frame size at which we will generate a loop to probe the stack.
@@ -6491,11 +6613,7 @@ public:
inline bool IsTargetAbi(CORINFO_RUNTIME_ABI abi)
{
-#if COR_JIT_EE_VERSION > 460
return eeGetEEInfo()->targetAbi == abi;
-#else
- return CORINFO_DESKTOP_ABI == abi;
-#endif
}
inline bool generateCFIUnwindCodes()
@@ -7690,28 +7808,20 @@ public:
// PInvoke transitions inline (e.g. when targeting CoreRT).
inline bool ShouldUsePInvokeHelpers()
{
-#if COR_JIT_EE_VERSION > 460
return jitFlags->IsSet(JitFlags::JIT_FLAG_USE_PINVOKE_HELPERS);
-#else
- return false;
-#endif
}
// true if we should use insert the REVERSE_PINVOKE_{ENTER,EXIT} helpers in the method
// prolog/epilog
inline bool IsReversePInvoke()
{
-#if COR_JIT_EE_VERSION > 460
return jitFlags->IsSet(JitFlags::JIT_FLAG_REVERSE_PINVOKE);
-#else
- return false;
-#endif
}
// true if we must generate code compatible with JIT32 quirks
inline bool IsJit32Compat()
{
-#if defined(_TARGET_X86_) && COR_JIT_EE_VERSION > 460
+#if defined(_TARGET_X86_)
return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
#else
return false;
@@ -7721,9 +7831,9 @@ public:
// true if we must generate code compatible with Jit64 quirks
inline bool IsJit64Compat()
{
-#if defined(_TARGET_AMD64_) && COR_JIT_EE_VERSION > 460
+#if defined(_TARGET_AMD64_)
return jitFlags->IsSet(JitFlags::JIT_FLAG_DESKTOP_QUIRKS);
-#elif defined(_TARGET_AMD64_) && !defined(FEATURE_CORECLR)
+#elif !defined(FEATURE_CORECLR)
return true;
#else
return false;
@@ -7760,13 +7870,11 @@ public:
// (or)
// 3. When opts.compDbgEnC is true. (See also Compiler::compCompile).
//
-// When this flag is set, jit will allocate a gc-reference local variable (lvaSecurityObject),
-// which gets reported as a GC root to stackwalker.
-// (See also ICodeManager::GetAddrOfSecurityObject.)
+ // When this flag is set, jit will allocate a gc-reference local variable (lvaSecurityObject),
+ // which gets reported as a GC root to stackwalker.
+ // (See also ICodeManager::GetAddrOfSecurityObject.)
-#if RELOC_SUPPORT
bool compReloc;
-#endif
#ifdef DEBUG
#if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
@@ -7790,8 +7898,11 @@ public:
bool genFPopt; // Can we do frame-pointer-omission optimization?
bool altJit; // True if we are an altjit and are compiling this method
+#ifdef OPT_CONFIG
+ bool optRepeat; // Repeat optimizer phases k times
+#endif
+
#ifdef DEBUG
- bool optRepeat; // Repeat optimizer phases k times
bool compProcedureSplittingEH; // Separate cold code from hot code for functions with EH
bool dspCode; // Display native code generated
bool dspEHTable; // Display the EH table reported to the VM
@@ -9371,6 +9482,10 @@ const instruction INS_ADDC = INS_adc;
const instruction INS_SUBC = INS_sbc;
const instruction INS_NOT = INS_mvn;
+const instruction INS_ABS = INS_vabs;
+const instruction INS_ROUND = INS_invalid;
+const instruction INS_SQRT = INS_vsqrt;
+
#endif
#ifdef _TARGET_ARM64_
@@ -9392,6 +9507,10 @@ const instruction INS_ADDC = INS_adc;
const instruction INS_SUBC = INS_sbc;
const instruction INS_NOT = INS_mvn;
+const instruction INS_ABS = INS_fabs;
+const instruction INS_ROUND = INS_frintn;
+const instruction INS_SQRT = INS_fsqrt;
+
#endif
/*****************************************************************************/