Skip to content

Commit 33656f6

Browse files
jenatalillvm-beanz
andauthored
Change scope nested CFG passes to use a stack instead of recursion (#8227)
Fixes #8224 --------- Co-authored-by: Chris B <[email protected]>
1 parent 8d34720 commit 33656f6

1 file changed

Lines changed: 171 additions & 127 deletions

File tree

projects/dxilconv/lib/DxilConvPasses/ScopeNestedCFG.cpp

Lines changed: 171 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/Analysis/ReducibilityAnalysis.h"
1515

1616
#include "llvm/ADT/BitVector.h"
17+
#include "llvm/ADT/SmallVector.h"
1718
#include "llvm/Analysis/CFG.h"
1819
#include "llvm/Analysis/LoopPass.h"
1920
#include "llvm/IR/CFG.h"
@@ -140,16 +141,14 @@ class ScopeNestedCFG : public FunctionPass {
140141
// Preliminary CFG transformations and related utilities.
141142
//
142143
void SanitizeBranches();
143-
void SanitizeBranchesRec(BasicBlock *pBB,
144-
unordered_set<BasicBlock *> &VisitedBB);
145144
void CollectUniqueSuccessors(const BasicBlock *pBB,
146145
const BasicBlock *pSuccessorToExclude,
147146
vector<BasicBlock *> &Successors);
148147

149148
//
150149
// Loop region transformations.
151150
//
152-
void CollectLoopsRec(Loop *pLoop);
151+
void CollectLoops(Loop *pLoop);
153152

154153
void AnnotateBranch(BasicBlock *pBB, BranchKind Kind);
155154
BranchKind GetBranchAnnotation(const BasicBlock *pBB);
@@ -203,9 +202,6 @@ class ScopeNestedCFG : public FunctionPass {
203202
};
204203
void ComputeBlockTopologicalOrderAndReachability(
205204
BasicBlock *pEntry, BlockTopologicalOrderAndReachability &BTO);
206-
void ComputeBlockTopologicalOrderAndReachabilityRec(
207-
BasicBlock *pNode, BlockTopologicalOrderAndReachability &BTO,
208-
unordered_map<BasicBlock *, unsigned> &Marks);
209205

210206
//
211207
// Recovery of scope end points.
@@ -337,7 +333,7 @@ bool ScopeNestedCFG::runOnFunction(Function &F) {
337333
for (auto itLoop = m_pLI->begin(), endLoop = m_pLI->end(); itLoop != endLoop;
338334
++itLoop) {
339335
Loop *pLoop = *itLoop;
340-
CollectLoopsRec(pLoop);
336+
CollectLoops(pLoop);
341337
}
342338

343339
//
@@ -428,91 +424,89 @@ void ScopeNestedCFG::Clear() {
428424
// Preliminary CFG transformations and related utilities.
429425
//-----------------------------------------------------------------------------
430426
void ScopeNestedCFG::SanitizeBranches() {
431-
unordered_set<BasicBlock *> VisitedBB;
432-
SanitizeBranchesRec(m_pFunc->begin(), VisitedBB);
433-
}
427+
SmallPtrSet<BasicBlock *, 32> VisitedBB;
428+
SmallVector<BasicBlock *, 32> Worklist;
429+
Worklist.push_back(m_pFunc->begin());
434430

435-
void ScopeNestedCFG::SanitizeBranchesRec(
436-
BasicBlock *pBB, unordered_set<BasicBlock *> &VisitedBB) {
437-
// Mark pBB as visited, and return if pBB already has been visited.
438-
if (!VisitedBB.emplace(pBB).second)
439-
return;
431+
while (!Worklist.empty()) {
432+
BasicBlock *pBB = Worklist.pop_back_val();
440433

441-
// Sanitize branch.
442-
if (BranchInst *I = dyn_cast<BranchInst>(pBB->getTerminator())) {
443-
// a. Convert a conditional branch to unconditional, if successors are the
444-
// same.
445-
if (I->isConditional()) {
446-
BasicBlock *pSucc1 = I->getSuccessor(0);
447-
BasicBlock *pSucc2 = I->getSuccessor(1);
448-
if (pSucc1 == pSucc2) {
449-
BranchInst::Create(pSucc1, I);
450-
I->eraseFromParent();
434+
// Mark pBB as visited, and skip if pBB already has been visited.
435+
if (!VisitedBB.insert(pBB).second)
436+
continue;
437+
438+
// Sanitize branch.
439+
if (BranchInst *I = dyn_cast<BranchInst>(pBB->getTerminator())) {
440+
// a. Convert a conditional branch to unconditional, if successors are the
441+
// same.
442+
if (I->isConditional()) {
443+
BasicBlock *pSucc1 = I->getSuccessor(0);
444+
BasicBlock *pSucc2 = I->getSuccessor(1);
445+
if (pSucc1 == pSucc2) {
446+
BranchInst::Create(pSucc1, I);
447+
I->eraseFromParent();
448+
}
451449
}
452-
}
453-
} else if (SwitchInst *I = dyn_cast<SwitchInst>(pBB->getTerminator())) {
454-
// b. Group switch successors.
455-
struct SwitchCaseGroup {
456-
BasicBlock *pSuccBB;
457-
vector<ConstantInt *> CaseValue;
458-
};
459-
vector<SwitchCaseGroup> SwitchCaseGroups;
460-
unordered_map<BasicBlock *, unsigned> BB2GroupIdMap;
461-
BasicBlock *pDefaultBB = I->getDefaultDest();
450+
} else if (SwitchInst *I = dyn_cast<SwitchInst>(pBB->getTerminator())) {
451+
// b. Group switch successors.
452+
struct SwitchCaseGroup {
453+
BasicBlock *pSuccBB;
454+
SmallVector<ConstantInt *, 8> CaseValue;
455+
};
456+
SmallVector<SwitchCaseGroup, 8> SwitchCaseGroups;
457+
DenseMap<BasicBlock *, unsigned> BB2GroupIdMap;
458+
BasicBlock *pDefaultBB = I->getDefaultDest();
462459

463-
for (SwitchInst::CaseIt itCase = I->case_begin(), endCase = I->case_end();
464-
itCase != endCase; ++itCase) {
465-
BasicBlock *pSuccBB = itCase.getCaseSuccessor();
466-
ConstantInt *pCaseValue = itCase.getCaseValue();
460+
for (SwitchInst::CaseIt itCase = I->case_begin(), endCase = I->case_end();
461+
itCase != endCase; ++itCase) {
462+
BasicBlock *pSuccBB = itCase.getCaseSuccessor();
463+
ConstantInt *pCaseValue = itCase.getCaseValue();
467464

468-
if (pSuccBB == pDefaultBB) {
469465
// Assimilate this case label into default label.
470-
continue;
471-
}
466+
if (pSuccBB == pDefaultBB)
467+
continue;
472468

473-
auto itGroup = BB2GroupIdMap.insert({pSuccBB, SwitchCaseGroups.size()});
474-
if (itGroup.second) {
475-
SwitchCaseGroups.emplace_back(SwitchCaseGroup{});
476-
}
469+
auto itGroup = BB2GroupIdMap.insert({pSuccBB, SwitchCaseGroups.size()});
470+
if (itGroup.second)
471+
SwitchCaseGroups.emplace_back(SwitchCaseGroup{});
477472

478-
SwitchCaseGroup &G = SwitchCaseGroups[itGroup.first->second];
479-
G.pSuccBB = pSuccBB;
480-
G.CaseValue.emplace_back(pCaseValue);
481-
}
473+
SwitchCaseGroup &G = SwitchCaseGroups[itGroup.first->second];
474+
G.pSuccBB = pSuccBB;
475+
G.CaseValue.emplace_back(pCaseValue);
476+
}
482477

483-
if (SwitchCaseGroups.size() == 0) {
484-
// All case labels were assimilated into the default label.
485-
// Replace switch with an unconditional branch.
486-
BranchInst::Create(pDefaultBB, I);
487-
I->eraseFromParent();
488-
} else {
489-
// Rewrite switch instruction such that case labels are grouped by the
490-
// successor.
491-
unsigned CaseIdx = 0;
492-
for (const SwitchCaseGroup &G : SwitchCaseGroups) {
493-
for (ConstantInt *pCaseValue : G.CaseValue) {
494-
SwitchInst::CaseIt itCase(I, CaseIdx++);
495-
itCase.setSuccessor(G.pSuccBB);
496-
itCase.setValue(pCaseValue);
478+
if (SwitchCaseGroups.size() == 0) {
479+
// All case labels were assimilated into the default label.
480+
// Replace switch with an unconditional branch.
481+
BranchInst::Create(pDefaultBB, I);
482+
I->eraseFromParent();
483+
} else {
484+
// Rewrite switch instruction such that case labels are grouped by the
485+
// successor.
486+
unsigned CaseIdx = 0;
487+
for (const SwitchCaseGroup &G : SwitchCaseGroups) {
488+
for (ConstantInt *pCaseValue : G.CaseValue) {
489+
SwitchInst::CaseIt itCase(I, CaseIdx++);
490+
itCase.setSuccessor(G.pSuccBB);
491+
itCase.setValue(pCaseValue);
492+
}
497493
}
498-
}
499-
// Remove unused case labels.
500-
for (unsigned NumCases = I->getNumCases(); CaseIdx < NumCases;
501-
NumCases--) {
502-
I->removeCase(SwitchInst::CaseIt{I, NumCases - 1});
494+
// Remove unused case labels.
495+
for (unsigned NumCases = I->getNumCases(); CaseIdx < NumCases;
496+
--NumCases)
497+
I->removeCase(SwitchInst::CaseIt{I, NumCases - 1});
503498
}
504499
}
505-
}
506500

507-
// Recurse, visiting each successor group once.
508-
TerminatorInst *pTI = pBB->getTerminator();
509-
BasicBlock *pPrevSuccBB = nullptr;
510-
for (unsigned i = 0; i < pTI->getNumSuccessors(); i++) {
511-
BasicBlock *pSuccBB = pTI->getSuccessor(i);
512-
if (pSuccBB != pPrevSuccBB) {
513-
SanitizeBranchesRec(pSuccBB, VisitedBB);
501+
// Push successors onto worklist, visiting each successor group once.
502+
TerminatorInst *pTI = pBB->getTerminator();
503+
BasicBlock *pPrevSuccBB = nullptr;
504+
for (unsigned i = 0; i < pTI->getNumSuccessors(); i++) {
505+
BasicBlock *pSuccBB = pTI->getSuccessor(i);
506+
if (pSuccBB != pPrevSuccBB)
507+
Worklist.push_back(pSuccBB);
508+
pPrevSuccBB = pSuccBB;
514509
}
515-
pPrevSuccBB = pSuccBB;
516510
}
517511
}
518512

@@ -537,14 +531,22 @@ void ScopeNestedCFG::CollectUniqueSuccessors(
537531
//-----------------------------------------------------------------------------
538532
// Loop region transformations.
539533
//-----------------------------------------------------------------------------
540-
void ScopeNestedCFG::CollectLoopsRec(Loop *pLoop) {
541-
for (auto itLoop = pLoop->begin(), endLoop = pLoop->end(); itLoop != endLoop;
542-
++itLoop) {
543-
Loop *pNestedLoop = *itLoop;
544-
CollectLoopsRec(pNestedLoop);
534+
void ScopeNestedCFG::CollectLoops(Loop *pLoop) {
535+
// Iterative post-order: collect in reverse pre-order, then reverse.
536+
SmallVector<Loop *, 16> Stack;
537+
SmallVector<Loop *, 16> ReversePostOrder;
538+
Stack.push_back(pLoop);
539+
540+
while (!Stack.empty()) {
541+
Loop *pCurrent = Stack.pop_back_val();
542+
ReversePostOrder.push_back(pCurrent);
543+
for (auto it = pCurrent->begin(), end = pCurrent->end(); it != end; ++it)
544+
Stack.push_back(*it);
545545
}
546546

547-
m_Loops.emplace_back(pLoop);
547+
for (auto it = ReversePostOrder.rbegin(), end = ReversePostOrder.rend();
548+
it != end; ++it)
549+
m_Loops.emplace_back(*it);
548550
}
549551

550552
void ScopeNestedCFG::AnnotateBranch(BasicBlock *pBB, BranchKind Kind) {
@@ -988,60 +990,102 @@ void ScopeNestedCFG::BlockTopologicalOrderAndReachability::dump(
988990

989991
void ScopeNestedCFG::ComputeBlockTopologicalOrderAndReachability(
990992
BasicBlock *pEntry, BlockTopologicalOrderAndReachability &BTO) {
991-
unordered_map<BasicBlock *, unsigned> WaterMarks;
992-
ComputeBlockTopologicalOrderAndReachabilityRec(pEntry, BTO, WaterMarks);
993+
DenseMap<BasicBlock *, unsigned> Marks;
994+
unsigned NumBBs = (unsigned)pEntry->getParent()->getBasicBlockList().size();
995+
996+
struct StackFrame {
997+
BasicBlock *pNode;
998+
BasicBlock *pEffective;
999+
unique_ptr<BitVector> ReachableBBs;
1000+
succ_iterator CurrentSucc;
1001+
succ_iterator EndSucc;
1002+
bool Initialized;
1003+
1004+
StackFrame(BasicBlock *Node)
1005+
: pNode(Node), pEffective(nullptr), CurrentSucc(succ_begin(Node)),
1006+
EndSucc(succ_end(Node)), Initialized(false) {}
1007+
};
9931008

994-
#if SNCFG_DBG
995-
dbgs() << "\nBB topological order and reachable BBs rooted at "
996-
<< pEntry->getName() << ":\n";
997-
BTO.dump(dbgs());
998-
#endif
999-
}
1009+
SmallVector<StackFrame, 32> Stack;
1010+
Stack.emplace_back(pEntry);
10001011

1001-
void ScopeNestedCFG::ComputeBlockTopologicalOrderAndReachabilityRec(
1002-
BasicBlock *pNode, BlockTopologicalOrderAndReachability &BTO,
1003-
unordered_map<BasicBlock *, unsigned> &Marks) {
1004-
auto itMarkBB = Marks.find(pNode);
1005-
if (Marks.find(pNode) != Marks.end()) {
1006-
DXASSERT(itMarkBB->second == 2, "acyclic component has a cycle");
1007-
return;
1008-
}
1012+
while (!Stack.empty()) {
1013+
StackFrame &Frame = Stack.back();
10091014

1010-
unsigned NumBBs = (unsigned)pNode->getParent()->getBasicBlockList().size();
1015+
if (!Frame.Initialized) {
1016+
auto itMark = Marks.find(Frame.pNode);
1017+
if (itMark != Marks.end()) {
1018+
DXASSERT(itMark->second == 2, "acyclic component has a cycle");
1019+
Stack.pop_back();
1020+
continue;
1021+
}
10111022

1012-
// Region terminator.
1013-
if (IsAcyclicRegionTerminator(pNode)) {
1014-
Marks[pNode] = 2; // late watermark
1015-
BTO.AppendBlock(pNode, std::make_unique<BitVector>(NumBBs, false));
1016-
return;
1017-
}
1023+
// Region terminator.
1024+
if (IsAcyclicRegionTerminator(Frame.pNode)) {
1025+
Marks[Frame.pNode] = 2; // late watermark
1026+
BTO.AppendBlock(Frame.pNode,
1027+
std::make_unique<BitVector>(NumBBs, false));
1028+
Stack.pop_back();
1029+
continue;
1030+
}
10181031

1019-
BasicBlock *pNodeToFollowSuccessors =
1020-
GetEffectiveNodeToFollowSuccessor(pNode);
1032+
BasicBlock *pEffective = GetEffectiveNodeToFollowSuccessor(Frame.pNode);
10211033

1022-
// Loop with no exit.
1023-
if (pNodeToFollowSuccessors == nullptr) {
1024-
Marks[pNode] = 2; // late watermark
1025-
BTO.AppendBlock(pNode, std::make_unique<BitVector>(NumBBs, false));
1026-
return;
1027-
}
1034+
// Loop with no exit.
1035+
if (pEffective == nullptr) {
1036+
Marks[Frame.pNode] = 2; // late watermark
1037+
BTO.AppendBlock(Frame.pNode,
1038+
std::make_unique<BitVector>(NumBBs, false));
1039+
Stack.pop_back();
1040+
continue;
1041+
}
10281042

1029-
Marks[pNode] = 1; // early watermark
1043+
Frame.Initialized = true;
1044+
Frame.pEffective = pEffective;
1045+
Marks[Frame.pNode] = 1; // early watermark
1046+
Frame.ReachableBBs = std::make_unique<BitVector>(NumBBs, false);
1047+
Frame.CurrentSucc = succ_begin(pEffective);
1048+
Frame.EndSucc = succ_end(pEffective);
1049+
}
10301050

1031-
auto ReachableBBs = std::make_unique<BitVector>(NumBBs, false);
1032-
for (auto itSucc = succ_begin(pNodeToFollowSuccessors),
1033-
endSucc = succ_end(pNodeToFollowSuccessors);
1034-
itSucc != endSucc; ++itSucc) {
1035-
BasicBlock *pSuccBB = *itSucc;
1051+
// Process successors one at a time. When an unvisited successor is found,
1052+
// push it and revisit this frame later (without advancing the iterator so
1053+
// the now-visited successor will be unioned on the next visit).
1054+
bool PushedChild = false;
1055+
while (Frame.CurrentSucc != Frame.EndSucc) {
1056+
BasicBlock *pSuccBB = *Frame.CurrentSucc;
1057+
auto itMark = Marks.find(pSuccBB);
1058+
if (itMark != Marks.end()) {
1059+
DXASSERT(itMark->second == 2, "acyclic component has a cycle");
1060+
// Already processed, union reachable BBs and advance.
1061+
(*Frame.ReachableBBs) |= (*BTO.GetReachableBBs(pSuccBB));
1062+
++Frame.CurrentSucc;
1063+
} else {
1064+
// Successor not yet visited; push it for processing.
1065+
// Don't advance the iterator: when we return here the successor
1066+
// will be marked and we will union its reachability above.
1067+
Stack.emplace_back(pSuccBB);
1068+
PushedChild = true;
1069+
break;
1070+
}
1071+
}
10361072

1037-
ComputeBlockTopologicalOrderAndReachabilityRec(pSuccBB, BTO, Marks);
1038-
// Union reachable BBs.
1039-
(*ReachableBBs) |= (*BTO.GetReachableBBs(pSuccBB));
1040-
}
1073+
if (PushedChild)
1074+
continue;
10411075

1042-
Marks[pNode] = 2; // late watermark
1076+
// All successors processed.
1077+
BasicBlock *pNode = Frame.pNode;
1078+
unique_ptr<BitVector> ReachableBBs = std::move(Frame.ReachableBBs);
1079+
Marks[pNode] = 2; // late watermark
1080+
BTO.AppendBlock(pNode, std::move(ReachableBBs));
1081+
Stack.pop_back();
1082+
}
10431083

1044-
BTO.AppendBlock(pNode, std::move(ReachableBBs));
1084+
#if SNCFG_DBG
1085+
dbgs() << "\nBB topological order and reachable BBs rooted at "
1086+
<< pEntry->getName() << ":\n";
1087+
BTO.dump(dbgs());
1088+
#endif
10451089
}
10461090

10471091
//-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)