Skip to content

Commit e5e2cf1

Browse files
authored
Merge pull request #35608 from atrick/guard-simplify-loops
Add a safeguard to SimplifyCFG tryJumpThreading to avoid infinite loop peeling
2 parents 578adca + 8b20984 commit e5e2cf1

File tree

1 file changed

+33
-12
lines changed

1 file changed

+33
-12
lines changed

lib/SILOptimizer/Transforms/SimplifyCFG.cpp

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ class SimplifyCFG {
7979
llvm::SmallDenseMap<SILBasicBlock *, unsigned, 32> WorklistMap;
8080
// Keep track of loop headers - we don't want to jump-thread through them.
8181
SmallPtrSet<SILBasicBlock *, 32> LoopHeaders;
82+
// The set of cloned loop headers to avoid infinite loop peeling. Blocks in
83+
// this set may or may not still be LoopHeaders.
84+
// (ultimately this can be used to eliminate findLoopHeaders)
85+
SmallPtrSet<SILBasicBlock *, 4> ClonedLoopHeaders;
8286
// The cost (~ number of copied instructions) of jump threading per basic
8387
// block. Used to prevent infinite jump threading loops.
8488
llvm::SmallDenseMap<SILBasicBlock *, int, 8> JumpThreadingCost;
@@ -126,6 +130,16 @@ class SimplifyCFG {
126130
}
127131

128132
private:
133+
// Called when \p newBlock inherits the former predecessors of \p
134+
// oldBlock. e.g. if \p oldBlock was a loop header, then newBlock is now a
135+
// loop header.
136+
void substitutedBlockPreds(SILBasicBlock *oldBlock, SILBasicBlock *newBlock) {
137+
if (LoopHeaders.count(oldBlock))
138+
LoopHeaders.insert(newBlock);
139+
if (ClonedLoopHeaders.count(oldBlock))
140+
ClonedLoopHeaders.insert(newBlock);
141+
}
142+
129143
void clearWorklist() {
130144
WorklistMap.clear();
131145
WorklistList.clear();
@@ -171,8 +185,10 @@ class SimplifyCFG {
171185
// Remove it from the map as well.
172186
WorklistMap.erase(It);
173187

174-
if (LoopHeaders.count(BB))
188+
if (LoopHeaders.count(BB)) {
175189
LoopHeaders.erase(BB);
190+
ClonedLoopHeaders.erase(BB);
191+
}
176192
}
177193

178194
bool simplifyBlocks();
@@ -1083,10 +1099,13 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) {
10831099
return false;
10841100

10851101
// Don't jump thread through a potential header - this can produce irreducible
1086-
// control flow. Still, we make an exception for switch_enum.
1102+
// control flow and lead to infinite loop peeling.
10871103
bool DestIsLoopHeader = (LoopHeaders.count(DestBB) != 0);
10881104
if (DestIsLoopHeader) {
1089-
if (!isa<SwitchEnumInst>(destTerminator))
1105+
// Make an exception for switch_enum, but only if it's block was not already
1106+
// peeled out of it's original loop. In that case, further jump threading
1107+
// can accomplish nothing, and the loop will be infinitely peeled.
1108+
if (!isa<SwitchEnumInst>(destTerminator) || ClonedLoopHeaders.count(DestBB))
10901109
return false;
10911110
}
10921111

@@ -1132,8 +1151,14 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) {
11321151

11331152
// If we jump-thread a switch_enum in the loop header, we have to recalculate
11341153
// the loop header info.
1135-
if (DestIsLoopHeader)
1154+
//
1155+
// FIXME: findLoopHeaders should not be called repeatedly during simplify-cfg
1156+
// iteration. It is a whole-function analysis! It also does no nothing help to
1157+
// avoid infinite loop peeling.
1158+
if (DestIsLoopHeader) {
1159+
ClonedLoopHeaders.insert(Cloner.getNewBB());
11361160
findLoopHeaders();
1161+
}
11371162

11381163
++NumJumpThreads;
11391164
return true;
@@ -1372,8 +1397,7 @@ bool SimplifyCFG::simplifyBranchBlock(BranchInst *BI) {
13721397
for (auto &Succ : remainingBlock->getSuccessors())
13731398
addToWorklist(Succ);
13741399

1375-
if (LoopHeaders.count(deletedBlock))
1376-
LoopHeaders.insert(remainingBlock);
1400+
substitutedBlockPreds(deletedBlock, remainingBlock);
13771401

13781402
auto Iter = JumpThreadingCost.find(deletedBlock);
13791403
if (Iter != JumpThreadingCost.end()) {
@@ -1397,8 +1421,7 @@ bool SimplifyCFG::simplifyBranchBlock(BranchInst *BI) {
13971421
trampolineDest.newSourceBranchArgs);
13981422
// Eliminating the trampoline can expose opportunities to improve the
13991423
// new block we branch to.
1400-
if (LoopHeaders.count(DestBB))
1401-
LoopHeaders.insert(trampolineDest.destBB);
1424+
substitutedBlockPreds(DestBB, trampolineDest.destBB);
14021425

14031426
addToWorklist(trampolineDest.destBB);
14041427
BI->eraseFromParent();
@@ -1583,8 +1606,7 @@ bool SimplifyCFG::simplifyCondBrBlock(CondBranchInst *BI) {
15831606
BI->getTrueBBCount(), BI->getFalseBBCount());
15841607
BI->eraseFromParent();
15851608

1586-
if (LoopHeaders.count(TrueSide))
1587-
LoopHeaders.insert(ThisBB);
1609+
substitutedBlockPreds(TrueSide, ThisBB);
15881610
removeIfDead(TrueSide);
15891611
addToWorklist(ThisBB);
15901612
return true;
@@ -1602,8 +1624,7 @@ bool SimplifyCFG::simplifyCondBrBlock(CondBranchInst *BI) {
16021624
falseTrampolineDest.destBB, falseTrampolineDest.newSourceBranchArgs,
16031625
BI->getTrueBBCount(), BI->getFalseBBCount());
16041626
BI->eraseFromParent();
1605-
if (LoopHeaders.count(FalseSide))
1606-
LoopHeaders.insert(ThisBB);
1627+
substitutedBlockPreds(FalseSide, ThisBB);
16071628
removeIfDead(FalseSide);
16081629
addToWorklist(ThisBB);
16091630
return true;

0 commit comments

Comments
 (0)