[llvm] [SimpleLoopUnswitch] Allow trivial unswitch when exit LCSSA is a header PHI (PR #222962)
Dark Steve via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 11 20:36:30 PDT 2026
================
@@ -647,8 +657,14 @@ static bool unswitchTrivialBranch(Loop &L, CondBrInst &BI, DominatorTree &DT,
}
auto *ContinueBB = BI.getSuccessor(1 - LoopExitSuccIdx);
auto *ParentBB = BI.getParent();
- if (!ModifiedBranch &&
- !areLoopExitPHIsLoopInvariant(L, *ParentBB, *LoopExitBB)) {
+
+ // If the exit incomings aren't loop-invariant, the unswitch is still trivial
+ // when branch dominates the latch and every non-invariant incoming is a
+ // header PHI. Those incomings are repaired after unswitching.
+ // Branch always dominates the latch as guaranteed by the caller.
+ bool TrivialFromHeader = false;
+ if (!ModifiedBranch && !areLoopExitPHIsLoopInvariant(
----------------
PrasoonMishra wrote:
The utility is used in three places: two in `unswitchTrivialBranch` and one in `unswitchTrivialSwitch`. They aren't asking the same question, which is why I only relaxed one of them.
`areLoopExitPHIsLoopInvariant(L, *LoopLatch, *ULExit)` guard redirecting the branch's latch edge to the unique latch exit. The value that must appear on the bypass edge is the one at the last iteration, loop-invariance is exactly what makes that equal to the value at entry. Relaxing this to accept a header PHI would substitute the entry value and would be incorrect.
```
define i32 @g(i1 %c, i32 %n) {
entry:
br label %header
header:
%acc = phi i32 [ 0, %entry ], [ %accn, %latch ]
%i = phi i32 [ 0, %entry ], [ %in, %latch ]
br i1 %c, label %latch, label %other
other:
br label %latch
latch:
%accn = add i32 %acc, 1
%in = add i32 %i, 1
%cmp = icmp slt i32 %in, %n
br i1 %cmp, label %header, label %ulexit
ulexit:
%r = phi i32 [ %acc, %latch ]
ret i32 %r
}
```
With `%c = true`, `%n = 5` this returns `4`. Accepting `%acc` there and substituting its entry value returns `0`, because the loop now exits before %acc has been incremented. That would be wrong.
The call site I changed is the place where branch is hoisted into the preheader, so on the bypass edge the loop has not run and a header PHI still holds its entry value.
`unswitchTrivialSwitch` is the same situation as the one I changed, a switch version of the motivating loop which I did not extended. Happy to extend that as a follow-up or here,
https://github.com/llvm/llvm-project/pull/222962
More information about the llvm-commits
mailing list