diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index e73052a780f60..eb0e9f16759a2 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -4361,37 +4361,10 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // DoPhase(this, PHASE_INDXCALL, &Compiler::fgTransformIndirectCalls); - // PostImportPhase: cleanup inlinees + // Cleanup un-imported BBs, cleanup un-imported or + // partially imported try regions, add OSR step blocks. // - auto postImportPhase = [this]() { - - // If this is a viable inline candidate - if (compIsForInlining() && !compDonotInline()) - { - // Filter out unimported BBs in the inlinee - // - fgPostImportationCleanup(); - - // Update type of return spill temp if we have gathered - // better info when importing the inlinee, and the return - // spill temp is single def. - if (fgNeedReturnSpillTemp()) - { - CORINFO_CLASS_HANDLE retExprClassHnd = impInlineInfo->retExprClassHnd; - if (retExprClassHnd != nullptr) - { - LclVarDsc* returnSpillVarDsc = lvaGetDesc(lvaInlineeReturnSpillTemp); - - if (returnSpillVarDsc->lvSingleDef) - { - lvaUpdateClass(lvaInlineeReturnSpillTemp, retExprClassHnd, - impInlineInfo->retExprClassHndIsExact); - } - } - } - } - }; - DoPhase(this, PHASE_POST_IMPORT, postImportPhase); + DoPhase(this, PHASE_POST_IMPORT, &Compiler::fgPostImportationCleanup); // If we're importing for inlining, we're done. if (compIsForInlining()) @@ -4422,101 +4395,9 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl return; } -#if !FEATURE_EH - // If we aren't yet supporting EH in a compiler bring-up, remove as many EH handlers as possible, so - // we can pass tests that contain try/catch EH, but don't actually throw any exceptions. - fgRemoveEH(); -#endif // !FEATURE_EH - - // We could allow ESP frames. Just need to reserve space for - // pushing EBP if the method becomes an EBP-frame after an edit. - // Note that requiring a EBP Frame disallows double alignment. Thus if we change this - // we either have to disallow double alignment for E&C some other way or handle it in EETwain. - - if (opts.compDbgEnC) - { - codeGen->setFramePointerRequired(true); - - // We don't care about localloc right now. If we do support it, - // EECodeManager::FixContextForEnC() needs to handle it smartly - // in case the localloc was actually executed. - // - // compLocallocUsed = true; - } - - // Start phases that are broadly called morphing, and includes - // global morph, as well as other phases that massage the trees so - // that we can generate code out of them. + // Prepare for the morph phases // - auto morphInitPhase = [this]() { - - // Initialize the BlockSet epoch - NewBasicBlockEpoch(); - - fgOutgoingArgTemps = nullptr; - - // Insert call to class constructor as the first basic block if - // we were asked to do so. - if (info.compCompHnd->initClass(nullptr /* field */, nullptr /* method */, - impTokenLookupContextHandle /* context */) & - CORINFO_INITCLASS_USE_HELPER) - { - fgEnsureFirstBBisScratch(); - fgNewStmtAtBeg(fgFirstBB, fgInitThisClass()); - } - -#ifdef DEBUG - if (opts.compGcChecks) - { - for (unsigned i = 0; i < info.compArgsCount; i++) - { - if (lvaGetDesc(i)->TypeGet() == TYP_REF) - { - // confirm that the argument is a GC pointer (for debugging (GC stress)) - GenTree* op = gtNewLclvNode(i, TYP_REF); - op = gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_VOID, op); - - fgEnsureFirstBBisScratch(); - fgNewStmtAtEnd(fgFirstBB, op); - - if (verbose) - { - printf("\ncompGcChecks tree:\n"); - gtDispTree(op); - } - } - } - } -#endif // DEBUG - -#if defined(DEBUG) && defined(TARGET_XARCH) - if (opts.compStackCheckOnRet) - { - lvaReturnSpCheck = lvaGrabTempWithImplicitUse(false DEBUGARG("ReturnSpCheck")); - lvaSetVarDoNotEnregister(lvaReturnSpCheck, DoNotEnregisterReason::ReturnSpCheck); - lvaGetDesc(lvaReturnSpCheck)->lvType = TYP_I_IMPL; - } -#endif // defined(DEBUG) && defined(TARGET_XARCH) - -#if defined(DEBUG) && defined(TARGET_X86) - if (opts.compStackCheckOnCall) - { - lvaCallSpCheck = lvaGrabTempWithImplicitUse(false DEBUGARG("CallSpCheck")); - lvaGetDesc(lvaCallSpCheck)->lvType = TYP_I_IMPL; - } -#endif // defined(DEBUG) && defined(TARGET_X86) - - // Update flow graph after importation. - // Removes un-imported blocks, trims EH, and ensures correct OSR entry flow. - // - fgPostImportationCleanup(); - }; - DoPhase(this, PHASE_MORPH_INIT, morphInitPhase); - -#ifdef DEBUG - // Inliner could add basic blocks. Check that the flowgraph data is up-to-date - fgDebugCheckBBlist(false, false); -#endif // DEBUG + DoPhase(this, PHASE_MORPH_INIT, &Compiler::fgMorphInit); // Inline callee methods into this root method // @@ -4650,24 +4531,16 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // Run an early flow graph simplification pass // - auto earlyUpdateFlowGraphPhase = [this]() { - constexpr bool doTailDup = false; - fgUpdateFlowGraph(doTailDup); - }; - DoPhase(this, PHASE_EARLY_UPDATE_FLOW_GRAPH, earlyUpdateFlowGraphPhase); + DoPhase(this, PHASE_EARLY_UPDATE_FLOW_GRAPH, &Compiler::fgUpdateFlowGraphPhase); } // Promote struct locals // - auto promoteStructsPhase = [this]() { + DoPhase(this, PHASE_PROMOTE_STRUCTS, &Compiler::fgPromoteStructs); - // For x64 and ARM64 we need to mark irregular parameters - lvaRefCountState = RCS_EARLY; - fgResetImplicitByRefRefCount(); - - fgPromoteStructs(); - }; - DoPhase(this, PHASE_PROMOTE_STRUCTS, promoteStructsPhase); + // Enable early ref counting of locals + // + lvaRefCountState = RCS_EARLY; // Figure out what locals are address-taken. // @@ -4729,29 +4602,7 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // GS security checks for unsafe buffers // - auto gsPhase = [this]() { - unsigned prevBBCount = fgBBcount; - if (getNeedsGSSecurityCookie()) - { - gsGSChecksInitCookie(); - - if (compGSReorderStackLayout) - { - gsCopyShadowParams(); - } - - // If we needed to create any new BasicBlocks then renumber the blocks - if (fgBBcount > prevBBCount) - { - fgRenumberBlocks(); - } - } - else - { - JITDUMP("No GS security needed\n"); - } - }; - DoPhase(this, PHASE_GS_COOKIE, gsPhase); + DoPhase(this, PHASE_GS_COOKIE, &Compiler::gsPhase); // Compute the block and edge weights // @@ -4949,11 +4800,7 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl { // update the flowgraph if we modified it during the optimization phase // - auto optUpdateFlowGraphPhase = [this]() { - constexpr bool doTailDup = false; - fgUpdateFlowGraph(doTailDup); - }; - DoPhase(this, PHASE_OPT_UPDATE_FLOW_GRAPH, optUpdateFlowGraphPhase); + DoPhase(this, PHASE_OPT_UPDATE_FLOW_GRAPH, &Compiler::fgUpdateFlowGraphPhase); // Recompute the edge weight if we have modified the flow graph // diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 3291aca767c38..cc0e94cbe3600 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -2220,7 +2220,7 @@ class Compiler bool fgNormalizeEHCase2(); bool fgNormalizeEHCase3(); - void fgCreateFiltersForGenericExceptions(); + bool fgCreateFiltersForGenericExceptions(); void fgCheckForLoopsInHandlers(); @@ -4339,7 +4339,7 @@ class Compiler } BasicBlock* fgNewBasicBlock(BBjumpKinds jumpKind); - void fgEnsureFirstBBisScratch(); + bool fgEnsureFirstBBisScratch(); bool fgFirstBBisScratch(); bool fgBBisScratch(BasicBlock* block); @@ -4461,6 +4461,8 @@ class Compiler PhaseStatus fgTransformPatchpoints(); + PhaseStatus fgMorphInit(); + PhaseStatus fgInline(); PhaseStatus fgRemoveEmptyTry(); @@ -4522,7 +4524,7 @@ class Compiler // The number of separate return points in the method. unsigned fgReturnCount; - void fgAddInternal(); + PhaseStatus fgAddInternal(); enum class FoldResult { @@ -5222,7 +5224,7 @@ class Compiler unsigned fgGetNestingLevel(BasicBlock* block, unsigned* pFinallyNesting = nullptr); - void fgPostImportationCleanup(); + PhaseStatus fgPostImportationCleanup(); void fgRemoveStmt(BasicBlock* block, Statement* stmt DEBUGARG(bool isUnlink = false)); void fgUnlinkStmt(BasicBlock* block, Statement* stmt); @@ -5275,8 +5277,8 @@ class Compiler bool fgIsIntraHandlerPred(BasicBlock* predBlock, BasicBlock* block); bool fgAnyIntraHandlerPreds(BasicBlock* block); void fgInsertFuncletPrologBlock(BasicBlock* block); - void fgCreateFuncletPrologBlocks(); - void fgCreateFunclets(); + void fgCreateFuncletPrologBlocks(); + PhaseStatus fgCreateFunclets(); #else // !FEATURE_EH_FUNCLETS bool fgRelocateEHRegions(); #endif // !FEATURE_EH_FUNCLETS @@ -5301,10 +5303,10 @@ class Compiler #ifdef DEBUG void fgPrintEdgeWeights(); #endif - void fgComputeBlockAndEdgeWeights(); - weight_t fgComputeMissingBlockWeights(); - void fgComputeCalledCount(weight_t returnWeight); - void fgComputeEdgeWeights(); + PhaseStatus fgComputeBlockAndEdgeWeights(); + bool fgComputeMissingBlockWeights(weight_t* returnWeight); + bool fgComputeCalledCount(weight_t returnWeight); + PhaseStatus fgComputeEdgeWeights(); bool fgReorderBlocks(bool useProfile); @@ -5316,7 +5318,8 @@ class Compiler bool fgIsForwardBranch(BasicBlock* bJump, BasicBlock* bSrc = nullptr); - bool fgUpdateFlowGraph(bool doTailDup = false); + bool fgUpdateFlowGraph(bool doTailDup = false, bool isPhase = false); + PhaseStatus fgUpdateFlowGraphPhase(); PhaseStatus fgFindOperOrder(); @@ -5896,7 +5899,7 @@ class Compiler static fgWalkPreFn fgDebugCheckForTransformableIndirectCalls; #endif - void fgPromoteStructs(); + PhaseStatus fgPromoteStructs(); void fgMorphStructField(GenTree* tree, GenTree* parent); void fgMorphLocalField(GenTree* tree, GenTree* parent); @@ -5905,12 +5908,12 @@ class Compiler // Change implicit byrefs' types from struct to pointer, and for any that were // promoted, create new promoted struct temps. - void fgRetypeImplicitByRefArgs(); + PhaseStatus fgRetypeImplicitByRefArgs(); // Clear up annotations for any struct promotion temps created for implicit byrefs. void fgMarkDemotedImplicitByRefArgs(); - void fgMarkAddressExposedLocals(); + PhaseStatus fgMarkAddressExposedLocals(); void fgMarkAddressExposedLocals(Statement* stmt); PhaseStatus fgForwardSub(); @@ -10372,10 +10375,11 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX GSCookie gsGlobalSecurityCookieVal; // Value of global cookie if addr is NULL ShadowParamVarInfo* gsShadowVarInfo; // Table used by shadow param analysis code - void gsGSChecksInitCookie(); // Grabs cookie variable - void gsCopyShadowParams(); // Identify vulnerable params and create dhadow copies - bool gsFindVulnerableParams(); // Shadow param analysis code - void gsParamsToShadows(); // Insert copy code and replave param uses by shadow + PhaseStatus gsPhase(); + void gsGSChecksInitCookie(); // Grabs cookie variable + void gsCopyShadowParams(); // Identify vulnerable params and create dhadow copies + bool gsFindVulnerableParams(); // Shadow param analysis code + void gsParamsToShadows(); // Insert copy code and replave param uses by shadow static fgWalkPreFn gsMarkPtrsAndAssignGroups; // Shadow param analysis tree-walk static fgWalkPreFn gsReplaceShadowParams; // Shadow param replacement tree-walk diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 7f29a055fd6d2..f4e078cbaa1bc 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -231,7 +231,7 @@ BasicBlock* Compiler::fgNewBasicBlock(BBjumpKinds jumpKind) // fgEnsureFirstBBisScratch: Ensure that fgFirstBB is a scratch BasicBlock // // Returns: -// Nothing. May allocate a new block and alter the value of fgFirstBB. +// True, if a new basic block was allocated. // // Notes: // This should be called before adding on-entry initialization code to @@ -249,12 +249,12 @@ BasicBlock* Compiler::fgNewBasicBlock(BBjumpKinds jumpKind) // // Can be called at any time, and can be called multiple times. // -void Compiler::fgEnsureFirstBBisScratch() +bool Compiler::fgEnsureFirstBBisScratch() { // Have we already allocated a scratch block? if (fgFirstBBisScratch()) { - return; + return false; } assert(fgFirstBBScratch == nullptr); @@ -303,6 +303,8 @@ void Compiler::fgEnsureFirstBBisScratch() printf("New scratch " FMT_BB "\n", block->bbNum); } #endif + + return true; } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/fgflow.cpp b/src/coreclr/jit/fgflow.cpp index 861902b5a9cb0..0eccd90a6c5b2 100644 --- a/src/coreclr/jit/fgflow.cpp +++ b/src/coreclr/jit/fgflow.cpp @@ -673,13 +673,6 @@ void Compiler::fgComputePreds() noway_assert(fgFirstBB != nullptr); #ifdef DEBUG - if (verbose) - { - printf("\n*************** In fgComputePreds()\n"); - fgDispBasicBlocks(); - printf("\n"); - } - // Check that the block numbers are increasing order. unsigned lastBBnum = fgFirstBB->bbNum; for (BasicBlock* const block : Blocks(fgFirstBB->bbNext)) @@ -831,15 +824,6 @@ void Compiler::fgComputePreds() fgModified = false; fgComputePredsDone = true; - -#ifdef DEBUG - if (verbose) - { - printf("\n*************** After fgComputePreds()\n"); - fgDispBasicBlocks(); - printf("\n"); - } -#endif } unsigned Compiler::fgNSuccsOfFinallyRet(BasicBlock* block) diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index 86a42a2b87a88..7c8cdd27e0609 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -652,6 +652,11 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitorretExprClassHnd; + if (retExprClassHnd != nullptr) + { + LclVarDsc* returnSpillVarDsc = lvaGetDesc(lvaInlineeReturnSpillTemp); + + if (returnSpillVarDsc->lvSingleDef) + { + lvaUpdateClass(lvaInlineeReturnSpillTemp, retExprClassHnd, impInlineInfo->retExprClassHndIsExact); + } + } + } + } BasicBlock* cur; BasicBlock* nxt; @@ -1462,7 +1490,7 @@ void Compiler::fgPostImportationCleanup() // if ((removedBlks == 0) && !(opts.IsOSR() && fgOSREntryBB->hasTryIndex())) { - return; + return PhaseStatus::MODIFIED_NOTHING; } // Update all references in the exception handler table. @@ -1662,6 +1690,8 @@ void Compiler::fgPostImportationCleanup() // If this is OSR, and the OSR entry was mid-try or in a nested try entry, // add the appropriate step block logic. // + unsigned addedBlocks = 0; + if (opts.IsOSR()) { BasicBlock* const osrEntry = fgOSREntryBB; @@ -1700,8 +1730,8 @@ void Compiler::fgPostImportationCleanup() // Helper method to add flow // - auto addConditionalFlow = [this, entryStateVar, &entryJumpTarget](BasicBlock* fromBlock, - BasicBlock* toBlock) { + auto addConditionalFlow = [this, entryStateVar, &entryJumpTarget, &addedBlocks](BasicBlock* fromBlock, + BasicBlock* toBlock) { // We may have previously though this try entry was unreachable, but now we're going to // step through it on the way to the OSR entry. So ensure it has plausible profile weight. @@ -1716,6 +1746,7 @@ void Compiler::fgPostImportationCleanup() BasicBlock* const newBlock = fgSplitBlockAtBeginning(fromBlock); fromBlock->bbFlags |= BBF_INTERNAL; newBlock->bbFlags &= ~BBF_DONT_REMOVE; + addedBlocks++; GenTree* const entryStateLcl = gtNewLclvNode(entryStateVar, TYP_INT); GenTree* const compareEntryStateToZero = @@ -1807,13 +1838,23 @@ void Compiler::fgPostImportationCleanup() } } - // Renumber the basic blocks - JITDUMP("\nRenumbering the basic blocks for fgPostImporterCleanup\n"); - fgRenumberBlocks(); + // Did we alter any flow or EH? + // + const bool madeChanges = (addedBlocks > 0) || (delCnt > 0) || (removedBlks > 0); + + // Renumber the basic blocks if so. + // + if (madeChanges) + { + JITDUMP("\nRenumbering the basic blocks for fgPostImportationCleanup\n"); + fgRenumberBlocks(); + } #ifdef DEBUG fgVerifyHandlerTab(); #endif // DEBUG + + return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; } //------------------------------------------------------------- @@ -2779,7 +2820,8 @@ bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block) { assert(block->isEmpty()); - BasicBlock* bPrev = block->bbPrev; + bool madeChanges = false; + BasicBlock* bPrev = block->bbPrev; switch (block->bbJumpKind) { @@ -2918,6 +2960,8 @@ bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block) gtSetStmtInfo(nopStmt); } + madeChanges = true; + #ifdef DEBUG if (verbose) { @@ -2976,13 +3020,15 @@ bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block) /* Remove the block */ compCurBB = block; fgRemoveBlock(block, /* unreachable */ false); - return true; + madeChanges = true; + break; default: noway_assert(!"Unexpected bbJumpKind"); break; } - return false; + + return madeChanges; } //------------------------------------------------------------- @@ -5875,6 +5921,21 @@ bool Compiler::fgReorderBlocks(bool useProfile) #pragma warning(pop) #endif +//------------------------------------------------------------- +// fgUpdateFlowGraphPhase: run flow graph optimization as a +// phase, with no tail duplication +// +// Returns: +// Suitable phase status +// +PhaseStatus Compiler::fgUpdateFlowGraphPhase() +{ + constexpr bool doTailDup = false; + constexpr bool isPhase = true; + const bool madeChanges = fgUpdateFlowGraph(doTailDup, isPhase); + return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; +} + //------------------------------------------------------------- // fgUpdateFlowGraph: Removes any empty blocks, unreachable blocks, and redundant jumps. // Most of those appear after dead store removal and folding of conditionals. @@ -5882,6 +5943,7 @@ bool Compiler::fgReorderBlocks(bool useProfile) // // Arguments: // doTailDuplication - true to attempt tail duplication optimization +// isPhase - true if being run as the only thing in a phase // // Returns: true if the flowgraph has been modified // @@ -5889,10 +5951,10 @@ bool Compiler::fgReorderBlocks(bool useProfile) // Debuggable code and Min Optimization JIT also introduces basic blocks // but we do not optimize those! // -bool Compiler::fgUpdateFlowGraph(bool doTailDuplication) +bool Compiler::fgUpdateFlowGraph(bool doTailDuplication, bool isPhase) { #ifdef DEBUG - if (verbose) + if (verbose && !isPhase) { printf("\n*************** In fgUpdateFlowGraph()"); } @@ -5903,7 +5965,7 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication) noway_assert(opts.OptimizationEnabled()); #ifdef DEBUG - if (verbose) + if (verbose && !isPhase) { printf("\nBefore updating the flow graph:\n"); fgDispBasicBlocks(verboseTrees); @@ -6371,32 +6433,32 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication) } while (change); #ifdef DEBUG - if (verbose && modified) + if (!isPhase) { - printf("\nAfter updating the flow graph:\n"); - fgDispBasicBlocks(verboseTrees); - fgDispHandlerTab(); - } + if (verbose && modified) + { + printf("\nAfter updating the flow graph:\n"); + fgDispBasicBlocks(verboseTrees); + fgDispHandlerTab(); + } - if (compRationalIRForm) - { - for (BasicBlock* const block : Blocks()) + if (compRationalIRForm) { - LIR::AsRange(block).CheckLIR(this); + for (BasicBlock* const block : Blocks()) + { + LIR::AsRange(block).CheckLIR(this); + } } - } - fgVerifyHandlerTab(); - // Make sure that the predecessor lists are accurate - fgDebugCheckBBlist(); - fgDebugCheckUpdate(); + fgVerifyHandlerTab(); + // Make sure that the predecessor lists are accurate + fgDebugCheckBBlist(); + fgDebugCheckUpdate(); + } #endif // DEBUG return modified; } -#ifdef _PREFAST_ -#pragma warning(pop) -#endif //------------------------------------------------------------- // fgGetCodeEstimate: Compute a code size estimate for the block, including all statements diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp index bf3e77fc78405..22ef8e2d32911 100644 --- a/src/coreclr/jit/fgprofile.cpp +++ b/src/coreclr/jit/fgprofile.cpp @@ -3464,15 +3464,16 @@ void flowList::setEdgeWeights(weight_t theMinWeight, weight_t theMaxWeight, Basi // fgComputeBlockAndEdgeWeights: determine weights for blocks // and optionally for edges // -void Compiler::fgComputeBlockAndEdgeWeights() +// Returns: +// Suitable phase status +// +PhaseStatus Compiler::fgComputeBlockAndEdgeWeights() { - JITDUMP("*************** In fgComputeBlockAndEdgeWeights()\n"); - const bool usingProfileWeights = fgIsUsingProfileWeights(); - - fgModified = false; - fgHaveValidEdgeWeights = false; - fgCalledCount = BB_UNITY_WEIGHT; + bool madeChanges = false; + fgModified = false; + fgHaveValidEdgeWeights = false; + fgCalledCount = BB_UNITY_WEIGHT; #if DEBUG if (verbose) @@ -3482,35 +3483,47 @@ void Compiler::fgComputeBlockAndEdgeWeights() } #endif // DEBUG - const weight_t returnWeight = fgComputeMissingBlockWeights(); + weight_t returnWeight = BB_UNITY_WEIGHT; + + madeChanges |= fgComputeMissingBlockWeights(&returnWeight); if (usingProfileWeights) { - fgComputeCalledCount(returnWeight); + madeChanges |= fgComputeCalledCount(returnWeight); } else { JITDUMP(" -- no profile data, so using default called count\n"); } - fgComputeEdgeWeights(); + PhaseStatus edgeStatus = fgComputeEdgeWeights(); + + if (edgeStatus != PhaseStatus::MODIFIED_NOTHING) + { + return edgeStatus; + } + + return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; } //------------------------------------------------------------- // fgComputeMissingBlockWeights: determine weights for blocks // that were not profiled and do not yet have weights. // +// Arguments +// returnWeight [out] - sum of weights for all return and throw blocks +// // Returns: -// sum of weights for all return and throw blocks in the method - -weight_t Compiler::fgComputeMissingBlockWeights() +// true if any changes made +// +bool Compiler::fgComputeMissingBlockWeights(weight_t* returnWeight) { BasicBlock* bSrc; BasicBlock* bDst; unsigned iterations = 0; bool changed; bool modified = false; - weight_t returnWeight; + weight_t weight; // If we have any blocks that did not have profile derived weight // we will try to fix their weight up here @@ -3518,8 +3531,8 @@ weight_t Compiler::fgComputeMissingBlockWeights() modified = false; do // while (changed) { - changed = false; - returnWeight = 0; + changed = false; + weight = 0; iterations++; for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext) @@ -3640,7 +3653,7 @@ weight_t Compiler::fgComputeMissingBlockWeights() // if (bDst->hasProfileWeight() && bDst->KindIs(BBJ_RETURN, BBJ_THROW)) { - returnWeight += bDst->bbWeight; + weight += bDst->bbWeight; } } } @@ -3658,7 +3671,9 @@ weight_t Compiler::fgComputeMissingBlockWeights() } #endif - return returnWeight; + *returnWeight = weight; + + return modified; } //------------------------------------------------------------- @@ -3667,12 +3682,16 @@ weight_t Compiler::fgComputeMissingBlockWeights() // // Argument: // returnWeight - sum of weights for all return and throw blocks - -void Compiler::fgComputeCalledCount(weight_t returnWeight) +// +// Returns: +// true if any changes were made +// +bool Compiler::fgComputeCalledCount(weight_t returnWeight) { // When we are not using profile data we have already setup fgCalledCount // only set it here if we are using profile data assert(fgIsUsingProfileWeights()); + bool madeChanges = false; BasicBlock* firstILBlock = fgFirstBB; // The first block for IL code (i.e. for the IL code at offset 0) @@ -3714,6 +3733,7 @@ void Compiler::fgComputeCalledCount(weight_t returnWeight) if (fgFirstBBisScratch()) { fgFirstBB->setBBProfileWeight(fgCalledCount); + madeChanges = true; } #if DEBUG @@ -3722,12 +3742,17 @@ void Compiler::fgComputeCalledCount(weight_t returnWeight) printf("We are using the Profile Weights and fgCalledCount is " FMT_WT "\n", fgCalledCount); } #endif + + return madeChanges; } //------------------------------------------------------------- // fgComputeEdgeWeights: compute edge weights from block weights - -void Compiler::fgComputeEdgeWeights() +// +// Returns: +// Suitable phase status +// +PhaseStatus Compiler::fgComputeEdgeWeights() { const bool isOptimizing = opts.OptimizationEnabled(); const bool usingProfileWeights = fgIsUsingProfileWeights(); @@ -3735,7 +3760,7 @@ void Compiler::fgComputeEdgeWeights() if (!isOptimizing || !usingProfileWeights) { JITDUMP(" -- not optimizing or no profile data, so not computing edge weights\n"); - return; + return PhaseStatus::MODIFIED_NOTHING; } BasicBlock* bSrc; @@ -4102,6 +4127,8 @@ EARLY_EXIT:; fgHaveValidEdgeWeights = !inconsistentProfileData; fgEdgeWeightsComputed = true; + + return PhaseStatus::MODIFIED_EVERYTHING; } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 7d57cdcb65eac..adb0c53158342 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -2210,7 +2210,10 @@ class MergedReturns //------------------------------------------------------------------------ // PlaceReturns: Move any generated const return blocks to an appropriate - // spot in the lexical block list. + // spot in the lexical block list. + // + // Returns: + // True if any returns were impacted. // // Notes: // The goal is to set things up favorably for a reasonable layout without @@ -2221,12 +2224,12 @@ class MergedReturns // there to it can become fallthrough without requiring any motion to be // performed by fgReorderBlocks. // - void PlaceReturns() + bool PlaceReturns() { if (!mergingReturns) { // No returns generated => no returns to place. - return; + return false; } for (unsigned index = 0; index < comp->fgReturnCount; ++index) @@ -2249,6 +2252,8 @@ class MergedReturns // affect program behavior. comp->fgExtendEHRegionAfter(insertionPoint); } + + return true; } private: @@ -2581,24 +2586,35 @@ class MergedReturns }; } -/***************************************************************************** -* -* Add any internal blocks/trees we may need -*/ - -void Compiler::fgAddInternal() +//------------------------------------------------------------------------ +// fgAddInternal: add blocks and trees to express special method semantics +// +// Notes: +// * rewrites shared generic catches in to filters +// * adds code to handle modifiable this +// * determines number of epilogs and merges returns +// * does special setup for pinvoke/reverse pinvoke methods +// * adds callouts and EH for synchronized methods +// * adds just my code callback +// +// Returns: +// Suitable phase status. +// +PhaseStatus Compiler::fgAddInternal() { noway_assert(!compIsForInlining()); + bool madeChanges = false; + // For runtime determined Exception types we're going to emit a fake EH filter with isinst for this // type with a runtime lookup - fgCreateFiltersForGenericExceptions(); + madeChanges |= fgCreateFiltersForGenericExceptions(); // The backend requires a scratch BB into which it can safely insert a P/Invoke method prolog if one is // required. Similarly, we need a scratch BB for poisoning. Create it here. if (compMethodRequiresPInvokeFrame() || compShouldPoisonFrame()) { - fgEnsureFirstBBisScratch(); + madeChanges |= fgEnsureFirstBBisScratch(); fgFirstBB->bbFlags |= BBF_DONT_REMOVE; } @@ -2660,6 +2676,8 @@ void Compiler::fgAddInternal() printf("\n"); } #endif + + madeChanges = true; } } @@ -2732,7 +2750,7 @@ void Compiler::fgAddInternal() } } - merger.PlaceReturns(); + madeChanges |= merger.PlaceReturns(); if (compMethodRequiresPInvokeFrame()) { @@ -2796,6 +2814,8 @@ void Compiler::fgAddInternal() fgEnsureFirstBBisScratch(); fgNewStmtAtEnd(fgFirstBB, gtNewQmarkNode(TYP_VOID, guardCheckCond, callback->AsColon())); + + madeChanges = true; } #if !defined(FEATURE_EH_FUNCLETS) @@ -2872,6 +2892,7 @@ void Compiler::fgAddInternal() // Reset cookies used to track start and end of the protected region in synchronized methods syncStartEmitCookie = NULL; syncEndEmitCookie = NULL; + madeChanges = true; } #endif // !FEATURE_EH_FUNCLETS @@ -2879,6 +2900,7 @@ void Compiler::fgAddInternal() if (opts.IsReversePInvoke()) { fgAddReversePInvokeEnterExit(); + madeChanges = true; } #ifdef DEBUG @@ -2889,6 +2911,8 @@ void Compiler::fgAddInternal() fgDispHandlerTab(); } #endif + + return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; } /*****************************************************************************/ @@ -3275,16 +3299,17 @@ void Compiler::fgInsertFuncletPrologBlock(BasicBlock* block) assert((newHead->bbFlags & BBF_INTERNAL) == BBF_INTERNAL); } -/***************************************************************************** - * - * Every funclet will have a prolog. That prolog will be inserted as the first instructions - * in the first block of the funclet. If the prolog is also the head block of a loop, we - * would end up with the prolog instructions being executed more than once. - * Check for this by searching the predecessor list for loops, and create a new prolog header - * block when needed. We detect a loop by looking for any predecessor that isn't in the - * handler's try region, since the only way to get into a handler is via that try region. - */ - +//------------------------------------------------------------------------ +// fgCreateFuncletPrologBlocks: create prolog blocks for funclets if needed +// +// Notes: +// Every funclet will have a prolog. That prolog will be inserted as the first instructions +// in the first block of the funclet. If the prolog is also the head block of a loop, we +// would end up with the prolog instructions being executed more than once. +// Check for this by searching the predecessor list for loops, and create a new prolog header +// block when needed. We detect a loop by looking for any predecessor that isn't in the +// handler's try region, since the only way to get into a handler is via that try region. +// void Compiler::fgCreateFuncletPrologBlocks() { noway_assert(fgComputePredsDone); @@ -3341,23 +3366,19 @@ void Compiler::fgCreateFuncletPrologBlocks() } } -/***************************************************************************** - * - * Function to create funclets out of all EH catch/finally/fault blocks. - * We only move filter and handler blocks, not try blocks. - */ - -void Compiler::fgCreateFunclets() +//------------------------------------------------------------------------ +// fgCreateFunclets: create funclets for EH catch/finally/fault blocks. +// +// Returns: +// Suitable phase status +// +// Notes: +// We only move filter and handler blocks, not try blocks. +// +PhaseStatus Compiler::fgCreateFunclets() { assert(!fgFuncletsCreated); -#ifdef DEBUG - if (verbose) - { - printf("*************** In fgCreateFunclets()\n"); - } -#endif - fgCreateFuncletPrologBlocks(); unsigned XTnum; @@ -3417,17 +3438,7 @@ void Compiler::fgCreateFunclets() fgFuncletsCreated = true; -#if DEBUG - if (verbose) - { - JITDUMP("\nAfter fgCreateFunclets()"); - fgDispBasicBlocks(); - fgDispHandlerTab(); - } - - fgVerifyHandlerTab(); - fgDebugCheckBBlist(); -#endif // DEBUG + return (compHndBBtabCount > 0) ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/gschecks.cpp b/src/coreclr/jit/gschecks.cpp index f115a6e36b14e..3030501ea6ea6 100644 --- a/src/coreclr/jit/gschecks.cpp +++ b/src/coreclr/jit/gschecks.cpp @@ -15,6 +15,42 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #pragma hdrstop #endif +//------------------------------------------------------------------------ +// gsPhase: modify IR and symbols to implement stack security checks +// +// Returns: +// Suitable phase status +// +PhaseStatus Compiler::gsPhase() +{ + bool madeChanges = false; + + if (getNeedsGSSecurityCookie()) + { + unsigned const prevBBCount = fgBBcount; + gsGSChecksInitCookie(); + + if (compGSReorderStackLayout) + { + gsCopyShadowParams(); + } + + // If we needed to create any new BasicBlocks then renumber the blocks + if (fgBBcount > prevBBCount) + { + fgRenumberBlocks(); + } + + madeChanges = true; + } + else + { + JITDUMP("No GS security needed\n"); + } + + return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; +} + /***************************************************************************** * gsGSChecksInitCookie * Grabs the cookie for detecting overflow of unsafe buffers. diff --git a/src/coreclr/jit/jiteh.cpp b/src/coreclr/jit/jiteh.cpp index 278723442c316..0c3dc5b6fd27e 100644 --- a/src/coreclr/jit/jiteh.cpp +++ b/src/coreclr/jit/jiteh.cpp @@ -2512,9 +2512,13 @@ bool Compiler::fgNormalizeEHCase2() // EH filter that performs "catchArg isinst T!!" and in case of success forwards to the // original EH handler. // - -void Compiler::fgCreateFiltersForGenericExceptions() +// Returns: +// True if any changes were made +// +bool Compiler::fgCreateFiltersForGenericExceptions() { + bool madeChanges = false; + for (unsigned ehNum = 0; ehNum < compHndBBtabCount; ehNum++) { EHblkDsc* eh = ehGetDsc(ehNum); @@ -2589,8 +2593,12 @@ void Compiler::fgCreateFiltersForGenericExceptions() fgDumpBlock(filterBb); } #endif // DEBUG + + madeChanges = true; } } + + return madeChanges; } bool Compiler::fgNormalizeEHCase3() diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index cb75328eccb76..6cfacbdf2e7ca 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -298,7 +298,8 @@ class LocalAddressVisitor final : public GenTreeVisitor }; ArrayStack m_valueStack; - INDEBUG(bool m_stmtModified;) + bool m_stmtModified; + bool m_madeChanges; public: enum @@ -311,10 +312,18 @@ class LocalAddressVisitor final : public GenTreeVisitor }; LocalAddressVisitor(Compiler* comp) - : GenTreeVisitor(comp), m_valueStack(comp->getAllocator(CMK_LocalAddressVisitor)) + : GenTreeVisitor(comp) + , m_valueStack(comp->getAllocator(CMK_LocalAddressVisitor)) + , m_stmtModified(false) + , m_madeChanges(false) { } + bool MadeChanges() const + { + return m_madeChanges; + } + void VisitStmt(Statement* stmt) { #ifdef DEBUG @@ -322,10 +331,10 @@ class LocalAddressVisitor final : public GenTreeVisitor { printf("LocalAddressVisitor visiting statement:\n"); m_compiler->gtDispStmt(stmt); - m_stmtModified = false; } #endif // DEBUG + m_stmtModified = false; WalkTree(stmt->GetRootNodePointer(), nullptr); // We could have something a statement like IND(ADDR(LCL_VAR)) so we need to escape @@ -345,6 +354,7 @@ class LocalAddressVisitor final : public GenTreeVisitor PopValue(); assert(m_valueStack.Empty()); + m_madeChanges |= m_stmtModified; #ifdef DEBUG if (m_compiler->verbose) @@ -873,9 +883,8 @@ class LocalAddressVisitor final : public GenTreeVisitor } // Local address nodes never have side effects (nor any other flags, at least at this point). - addr->gtFlags = GTF_EMPTY; - - INDEBUG(m_stmtModified = true;) + addr->gtFlags = GTF_EMPTY; + m_stmtModified = true; } //------------------------------------------------------------------------ @@ -902,7 +911,7 @@ class LocalAddressVisitor final : public GenTreeVisitor case IndirTransform::Nop: indir->gtBashToNOP(); - INDEBUG(m_stmtModified = true); + m_stmtModified = true; return; case IndirTransform::LclVar: @@ -942,8 +951,7 @@ class LocalAddressVisitor final : public GenTreeVisitor } lclNode->gtFlags = lclNodeFlags; - - INDEBUG(m_stmtModified = true); + m_stmtModified = true; } //------------------------------------------------------------------------ @@ -1065,7 +1073,7 @@ class LocalAddressVisitor final : public GenTreeVisitor assert(node->OperIs(GT_FIELD)); // TODO-Cleanup: Move fgMorphStructField implementation here, it's not used anywhere else. m_compiler->fgMorphStructField(node, user); - INDEBUG(m_stmtModified |= node->OperIs(GT_LCL_VAR);) + m_stmtModified |= node->OperIs(GT_LCL_VAR); } //------------------------------------------------------------------------ @@ -1088,7 +1096,7 @@ class LocalAddressVisitor final : public GenTreeVisitor assert(node->OperIs(GT_LCL_FLD)); // TODO-Cleanup: Move fgMorphLocalField implementation here, it's not used anywhere else. m_compiler->fgMorphLocalField(node, user); - INDEBUG(m_stmtModified |= node->OperIs(GT_LCL_VAR);) + m_stmtModified |= node->OperIs(GT_LCL_VAR); } //------------------------------------------------------------------------ @@ -1197,20 +1205,16 @@ class LocalAddressVisitor final : public GenTreeVisitor // fgMarkAddressExposedLocals: Traverses the entire method and marks address // exposed locals. // +// Returns: +// Suitable phase status +// // Notes: // Trees such as IND(ADDR(LCL_VAR)), that morph is expected to fold // to just LCL_VAR, do not result in the involved local being marked // address exposed. // -void Compiler::fgMarkAddressExposedLocals() +PhaseStatus Compiler::fgMarkAddressExposedLocals() { -#ifdef DEBUG - if (verbose) - { - printf("\n*************** In fgMarkAddressExposedLocals()\n"); - } -#endif // DEBUG - LocalAddressVisitor visitor(this); for (BasicBlock* const block : Blocks()) @@ -1223,6 +1227,8 @@ void Compiler::fgMarkAddressExposedLocals() visitor.VisitStmt(stmt); } } + + return visitor.MadeChanges() ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index fff00343e888a..ff657de745a7c 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -17,6 +17,101 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "allocacheck.h" // for alloca +//------------------------------------------------------------- +// fgMorphInit: prepare for running the morph phases +// +// Returns: +// suitable phase status +// +PhaseStatus Compiler::fgMorphInit() +{ + bool madeChanges = false; + +#if !FEATURE_EH + // If we aren't yet supporting EH in a compiler bring-up, remove as many EH handlers as possible, so + // we can pass tests that contain try/catch EH, but don't actually throw any exceptions. + fgRemoveEH(); + madeChanges = true; +#endif // !FEATURE_EH + + // We could allow ESP frames. Just need to reserve space for + // pushing EBP if the method becomes an EBP-frame after an edit. + // Note that requiring a EBP Frame disallows double alignment. Thus if we change this + // we either have to disallow double alignment for E&C some other way or handle it in EETwain. + + if (opts.compDbgEnC) + { + codeGen->setFramePointerRequired(true); + + // We don't care about localloc right now. If we do support it, + // EECodeManager::FixContextForEnC() needs to handle it smartly + // in case the localloc was actually executed. + // + // compLocallocUsed = true; + } + + // Initialize the BlockSet epoch + NewBasicBlockEpoch(); + + fgOutgoingArgTemps = nullptr; + + // Insert call to class constructor as the first basic block if + // we were asked to do so. + if (info.compCompHnd->initClass(nullptr /* field */, nullptr /* method */, + impTokenLookupContextHandle /* context */) & + CORINFO_INITCLASS_USE_HELPER) + { + fgEnsureFirstBBisScratch(); + fgNewStmtAtBeg(fgFirstBB, fgInitThisClass()); + madeChanges = true; + } + +#ifdef DEBUG + if (opts.compGcChecks) + { + for (unsigned i = 0; i < info.compArgsCount; i++) + { + if (lvaGetDesc(i)->TypeGet() == TYP_REF) + { + // confirm that the argument is a GC pointer (for debugging (GC stress)) + GenTree* op = gtNewLclvNode(i, TYP_REF); + op = gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_VOID, op); + + fgEnsureFirstBBisScratch(); + fgNewStmtAtEnd(fgFirstBB, op); + madeChanges = true; + if (verbose) + { + printf("\ncompGcChecks tree:\n"); + gtDispTree(op); + } + } + } + } +#endif // DEBUG + +#if defined(DEBUG) && defined(TARGET_XARCH) + if (opts.compStackCheckOnRet) + { + lvaReturnSpCheck = lvaGrabTempWithImplicitUse(false DEBUGARG("ReturnSpCheck")); + lvaSetVarDoNotEnregister(lvaReturnSpCheck, DoNotEnregisterReason::ReturnSpCheck); + lvaGetDesc(lvaReturnSpCheck)->lvType = TYP_I_IMPL; + madeChanges = true; + } +#endif // defined(DEBUG) && defined(TARGET_XARCH) + +#if defined(DEBUG) && defined(TARGET_X86) + if (opts.compStackCheckOnCall) + { + lvaCallSpCheck = lvaGrabTempWithImplicitUse(false DEBUGARG("CallSpCheck")); + lvaGetDesc(lvaCallSpCheck)->lvType = TYP_I_IMPL; + madeChanges = true; + } +#endif // defined(DEBUG) && defined(TARGET_X86) + + return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; +} + // Convert the given node into a call to the specified helper passing // the given argument list. // @@ -15953,29 +16048,24 @@ void Compiler::fgPostExpandQmarkChecks() } #endif -/***************************************************************************** - * - * Promoting struct locals - */ -void Compiler::fgPromoteStructs() +//------------------------------------------------------------------------ +// fgPromoteStructs: promote structs to collections of per-field locals +// +// Returns: +// Suitable phase status. +// +PhaseStatus Compiler::fgPromoteStructs() { -#ifdef DEBUG - if (verbose) - { - printf("*************** In fgPromoteStructs()\n"); - } -#endif // DEBUG - if (!opts.OptEnabled(CLFLG_STRUCTPROMOTE)) { JITDUMP(" promotion opt flag not enabled\n"); - return; + return PhaseStatus::MODIFIED_NOTHING; } if (fgNoStructPromotion) { JITDUMP(" promotion disabled by JitNoStructPromotion\n"); - return; + return PhaseStatus::MODIFIED_NOTHING; } #if 0 @@ -15998,7 +16088,7 @@ void Compiler::fgPromoteStructs() } if (methHash < methHashLo || methHash > methHashHi) { - return; + return PhaseStatus::MODIFIED_NOTHING; } else { @@ -16012,7 +16102,7 @@ void Compiler::fgPromoteStructs() if (info.compIsVarArgs) { JITDUMP(" promotion disabled because of varargs\n"); - return; + return PhaseStatus::MODIFIED_NOTHING; } #ifdef DEBUG @@ -16031,6 +16121,7 @@ void Compiler::fgPromoteStructs() // lvaStructPromotionInfo structPromotionInfo; bool tooManyLocalsReported = false; + bool madeChanges = false; // Clear the structPromotionHelper, since it is used during inlining, at which point it // may be conservative about looking up SIMD info. @@ -16065,6 +16156,8 @@ void Compiler::fgPromoteStructs() promotedVar = structPromotionHelper->TryPromoteStructVar(lclNum); } + madeChanges |= promotedVar; + if (!promotedVar && varDsc->lvIsSIMDType() && !varDsc->lvFieldAccessed) { // Even if we have not used this in a SIMD intrinsic, if it is not being promoted, @@ -16074,12 +16167,14 @@ void Compiler::fgPromoteStructs() } #ifdef DEBUG - if (verbose) + if (verbose && madeChanges) { printf("\nlvaTable after fgPromoteStructs\n"); lvaTableDump(); } #endif // DEBUG + + return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; } void Compiler::fgMorphStructField(GenTree* tree, GenTree* parent) @@ -16339,37 +16434,6 @@ void Compiler::fgMorphLocalField(GenTree* tree, GenTree* parent) } } -//------------------------------------------------------------------------ -// fgResetImplicitByRefRefCount: Clear the ref count field of all implicit byrefs - -void Compiler::fgResetImplicitByRefRefCount() -{ -#if FEATURE_IMPLICIT_BYREFS -#ifdef DEBUG - if (verbose) - { - printf("\n*************** In fgResetImplicitByRefRefCount()\n"); - } -#endif // DEBUG - - for (unsigned lclNum = 0; lclNum < info.compArgsCount; ++lclNum) - { - LclVarDsc* varDsc = lvaGetDesc(lclNum); - - if (varDsc->lvIsImplicitByRef) - { - // Clear the ref count field; fgMarkAddressTakenLocals will increment it per - // appearance of implicit-by-ref param so that call arg morphing can do an - // optimization for single-use implicit-by-ref params whose single use is as - // an outgoing call argument. - varDsc->setLvRefCnt(0, RCS_EARLY); - varDsc->setLvRefCntWtd(0, RCS_EARLY); - } - } - -#endif // FEATURE_IMPLICIT_BYREFS -} - //------------------------------------------------------------------------ // fgRetypeImplicitByRefArgs: Update the types on implicit byref parameters' `LclVarDsc`s (from // struct to pointer). Also choose (based on address-exposed analysis) @@ -16379,15 +16443,14 @@ void Compiler::fgResetImplicitByRefRefCount() // so that fgMorphExpandImplicitByRefArg will know to rewrite their // appearances using indirections off the pointer parameters. // -void Compiler::fgRetypeImplicitByRefArgs() +// Returns: +// Suitable phase status +// +PhaseStatus Compiler::fgRetypeImplicitByRefArgs() { + bool madeChanges = false; + #if FEATURE_IMPLICIT_BYREFS -#ifdef DEBUG - if (verbose) - { - printf("\n*************** In fgRetypeImplicitByRefArgs()\n"); - } -#endif // DEBUG for (unsigned lclNum = 0; lclNum < info.compArgsCount; lclNum++) { @@ -16395,6 +16458,8 @@ void Compiler::fgRetypeImplicitByRefArgs() if (lvaIsImplicitByRefLocal(lclNum)) { + madeChanges = true; + unsigned size; if (varDsc->lvSize() > REGSIZE_BYTES) @@ -16588,6 +16653,8 @@ void Compiler::fgRetypeImplicitByRefArgs() } #endif // FEATURE_IMPLICIT_BYREFS + + return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/phase.cpp b/src/coreclr/jit/phase.cpp index 56f8fdd0262db..55fe5dec844ae 100644 --- a/src/coreclr/jit/phase.cpp +++ b/src/coreclr/jit/phase.cpp @@ -167,37 +167,39 @@ void Phase::PostPhase(PhaseStatus status) // clang-format off static Phases s_allowlist[] = { - // pre import + PHASE_PRE_IMPORT, PHASE_INCPROFILE, PHASE_IBCPREP, PHASE_IMPORTATION, PHASE_PATCHPOINTS, PHASE_IBCINSTR, PHASE_INDXCALL, - // post import - // morph init + PHASE_POST_IMPORT, + PHASE_MORPH_INIT, PHASE_MORPH_INLINE, PHASE_ALLOCATE_OBJECTS, - // add internal + PHASE_MORPH_ADD_INTERNAL, PHASE_EMPTY_TRY, PHASE_EMPTY_FINALLY, PHASE_MERGE_FINALLY_CHAINS, PHASE_CLONE_FINALLY, - // finally flags - // compute preds + PHASE_UPDATE_FINALLY_FLAGS, + PHASE_COMPUTE_PREDS, PHASE_MERGE_THROWS, - // early fg update - // promote structs - // mark addr exposed locals + PHASE_EARLY_UPDATE_FLOW_GRAPH, + PHASE_PROMOTE_STRUCTS, + PHASE_STR_ADRLCL, PHASE_FWD_SUB, - // morph implicit byref + PHASE_MORPH_IMPBYREF, // // (enable all phase checks) // PHASE_MORPH_GLOBAL, - // gs cookie - // compute edge weights - // create funclets + PHASE_GS_COOKIE, + PHASE_COMPUTE_EDGE_WEIGHTS, +#if defined(FEATURE_EH_FUNCLETS) + PHASE_CREATE_FUNCLETS, +#endif PHASE_INVERT_LOOPS, PHASE_OPTIMIZE_FLOW, // reachability @@ -221,7 +223,7 @@ void Phase::PostPhase(PhaseStatus status) // cse // assertion prop // range check - // update flow + // PHASE_OPT_UPDATE_FLOW_GRAPH, // edge weights 2 PHASE_INSERT_GC_POLLS, PHASE_OPTIMIZE_LAYOUT,