[llvm] [LoopFusion] Fix out-of-date LoopInfo being used during fusion (PR #189452)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 30 11:50:25 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Congzhe (CongzheUalberta)
<details>
<summary>Changes</summary>
This is fix for [187902](https://github.com/llvm/llvm-project/issues/187902).
The reason for the bug is that, `mergeLatch()` is called at a place where control flow and dominator trees have been updated but LoopInfo has not completed the update yet. `mergeLatch()` calls into ScalarEvolution that uses LoopInfo, where out-of-date LoopInfo would result in crash or unpredicatable results.
This patch moves `mergeLatch()` to the place where LoopInfo has completed its update and hence is in a valid state.
---
Full diff: https://github.com/llvm/llvm-project/pull/189452.diff
1 Files Affected:
- (modified) llvm/lib/Transforms/Scalar/LoopFuse.cpp (+22-22)
``````````diff
diff --git a/llvm/lib/Transforms/Scalar/LoopFuse.cpp b/llvm/lib/Transforms/Scalar/LoopFuse.cpp
index 23bba139212e8..07cc86c76ca1d 100644
--- a/llvm/lib/Transforms/Scalar/LoopFuse.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopFuse.cpp
@@ -1676,19 +1676,6 @@ struct LoopFuser {
SE.forgetLoop(FC1.L);
SE.forgetLoop(FC0.L);
- // Move instructions from FC0.Latch to FC1.Latch.
- // Note: mergeLatch requires an updated DT.
- mergeLatch(FC0, FC1);
-
- // Forget block dispositions as well, so that there are no dangling
- // pointers to erased/free'ed blocks. It should be done after mergeLatch()
- // since merging the latches may affect the dispositions.
- SE.forgetBlockAndLoopDispositions();
-
- // Forget the cached SCEV values including the induction variable that may
- // have changed after the fusion.
- SE.forgetLoop(FC0.L);
-
// Merge the loops.
SmallVector<BasicBlock *, 8> Blocks(FC1.L->blocks());
for (BasicBlock *BB : Blocks) {
@@ -1708,6 +1695,19 @@ struct LoopFuser {
// Delete the now empty loop L1.
LI.erase(FC1.L);
+ // Move instructions from FC0.Latch to FC1.Latch.
+ // Note: mergeLatch requires an updated DT.
+ mergeLatch(FC0, FC1);
+
+ // Forget block dispositions as well, so that there are no dangling
+ // pointers to erased/free'ed blocks. It should be done after mergeLatch()
+ // since merging the latches may affect the dispositions.
+ SE.forgetBlockAndLoopDispositions();
+
+ // Forget the cached SCEV values including the induction variable that may
+ // have changed after the fusion.
+ SE.forgetLoop(FC0.L);
+
#ifndef NDEBUG
assert(!verifyFunction(*FC0.Header->getParent(), &errs()));
assert(DT.verify(DominatorTree::VerificationLevel::Fast));
@@ -1978,15 +1978,6 @@ struct LoopFuser {
SE.forgetLoop(FC1.L);
SE.forgetLoop(FC0.L);
- // Move instructions from FC0.Latch to FC1.Latch.
- // Note: mergeLatch requires an updated DT.
- mergeLatch(FC0, FC1);
-
- // Forget block dispositions as well, so that there are no dangling
- // pointers to erased/free'ed blocks. It should be done after mergeLatch()
- // since merging the latches may affect the dispositions.
- SE.forgetBlockAndLoopDispositions();
-
// Merge the loops.
SmallVector<BasicBlock *, 8> Blocks(FC1.L->blocks());
for (BasicBlock *BB : Blocks) {
@@ -2006,6 +1997,15 @@ struct LoopFuser {
// Delete the now empty loop L1.
LI.erase(FC1.L);
+ // Move instructions from FC0.Latch to FC1.Latch.
+ // Note: mergeLatch requires an updated DT.
+ mergeLatch(FC0, FC1);
+
+ // Forget block dispositions as well, so that there are no dangling
+ // pointers to erased/free'ed blocks. It should be done after mergeLatch()
+ // since merging the latches may affect the dispositions.
+ SE.forgetBlockAndLoopDispositions();
+
#ifndef NDEBUG
assert(!verifyFunction(*FC0.Header->getParent(), &errs()));
assert(DT.verify(DominatorTree::VerificationLevel::Fast));
``````````
</details>
https://github.com/llvm/llvm-project/pull/189452
More information about the llvm-commits
mailing list