[llvm] [FixIrreducible][UnifyLoopExits] Support switch statements (PR #206567)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 30 12:46:45 PDT 2026


================
@@ -309,20 +309,23 @@ static bool fixIrreducible(Cycle &C, CycleInfo &CI, DominatorTree &DT,
                         << " -> " << printBasicBlock(Succ0)
                         << (Succ0 && Succ1 ? " " : "") << printBasicBlock(Succ1)
                         << '\n');
-    } else if (CallBrInst *CallBr = dyn_cast<CallBrInst>(P->getTerminator())) {
-      for (unsigned I = 0; I < CallBr->getNumSuccessors(); ++I) {
-        BasicBlock *Succ = CallBr->getSuccessor(I);
+    } else if (isa<CallBrInst>(P->getTerminator()) ||
+               isa<SwitchInst>(P->getTerminator())) {
+      Instruction *Term = P->getTerminator();
+      for (unsigned I = 0; I < Term->getNumSuccessors(); ++I) {
+        BasicBlock *Succ = Term->getSuccessor(I);
         if (Succ != Header)
           continue;
-        BasicBlock *NewSucc = SplitCallBrEdge(P, Succ, I, &DTU, &CI, LI);
+        BasicBlock *NewSucc = SplitMultiBrEdge(P, Succ, I, &DTU, &CI, LI);
         CHub.addBranch(NewSucc, Succ);
----------------
hertelukas wrote:

Maybe I'm overlooking something, but isn't that a different issue? For the conditional branch, the pass assumed that only one branch is incident on the header, which has led to the bug. We aren't doing that - we check for each successor if it's the header and introduce a split (for each edge, which might lead to redundant splits).

```llvm
define void @foo_switch(i32 %c) {
entry:
  br i1 false, label %a, label %b
a:
  switch i32 %c, label %b [ i32 0, label %b ]
b:
  br i1 false, label %exit, label %a
exit:
  ret void
}

; Resulting in:

define void @foo_switch(i32 %c) {
entry:
  br label %irr.guard
a:                                                ; preds = %irr.guard, %b
  switch i32 %c, label %a.target.b [
    i32 0, label %a.target.b1
  ]
b:                                                ; preds = %irr.guard
  br i1 false, label %exit, label %a
exit:                                             ; preds = %b
  ret void
a.target.b:                                       ; preds = %a
  br label %irr.guard
a.target.b1:                                      ; preds = %a
  br label %irr.guard
irr.guard:                                        ; preds = %entry, %a.target.b1, %a.target.b
  %Guard.b = phi i1 [ true, %a.target.b ], [ true, %a.target.b1 ], [ true, %entry ]
  br i1 %Guard.b, label %b, label %a
}
```

Playing around with the example a bit (trying to figure out if we can avoid some splits), phi nodes don't seem to get handled correctly then (also with `callbr`). 

https://godbolt.org/z/PvTvchqx1

Since this seems like a separate issue, should I address it in this PR or file a new bug? I'll look into it anyway.

https://github.com/llvm/llvm-project/pull/206567


More information about the llvm-commits mailing list