Skip to content

Commit ae0a74e

Browse files
committed
Change scope nested CFG passes to use a stack instead of recursion
1 parent 1f63535 commit ae0a74e

1 file changed

Lines changed: 174 additions & 127 deletions

File tree

projects/dxilconv/lib/DxilConvPasses/ScopeNestedCFG.cpp

Lines changed: 174 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,90 @@ 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+
}
493+
}
494+
// Remove unused case labels.
495+
for (unsigned NumCases = I->getNumCases(); CaseIdx < NumCases;
496+
NumCases--) {
497+
I->removeCase(SwitchInst::CaseIt{I, NumCases - 1});
497498
}
498-
}
499-
// Remove unused case labels.
500-
for (unsigned NumCases = I->getNumCases(); CaseIdx < NumCases;
501-
NumCases--) {
502-
I->removeCase(SwitchInst::CaseIt{I, NumCases - 1});
503499
}
504500
}
505-
}
506501

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);
502+
// Push successors onto worklist, visiting each successor group once.
503+
TerminatorInst *pTI = pBB->getTerminator();
504+
BasicBlock *pPrevSuccBB = nullptr;
505+
for (unsigned i = 0; i < pTI->getNumSuccessors(); i++) {
506+
BasicBlock *pSuccBB = pTI->getSuccessor(i);
507+
if (pSuccBB != pPrevSuccBB)
508+
Worklist.push_back(pSuccBB);
509+
pPrevSuccBB = pSuccBB;
514510
}
515-
pPrevSuccBB = pSuccBB;
516511
}
517512
}
518513

@@ -537,14 +532,24 @@ void ScopeNestedCFG::CollectUniqueSuccessors(
537532
//-----------------------------------------------------------------------------
538533
// Loop region transformations.
539534
//-----------------------------------------------------------------------------
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);
535+
void ScopeNestedCFG::CollectLoops(Loop *pLoop) {
536+
// Iterative post-order: collect in reverse pre-order, then reverse.
537+
SmallVector<Loop *, 16> Stack;
538+
SmallVector<Loop *, 16> ReversePostOrder;
539+
Stack.push_back(pLoop);
540+
541+
while (!Stack.empty()) {
542+
Loop *pCurrent = Stack.pop_back_val();
543+
ReversePostOrder.push_back(pCurrent);
544+
for (auto it = pCurrent->begin(), end = pCurrent->end(); it != end; ++it) {
545+
Stack.push_back(*it);
546+
}
545547
}
546548

547-
m_Loops.emplace_back(pLoop);
549+
for (auto it = ReversePostOrder.rbegin(), end = ReversePostOrder.rend();
550+
it != end; ++it) {
551+
m_Loops.emplace_back(*it);
552+
}
548553
}
549554

550555
void ScopeNestedCFG::AnnotateBranch(BasicBlock *pBB, BranchKind Kind) {
@@ -988,60 +993,102 @@ void ScopeNestedCFG::BlockTopologicalOrderAndReachability::dump(
988993

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

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-
}
1012+
SmallVector<StackFrame, 32> Stack;
1013+
Stack.emplace_back(pEntry);
10001014

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-
}
1015+
while (!Stack.empty()) {
1016+
StackFrame &Frame = Stack.back();
10091017

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

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-
}
1026+
// Region terminator.
1027+
if (IsAcyclicRegionTerminator(Frame.pNode)) {
1028+
Marks[Frame.pNode] = 2; // late watermark
1029+
BTO.AppendBlock(Frame.pNode,
1030+
std::make_unique<BitVector>(NumBBs, false));
1031+
Stack.pop_back();
1032+
continue;
1033+
}
10181034

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

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-
}
1037+
// Loop with no exit.
1038+
if (pEffective == nullptr) {
1039+
Marks[Frame.pNode] = 2; // late watermark
1040+
BTO.AppendBlock(Frame.pNode,
1041+
std::make_unique<BitVector>(NumBBs, false));
1042+
Stack.pop_back();
1043+
continue;
1044+
}
10281045

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

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

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

1042-
Marks[pNode] = 2; // late watermark
1079+
// All successors processed.
1080+
BasicBlock *pNode = Frame.pNode;
1081+
auto ReachableBBs = std::move(Frame.ReachableBBs);
1082+
Marks[pNode] = 2; // late watermark
1083+
BTO.AppendBlock(pNode, std::move(ReachableBBs));
1084+
Stack.pop_back();
1085+
}
10431086

1044-
BTO.AppendBlock(pNode, std::move(ReachableBBs));
1087+
#if SNCFG_DBG
1088+
dbgs() << "\nBB topological order and reachable BBs rooted at "
1089+
<< pEntry->getName() << ":\n";
1090+
BTO.dump(dbgs());
1091+
#endif
10451092
}
10461093

10471094
//-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)