[llvm] [LoopFusion] Do not fuse loops containing convergent operations (PR #203460)
Madhur Amilkanthwar via llvm-commits
llvm-commits at lists.llvm.org
Sun Jun 14 23:52:30 PDT 2026
================
@@ -203,6 +204,16 @@ struct FusionCandidate {
"Loop contains an atomic access");
return;
}
+ // A convergent operation requires the set of threads executing it to be
+ // unchanged; fusion moves it into a different loop, so reject the
+ // candidate. See LangRef on the 'convergent' attribute.
+ if (const auto *CB = dyn_cast<CallBase>(&I); CB && CB->isConvergent()) {
+ invalidate();
+ ++ContainsConvergentOp;
+ reportInvalidCandidate("ContainsConvergentOp",
+ "Loop contains a convergent operation");
+ return;
+ }
----------------
madhur13490 wrote:
I think that is too conservative and we don't require that.
It only needs each call to be safe to relocate and interleave with the other loop's body. There are exactly four independent hazards a call can pose, and three of them are already handled:
* Memory effects — already handled by the dependence analysis. `DependenceInfo::depends` returns a fully conservative ("confused") dependence for anything that isn't a plain load/store:
* Exceptions — already handled: the I.mayThrow() check rejects any non-nounwind call before we ever reach the call test.
* Convergence — not otherwise modeled.
* Non-returning calls — also not modeled. If a call may not return, interleaving lets the second loop's side effects execute before the first loop's would-be-hang, which is observable.
I think I should also do something like below in this PR.
```
if (const auto *CB = dyn_cast<CallBase>(&I);
CB && (CB->isConvergent() || !CB->willReturn())) {
```
https://github.com/llvm/llvm-project/pull/203460
More information about the llvm-commits
mailing list