Skip to content

Commit e13248a

Browse files
committed
[UnifyLoopExits] Reduce number of guard blocks
UnifyLoopExits creates a single exit, a control flow hub, for loops with multiple exits. There is an input to the block for each loop exiting block and an output from the block for each loop exit block. Multiple checks, or guard blocks, are needed to branch to the correct exit block. For large loops with lots of exit blocks, all the extra guard blocks cause problems for StructurizeCFG and subsequent passes. This patch reduces the number of guard blocks needed when the exit blocks branch to a common block (e.g., an unreachable block). The guard blocks are reduced by changing the inputs and outputs of the control flow hub. The inputs are the exit blocks and the outputs are the common block. Reducing the guard blocks enables StructurizeCFG to reorder the basic blocks in the CFG to reduce the values that exit a loop with multiple exits. This reduces the compile-time of StructurizeCFG and also reduces register pressure. Differential Revision: https://reviews.llvm.org/D123230
1 parent 5011b4c commit e13248a

File tree

2 files changed

+508
-1
lines changed

2 files changed

+508
-1
lines changed

llvm/lib/Transforms/Utils/UnifyLoopExits.cpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
145145
// locate the exit blocks.
146146
SetVector<BasicBlock *> ExitingBlocks;
147147
SetVector<BasicBlock *> Exits;
148+
// Record the exit blocks that branch to the same block.
149+
MapVector<BasicBlock *, SetVector<BasicBlock *> > CommonSuccs;
148150

149151
// We need SetVectors, but the Loop API takes a vector, so we use a temporary.
150152
SmallVector<BasicBlock *, 8> Temp;
@@ -158,6 +160,11 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
158160
if (SL == L || L->contains(SL))
159161
continue;
160162
Exits.insert(S);
163+
// The typical case for reducing the number of guard blocks occurs when
164+
// the exit block has a single predecessor and successor.
165+
if (S->getSinglePredecessor())
166+
if (auto *Succ = S->getSingleSuccessor())
167+
CommonSuccs[Succ].insert(S);
161168
}
162169
}
163170

@@ -172,13 +179,39 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
172179
for (auto EB : ExitingBlocks) {
173180
dbgs() << " " << EB->getName();
174181
}
175-
dbgs() << "\n";);
182+
dbgs() << "\n";
183+
184+
dbgs() << "Exit blocks with a common successor:\n";
185+
for (auto CS : CommonSuccs) {
186+
dbgs() << " Succ " << CS.first->getName() << ", exits:";
187+
for (auto Exit : CS.second)
188+
dbgs() << " " << Exit->getName();
189+
dbgs() << "\n";
190+
});
176191

177192
if (Exits.size() <= 1) {
178193
LLVM_DEBUG(dbgs() << "loop does not have multiple exits; nothing to do\n");
179194
return false;
180195
}
181196

197+
// When multiple exit blocks branch to the same block, change the control
198+
// flow hub to after the exit blocks rather than before. This reduces the
199+
// number of guard blocks needed after the loop.
200+
for (auto CS : CommonSuccs) {
201+
auto CB = CS.first;
202+
auto Preds = CS.second;
203+
if (Exits.contains(CB))
204+
continue;
205+
if (Preds.size() < 2 || Preds.size() == Exits.size())
206+
continue;
207+
for (auto Exit : Preds) {
208+
Exits.remove(Exit);
209+
ExitingBlocks.remove(Exit->getSinglePredecessor());
210+
ExitingBlocks.insert(Exit);
211+
}
212+
Exits.insert(CB);
213+
}
214+
182215
SmallVector<BasicBlock *, 8> GuardBlocks;
183216
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
184217
auto LoopExitBlock = CreateControlFlowHub(&DTU, GuardBlocks, ExitingBlocks,
@@ -198,6 +231,17 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
198231
if (auto ParentLoop = L->getParentLoop()) {
199232
for (auto G : GuardBlocks) {
200233
ParentLoop->addBasicBlockToLoop(G, LI);
234+
// Ensure the guard block predecessors are in a valid loop. After the
235+
// change to the control flow hub for common successors, a guard block
236+
// predecessor may not be in a loop or may be in an outer loop.
237+
for (auto Pred : predecessors(G)) {
238+
auto PredLoop = LI.getLoopFor(Pred);
239+
if (!ParentLoop->contains(PredLoop)) {
240+
if (PredLoop)
241+
LI.removeBlock(Pred);
242+
ParentLoop->addBasicBlockToLoop(Pred, LI);
243+
}
244+
}
201245
}
202246
ParentLoop->verifyLoop();
203247
}

0 commit comments

Comments
 (0)