diff --git a/src/coreclr/jit/block.cpp b/src/coreclr/jit/block.cpp index c365b2a774a076..446733c80853cd 100644 --- a/src/coreclr/jit/block.cpp +++ b/src/coreclr/jit/block.cpp @@ -1609,9 +1609,8 @@ BasicBlock* BasicBlock::New(Compiler* compiler) block->bbNatLoopNum = BasicBlock::NOT_IN_LOOP; - block->bbPreorderNum = 0; - block->bbPostorderNum = 0; - block->bbNewPostorderNum = 0; + block->bbPreorderNum = 0; + block->bbPostorderNum = 0; return block; } diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index ba8156be7a35dd..40405678fae98d 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -1302,9 +1302,8 @@ struct BasicBlock : private LIR::Range void* bbSparseCountInfo; // Used early on by fgIncorporateEdgeCounts - unsigned bbPreorderNum; // the block's preorder number in the graph (1...fgMaxBBNum] - unsigned bbPostorderNum; // the block's postorder number in the graph (1...fgMaxBBNum] - unsigned bbNewPostorderNum; // the block's postorder number in the graph [0...postOrderCount) + unsigned bbPreorderNum; // the block's preorder number in the graph [0...postOrderCount) + unsigned bbPostorderNum; // the block's postorder number in the graph [0...postOrderCount) IL_OFFSET bbCodeOffs; // IL offset of the beginning of the block IL_OFFSET bbCodeOffsEnd; // IL offset past the end of the block. Thus, the [bbCodeOffs..bbCodeOffsEnd) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index f01eb2b74bf0ef..e09aac3ac123cf 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -287,9 +287,6 @@ Histogram bbCntTable(bbCntBuckets); unsigned bbSizeBuckets[] = {1, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 0}; Histogram bbOneBBSizeTable(bbSizeBuckets); -unsigned domsChangedIterationBuckets[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0}; -Histogram domsChangedIterationTable(domsChangedIterationBuckets); - unsigned computeReachabilitySetsIterationBuckets[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0}; Histogram computeReachabilitySetsIterationTable(computeReachabilitySetsIterationBuckets); @@ -1562,12 +1559,6 @@ void Compiler::compShutdown() bbOneBBSizeTable.dump(jitstdout()); jitprintf("--------------------------------------------------\n"); - jitprintf("--------------------------------------------------\n"); - jitprintf("fgComputeDoms `while (change)` iterations:\n"); - jitprintf("--------------------------------------------------\n"); - domsChangedIterationTable.dump(jitstdout()); - jitprintf("--------------------------------------------------\n"); - jitprintf("--------------------------------------------------\n"); jitprintf("fgComputeReachabilitySets `while (change)` iterations:\n"); jitprintf("--------------------------------------------------\n"); @@ -5836,7 +5827,7 @@ void Compiler::RecomputeFlowGraphAnnotations() assert(JitConfig.JitOptRepeatCount() > 0); // Recompute reachability sets, dominators, and loops. optResetLoopInfo(); - fgDomsComputed = false; + fgComputeReachability(); optSetBlockWeights(); optFindLoops(); @@ -5858,7 +5849,6 @@ void Compiler::RecomputeFlowGraphAnnotations() optLoopTableValid = false; optLoopTable = nullptr; optLoopCount = 0; - fgDomsComputed = false; } /*****************************************************************************/ @@ -9332,8 +9322,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX * cVarsFinal, dVarsFinal : Display the local variable table (call lvaTableDump(FINAL_FRAME_LAYOUT)). * cBlockPreds, dBlockPreds : Display a block's predecessors (call block->dspPreds()). * cBlockSuccs, dBlockSuccs : Display a block's successors (call block->dspSuccs(compiler)). - * cReach, dReach : Display all block reachability (call fgDispReach()). - * cDoms, dDoms : Display all block dominators (call fgDispDoms()). + * cReach, dReach : Display all block reachability (call BlockReachabilitySets::Dump). + * cDoms, dDoms : Display all block dominators (call FlowGraphDominatorTree::Dump). * cLiveness, dLiveness : Display per-block variable liveness (call fgDispBBLiveness()). * cCVarSet, dCVarSet : Display a "converted" VARSET_TP: the varset is assumed to be tracked variable * indices. These are converted to variable numbers and sorted. (Calls @@ -9658,7 +9648,14 @@ JITDBGAPI void __cdecl cDoms(Compiler* comp) { static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called printf("===================================================================== *Doms %u\n", sequenceNumber++); - comp->fgDispDoms(); + if (comp->m_domTree != nullptr) + { + comp->m_domTree->Dump(); + } + else + { + printf(" Not computed\n"); + } } JITDBGAPI void __cdecl cLiveness(Compiler* comp) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 521aa32777b4be..960d6becf38ab4 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -1568,22 +1568,6 @@ enum API_ICorJitInfo_Names API_COUNT }; -enum class FlowGraphUpdates -{ - COMPUTE_BASICS = 0, // renumber blocks, reachability, etc - COMPUTE_DOMS = 1 << 0, // recompute dominators -}; - -inline constexpr FlowGraphUpdates operator|(FlowGraphUpdates a, FlowGraphUpdates b) -{ - return (FlowGraphUpdates)((unsigned int)a | (unsigned int)b); -} - -inline constexpr FlowGraphUpdates operator&(FlowGraphUpdates a, FlowGraphUpdates b) -{ - return (FlowGraphUpdates)((unsigned int)a & (unsigned int)b); -} - // Profile checking options // // clang-format off @@ -2348,7 +2332,7 @@ class FlowGraphNaturalLoops class FlowGraphDominatorTree { template - friend class NewDomTreeVisitor; + friend class DomTreeVisitor; const FlowGraphDfsTree* m_dfsTree; const DomTreeNode* m_domTree; @@ -2368,6 +2352,10 @@ class FlowGraphDominatorTree BasicBlock* Intersect(BasicBlock* block, BasicBlock* block2); bool Dominates(BasicBlock* dominator, BasicBlock* dominated); +#ifdef DEBUG + void Dump(); +#endif + static FlowGraphDominatorTree* Build(const FlowGraphDfsTree* dfsTree); }; @@ -5012,15 +5000,6 @@ class Compiler FlowGraphDominatorTree* m_domTree; BlockReachabilitySets* m_reachabilitySets; - // After the dominance tree is computed, we cache a DFS preorder number and DFS postorder number to compute - // dominance queries in O(1). fgDomTreePreOrder and fgDomTreePostOrder are arrays giving the block's preorder and - // postorder number, respectively. The arrays are indexed by basic block number. (Note that blocks are numbered - // starting from one. Thus, we always waste element zero. This makes debugging easier and makes the code less likely - // to suffer from bugs stemming from forgetting to add or subtract one from the block number to form an array - // index). The arrays are of size fgBBNumMax + 1. - unsigned* fgDomTreePreOrder; - unsigned* fgDomTreePostOrder; - bool fgBBVarSetsInited; // Track how many artificial ref counts we've added to fgEntryBB (for OSR) @@ -5140,7 +5119,6 @@ class Compiler bool fgModified; // True if the flow graph has been modified recently bool fgPredsComputed; // Have we computed the bbPreds list - bool fgDomsComputed; // Have we computed the dominator sets? bool fgReturnBlocksComputed; // Have we computed the return blocks list? bool fgOptimizedFinally; // Did we optimize any try-finallys? bool fgCanonicalizedFirstBB; // TODO-Quirk: did we end up canonicalizing first BB? @@ -5788,18 +5766,9 @@ class Compiler void vnPrint(ValueNum vn, unsigned level); #endif - bool fgDominate(const BasicBlock* b1, const BasicBlock* b2); // Return true if b1 dominates b2 - // Dominator computation member functions // Not exposed outside Compiler protected: - // Compute immediate dominators, the dominator tree and and its pre/post-order travsersal numbers. - void fgComputeDoms(); - - 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. - void fgComputeReturnBlocks(); // Initialize fgReturnBlocks to a list of BBJ_RETURN blocks. // Remove blocks determined to be unreachable by the 'canRemoveBlock'. @@ -5808,34 +5777,10 @@ class Compiler PhaseStatus fgComputeReachability(); // Perform flow graph node reachability analysis. - PhaseStatus fgComputeDominators(); // Compute (new) dominators + PhaseStatus fgComputeDominators(); // Compute dominators bool fgRemoveDeadBlocks(); // Identify and remove dead blocks. - BasicBlock* fgIntersectDom(BasicBlock* a, BasicBlock* b); // Intersect two immediate dominator sets. - - unsigned fgDfsReversePostorder(); - void fgDfsReversePostorderHelper(BasicBlock* block, - BlockSet& visited, - unsigned& preorderIndex, - unsigned& reversePostorderIndex); - - INDEBUG(void fgDispDomTree(DomTreeNode* domTree);) // Helper that prints out the Dominator Tree in debug builds. - - DomTreeNode* fgBuildDomTree(); // Once we compute all the immediate dominator sets for each node in the flow graph - // (performed by fgComputeDoms), this procedure builds the dominance tree represented - // adjacency lists. - - // In order to speed up the queries of the form 'Does A dominates B', we can perform a DFS preorder and postorder - // traversal of the dominance tree and the dominance query will become A dominates B iif preOrder(A) <= preOrder(B) - // && postOrder(A) >= postOrder(B) making the computation O(1). - void fgNumberDomTree(DomTreeNode* domTree); - - // When the flow graph changes, we need to update the block numbers, reachability sets, - // dominators, and possibly loops. - // - void fgUpdateChangedFlowGraph(FlowGraphUpdates updates); - public: enum GCPollType { @@ -6124,7 +6069,6 @@ class Compiler #ifdef DEBUG - void fgDispDoms(); void fgDispBBLiveness(BasicBlock* block); void fgDispBBLiveness(); void fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth = 0); @@ -12009,94 +11953,13 @@ class GenericTreeWalker final // A dominator tree visitor implemented using the curiously-recurring-template pattern, similar to GenTreeVisitor. template class DomTreeVisitor -{ -protected: - Compiler* const m_compiler; - DomTreeNode* const m_domTree; - - DomTreeVisitor(Compiler* compiler, DomTreeNode* domTree) : m_compiler(compiler), m_domTree(domTree) - { - } - - void Begin() - { - } - - void PreOrderVisit(BasicBlock* block) - { - } - - void PostOrderVisit(BasicBlock* block) - { - } - - void End() - { - } - -public: - //------------------------------------------------------------------------ - // WalkTree: Walk the dominator tree, starting from fgFirstBB. - // - // Parameter: - // tree - Dominator tree nodes. - // - // Notes: - // This performs a non-recursive, non-allocating walk of the tree by using - // DomTreeNode's firstChild and nextSibling links to locate the children of - // a node and BasicBlock's bbIDom parent link to go back up the tree when - // no more children are left. - // - // Forests are also supported, provided that all the roots are chained via - // DomTreeNode::nextSibling to fgFirstBB. - // - void WalkTree() - { - static_cast(this)->Begin(); - - for (BasicBlock *next, *block = m_compiler->fgFirstBB; block != nullptr; block = next) - { - static_cast(this)->PreOrderVisit(block); - - next = m_domTree[block->bbNum].firstChild; - - if (next != nullptr) - { - assert(next->bbIDom == block); - continue; - } - - do - { - static_cast(this)->PostOrderVisit(block); - - next = m_domTree[block->bbNum].nextSibling; - - if (next != nullptr) - { - assert(next->bbIDom == block->bbIDom); - break; - } - - block = block->bbIDom; - - } while (block != nullptr); - } - - static_cast(this)->End(); - } -}; - -// A dominator tree visitor implemented using the curiously-recurring-template pattern, similar to GenTreeVisitor. -template -class NewDomTreeVisitor { friend class FlowGraphDominatorTree; protected: Compiler* m_compiler; - NewDomTreeVisitor(Compiler* compiler) : m_compiler(compiler) + DomTreeVisitor(Compiler* compiler) : m_compiler(compiler) { } @@ -12125,7 +11988,7 @@ class NewDomTreeVisitor { static_cast(this)->PreOrderVisit(block); - next = tree[block->bbNewPostorderNum].firstChild; + next = tree[block->bbPostorderNum].firstChild; if (next != nullptr) { @@ -12137,7 +12000,7 @@ class NewDomTreeVisitor { static_cast(this)->PostOrderVisit(block); - next = tree[block->bbNewPostorderNum].nextSibling; + next = tree[block->bbPostorderNum].nextSibling; if (next != nullptr) { @@ -12304,7 +12167,6 @@ extern size_t gcPtrMapNSize; #if COUNT_BASIC_BLOCKS extern Histogram bbCntTable; extern Histogram bbOneBBSizeTable; -extern Histogram domsChangedIterationTable; extern Histogram computeReachabilitySetsIterationTable; #endif diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 4acf9046caaa9e..c7554872f7e433 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -5011,7 +5011,7 @@ BasicBlockVisit FlowGraphNaturalLoop::VisitLoopBlocksReversePostOrder(TFunc func // loop block rpo index = head block rpoIndex + index // loop block po index = PostOrderCount - 1 - loop block rpo index // = headPreOrderIndex - index - unsigned poIndex = m_header->bbNewPostorderNum - index; + unsigned poIndex = m_header->bbPostorderNum - index; assert(poIndex < m_dfsTree->GetPostOrderCount()); return func(m_dfsTree->GetPostOrder(poIndex)) == BasicBlockVisit::Continue; }); @@ -5039,7 +5039,7 @@ BasicBlockVisit FlowGraphNaturalLoop::VisitLoopBlocksPostOrder(TFunc func) { BitVecTraits traits(m_blocksSize, m_dfsTree->GetCompiler()); bool result = BitVecOps::VisitBitsReverse(&traits, m_blocks, [=](unsigned index) { - unsigned poIndex = m_header->bbNewPostorderNum - index; + unsigned poIndex = m_header->bbPostorderNum - index; assert(poIndex < m_dfsTree->GetPostOrderCount()); return func(m_dfsTree->GetPostOrder(poIndex)) == BasicBlockVisit::Continue; }); diff --git a/src/coreclr/jit/copyprop.cpp b/src/coreclr/jit/copyprop.cpp index 9af47dd99aa15c..90a593ef65b2fe 100644 --- a/src/coreclr/jit/copyprop.cpp +++ b/src/coreclr/jit/copyprop.cpp @@ -454,7 +454,7 @@ PhaseStatus Compiler::optVnCopyProp() VarSetOps::AssignNoCopy(this, compCurLife, VarSetOps::MakeEmpty(this)); - class CopyPropDomTreeVisitor : public NewDomTreeVisitor + class CopyPropDomTreeVisitor : public DomTreeVisitor { // The map from lclNum to its recently live definitions as a stack. LclNumToLiveDefsMap m_curSsaName; @@ -462,7 +462,7 @@ PhaseStatus Compiler::optVnCopyProp() public: CopyPropDomTreeVisitor(Compiler* compiler) - : NewDomTreeVisitor(compiler), m_curSsaName(compiler->getAllocator(CMK_CopyProp)), m_madeChanges(false) + : DomTreeVisitor(compiler), m_curSsaName(compiler->getAllocator(CMK_CopyProp)), m_madeChanges(false) { } diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 0a22fb43cecdc0..1d3a3915aea302 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -30,8 +30,6 @@ void Compiler::fgInit() fgRangeUsedInEdgeWeights = true; fgCalledCount = BB_ZERO_WEIGHT; - /* We haven't yet computed the dominator sets */ - fgDomsComputed = false; fgReturnBlocksComputed = false; /* Initialize the basic block list */ @@ -5608,12 +5606,6 @@ bool Compiler::fgRenumberBlocks() { assert(fgPredsComputed); - // If we renumber the blocks the dominator information will be out-of-date - if (fgDomsComputed) - { - noway_assert(!"Can't call Compiler::fgRenumberBlocks() when fgDomsComputed==true"); - } - JITDUMP("\n*************** Before renumbering the basic blocks\n"); JITDUMPEXEC(fgDispBasicBlocks()); JITDUMPEXEC(fgDispHandlerTab()); diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index f77cca453519a7..95e6b6a858f6a6 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -1815,7 +1815,7 @@ void Compiler::fgDumpFlowGraphLoops(FILE* file) fprintf(m_file, "%*s", m_indent, ""); loop->VisitLoopBlocksReversePostOrder([=](BasicBlock* block) { - if (BitVecOps::IsMember(&m_traits, m_outputBlocks, block->bbNewPostorderNum)) + if (BitVecOps::IsMember(&m_traits, m_outputBlocks, block->bbPostorderNum)) { return BasicBlockVisit::Continue; } @@ -1833,7 +1833,7 @@ void Compiler::fgDumpFlowGraphLoops(FILE* file) } fprintf(m_file, FMT_BB ";", block->bbNum); - BitVecOps::AddElemD(&m_traits, m_outputBlocks, block->bbNewPostorderNum); + BitVecOps::AddElemD(&m_traits, m_outputBlocks, block->bbPostorderNum); return BasicBlockVisit::Continue; }); @@ -1860,33 +1860,6 @@ void Compiler::fgDumpFlowGraphLoops(FILE* file) /*****************************************************************************/ #ifdef DEBUG -void Compiler::fgDispDoms() -{ - // Don't bother printing this when we have a large number of BasicBlocks in the method - if (fgBBcount > 256) - { - return; - } - - printf("------------------------------------------------\n"); - printf("BBnum Dominated by\n"); - printf("------------------------------------------------\n"); - - for (unsigned i = 1; i <= fgBBNumMax; ++i) - { - BasicBlock* current = fgBBReversePostorder[i]; - printf(FMT_BB ": ", current->bbNum); - while (current != current->bbIDom) - { - printf(FMT_BB " ", current->bbNum); - current = current->bbIDom; - } - printf("\n"); - } -} - -/*****************************************************************************/ - void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 */) { const unsigned __int64 flags = block->GetFlagsRaw(); @@ -5084,22 +5057,22 @@ void Compiler::fgDebugCheckLoopTable() // 1. The pre-header dominates the entry (if pre-headers are required). // 2. The entry dominates the exit. // 3. The IDom tree from the exit reaches the entry. - if (fgDomsComputed) + if (m_domTree != nullptr) { if (optLoopsRequirePreHeaders) { - assert(fgDominate(loop.lpHead, loop.lpEntry)); + assert(m_domTree->Dominates(loop.lpHead, loop.lpEntry)); } if (loop.lpExitCnt == 1) { assert(loop.lpExit != nullptr); - assert(fgDominate(loop.lpEntry, loop.lpExit)); + assert(m_domTree->Dominates(loop.lpEntry, loop.lpExit)); BasicBlock* cur = loop.lpExit; while ((cur != nullptr) && (cur != loop.lpEntry)) { - assert(fgDominate(cur, loop.lpExit)); + assert(m_domTree->Dominates(cur, loop.lpExit)); cur = cur->bbIDom; } assert(cur == loop.lpEntry); // We must be able to reach the entry from the exit via the IDom tree. @@ -5180,7 +5153,7 @@ void Compiler::fgDebugCheckDfsTree() unsigned count = fgRunDfs([](BasicBlock* block, unsigned preorderNum) { assert(block->bbPreorderNum == preorderNum); }, [=](BasicBlock* block, unsigned postorderNum) { - assert(block->bbNewPostorderNum == postorderNum); + assert(block->bbPostorderNum == postorderNum); assert(m_dfsTree->GetPostOrder(postorderNum) == block); }, [](BasicBlock* block, BasicBlock* succ) {}); diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index a6dfd2b2a733d0..b48f1450a1a857 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -11,107 +11,6 @@ // Flowgraph Optimization -//------------------------------------------------------------------------ -// fgDominate: Returns true if block `b1` dominates block `b2`. -// -// Arguments: -// b1, b2 -- Two blocks to compare. -// -// Return Value: -// true if `b1` dominates `b2`. If either b1 or b2 were created after dominators were calculated, -// but the dominator information still exists, try to determine if we can make a statement about -// b1 dominating b2 based on existing dominator information and other information, such as -// predecessor lists or loop information. -// -// Assumptions: -// -- Dominators have been calculated (`fgDomsComputed` is true). -// -bool Compiler::fgDominate(const BasicBlock* b1, const BasicBlock* b2) -{ - noway_assert(fgDomsComputed); - - // - // If the fgModified flag is false then we made some modifications to - // the flow graph, like adding a new block or changing a conditional branch - // into an unconditional branch. - // - // We can continue to use the dominator and reachable information to - // unmark loops as long as we haven't renumbered the blocks or we aren't - // asking for information about a new block. - // - - if (b2->bbNum > fgDomBBcount) - { - if (b1 == b2) - { - return true; - } - - for (BasicBlock* const predBlock : b2->PredBlocks()) - { - if (!fgDominate(b1, predBlock)) - { - return false; - } - } - - return b2->bbPreds != nullptr; - } - - if (b1->bbNum > fgDomBBcount) - { - // unknown dominators; err on the safe side and return false - return false; - } - - /* Check if b1 dominates b2 */ - unsigned numA = b1->bbNum; - noway_assert(numA <= fgDomBBcount); - unsigned numB = b2->bbNum; - noway_assert(numB <= fgDomBBcount); - - // What we want to ask here is basically if A is in the middle of the path from B to the root (the entry node) - // in the dominator tree. Turns out that can be translated as: - // - // A dom B <-> preorder(A) <= preorder(B) && postorder(A) >= postorder(B) - // - // where the equality holds when you ask if A dominates itself. - bool treeDom = - fgDomTreePreOrder[numA] <= fgDomTreePreOrder[numB] && fgDomTreePostOrder[numA] >= fgDomTreePostOrder[numB]; - - return treeDom; -} - -//------------------------------------------------------------------------ -// fgUpdateChangedFlowGraph: Update changed flow graph information. -// -// If the flow graph has changed, we need to recompute various information if we want to use it again. -// This does similar work to `fgComputeReachability`, but the caller can pick and choose what needs -// to be recomputed if they know certain things do NOT need to be recomputed. -// -// Arguments: -// updates -- enum flag set indicating what to update -// -// Notes: -// Always renumbers, computes enter blocks, and computes reachability. -// Optionally rebuilds dominators, return blocks, and computes loop information. -// -void Compiler::fgUpdateChangedFlowGraph(FlowGraphUpdates updates) -{ - const bool computeDoms = ((updates & FlowGraphUpdates::COMPUTE_DOMS) == FlowGraphUpdates::COMPUTE_DOMS); - - // We need to clear this so we don't hit an assert calling fgRenumberBlocks(). - fgDomsComputed = false; - - JITDUMP("\nRenumbering the basic blocks for fgUpdateChangeFlowGraph\n"); - fgRenumberBlocks(); - fgDfsReversePostorder(); - if (computeDoms) - { - fgComputeDoms(); - } -} - //------------------------------------------------------------------------ // fgComputeReturnBlocks: Compute the set of BBJ_RETURN blocks. // @@ -287,19 +186,9 @@ PhaseStatus Compiler::fgComputeReachability() madeChanges |= fgRenumberBlocks(); - fgDfsReversePostorder(); - - // fgDfsReversePostorder reassigns preorder numbers, so recompute the DFS. - m_dfsTree = fgComputeDfs(); - fgComputeReturnBlocks(); m_reachabilitySets = BlockReachabilitySets::Build(m_dfsTree); - - // - // Now, compute the dominators - // - - fgComputeDoms(); + m_domTree = FlowGraphDominatorTree::Build(m_dfsTree); return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; } @@ -314,15 +203,6 @@ bool Compiler::fgRemoveDeadBlocks() unsigned prevFgCurBBEpoch = fgCurBBEpoch; EnsureBasicBlockEpoch(); - if (prevFgCurBBEpoch != fgCurBBEpoch) - { - // If Epoch has changed, reset the doms computed as well because - // in future, during insert gc polls or lowering, when we compact - // blocks during flowgraph update, it might propagate the invalid - // bbReach as well (although Epoch adjustment resets fgReachabilitySetsValid). - fgDomsComputed = false; - } - BlockSet visitedBlocks(BlockSetOps::MakeEmpty(this)); jitstd::list worklist(jitstd::allocator(getAllocator(CMK_Reachability))); @@ -419,610 +299,7 @@ bool Compiler::fgRemoveDeadBlocks() } //------------------------------------------------------------- -// fgDfsReversePostorder: Depth first search to establish block -// preorder and reverse postorder numbers, plus a reverse postorder for blocks, -// using all entry blocks and EH handler blocks as start blocks. -// -// Notes: -// Each block's `bbPreorderNum` and `bbPostorderNum` is set. -// The `fgBBReversePostorder` array is filled in with the `BasicBlock*` in reverse post-order. -// -// Unreachable blocks will have higher pre and post order numbers than reachable blocks. -// Hence they will appear at lower indices in the fgBBReversePostorder array. -// -unsigned Compiler::fgDfsReversePostorder() -{ - assert(fgBBcount == fgBBNumMax); - assert(BasicBlockBitSetTraits::GetSize(this) == fgBBNumMax + 1); - fgBBReversePostorder = new (this, CMK_DominatorMemory) BasicBlock*[fgBBNumMax + 1]{}; - BlockSet visited(BlockSetOps::MakeEmpty(this)); - - unsigned preorderIndex = 1; - unsigned postorderIndex = 1; - - // Walk from our primary root. - // - fgDfsReversePostorderHelper(fgFirstBB, visited, preorderIndex, postorderIndex); - - // For OSR, walk from the original method entry too. - // - if (opts.IsOSR() && (fgEntryBB != nullptr)) - { - if (!BlockSetOps::IsMember(this, visited, fgEntryBB->bbNum)) - { - fgDfsReversePostorderHelper(fgEntryBB, visited, preorderIndex, postorderIndex); - } - } - - // If we didn't end up visiting everything, try the EH roots. - // - if ((preorderIndex != fgBBcount + 1) && !compIsForInlining()) - { - for (EHblkDsc* const HBtab : EHClauses(this)) - { - if (HBtab->HasFilter()) - { - BasicBlock* const filterBlock = HBtab->ebdFilter; - if (!BlockSetOps::IsMember(this, visited, filterBlock->bbNum)) - { - fgDfsReversePostorderHelper(filterBlock, visited, preorderIndex, postorderIndex); - } - } - - BasicBlock* const handlerBlock = HBtab->ebdHndBeg; - if (!BlockSetOps::IsMember(this, visited, handlerBlock->bbNum)) - { - fgDfsReversePostorderHelper(handlerBlock, visited, preorderIndex, postorderIndex); - } - } - } - - // That's everything reachable from the roots. - // - const unsigned highestReachablePostorderNumber = postorderIndex - 1; - - // If we still didn't end up visiting everything, visit what remains. - // - if (highestReachablePostorderNumber != fgBBcount) - { - JITDUMP("DFS: there are %u unreachable blocks\n", fgBBcount - highestReachablePostorderNumber); - for (BasicBlock* const block : Blocks()) - { - if (!BlockSetOps::IsMember(this, visited, block->bbNum)) - { - fgDfsReversePostorderHelper(block, visited, preorderIndex, postorderIndex); - } - } - } - - // After the DFS reverse postorder is completed, we must have visited all the basic blocks. - noway_assert(preorderIndex == fgBBcount + 1); - noway_assert(postorderIndex == fgBBcount + 1); - noway_assert(fgBBNumMax == fgBBcount); - -#ifdef DEBUG - if (0 && verbose) - { - printf("\nAfter doing a post order traversal of the BB graph, this is the ordering:\n"); - for (unsigned i = 1; i <= fgBBNumMax; ++i) - { - printf("%02u -> " FMT_BB "\n", i, fgBBReversePostorder[i]->bbNum); - } - printf("\n"); - } -#endif // DEBUG - - return highestReachablePostorderNumber; -} - -//------------------------------------------------------------------------ -// fgDfsReversePostorderHelper: Helper to assign post-order numbers to blocks -// -// Arguments: -// block - The starting entry block -// visited - The set of visited blocks -// preorderIndex - preorder visit counter -// postorderIndex - postorder visit counter -// -// Notes: -// Compute a non-recursive DFS traversal of the flow graph using an -// evaluation stack to assign pre and post-order numbers. -// -void Compiler::fgDfsReversePostorderHelper(BasicBlock* block, - BlockSet& visited, - unsigned& preorderIndex, - unsigned& postorderIndex) -{ - // Assume we haven't visited this node yet (callers ensure this). - assert(!BlockSetOps::IsMember(this, visited, block->bbNum)); - - struct DfsBlockEntry - { - public: - DfsBlockEntry(Compiler* comp, BasicBlock* block) : m_block(block), m_nSucc(block->NumSucc(comp)), m_iter(0) - { - } - - BasicBlock* getBlock() - { - return m_block; - } - - BasicBlock* getNextSucc(Compiler* comp) - { - if (m_iter >= m_nSucc) - { - return nullptr; - } - return m_block->GetSucc(m_iter++, comp); - } - - private: - BasicBlock* m_block; - unsigned m_nSucc; - unsigned m_iter; - }; - - // Allocate a local stack to hold the DFS traversal actions necessary - // to compute pre/post-ordering of the control flowgraph. - ArrayStack stack(getAllocator(CMK_ArrayStack)); - - // Push the first block on the stack to seed the traversal, mark it visited to avoid backtracking, - // and give it a preorder number. - stack.Emplace(this, block); - BlockSetOps::AddElemD(this, visited, block->bbNum); - block->bbPreorderNum = preorderIndex++; - - // The search is terminated once all the actions have been processed. - while (!stack.Empty()) - { - DfsBlockEntry& current = stack.TopRef(); - BasicBlock* const succ = current.getNextSucc(this); - - if (succ == nullptr) - { - BasicBlock* const block = current.getBlock(); - - // Final visit to this node - // - block->bbPostorderNum = postorderIndex; - - // Compute the index of block in the reverse postorder and - // update the reverse postorder accordingly. - // - assert(postorderIndex <= fgBBcount); - unsigned reversePostorderIndex = fgBBcount - postorderIndex + 1; - fgBBReversePostorder[reversePostorderIndex] = block; - postorderIndex++; - - stack.Pop(); - continue; - } - - if (BlockSetOps::IsMember(this, visited, succ->bbNum)) - { - // Already visited this succ - // - continue; - } - - stack.Emplace(this, succ); - BlockSetOps::AddElemD(this, visited, succ->bbNum); - succ->bbPreorderNum = preorderIndex++; - } -} - -//------------------------------------------------------------------------ -// fgComputeDoms: Computer dominators. Use `fgDominate()` to check dominance. -// -// Compute immediate dominators, the dominator tree and and its pre/post-order traversal numbers. -// -// Also sets BBF_DOMINATED_BY_EXCEPTIONAL_ENTRY flag on blocks dominated by exceptional entry blocks. -// -// Notes: -// Immediate dominator computation is based on "A Simple, Fast Dominance Algorithm" -// by Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy. -// -void Compiler::fgComputeDoms() -{ -#ifdef DEBUG - if (verbose) - { - printf("*************** In fgComputeDoms\n"); - } - - fgVerifyHandlerTab(); - - // Make sure that the predecessor lists are accurate. - // Also check that the blocks are properly, densely numbered (so calling fgRenumberBlocks is not necessary). - fgDebugCheckBBlist(true); - - // Assert things related to the BlockSet epoch. - assert(fgBBcount == fgBBNumMax); - assert(BasicBlockBitSetTraits::GetSize(this) == fgBBNumMax + 1); -#endif // DEBUG - - // flRoot and bbRoot represent an imaginary unique entry point in the flow graph. - // All the orphaned EH blocks and fgFirstBB will temporarily have its predecessors list - // (with bbRoot as the only basic block in it) set as flRoot. - // Later on, we clear their predecessors and let them to be nullptr again. - // Since we number basic blocks starting at one, the imaginary entry block is conveniently numbered as zero. - - BasicBlock bbRoot; - - bbRoot.bbPreds = nullptr; - bbRoot.bbNum = 0; - bbRoot.bbIDom = &bbRoot; - bbRoot.bbPostorderNum = fgBBNumMax + 1; - bbRoot.SetFlagsRaw(BBF_EMPTY); - - FlowEdge flRoot(&bbRoot, nullptr); - - noway_assert(fgBBReversePostorder[0] == nullptr); - fgBBReversePostorder[0] = &bbRoot; - - // Mark both bbRoot and fgFirstBB processed - BlockSet processedBlks(BlockSetOps::MakeEmpty(this)); - BlockSetOps::AddElemD(this, processedBlks, 0); // bbRoot == block #0 - BlockSetOps::AddElemD(this, processedBlks, 1); // fgFirstBB == block #1 - assert(fgFirstBB->bbNum == 1); - - // Special case fgFirstBB to say its IDom is bbRoot. - fgFirstBB->bbIDom = &bbRoot; - - BasicBlock* block = nullptr; - - for (block = fgFirstBB->Next(); block != nullptr; block = block->Next()) - { - // If any basic block has no predecessors then we flag it as processed and temporarily - // mark its predecessor list to be flRoot. This makes the flowgraph connected, - // a precondition that is needed by the dominance algorithm to operate properly. - if (block->bbPreds == nullptr) - { - block->bbPreds = &flRoot; - block->bbIDom = &bbRoot; - BlockSetOps::AddElemD(this, processedBlks, block->bbNum); - } - else - { - block->bbIDom = nullptr; - } - } - - // Mark the EH blocks as entry blocks and also flag them as processed. - if (compHndBBtabCount > 0) - { - for (EHblkDsc* const HBtab : EHClauses(this)) - { - if (HBtab->HasFilter()) - { - HBtab->ebdFilter->bbIDom = &bbRoot; - BlockSetOps::AddElemD(this, processedBlks, HBtab->ebdFilter->bbNum); - } - HBtab->ebdHndBeg->bbIDom = &bbRoot; - BlockSetOps::AddElemD(this, processedBlks, HBtab->ebdHndBeg->bbNum); - } - } - - // Now proceed to compute the immediate dominators for each basic block. - bool changed = true; - unsigned changedIterCount = 1; - while (changed) - { - changed = false; - // Process each actual block; don't process the imaginary predecessor block. - for (unsigned i = 1; i <= fgBBNumMax; ++i) - { - FlowEdge* first = nullptr; - BasicBlock* newidom = nullptr; - block = fgBBReversePostorder[i]; - - // If we have a block that has bbRoot as its bbIDom - // it means we flag it as processed and as an entry block so - // in this case we're all set. - if (block->bbIDom == &bbRoot) - { - continue; - } - - // Pick up the first processed predecessor of the current block. - for (first = block->bbPreds; first != nullptr; first = first->getNextPredEdge()) - { - if (BlockSetOps::IsMember(this, processedBlks, first->getSourceBlock()->bbNum)) - { - break; - } - } - noway_assert(first != nullptr); - - // We assume the first processed predecessor will be the - // immediate dominator and then compute the forward flow analysis. - newidom = first->getSourceBlock(); - for (FlowEdge* p = block->bbPreds; p != nullptr; p = p->getNextPredEdge()) - { - if (p->getSourceBlock() == first->getSourceBlock()) - { - continue; - } - if (p->getSourceBlock()->bbIDom != nullptr) - { - // fgIntersectDom is basically the set intersection between - // the dominance sets of the new IDom and the current predecessor - // Since the nodes are ordered in DFS inverse post order and - // IDom induces a tree, fgIntersectDom actually computes - // the lowest common ancestor in the dominator tree. - newidom = fgIntersectDom(p->getSourceBlock(), newidom); - } - } - - // If the Immediate dominator changed, assign the new one - // to the current working basic block. - if (block->bbIDom != newidom) - { - noway_assert(newidom != nullptr); - block->bbIDom = newidom; - changed = true; - } - BlockSetOps::AddElemD(this, processedBlks, block->bbNum); - } - - ++changedIterCount; - } - -#if COUNT_BASIC_BLOCKS - domsChangedIterationTable.record(changedIterCount); -#endif // COUNT_BASIC_BLOCKS - - // As stated before, once we have computed immediate dominance we need to clear - // all the basic blocks whose predecessor list was set to flRoot. This - // reverts that and leaves the blocks the same as before. - for (BasicBlock* const block : Blocks()) - { - if (block->bbPreds == &flRoot) - { - block->bbPreds = nullptr; - } - } - -#ifdef DEBUG - if (verbose) - { - fgDispDoms(); - } -#endif - - fgNumberDomTree(fgBuildDomTree()); - - fgModified = false; - fgDomBBcount = fgBBcount; - assert(fgBBcount == fgBBNumMax); - assert(BasicBlockBitSetTraits::GetSize(this) == fgDomBBcount + 1); - - fgDomsComputed = true; -} - -//------------------------------------------------------------------------ -// fgBuildDomTree: Build the dominator tree for the current flowgraph. -// -// Returns: -// An array of dominator tree nodes, indexed by BasicBlock::bbNum. -// -// Notes: -// Immediate dominators must have already been computed in BasicBlock::bbIDom -// before calling this. -// -DomTreeNode* Compiler::fgBuildDomTree() -{ - JITDUMP("\nInside fgBuildDomTree\n"); - - unsigned bbArraySize = fgBBNumMax + 1; - DomTreeNode* domTree = new (this, CMK_DominatorMemory) DomTreeNode[bbArraySize]{}; - - BasicBlock* imaginaryRoot = fgFirstBB->bbIDom; - - if (imaginaryRoot != nullptr) - { - // If the first block has a dominator then this must be the imaginary entry block added - // by fgComputeDoms, it is not actually part of the flowgraph and should have number 0. - assert(imaginaryRoot->bbNum == 0); - assert(imaginaryRoot->bbIDom == imaginaryRoot); - - // Clear the imaginary dominator to turn the tree back to a forest. - fgFirstBB->bbIDom = nullptr; - } - - // If the imaginary root is present then we'll need to create a forest instead of a tree. - // Forest roots are chained via DomTreeNode::nextSibling and we keep track of this list's - // tail in order to append to it. The head of the list is fgFirstBB, by construction. - BasicBlock* rootListTail = fgFirstBB; - - // Traverse the entire block list to build the dominator tree. Skip fgFirstBB - // as it is always a root of the dominator forest. - for (BasicBlock* const block : Blocks(fgFirstBB->Next())) - { - BasicBlock* parent = block->bbIDom; - - if (parent != imaginaryRoot) - { - assert(block->bbNum < bbArraySize); - assert(parent->bbNum < bbArraySize); - - domTree[block->bbNum].nextSibling = domTree[parent->bbNum].firstChild; - domTree[parent->bbNum].firstChild = block; - } - else if (imaginaryRoot != nullptr) - { - assert(rootListTail->bbNum < bbArraySize); - - domTree[rootListTail->bbNum].nextSibling = block; - rootListTail = block; - - // Clear the imaginary dominator to turn the tree back to a forest. - block->bbIDom = nullptr; - } - } - - JITDUMP("\nAfter computing the Dominance Tree:\n"); - DBEXEC(verbose, fgDispDomTree(domTree)); - - return domTree; -} - -#ifdef DEBUG -void Compiler::fgDispDomTree(DomTreeNode* domTree) -{ - for (unsigned i = 1; i <= fgBBNumMax; ++i) - { - if (domTree[i].firstChild != nullptr) - { - printf(FMT_BB " : ", i); - for (BasicBlock* child = domTree[i].firstChild; child != nullptr; child = domTree[child->bbNum].nextSibling) - { - printf(FMT_BB " ", child->bbNum); - } - printf("\n"); - } - } - printf("\n"); -} -#endif // DEBUG - -//------------------------------------------------------------------------ -// fgNumberDomTree: Assign pre/post-order numbers to the dominator tree. -// -// Arguments: -// domTree - The dominator tree node array -// -// Notes: -// Runs a non-recursive DFS traversal of the dominator tree to assign -// pre-order and post-order numbers. These numbers are used to provide -// constant time lookup ancestor/descendent tests between pairs of nodes -// in the tree. -// -void Compiler::fgNumberDomTree(DomTreeNode* domTree) -{ - class NumberDomTreeVisitor : public DomTreeVisitor - { - unsigned m_preNum; - unsigned m_postNum; - - public: - NumberDomTreeVisitor(Compiler* compiler, DomTreeNode* domTree) : DomTreeVisitor(compiler, domTree) - { - } - - void Begin() - { - unsigned bbArraySize = m_compiler->fgBBNumMax + 1; - m_compiler->fgDomTreePreOrder = new (m_compiler, CMK_DominatorMemory) unsigned[bbArraySize]{}; - m_compiler->fgDomTreePostOrder = new (m_compiler, CMK_DominatorMemory) unsigned[bbArraySize]{}; - - // The preorder and postorder numbers. - // We start from 1 to match the bbNum ordering. - m_preNum = 1; - m_postNum = 1; - } - - void PreOrderVisit(BasicBlock* block) - { - m_compiler->fgDomTreePreOrder[block->bbNum] = m_preNum++; - } - - void PostOrderVisit(BasicBlock* block) - { - m_compiler->fgDomTreePostOrder[block->bbNum] = m_postNum++; - } - - void End() - { - noway_assert(m_preNum == m_compiler->fgBBNumMax + 1); - noway_assert(m_postNum == m_compiler->fgBBNumMax + 1); - - noway_assert(m_compiler->fgDomTreePreOrder[0] == 0); // Unused first element - noway_assert(m_compiler->fgDomTreePostOrder[0] == 0); // Unused first element - noway_assert(m_compiler->fgDomTreePreOrder[1] == 1); // First block should be first in pre order - -#ifdef DEBUG - if (m_compiler->verbose) - { - printf("\nAfter numbering the dominator tree:\n"); - for (unsigned i = 1; i <= m_compiler->fgBBNumMax; ++i) - { - printf(FMT_BB ": pre=%02u, post=%02u\n", i, m_compiler->fgDomTreePreOrder[i], - m_compiler->fgDomTreePostOrder[i]); - } - } -#endif // DEBUG - } - }; - - NumberDomTreeVisitor visitor(this, domTree); - visitor.WalkTree(); -} - -//------------------------------------------------------------- -// fgIntersectDom: Intersect two immediate dominator sets. -// -// Find the lowest common ancestor in the dominator tree between two basic blocks. The LCA in the dominance tree -// represents the closest dominator between the two basic blocks. Used to adjust the IDom value in fgComputeDoms. -// -// Arguments: -// a, b - two blocks to intersect -// -// Returns: -// The least common ancestor of `a` and `b` in the IDom tree. -// -BasicBlock* Compiler::fgIntersectDom(BasicBlock* a, BasicBlock* b) -{ - BasicBlock* finger1 = a; - BasicBlock* finger2 = b; - while (finger1 != finger2) - { - while (finger1->bbPostorderNum < finger2->bbPostorderNum) - { - finger1 = finger1->bbIDom; - } - while (finger2->bbPostorderNum < finger1->bbPostorderNum) - { - finger2 = finger2->bbIDom; - } - } - return finger1; -} - -//------------------------------------------------------------- -// fgGetDominatorSet: Return a set of blocks that dominate `block`. -// -// Note: this is slow compared to calling fgDominate(), especially if doing a single check comparing -// two blocks. -// -// Arguments: -// block - get the set of blocks which dominate this block -// -// Returns: -// A set of blocks which dominate `block`. -// -BlockSet_ValRet_T Compiler::fgGetDominatorSet(BasicBlock* block) -{ - assert(block != nullptr); - - BlockSet domSet(BlockSetOps::MakeEmpty(this)); - - do - { - BlockSetOps::AddElemD(this, domSet, block->bbNum); - if (block == block->bbIDom) - { - break; // We found a cycle in the IDom list, so we're done. - } - block = block->bbIDom; - } while (block != nullptr); - - return domSet; -} - -//------------------------------------------------------------- -// fgComputeDominators: Compute new dominators +// fgComputeDominators: Compute dominators // // Returns: // Suitable phase status. @@ -2085,8 +1362,6 @@ void Compiler::fgCompactBlocks(BasicBlock* block, BasicBlock* bNext) block->RemoveFlags(BBF_NONE_QUIRK); } - assert(!fgDomsComputed); - if (optLoopTableValid) { fgUpdateLoopsAfterCompacting(block, bNext); @@ -5596,9 +4871,7 @@ PhaseStatus Compiler::fgUpdateFlowGraphPhase() constexpr bool isPhase = true; const bool madeChanges = fgUpdateFlowGraph(doTailDup, isPhase); - // Dominator and reachability sets are no longer valid. // The loop table is no longer valid. - fgDomsComputed = false; optLoopTableValid = false; optLoopsRequirePreHeaders = false; diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index f47e2ba9bd44f5..7a12698b8481af 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -155,7 +155,7 @@ PhaseStatus Compiler::fgInsertGCPolls() if (createdPollBlocks) { noway_assert(opts.OptimizationEnabled()); - fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); + fgRenumberBlocks(); } return result; @@ -2849,7 +2849,6 @@ void Compiler::fgInsertFuncletPrologBlock(BasicBlock* block) void Compiler::fgCreateFuncletPrologBlocks() { noway_assert(fgPredsComputed); - noway_assert(!fgDomsComputed); // this function doesn't maintain the dom sets assert(!fgFuncletsCreated); bool prologBlocksCreated = false; @@ -3954,7 +3953,7 @@ void Compiler::fgLclFldAssign(unsigned lclNum) // bool FlowGraphDfsTree::Contains(BasicBlock* block) const { - return (block->bbNewPostorderNum < m_postOrderCount) && (m_postOrder[block->bbNewPostorderNum] == block); + return (block->bbPostorderNum < m_postOrderCount) && (m_postOrder[block->bbPostorderNum] == block); } //------------------------------------------------------------------------ @@ -3976,7 +3975,7 @@ bool FlowGraphDfsTree::IsAncestor(BasicBlock* ancestor, BasicBlock* descendant) { assert(Contains(ancestor) && Contains(descendant)); return (ancestor->bbPreorderNum <= descendant->bbPreorderNum) && - (descendant->bbNewPostorderNum <= ancestor->bbNewPostorderNum); + (descendant->bbPostorderNum <= ancestor->bbPostorderNum); } //------------------------------------------------------------------------ @@ -3995,12 +3994,12 @@ FlowGraphDfsTree* Compiler::fgComputeDfs() bool hasCycle = false; auto visitPreorder = [](BasicBlock* block, unsigned preorderNum) { - block->bbPreorderNum = preorderNum; - block->bbNewPostorderNum = UINT_MAX; + block->bbPreorderNum = preorderNum; + block->bbPostorderNum = UINT_MAX; }; auto visitPostorder = [=](BasicBlock* block, unsigned postorderNum) { - block->bbNewPostorderNum = postorderNum; + block->bbPostorderNum = postorderNum; assert(postorderNum < fgBBcount); postOrder[postorderNum] = block; }; @@ -4008,7 +4007,7 @@ FlowGraphDfsTree* Compiler::fgComputeDfs() auto visitEdge = [&hasCycle](BasicBlock* block, BasicBlock* succ) { // Check if block -> succ is a backedge, in which case the flow // graph has a cycle. - if ((succ->bbPreorderNum <= block->bbPreorderNum) && (succ->bbNewPostorderNum == UINT_MAX)) + if ((succ->bbPreorderNum <= block->bbPreorderNum) && (succ->bbPostorderNum == UINT_MAX)) { hasCycle = true; } @@ -4087,7 +4086,7 @@ unsigned FlowGraphNaturalLoop::LoopBlockBitVecIndex(BasicBlock* block) { assert(m_dfsTree->Contains(block)); - unsigned index = m_header->bbNewPostorderNum - block->bbNewPostorderNum; + unsigned index = m_header->bbPostorderNum - block->bbPostorderNum; assert(index < m_blocksSize); return index; } @@ -4110,12 +4109,12 @@ unsigned FlowGraphNaturalLoop::LoopBlockBitVecIndex(BasicBlock* block) // bool FlowGraphNaturalLoop::TryGetLoopBlockBitVecIndex(BasicBlock* block, unsigned* pIndex) { - if (block->bbNewPostorderNum > m_header->bbNewPostorderNum) + if (block->bbPostorderNum > m_header->bbPostorderNum) { return false; } - unsigned index = m_header->bbNewPostorderNum - block->bbNewPostorderNum; + unsigned index = m_header->bbPostorderNum - block->bbPostorderNum; if (index >= m_blocksSize) { return false; @@ -4315,7 +4314,7 @@ FlowGraphNaturalLoops* FlowGraphNaturalLoops::Find(const FlowGraphDfsTree* dfsTr { unsigned rpoNum = dfsTree->GetPostOrderCount() - i; BasicBlock* const block = dfsTree->GetPostOrder(i - 1); - JITDUMP("%02u -> " FMT_BB "[%u, %u]\n", rpoNum, block->bbNum, block->bbPreorderNum, block->bbNewPostorderNum); + JITDUMP("%02u -> " FMT_BB "[%u, %u]\n", rpoNum, block->bbNum, block->bbPreorderNum, block->bbPostorderNum); } unsigned improperLoopHeaders = 0; @@ -4366,7 +4365,7 @@ FlowGraphNaturalLoops* FlowGraphNaturalLoops::Find(const FlowGraphDfsTree* dfsTr // this is a natural loop and to find all the blocks in the loop. // - loop->m_blocksSize = loop->m_header->bbNewPostorderNum + 1; + loop->m_blocksSize = loop->m_header->bbPostorderNum + 1; BitVecTraits loopTraits = loop->LoopBlockTraits(); loop->m_blocks = BitVecOps::MakeEmpty(&loopTraits); @@ -5508,11 +5507,11 @@ BasicBlock* FlowGraphDominatorTree::IntersectDom(BasicBlock* finger1, BasicBlock { while (finger1 != finger2) { - if (finger1 == nullptr || finger2 == nullptr) + if ((finger1 == nullptr) || (finger2 == nullptr)) { return nullptr; } - while (finger1 != nullptr && finger1->bbNewPostorderNum < finger2->bbNewPostorderNum) + while ((finger1 != nullptr) && (finger1->bbPostorderNum < finger2->bbPostorderNum)) { finger1 = finger1->bbIDom; } @@ -5520,7 +5519,7 @@ BasicBlock* FlowGraphDominatorTree::IntersectDom(BasicBlock* finger1, BasicBlock { return nullptr; } - while (finger2 != nullptr && finger2->bbNewPostorderNum < finger1->bbNewPostorderNum) + while ((finger2 != nullptr) && (finger2->bbPostorderNum < finger1->bbPostorderNum)) { finger2 = finger2->bbIDom; } @@ -5560,10 +5559,37 @@ bool FlowGraphDominatorTree::Dominates(BasicBlock* dominator, BasicBlock* domina // // where the equality holds when you ask if A dominates itself. // - return (m_preorderNum[dominator->bbNewPostorderNum] <= m_preorderNum[dominated->bbNewPostorderNum]) && - (m_postorderNum[dominator->bbNewPostorderNum] >= m_postorderNum[dominated->bbNewPostorderNum]); + return (m_preorderNum[dominator->bbPostorderNum] <= m_preorderNum[dominated->bbPostorderNum]) && + (m_postorderNum[dominator->bbPostorderNum] >= m_postorderNum[dominated->bbPostorderNum]); } +#ifdef DEBUG +//------------------------------------------------------------------------ +// FlowGraphDominatorTree::Dump: Dump a textual representation of the dominator +// tree. +// +void FlowGraphDominatorTree::Dump() +{ + Compiler* comp = m_dfsTree->GetCompiler(); + + for (BasicBlock* block : comp->Blocks()) + { + if (!m_dfsTree->Contains(block) || (m_domTree[block->bbPostorderNum].firstChild == nullptr)) + continue; + + printf(FMT_BB " : ", block->bbNum); + for (BasicBlock* child = m_domTree[block->bbPostorderNum].firstChild; child != nullptr; + child = m_domTree[child->bbPostorderNum].nextSibling) + { + printf(FMT_BB " ", child->bbNum); + } + printf("\n"); + } + + printf("\n"); +} +#endif + //------------------------------------------------------------------------ // FlowGraphDominatorTree::Build: Compute the dominator tree for the blocks in // the DFS tree. @@ -5589,6 +5615,7 @@ FlowGraphDominatorTree* FlowGraphDominatorTree::Build(const FlowGraphDfsTree* df // Reset BlockPredsWithEH cache. comp->m_blockToEHPreds = nullptr; + comp->m_dominancePreds = nullptr; assert((comp->fgFirstBB->bbPreds == nullptr) && !comp->fgFirstBB->hasTryIndex()); assert(postOrder[count - 1] == comp->fgFirstBB); @@ -5617,7 +5644,7 @@ FlowGraphDominatorTree* FlowGraphDominatorTree::Build(const FlowGraphDfsTree* df continue; // Unreachable pred } - if ((numIters <= 0) && (domPred->bbNewPostorderNum <= poNum)) + if ((numIters <= 0) && (domPred->bbPostorderNum <= poNum)) { continue; // Pred not yet visited } @@ -5632,6 +5659,7 @@ FlowGraphDominatorTree* FlowGraphDominatorTree::Build(const FlowGraphDfsTree* df } } + assert(bbIDom != nullptr); // Did we change the bbIDom value? If so, we go around the outer loop again. if (block->bbIDom != bbIDom) { @@ -5656,8 +5684,8 @@ FlowGraphDominatorTree* FlowGraphDominatorTree::Build(const FlowGraphDfsTree* df assert(parent != nullptr); assert(dfsTree->Contains(block) && dfsTree->Contains(parent)); - domTree[i].nextSibling = domTree[parent->bbNewPostorderNum].firstChild; - domTree[parent->bbNewPostorderNum].firstChild = block; + domTree[i].nextSibling = domTree[parent->bbPostorderNum].firstChild; + domTree[parent->bbPostorderNum].firstChild = block; } #ifdef DEBUG @@ -5674,7 +5702,7 @@ FlowGraphDominatorTree* FlowGraphDominatorTree::Build(const FlowGraphDfsTree* df printf(FMT_BB " :", postOrder[poNum]->bbNum); for (BasicBlock* child = domTree[poNum].firstChild; child != nullptr; - child = domTree[child->bbNewPostorderNum].nextSibling) + child = domTree[child->bbPostorderNum].nextSibling) { printf(" " FMT_BB, child->bbNum); } @@ -5685,7 +5713,7 @@ FlowGraphDominatorTree* FlowGraphDominatorTree::Build(const FlowGraphDfsTree* df #endif // Assign preorder/postorder nums for fast "domnates" queries. - class NumberDomTreeVisitor : public NewDomTreeVisitor + class NumberDomTreeVisitor : public DomTreeVisitor { unsigned* m_preorderNums; unsigned* m_postorderNums; @@ -5694,18 +5722,18 @@ FlowGraphDominatorTree* FlowGraphDominatorTree::Build(const FlowGraphDfsTree* df public: NumberDomTreeVisitor(Compiler* comp, unsigned* preorderNums, unsigned* postorderNums) - : NewDomTreeVisitor(comp), m_preorderNums(preorderNums), m_postorderNums(postorderNums) + : DomTreeVisitor(comp), m_preorderNums(preorderNums), m_postorderNums(postorderNums) { } void PreOrderVisit(BasicBlock* block) { - m_preorderNums[block->bbNewPostorderNum] = m_preNum++; + m_preorderNums[block->bbPostorderNum] = m_preNum++; } void PostOrderVisit(BasicBlock* block) { - m_postorderNums[block->bbNewPostorderNum] = m_postNum++; + m_postorderNums[block->bbPostorderNum] = m_postNum++; } }; @@ -5736,7 +5764,7 @@ FlowGraphNaturalLoop* BlockToNaturalLoopMap::GetLoop(BasicBlock* block) return nullptr; } - unsigned index = m_indices[block->bbNewPostorderNum]; + unsigned index = m_indices[block->bbPostorderNum]; if (index == UINT_MAX) { return nullptr; @@ -5771,7 +5799,7 @@ BlockToNaturalLoopMap* BlockToNaturalLoopMap::Build(FlowGraphNaturalLoops* loops for (FlowGraphNaturalLoop* loop : loops->InReversePostOrder()) { loop->VisitLoopBlocks([=](BasicBlock* block) { - indices[block->bbNewPostorderNum] = loop->GetIndex(); + indices[block->bbPostorderNum] = loop->GetIndex(); return BasicBlockVisit::Continue; }); } @@ -5816,8 +5844,8 @@ BlockReachabilitySets* BlockReachabilitySets::Build(FlowGraphDfsTree* dfsTree) for (BasicBlock* const predBlock : block->PredBlocks()) { - change |= BitVecOps::UnionDChanged(&postOrderTraits, sets[block->bbNewPostorderNum], - sets[predBlock->bbNewPostorderNum]); + change |= BitVecOps::UnionDChanged(&postOrderTraits, sets[block->bbPostorderNum], + sets[predBlock->bbPostorderNum]); } } @@ -5862,7 +5890,7 @@ bool BlockReachabilitySets::CanReach(BasicBlock* from, BasicBlock* to) } BitVecTraits poTraits = m_dfsTree->PostOrderTraits(); - return BitVecOps::IsMember(&poTraits, m_reachabilitySets[to->bbNewPostorderNum], from->bbNewPostorderNum); + return BitVecOps::IsMember(&poTraits, m_reachabilitySets[to->bbPostorderNum], from->bbPostorderNum); } #ifdef DEBUG @@ -5883,7 +5911,7 @@ void BlockReachabilitySets::Dump() printf(FMT_BB " : ", block->bbNum); if (m_dfsTree->Contains(block)) { - BitVecOps::Iter iter(&postOrderTraits, m_reachabilitySets[block->bbNewPostorderNum]); + BitVecOps::Iter iter(&postOrderTraits, m_reachabilitySets[block->bbPostorderNum]); unsigned poNum = 0; const char* sep = ""; while (iter.NextElem(&poNum)) diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index 00f1f06b80cdfd..507ee46f479eb5 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -867,7 +867,7 @@ PhaseStatus Compiler::fgExpandHelper(bool skipRarelyRunBlocks) if ((result == PhaseStatus::MODIFIED_EVERYTHING) && opts.OptimizationEnabled()) { - fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); + fgRenumberBlocks(); } return result; diff --git a/src/coreclr/jit/ifconversion.cpp b/src/coreclr/jit/ifconversion.cpp index 4b3401fe657f97..f9cb5af17925e7 100644 --- a/src/coreclr/jit/ifconversion.cpp +++ b/src/coreclr/jit/ifconversion.cpp @@ -775,7 +775,7 @@ PhaseStatus Compiler::optIfConversion() bool madeChanges = false; // This phase does not respect SSA: assignments are deleted/moved. - assert(!fgDomsComputed); + assert(!fgSsaValid); optReachableBitVecTraits = nullptr; #if defined(TARGET_ARM64) || defined(TARGET_XARCH) diff --git a/src/coreclr/jit/loopcloning.cpp b/src/coreclr/jit/loopcloning.cpp index 6963d2494d85a8..108bdf4e5181ab 100644 --- a/src/coreclr/jit/loopcloning.cpp +++ b/src/coreclr/jit/loopcloning.cpp @@ -3159,7 +3159,6 @@ PhaseStatus Compiler::optCloneLoops() if (optLoopsCloned > 0) { - fgDomsComputed = false; fgRenumberBlocks(); fgInvalidateDfsTree(); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 73a65b96474aec..bd3685cd9b4e16 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -13892,7 +13892,7 @@ void Compiler::fgMorphBlock(BasicBlock* block) // An equal number means pred == block (block is a self-loop). // Either way the assertion info is not available, and we must assume the worst. // - if (pred->bbNewPostorderNum <= block->bbNewPostorderNum) + if (pred->bbPostorderNum <= block->bbPostorderNum) { JITDUMP(FMT_BB " pred " FMT_BB " not processed; clearing assertions in\n", block->bbNum, pred->bbNum); diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 5c75c6a6ce8f3f..b7679a56f67861 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -65,16 +65,41 @@ DataFlow::DataFlow(Compiler* pCompiler) : m_pCompiler(pCompiler) PhaseStatus Compiler::optSetBlockWeights() { noway_assert(opts.OptimizationEnabled()); - assert(fgDomsComputed); + assert(m_domTree != nullptr); assert(fgReturnBlocksComputed); bool madeChanges = false; bool firstBBDominatesAllReturns = true; const bool usingProfileWeights = fgIsUsingProfileWeights(); + // TODO-Quirk: Previously, this code ran on a dominator tree based only on + // regular flow. This meant that all handlers were not considered to be + // dominated by fgFirstBB. When those handlers could reach a return + // block that return was also not considered to be dominated by fgFirstBB. + // In practice the code below would then not make any changes for those + // functions. We emulate that behavior here. + for (EHblkDsc* eh : EHClauses(this)) + { + BasicBlock* flowBlock = eh->ExFlowBlock(); + + for (BasicBlockList* retBlocks = fgReturnBlocks; retBlocks != nullptr; retBlocks = retBlocks->next) + { + if (m_dfsTree->Contains(flowBlock) && m_reachabilitySets->CanReach(flowBlock, retBlocks->block)) + { + firstBBDominatesAllReturns = false; + break; + } + } + + if (!firstBBDominatesAllReturns) + { + break; + } + } + for (BasicBlock* const block : Blocks()) { - /* Blocks that can't be reached via the first block are rarely executed */ + // Blocks that can't be reached via the first block are rarely executed if (!m_reachabilitySets->CanReach(fgFirstBB, block) && !block->isRunRarely()) { madeChanges = true; @@ -95,7 +120,8 @@ PhaseStatus Compiler::optSetBlockWeights() for (BasicBlockList* retBlocks = fgReturnBlocks; retBlocks != nullptr; retBlocks = retBlocks->next) { - if (!fgDominate(block, retBlocks->block)) + // TODO-Quirk: Returns that are unreachable can just be ignored. + if (!m_dfsTree->Contains(retBlocks->block) || !m_domTree->Dominates(block, retBlocks->block)) { blockDominatesAllReturns = false; break; @@ -225,7 +251,7 @@ void Compiler::optScaleLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk) BasicBlock* backedge = tmp->getSourceBlock(); reachable |= m_reachabilitySets->CanReach(curBlk, backedge); - dominates |= fgDominate(curBlk, backedge); + dominates |= m_domTree->Dominates(curBlk, backedge); if (dominates && reachable) { @@ -361,7 +387,7 @@ void Compiler::optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk) { weight_t scale = 1.0 / BB_LOOP_WEIGHT_SCALE; - if (!fgDominate(curBlk, endBlk)) + if (!m_domTree->Dominates(curBlk, endBlk)) { scale *= 2; } @@ -498,7 +524,7 @@ void Compiler::optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmar if (!skipUnmarkLoop && // If we want to unmark this loop... (fgCurBBEpochSize == fgBBNumMax + 1) && // We didn't add new blocks since last renumber... - fgDomsComputed && // Given the doms are computed and valid... + (m_reachabilitySets != nullptr) && // Given the reachability sets are computed and valid... (fgCurBBEpochSize == fgDomBBcount + 1)) { // This block must reach conditionally or always @@ -1820,7 +1846,7 @@ class LoopSearch // and when we process its unique predecessor we'll abort if ENTRY // doesn't dominate that. } - else if (!comp->fgDominate(entry, block)) + else if (!comp->m_domTree->Dominates(entry, block)) { JITDUMP(" (find cycle) entry:" FMT_BB " does not dominate " FMT_BB "\n", entry->bbNum, block->bbNum); return false; @@ -1847,7 +1873,7 @@ class LoopSearch // of an outer loop. For the dominance test, if `predBlock` is a new block, use // its unique predecessor since the dominator tree has info for that. BasicBlock* effectivePred = (predBlock->bbNum > oldBlockMaxNum ? predBlock->Prev() : predBlock); - if (comp->fgDominate(entry, effectivePred)) + if (comp->m_domTree->Dominates(entry, effectivePred)) { // Outer loop back-edge continue; @@ -2454,7 +2480,6 @@ void Compiler::optFindNaturalLoops() } #endif // DEBUG - noway_assert(fgDomsComputed); assert(fgHasLoops); #if COUNT_LOOPS @@ -2548,7 +2573,9 @@ void Compiler::optFindNaturalLoops() if (mod) { fgInvalidateDfsTree(); - fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_DOMS); + fgRenumberBlocks(); + m_dfsTree = fgComputeDfs(); + m_domTree = FlowGraphDominatorTree::Build(m_dfsTree); } // Now the loop indices are stable. We can figure out parent/child relationships @@ -3937,7 +3964,6 @@ PhaseStatus Compiler::optUnrollLoops() if (change && !BitVecOps::IsEmpty(&loopTraits, loopsWithUnrolledDescendant) && (passes < 10)) { - fgDomsComputed = false; fgRenumberBlocks(); // For proper lexical visit fgInvalidateDfsTree(); m_dfsTree = fgComputeDfs(); @@ -3963,7 +3989,6 @@ PhaseStatus Compiler::optUnrollLoops() fgDfsBlocksAndRemove(); m_loops = FlowGraphNaturalLoops::Find(m_dfsTree); - fgDomsComputed = false; fgRenumberBlocks(); DBEXEC(verbose, fgDispBasicBlocks()); @@ -4747,6 +4772,10 @@ void Compiler::optFindAndScaleGeneralLoopBlocks() { m_reachabilitySets = BlockReachabilitySets::Build(m_dfsTree); } + if (m_domTree == nullptr) + { + m_domTree = FlowGraphDominatorTree::Build(m_dfsTree); + } unsigned generalLoopCount = 0; @@ -4844,7 +4873,6 @@ void Compiler::optFindLoops() #endif noway_assert(opts.OptimizationEnabled()); - assert(fgDomsComputed); optMarkLoopHeads(); @@ -4878,9 +4906,6 @@ PhaseStatus Compiler::optFindLoopsPhase() optLoopTable = nullptr; optLoopCount = 0; - // Old dominators and reachability sets are no longer valid. - fgDomsComputed = false; - return PhaseStatus::MODIFIED_EVERYTHING; } @@ -4894,8 +4919,9 @@ void Compiler::optFindNewLoops() if (optCanonicalizeLoops(m_loops)) { fgInvalidateDfsTree(); - fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_DOMS); + fgRenumberBlocks(); m_dfsTree = fgComputeDfs(); + m_domTree = FlowGraphDominatorTree::Build(m_dfsTree); m_loops = FlowGraphNaturalLoops::Find(m_dfsTree); } diff --git a/src/coreclr/jit/redundantbranchopts.cpp b/src/coreclr/jit/redundantbranchopts.cpp index e5fe4d8990f102..235a5fc1d5f40c 100644 --- a/src/coreclr/jit/redundantbranchopts.cpp +++ b/src/coreclr/jit/redundantbranchopts.cpp @@ -19,12 +19,12 @@ PhaseStatus Compiler::optRedundantBranches() } #endif // DEBUG - class OptRedundantBranchesDomTreeVisitor : public NewDomTreeVisitor + class OptRedundantBranchesDomTreeVisitor : public DomTreeVisitor { public: bool madeChanges; - OptRedundantBranchesDomTreeVisitor(Compiler* compiler) : NewDomTreeVisitor(compiler), madeChanges(false) + OptRedundantBranchesDomTreeVisitor(Compiler* compiler) : DomTreeVisitor(compiler), madeChanges(false) { } diff --git a/src/coreclr/jit/ssabuilder.cpp b/src/coreclr/jit/ssabuilder.cpp index 6ffc6df7b635ff..2072591bcd5a9a 100644 --- a/src/coreclr/jit/ssabuilder.cpp +++ b/src/coreclr/jit/ssabuilder.cpp @@ -141,9 +141,19 @@ void SsaBuilder::ComputeDominanceFrontiers(BasicBlock** postOrder, int count, Bl // Otherwise, there are > 1 preds. Each is a candidate B2 in the definition -- // *unless* it dominates "block"/B3. + FlowGraphDfsTree* dfsTree = m_pCompiler->m_dfsTree; + FlowGraphDominatorTree* domTree = m_pCompiler->m_domTree; + for (FlowEdge* pred = blockPreds; pred != nullptr; pred = pred->getNextPredEdge()) { - DBG_SSA_JITDUMP(" Considering predecessor " FMT_BB ".\n", pred->getSourceBlock()->bbNum); + BasicBlock* predBlock = pred->getSourceBlock(); + DBG_SSA_JITDUMP(" Considering predecessor " FMT_BB ".\n", predBlock->bbNum); + + if (!dfsTree->Contains(predBlock)) + { + DBG_SSA_JITDUMP(" Unreachable node\n"); + continue; + } // If we've found a B2, then consider the possible B1's. We start with // B2, since a block dominates itself, then traverse upwards in the dominator @@ -153,7 +163,7 @@ void SsaBuilder::ComputeDominanceFrontiers(BasicBlock** postOrder, int count, Bl // Along this way, make "block"/B3 part of the dom frontier of the B1. // When we reach this immediate dominator, the definition no longer applies, since this // potential B1 *does* dominate "block"/B3, so we stop. - for (BasicBlock* b1 = pred->getSourceBlock(); (b1 != nullptr) && (b1 != block->bbIDom); // !root && !loop + for (BasicBlock* b1 = predBlock; (b1 != nullptr) && (b1 != block->bbIDom); // !root && !loop b1 = b1->bbIDom) { DBG_SSA_JITDUMP(" Adding " FMT_BB " to dom frontier of pred dom " FMT_BB ".\n", block->bbNum, @@ -221,7 +231,7 @@ void SsaBuilder::ComputeIteratedDominanceFrontier(BasicBlock* b, const BlkToBlkV for (BasicBlock* f : *bDF) { - BitVecOps::AddElemD(&m_visitedTraits, m_visited, f->bbNewPostorderNum); + BitVecOps::AddElemD(&m_visitedTraits, m_visited, f->bbPostorderNum); bIDF->push_back(f); } @@ -239,7 +249,7 @@ void SsaBuilder::ComputeIteratedDominanceFrontier(BasicBlock* b, const BlkToBlkV { for (BasicBlock* ff : *fDF) { - if (BitVecOps::TryAddElemD(&m_visitedTraits, m_visited, ff->bbNewPostorderNum)) + if (BitVecOps::TryAddElemD(&m_visitedTraits, m_visited, ff->bbPostorderNum)) { bIDF->push_back(ff); } @@ -1213,7 +1223,7 @@ void SsaBuilder::RenameVariables() // memory ssa numbers to have some initial value. for (BasicBlock* const block : m_pCompiler->Blocks()) { - if (block->bbIDom == nullptr) + if (!m_pCompiler->m_dfsTree->Contains(block)) { for (MemoryKind memoryKind : allMemoryKinds()) { @@ -1223,14 +1233,14 @@ void SsaBuilder::RenameVariables() } } - class SsaRenameDomTreeVisitor : public NewDomTreeVisitor + class SsaRenameDomTreeVisitor : public DomTreeVisitor { SsaBuilder* m_builder; SsaRenameState* m_renameStack; public: SsaRenameDomTreeVisitor(Compiler* compiler, SsaBuilder* builder, SsaRenameState* renameStack) - : NewDomTreeVisitor(compiler), m_builder(builder), m_renameStack(renameStack) + : DomTreeVisitor(compiler), m_builder(builder), m_renameStack(renameStack) { } diff --git a/src/coreclr/jit/switchrecognition.cpp b/src/coreclr/jit/switchrecognition.cpp index 4d3e72d842a08f..7ab33d07c3c34b 100644 --- a/src/coreclr/jit/switchrecognition.cpp +++ b/src/coreclr/jit/switchrecognition.cpp @@ -38,7 +38,7 @@ PhaseStatus Compiler::optSwitchRecognition() if (modified) { - fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); + fgRenumberBlocks(); return PhaseStatus::MODIFIED_EVERYTHING; } #endif