Skip to content

Commit f59a3f5

Browse files
authored
JIT: fix fgDfsReversePostorder (#82950)
This method was not doing a proper depth first search, so the reverse postorder it created was flawed.
1 parent 880e73c commit f59a3f5

File tree

2 files changed

+75
-56
lines changed

2 files changed

+75
-56
lines changed

src/coreclr/jit/block.h

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,28 +1946,6 @@ inline PredBlockList::iterator& PredBlockList::iterator::operator++()
19461946
return *this;
19471947
}
19481948

1949-
// This enum represents a pre/post-visit action state to emulate a depth-first
1950-
// spanning tree traversal of a tree or graph.
1951-
enum DfsStackState
1952-
{
1953-
DSS_Invalid, // The initialized, invalid error state
1954-
DSS_Pre, // The DFS pre-order (first visit) traversal state
1955-
DSS_Post // The DFS post-order (last visit) traversal state
1956-
};
1957-
1958-
// These structs represents an entry in a stack used to emulate a non-recursive
1959-
// depth-first spanning tree traversal of a graph. The entry contains either a
1960-
// block pointer or a block number depending on which is more useful.
1961-
struct DfsBlockEntry
1962-
{
1963-
DfsStackState dfsStackState; // The pre/post traversal action for this entry
1964-
BasicBlock* dfsBlock; // The corresponding block for the action
1965-
1966-
DfsBlockEntry(DfsStackState state, BasicBlock* basicBlock) : dfsStackState(state), dfsBlock(basicBlock)
1967-
{
1968-
}
1969-
};
1970-
19711949
/*****************************************************************************
19721950
*
19731951
* The following call-backs supplied by the client; it's used by the code

src/coreclr/jit/fgopt.cpp

Lines changed: 75 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,20 @@ void Compiler::fgDfsReversePostorder()
789789
}
790790
}
791791

792+
// If there are still unvisited blocks (say isolated cycles), visit them too.
793+
//
794+
if (preorderIndex != fgBBcount + 1)
795+
{
796+
JITDUMP("DFS: flow graph has some isolated cycles, doing extra traversals\n");
797+
for (BasicBlock* const block : Blocks())
798+
{
799+
if (!BlockSetOps::IsMember(this, visited, block->bbNum))
800+
{
801+
fgDfsReversePostorderHelper(block, visited, preorderIndex, postorderIndex);
802+
}
803+
}
804+
}
805+
792806
// After the DFS reverse postorder is completed, we must have visited all the basic blocks.
793807
noway_assert(preorderIndex == fgBBcount + 1);
794808
noway_assert(postorderIndex == fgBBcount + 1);
@@ -866,64 +880,91 @@ void Compiler::fgDfsReversePostorderHelper(BasicBlock* block,
866880
// Assume we haven't visited this node yet (callers ensure this).
867881
assert(!BlockSetOps::IsMember(this, visited, block->bbNum));
868882

883+
struct DfsBlockEntry
884+
{
885+
public:
886+
DfsBlockEntry(Compiler* comp, BasicBlock* block) : m_block(block), m_nSucc(block->NumSucc(comp)), m_iter(0)
887+
{
888+
}
889+
890+
BasicBlock* getBlock()
891+
{
892+
return m_block;
893+
}
894+
895+
bool atStart()
896+
{
897+
return m_iter == 0;
898+
}
899+
900+
BasicBlock* getNextSucc(Compiler* comp)
901+
{
902+
if (m_iter >= m_nSucc)
903+
{
904+
return nullptr;
905+
}
906+
return m_block->GetSucc(m_iter++, comp);
907+
}
908+
909+
private:
910+
BasicBlock* m_block;
911+
unsigned m_nSucc;
912+
unsigned m_iter;
913+
};
914+
869915
// Allocate a local stack to hold the DFS traversal actions necessary
870916
// to compute pre/post-ordering of the control flowgraph.
871917
ArrayStack<DfsBlockEntry> stack(getAllocator(CMK_ArrayStack));
872918

873919
// Push the first block on the stack to seed the traversal.
874-
stack.Push(DfsBlockEntry(DSS_Pre, block));
920+
stack.Emplace(this, block);
875921

876922
// Flag the node we just visited to avoid backtracking.
877923
BlockSetOps::AddElemD(this, visited, block->bbNum);
878924

879925
// The search is terminated once all the actions have been processed.
880926
while (!stack.Empty())
881927
{
882-
DfsBlockEntry current = stack.Pop();
883-
BasicBlock* currentBlock = current.dfsBlock;
928+
DfsBlockEntry& current = stack.TopRef();
929+
BasicBlock* const block = current.getBlock();
884930

885-
if (current.dfsStackState == DSS_Pre)
931+
if (current.atStart())
886932
{
887-
// This is a pre-visit that corresponds to the first time the
888-
// node is encountered in the spanning tree and receives pre-order
889-
// numberings. By pushing the post-action on the stack here we
890-
// are guaranteed to only process it after all of its successors
891-
// pre and post actions are processed.
892-
stack.Push(DfsBlockEntry(DSS_Post, currentBlock));
893-
currentBlock->bbPreorderNum = preorderIndex;
933+
// Initial visit to this node
934+
//
935+
block->bbPreorderNum = preorderIndex;
894936
preorderIndex++;
895-
896-
for (BasicBlock* const succ : currentBlock->Succs(this))
897-
{
898-
// If this is a node we haven't seen before, go ahead and process
899-
if (!BlockSetOps::IsMember(this, visited, succ->bbNum))
900-
{
901-
// Push a pre-visit action for this successor onto the stack and
902-
// mark it as visited in case this block has multiple successors
903-
// to the same node (multi-graph).
904-
stack.Push(DfsBlockEntry(DSS_Pre, succ));
905-
BlockSetOps::AddElemD(this, visited, succ->bbNum);
906-
}
907-
}
908937
}
909-
else
910-
{
911-
// This is a post-visit that corresponds to the last time the
912-
// node is visited in the spanning tree and only happens after
913-
// all descendents in the spanning tree have had pre and post
914-
// actions applied.
915938

916-
assert(current.dfsStackState == DSS_Post);
917-
currentBlock->bbPostorderNum = postorderIndex;
939+
BasicBlock* const succ = current.getNextSucc(this);
918940

919-
// Compute the index of this in the reverse postorder and
941+
if (succ == nullptr)
942+
{
943+
// Final visit to this node
944+
//
945+
block->bbPostorderNum = postorderIndex;
946+
947+
// Compute the index of block in the reverse postorder and
920948
// update the reverse postorder accordingly.
921949
//
922950
assert(postorderIndex <= fgBBcount);
923951
unsigned reversePostorderIndex = fgBBcount - postorderIndex + 1;
924-
fgBBReversePostorder[reversePostorderIndex] = currentBlock;
952+
fgBBReversePostorder[reversePostorderIndex] = block;
925953
postorderIndex++;
954+
955+
stack.Pop();
956+
continue;
926957
}
958+
959+
if (BlockSetOps::IsMember(this, visited, succ->bbNum))
960+
{
961+
// Already visited this succ
962+
//
963+
continue;
964+
}
965+
966+
BlockSetOps::AddElemD(this, visited, succ->bbNum);
967+
stack.Emplace(this, succ);
927968
}
928969
}
929970

0 commit comments

Comments
 (0)