Skip to content

Commit 1ff715f

Browse files
authored
JIT: stop computing dom start nodes for morph RPO (#94497)
Remove the up-front computation of enter blocks and dom start nodes from the DFS computations used for RPO. Also lay the groundwork for removing unreachable blocks, by tracking the postorder number of the last reachable block. Contributes to #93246.
1 parent 3c5123e commit 1ff715f

File tree

4 files changed

+68
-77
lines changed

4 files changed

+68
-77
lines changed

src/coreclr/jit/compiler.h

+1-4
Original file line numberDiff line numberDiff line change
@@ -5329,15 +5329,12 @@ class Compiler
53295329

53305330
BasicBlock* fgIntersectDom(BasicBlock* a, BasicBlock* b); // Intersect two immediate dominator sets.
53315331

5332-
void fgDfsReversePostorder();
5332+
unsigned fgDfsReversePostorder();
53335333
void fgDfsReversePostorderHelper(BasicBlock* block,
53345334
BlockSet& visited,
53355335
unsigned& preorderIndex,
53365336
unsigned& reversePostorderIndex);
53375337

5338-
BlockSet_ValRet_T fgDomFindStartNodes(); // Computes which basic blocks don't have incoming edges in the flow graph.
5339-
// Returns this as a set.
5340-
53415338
INDEBUG(void fgDispDomTree(DomTreeNode* domTree);) // Helper that prints out the Dominator Tree in debug builds.
53425339

53435340
DomTreeNode* fgBuildDomTree(); // Once we compute all the immediate dominator sets for each node in the flow graph

src/coreclr/jit/fgopt.cpp

+62-70
Original file line numberDiff line numberDiff line change
@@ -763,59 +763,87 @@ bool Compiler::fgRemoveDeadBlocks()
763763

764764
//-------------------------------------------------------------
765765
// fgDfsReversePostorder: Depth first search to establish block
766-
// preorder and reverse postorder numbers, plus a reverse postorder for blocks.
766+
// preorder and reverse postorder numbers, plus a reverse postorder for blocks,
767+
// using all entry blocks and EH handler blocks as start blocks.
767768
//
768769
// Notes:
769-
// Assumes caller has computed the fgEnterBlks set.
770-
//
771770
// Each block's `bbPreorderNum` and `bbPostorderNum` is set.
772-
//
773771
// The `fgBBReversePostorder` array is filled in with the `BasicBlock*` in reverse post-order.
774-
//
775772
// This algorithm only pays attention to the actual blocks. It ignores any imaginary entry block.
776773
//
777-
void Compiler::fgDfsReversePostorder()
774+
// Unreachable blocks will have higher pre and post order numbers than reachable blocks.
775+
// Hence they will appear at lower indices in the fgBBReversePostorder array.
776+
//
777+
unsigned Compiler::fgDfsReversePostorder()
778778
{
779779
assert(fgBBcount == fgBBNumMax);
780780
assert(BasicBlockBitSetTraits::GetSize(this) == fgBBNumMax + 1);
781-
782-
// Make sure fgEnterBlks are still there in startNodes, even if they participate in a loop (i.e., there is
783-
// an incoming edge into the block).
784-
assert(fgEnterBlksSetValid);
785-
786781
fgBBReversePostorder = new (this, CMK_DominatorMemory) BasicBlock*[fgBBNumMax + 1]{};
787-
788-
// visited : Once we run the DFS post order sort recursive algorithm, we mark the nodes we visited to avoid
789-
// backtracking.
790782
BlockSet visited(BlockSetOps::MakeEmpty(this));
791783

792-
// We begin by figuring out which basic blocks don't have incoming edges and mark them as
793-
// start nodes. Later on we run the recursive algorithm for each node that we
794-
// mark in this step.
795-
BlockSet_ValRet_T startNodes = fgDomFindStartNodes();
796-
797-
BlockSetOps::UnionD(this, startNodes, fgEnterBlks);
798-
assert(BlockSetOps::IsMember(this, startNodes, fgFirstBB->bbNum));
799-
800-
// Call the flowgraph DFS traversal helper.
801784
unsigned preorderIndex = 1;
802785
unsigned postorderIndex = 1;
803-
for (BasicBlock* const block : Blocks())
786+
787+
// Walk from our primary root.
788+
//
789+
fgDfsReversePostorderHelper(fgFirstBB, visited, preorderIndex, postorderIndex);
790+
791+
// If we didn't end up visiting everything, try the EH roots.
792+
//
793+
if (preorderIndex != fgBBcount + 1)
804794
{
805-
// If the block has no predecessors, and we haven't already visited it (because it's in fgEnterBlks but also
806-
// reachable from the first block), go ahead and traverse starting from this block.
807-
if (BlockSetOps::IsMember(this, startNodes, block->bbNum) &&
808-
!BlockSetOps::IsMember(this, visited, block->bbNum))
795+
for (EHblkDsc* const HBtab : EHClauses(this))
809796
{
810-
fgDfsReversePostorderHelper(block, visited, preorderIndex, postorderIndex);
797+
if (HBtab->HasFilter())
798+
{
799+
BasicBlock* const filterBlock = HBtab->ebdFilter;
800+
if (!BlockSetOps::IsMember(this, visited, filterBlock->bbNum))
801+
{
802+
fgDfsReversePostorderHelper(filterBlock, visited, preorderIndex, postorderIndex);
803+
}
804+
}
805+
806+
BasicBlock* const handlerBlock = HBtab->ebdHndBeg;
807+
if (!BlockSetOps::IsMember(this, visited, handlerBlock->bbNum))
808+
{
809+
fgDfsReversePostorderHelper(handlerBlock, visited, preorderIndex, postorderIndex);
810+
}
811+
812+
#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
813+
// For ARM code, prevent creating retless calls by visiting the call finally successors
814+
//
815+
if (HBtab->HasFinallyHandler())
816+
{
817+
for (BasicBlock* const finallyPredBlock : handlerBlock->PredBlocks())
818+
{
819+
// In some rare cases the finally is a loop entry.
820+
//
821+
if (!finallyPredBlock->KindIs(BBJ_CALLFINALLY))
822+
{
823+
continue;
824+
}
825+
assert(finallyPredBlock->isBBCallAlwaysPair());
826+
BasicBlock* const pairTailBlock = finallyPredBlock->Next();
827+
828+
if (!BlockSetOps::IsMember(this, visited, pairTailBlock->bbNum))
829+
{
830+
fgDfsReversePostorderHelper(pairTailBlock, visited, preorderIndex, postorderIndex);
831+
}
832+
}
833+
}
834+
#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
811835
}
812836
}
813837

814-
// If there are still unvisited blocks (say isolated cycles), visit them too.
838+
// That's everything reachable from the roots.
815839
//
816-
if (preorderIndex != fgBBcount + 1)
840+
const unsigned highestReachablePostorderNumber = postorderIndex - 1;
841+
842+
// If we still didn't end up visiting everything, visit what remains.
843+
//
844+
if (highestReachablePostorderNumber != fgBBcount)
817845
{
818-
JITDUMP("DFS: flow graph has some isolated cycles, doing extra traversals\n");
846+
JITDUMP("DFS: there are %u unreachable blocks\n", fgBBcount - highestReachablePostorderNumber);
819847
for (BasicBlock* const block : Blocks())
820848
{
821849
if (!BlockSetOps::IsMember(this, visited, block->bbNum))
@@ -841,48 +869,12 @@ void Compiler::fgDfsReversePostorder()
841869
printf("\n");
842870
}
843871
#endif // DEBUG
844-
}
845-
846-
//-------------------------------------------------------------
847-
// fgDomFindStartNodes: Helper for dominance computation to find the start nodes block set.
848-
//
849-
// The start nodes is a set that represents which basic blocks in the flow graph don't have incoming edges.
850-
// We begin assuming everything is a start block and remove any block that is a successor of another.
851-
//
852-
// Returns:
853-
// Block set of start nodes.
854-
//
855-
BlockSet_ValRet_T Compiler::fgDomFindStartNodes()
856-
{
857-
BlockSet startNodes(BlockSetOps::MakeFull(this));
858-
859-
for (BasicBlock* const block : Blocks())
860-
{
861-
for (BasicBlock* const succ : block->Succs(this))
862-
{
863-
BlockSetOps::RemoveElemD(this, startNodes, succ->bbNum);
864-
}
865-
}
866-
867-
#ifdef DEBUG
868-
if (verbose)
869-
{
870-
printf("\nDominator computation start blocks (those blocks with no incoming edges):\n");
871-
BlockSetOps::Iter iter(this, startNodes);
872-
unsigned bbNum = 0;
873-
while (iter.NextElem(&bbNum))
874-
{
875-
printf(FMT_BB " ", bbNum);
876-
}
877-
printf("\n");
878-
}
879-
#endif // DEBUG
880872

881-
return startNodes;
873+
return highestReachablePostorderNumber;
882874
}
883875

884876
//------------------------------------------------------------------------
885-
// fgDfsReversePostorderHelper: Helper to assign post-order numbers to blocks.
877+
// fgDfsReversePostorderHelper: Helper to assign post-order numbers to blocks
886878
//
887879
// Arguments:
888880
// block - The starting entry block

src/coreclr/jit/fgprofilesynthesis.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,6 @@ void ProfileSynthesis::RandomizeLikelihoods()
790790
void ProfileSynthesis::BuildReversePostorder()
791791
{
792792
m_comp->EnsureBasicBlockEpoch();
793-
m_comp->fgComputeEnterBlocksSet();
794793
m_comp->fgDfsReversePostorder();
795794

796795
// Build map from bbNum to Block*.

src/coreclr/jit/morph.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -13938,8 +13938,6 @@ PhaseStatus Compiler::fgMorphBlocks()
1393813938
// We are optimizing. Process in RPO.
1393913939
//
1394013940
fgRenumberBlocks();
13941-
EnsureBasicBlockEpoch();
13942-
fgComputeEnterBlocksSet();
1394313941
fgDfsReversePostorder();
1394413942

1394513943
// Disallow general creation of new blocks or edges as it
@@ -13963,7 +13961,12 @@ PhaseStatus Compiler::fgMorphBlocks()
1396313961
fgFirstBB->Next()->bbFlags |= BBF_CAN_ADD_PRED;
1396413962
}
1396513963

13964+
// Remember this so we can sanity check that no new blocks will get created.
13965+
//
1396613966
unsigned const bbNumMax = fgBBNumMax;
13967+
13968+
// Morph the blocks in RPO.
13969+
//
1396713970
for (unsigned i = 1; i <= bbNumMax; i++)
1396813971
{
1396913972
BasicBlock* const block = fgBBReversePostorder[i];

0 commit comments

Comments
 (0)