Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5330,13 +5330,14 @@ class Compiler
BasicBlock* fgIntersectDom(BasicBlock* a, BasicBlock* b); // Intersect two immediate dominator sets.

void fgDfsReversePostorder();
unsigned fgDfsReversePostorderCore(BlockSet_ValArg_T startBlocks);
void fgDfsReversePostorderHelper(BasicBlock* block,
BlockSet& visited,
unsigned& preorderIndex,
unsigned& reversePostorderIndex);

BlockSet_ValRet_T fgDomFindStartNodes(); // Computes which basic blocks don't have incoming edges in the flow graph.
// Returns this as a set.
BlockSet_ValRet_T fgDomFindStartBlocks(); // Computes which basic blocks don't have incoming edges in the flow graph.
// Returns this as a set.

INDEBUG(void fgDispDomTree(DomTreeNode* domTree);) // Helper that prints out the Dominator Tree in debug builds.

Expand Down
68 changes: 43 additions & 25 deletions src/coreclr/jit/fgopt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -763,54 +763,70 @@ bool Compiler::fgRemoveDeadBlocks()

//-------------------------------------------------------------
// fgDfsReversePostorder: Depth first search to establish block
// preorder and reverse postorder numbers, plus a reverse postorder for blocks.
// preorder and reverse postorder numbers, plus a reverse postorder for blocks,
// using all entry blocks and blocks without preds as start lblocks.
//
// Notes:
// Assumes caller has computed the fgEnterBlks set.
//
// Each block's `bbPreorderNum` and `bbPostorderNum` is set.
//
// The `fgBBReversePostorder` array is filled in with the `BasicBlock*` in reverse post-order.
//
// This algorithm only pays attention to the actual blocks. It ignores any imaginary entry block.
//
void Compiler::fgDfsReversePostorder()
{
assert(fgBBcount == fgBBNumMax);
assert(BasicBlockBitSetTraits::GetSize(this) == fgBBNumMax + 1);

// Make sure fgEnterBlks are still there in startNodes, even if they participate in a loop (i.e., there is
// an incoming edge into the block).
assert(fgEnterBlksSetValid);

fgBBReversePostorder = new (this, CMK_DominatorMemory) BasicBlock*[fgBBNumMax + 1]{};

// visited : Once we run the DFS post order sort recursive algorithm, we mark the nodes we visited to avoid
// backtracking.
BlockSet visited(BlockSetOps::MakeEmpty(this));

// We begin by figuring out which basic blocks don't have incoming edges and mark them as
// start nodes. Later on we run the recursive algorithm for each node that we
// start blocks. Later on we run the recursive algorithm for each node that we
// mark in this step.
BlockSet_ValRet_T startNodes = fgDomFindStartNodes();
BlockSet_ValRet_T startBlocks = fgDomFindStartBlocks();
BlockSetOps::UnionD(this, startBlocks, fgEnterBlks);
assert(BlockSetOps::IsMember(this, startBlocks, fgFirstBB->bbNum));

BlockSetOps::UnionD(this, startNodes, fgEnterBlks);
assert(BlockSetOps::IsMember(this, startNodes, fgFirstBB->bbNum));
fgDfsReversePostorderCore(startBlocks);
}

//-------------------------------------------------------------
// fgDfsReversePostorderCore: Depth first search to establish block
// preorder and reverse postorder numbers, plus a reverse postorder for blocks,
// using a specified set of start blocks.
//
// Arguments:
// startBlocks: set of blocks to consider as DFS roots
//
// Returns:
// postorder number of last block reachable from the root set. Any block
// with a postorder number higher than this was not reachable from the root set.
//
// Notes:
// Each block's `bbPreorderNum` and `bbPostorderNum` is set.
// The `fgBBReversePostorder` array is filled in with the `BasicBlock*` in reverse post-order.
// This algorithm only pays attention to the actual blocks. It ignores any imaginary entry block.
//
unsigned Compiler::fgDfsReversePostorderCore(BlockSet_ValArg_T startBlocks)
{
assert(fgBBcount == fgBBNumMax);
assert(BasicBlockBitSetTraits::GetSize(this) == fgBBNumMax + 1);
fgBBReversePostorder = new (this, CMK_DominatorMemory) BasicBlock*[fgBBNumMax + 1]{};
BlockSet visited(BlockSetOps::MakeEmpty(this));

// Call the flowgraph DFS traversal helper.
unsigned preorderIndex = 1;
unsigned postorderIndex = 1;
for (BasicBlock* const block : Blocks())
{
// If the block has no predecessors, and we haven't already visited it (because it's in fgEnterBlks but also
// reachable from the first block), go ahead and traverse starting from this block.
if (BlockSetOps::IsMember(this, startNodes, block->bbNum) &&
// Spawn a DFS from each unvisited start block.
//
if (BlockSetOps::IsMember(this, startBlocks, block->bbNum) &&
!BlockSetOps::IsMember(this, visited, block->bbNum))
{
fgDfsReversePostorderHelper(block, visited, preorderIndex, postorderIndex);
}
}

const unsigned lastReachablePostorderNumber = postorderIndex;

// If there are still unvisited blocks (say isolated cycles), visit them too.
//
if (preorderIndex != fgBBcount + 1)
Expand Down Expand Up @@ -841,18 +857,20 @@ void Compiler::fgDfsReversePostorder()
printf("\n");
}
#endif // DEBUG

return lastReachablePostorderNumber;
}

//-------------------------------------------------------------
// fgDomFindStartNodes: Helper for dominance computation to find the start nodes block set.
// fgDomFindStartBlocks: Helper for dominance computation to find the start block set.
//
// The start nodes is a set that represents which basic blocks in the flow graph don't have incoming edges.
// The start block set represents basic blocks in the flow graph that do not have incoming edges.
// We begin assuming everything is a start block and remove any block that is a successor of another.
//
// Returns:
// Block set of start nodes.
// Block set describing the start blocks.
//
BlockSet_ValRet_T Compiler::fgDomFindStartNodes()
BlockSet_ValRet_T Compiler::fgDomFindStartBlocks()
{
BlockSet startNodes(BlockSetOps::MakeFull(this));

Expand Down
20 changes: 17 additions & 3 deletions src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13871,7 +13871,7 @@ PhaseStatus Compiler::fgMorphBlocks()
fgRenumberBlocks();
EnsureBasicBlockEpoch();
fgComputeEnterBlocksSet();
fgDfsReversePostorder();
const unsigned lastReachablePostorderNumber = fgDfsReversePostorderCore(fgEnterBlks);

// Disallow general creation of new blocks or edges as it
// would invalidate RPO.
Expand All @@ -13894,8 +13894,22 @@ PhaseStatus Compiler::fgMorphBlocks()
fgFirstBB->Next()->bbFlags |= BBF_CAN_ADD_PRED;
}

unsigned const bbNumMax = fgBBNumMax;
for (unsigned i = 1; i <= bbNumMax; i++)
// Remember this so we can sanity check that no new blocks will get created.
//
INDEBUG(unsigned const bbNumMax = fgBBNumMax;);

// Todo: verify enter block set is sufficient to allow actual removal here.
// Likely need to add genReturnBB, fgEntryBB (for OSR), and perhaps more.
//
if (lastReachablePostorderNumber < fgBBNumMax)
{
JITDUMP("Method has %u unreachable blocks, consider removing them\n",
fgBBNumMax - lastReachablePostorderNumber);
}

// Morph the blocks in RPO.
//
for (unsigned i = 1; i <= fgBBNumMax; i++)
{
BasicBlock* const block = fgBBReversePostorder[i];
fgMorphBlock(block);
Expand Down