79
79
// Limitation: The pass cannot handle switch statements and indirect
80
80
// branches. Both must be lowered to plain branches first.
81
81
//
82
+ // CallBr support: CallBr is handled as a more general branch instruction which
83
+ // can have multiple successors. The pass redirects the edges to intermediate
84
+ // target blocks that unconditionally branch to the original callbr target
85
+ // blocks. This allows the control flow hub to know to which of the original
86
+ // target blocks to jump to.
87
+ // Example input CFG:
88
+ // Entry (callbr)
89
+ // / \
90
+ // v v
91
+ // H ----> B
92
+ // ^ /|
93
+ // `----' |
94
+ // v
95
+ // Exit
96
+ //
97
+ // becomes:
98
+ // Entry (callbr)
99
+ // / \
100
+ // v v
101
+ // target.H target.B
102
+ // | |
103
+ // v v
104
+ // H ----> B
105
+ // ^ /|
106
+ // `----' |
107
+ // v
108
+ // Exit
109
+ //
110
+ // Note
111
+ // OUTPUT CFG: Converted to a natural loop with a new header N.
112
+ //
113
+ // Entry (callbr)
114
+ // / \
115
+ // v v
116
+ // target.H target.B
117
+ // \ /
118
+ // \ /
119
+ // v v
120
+ // N <---.
121
+ // / \ \
122
+ // / \ |
123
+ // v v /
124
+ // H --> B --'
125
+ // |
126
+ // v
127
+ // Exit
128
+ //
82
129
// ===----------------------------------------------------------------------===//
83
130
84
131
#include " llvm/Transforms/Utils/FixIrreducible.h"
@@ -231,6 +278,7 @@ static bool fixIrreducible(Cycle &C, CycleInfo &CI, DominatorTree &DT,
231
278
return false ;
232
279
LLVM_DEBUG (dbgs () << " Processing cycle:\n " << CI.print (&C) << " \n " ;);
233
280
281
+ DomTreeUpdater DTU (DT, DomTreeUpdater::UpdateStrategy::Eager);
234
282
ControlFlowHub CHub;
235
283
SetVector<BasicBlock *> Predecessors;
236
284
@@ -242,18 +290,33 @@ static bool fixIrreducible(Cycle &C, CycleInfo &CI, DominatorTree &DT,
242
290
}
243
291
244
292
for (BasicBlock *P : Predecessors) {
245
- auto *Branch = cast<BranchInst>(P->getTerminator ());
246
- // Exactly one of the two successors is the header.
247
- BasicBlock *Succ0 = Branch->getSuccessor (0 ) == Header ? Header : nullptr ;
248
- BasicBlock *Succ1 = Succ0 ? nullptr : Header;
249
- if (!Succ0)
250
- assert (Branch->getSuccessor (1 ) == Header);
251
- assert (Succ0 || Succ1);
252
- CHub.addBranch (P, Succ0, Succ1);
253
-
254
- LLVM_DEBUG (dbgs () << " Added internal branch: " << P->getName () << " -> "
255
- << (Succ0 ? Succ0->getName () : " " ) << " "
256
- << (Succ1 ? Succ1->getName () : " " ) << " \n " );
293
+ if (BranchInst *Branch = dyn_cast<BranchInst>(P->getTerminator ()); Branch) {
294
+ // Exactly one of the two successors is the header.
295
+ BasicBlock *Succ0 = Branch->getSuccessor (0 ) == Header ? Header : nullptr ;
296
+ BasicBlock *Succ1 = Succ0 ? nullptr : Header;
297
+ if (!Succ0)
298
+ assert (Branch->getSuccessor (1 ) == Header);
299
+ assert (Succ0 || Succ1);
300
+ CHub.addBranch (P, Succ0, Succ1);
301
+
302
+ LLVM_DEBUG (dbgs () << " Added internal branch: " << P->getName () << " -> "
303
+ << (Succ0 ? Succ0->getName () : " " ) << " "
304
+ << (Succ1 ? Succ1->getName () : " " ) << " \n " );
305
+ } else if (CallBrInst *CallBr = dyn_cast<CallBrInst>(P->getTerminator ());
306
+ CallBr) {
307
+ for (unsigned I = 0 ; I < CallBr->getNumSuccessors (); ++I) {
308
+ BasicBlock *Succ = CallBr->getSuccessor (I);
309
+ if (Succ != Header)
310
+ continue ;
311
+ BasicBlock *NewSucc = llvm::ControlFlowHub::createCallBrTarget (
312
+ CallBr, Succ, I, false , &CI, &DTU, LI);
313
+ CHub.addBranch (NewSucc, Succ);
314
+ LLVM_DEBUG (dbgs () << " Added internal branch: " << NewSucc->getName ()
315
+ << " -> " << Succ->getName () << " \n " );
316
+ }
317
+ } else {
318
+ llvm_unreachable (" Unsupported block terminator." );
319
+ }
257
320
}
258
321
259
322
// Redirect external incoming edges. This includes the edges on the header.
@@ -266,17 +329,32 @@ static bool fixIrreducible(Cycle &C, CycleInfo &CI, DominatorTree &DT,
266
329
}
267
330
268
331
for (BasicBlock *P : Predecessors) {
269
- auto *Branch = cast<BranchInst>(P->getTerminator ());
270
- BasicBlock *Succ0 = Branch->getSuccessor (0 );
271
- Succ0 = C.contains (Succ0) ? Succ0 : nullptr ;
272
- BasicBlock *Succ1 =
273
- Branch->isUnconditional () ? nullptr : Branch->getSuccessor (1 );
274
- Succ1 = Succ1 && C.contains (Succ1) ? Succ1 : nullptr ;
275
- CHub.addBranch (P, Succ0, Succ1);
276
-
277
- LLVM_DEBUG (dbgs () << " Added external branch: " << P->getName () << " -> "
278
- << (Succ0 ? Succ0->getName () : " " ) << " "
279
- << (Succ1 ? Succ1->getName () : " " ) << " \n " );
332
+ if (BranchInst *Branch = dyn_cast<BranchInst>(P->getTerminator ()); Branch) {
333
+ BasicBlock *Succ0 = Branch->getSuccessor (0 );
334
+ Succ0 = C.contains (Succ0) ? Succ0 : nullptr ;
335
+ BasicBlock *Succ1 =
336
+ Branch->isUnconditional () ? nullptr : Branch->getSuccessor (1 );
337
+ Succ1 = Succ1 && C.contains (Succ1) ? Succ1 : nullptr ;
338
+ CHub.addBranch (P, Succ0, Succ1);
339
+
340
+ LLVM_DEBUG (dbgs () << " Added external branch: " << P->getName () << " -> "
341
+ << (Succ0 ? Succ0->getName () : " " ) << " "
342
+ << (Succ1 ? Succ1->getName () : " " ) << " \n " );
343
+ } else if (CallBrInst *CallBr = dyn_cast<CallBrInst>(P->getTerminator ());
344
+ CallBr) {
345
+ for (unsigned I = 0 ; I < CallBr->getNumSuccessors (); ++I) {
346
+ BasicBlock *Succ = CallBr->getSuccessor (I);
347
+ if (!C.contains (Succ))
348
+ continue ;
349
+ BasicBlock *NewSucc = llvm::ControlFlowHub::createCallBrTarget (
350
+ CallBr, Succ, I, true , &CI, &DTU, LI);
351
+ CHub.addBranch (NewSucc, Succ);
352
+ LLVM_DEBUG (dbgs () << " Added external branch: " << NewSucc->getName ()
353
+ << " -> " << Succ->getName () << " \n " );
354
+ }
355
+ } else {
356
+ llvm_unreachable (" Unsupported block terminator." );
357
+ }
280
358
}
281
359
282
360
// Redirect all the backedges through a "hub" consisting of a series
@@ -292,7 +370,6 @@ static bool fixIrreducible(Cycle &C, CycleInfo &CI, DominatorTree &DT,
292
370
SetVector<BasicBlock *> Entries;
293
371
Entries.insert (C.entry_rbegin (), C.entry_rend ());
294
372
295
- DomTreeUpdater DTU (DT, DomTreeUpdater::UpdateStrategy::Eager);
296
373
CHub.finalize (&DTU, GuardBlocks, " irr" );
297
374
#if defined(EXPENSIVE_CHECKS)
298
375
assert (DT.verify (DominatorTree::VerificationLevel::Full));
@@ -325,7 +402,7 @@ static bool FixIrreducibleImpl(Function &F, CycleInfo &CI, DominatorTree &DT,
325
402
LLVM_DEBUG (dbgs () << " ===== Fix irreducible control-flow in function: "
326
403
<< F.getName () << " \n " );
327
404
328
- assert (hasOnlySimpleTerminator (F) && " Unsupported block terminator." );
405
+ assert (hasOnlySimpleTerminatorOrCallBr (F) && " Unsupported block terminator." );
329
406
330
407
bool Changed = false ;
331
408
for (Cycle *TopCycle : CI.toplevel_cycles ()) {
0 commit comments