diff options
Diffstat (limited to 'src/jit/compiler.h')
-rw-r--r-- | src/jit/compiler.h | 333 |
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 /*****************************************************************************/ |