Bug type: crash
Component: LoopFuse
Bug location: llvm/lib/Transforms/Scalar/LoopFuse.cpp: canSinkInst
collectMovablePreheaderInsts
movePreheaderInsts
Issue title: [Clang] Optimization LoopFuse.cpp crashes on valid LLVM IR. Assertion `!verifyFunction(*FC0.Header->getParent(), &errs())' failed.
Labels: loopoptim
crash
Reported by: zitongzhoueric

To reproduce: https://godbolt.org/z/zMEsM448G
`opt -passes=mem2reg,loop-rotate,loop-fusion {test}` crashes on the LLVMIR generated from `clang -O0` because of an assertion failure.
Stack Dump:
```
PHI node entries do not match predecessors!
  %sum1.0.lcssa = phi i32 [ %add, %for.inc ]
label %for.inc
label %for.inc6
opt: /root/llvm-project/llvm/lib/Transforms/Scalar/LoopFuse.cpp:1759: llvm::Loop* {anonymous}::LoopFuser::performFusion(const {anonymous}::FusionCandidate&, const {anonymous}::FusionCandidate&): Assertion `!verifyFunction(*FC0.Header->getParent(), &errs())' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S -passes=mem2reg,loop-rotate,loop-fusion <source>
1.	Running pass "function(mem2reg,loop(loop-rotate<header-duplication;no-prepare-for-lto>),loop-fusion)" on module "<source>"
2.	Running pass "loop-fusion" on function "main"
 #0 0x00000000054498e8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x54498e8)
 #1 0x00000000054472a4 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x0000704d50642520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x0000704d506969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x0000704d50642476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x0000704d506287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x0000704d5062871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x0000704d50639e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x000000000402a593 (anonymous namespace)::LoopFuser::performFusion((anonymous namespace)::FusionCandidate const&, (anonymous namespace)::FusionCandidate const&) LoopFuse.cpp:0:0
 #9 0x000000000402cab5 (anonymous namespace)::LoopFuser::fuseCandidates() LoopFuse.cpp:0:0
#10 0x000000000402e5c1 llvm::LoopFusePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x402e5c1)
#11 0x00000000031828ae llvm::detail::PassModel<llvm::Function, llvm::LoopFusePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x31828ae)
#12 0x0000000005243e40 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5243e40)
#13 0x0000000000e6e23e llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xe6e23e)
#14 0x000000000524275b llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x524275b)
#15 0x0000000000e6d54e llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xe6d54e)
#16 0x0000000005242160 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5242160)
#17 0x0000000000935dda llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x935dda)
#18 0x000000000092944c optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x92944c)
#19 0x0000704d50629d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#20 0x0000704d50629e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#21 0x0000000000920d25 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x920d25)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```

The Test IR causing the failure:
```
@.str = private unnamed_addr constant [7 x i8] c"%d %d\0A\00", align 1

define dso_local i32 @main() #0 {
entry:
  %retval = alloca i32, align 4
  %sum1 = alloca i32, align 4
  %sum2 = alloca i32, align 4
  %i = alloca i32, align 4
  %i1 = alloca i32, align 4
  store i32 0, ptr %retval, align 4
  store i32 0, ptr %sum1, align 4
  store i32 0, ptr %sum2, align 4
  store i32 0, ptr %i, align 4
  br label %for.cond

for.cond:
  %0 = load i32, ptr %i, align 4
  %cmp = icmp slt i32 %0, 10
  br i1 %cmp, label %for.body, label %for.end

for.body:
  %1 = load i32, ptr %i, align 4
  %2 = load i32, ptr %sum1, align 4
  %add = add nsw i32 %2, %1
  store i32 %add, ptr %sum1, align 4
  br label %for.inc

for.inc:
  %3 = load i32, ptr %i, align 4
  %inc = add nsw i32 %3, 1
  store i32 %inc, ptr %i, align 4
  br label %for.cond

for.end:
  store i32 0, ptr %i1, align 4
  br label %for.cond2

for.cond2:
  %4 = load i32, ptr %i1, align 4
  %cmp3 = icmp slt i32 %4, 10
  br i1 %cmp3, label %for.body4, label %for.end8

for.body4:
  %5 = load i32, ptr %i1, align 4
  %6 = load i32, ptr %i1, align 4
  %mul = mul nsw i32 %5, %6
  %7 = load i32, ptr %sum2, align 4
  %add5 = add nsw i32 %7, %mul
  store i32 %add5, ptr %sum2, align 4
  br label %for.inc6

for.inc6:
  %8 = load i32, ptr %i1, align 4
  %inc7 = add nsw i32 %8, 1
  store i32 %inc7, ptr %i1, align 4
  br label %for.cond2

for.end8:
  %9 = load i32, ptr %sum1, align 4
  %10 = load i32, ptr %sum2, align 4
  %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %9, i32 noundef %10)
  ret i32 0
}

declare i32 @printf(ptr noundef, ...) #1

attributes #0 = { noinline nounwind uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
```

It is generated from
```c
#include <stdio.h>
int main() {
    int sum1 = 0, sum2 = 0;
    for (int i = 0; i < 10; i++) {
        sum1 += i;
    }
    for (int i = 0; i < 10; i++) {
        sum2 += i * i;
    }
    printf("%d %d\n", sum1, sum2);
    return 0;
}
```



Fix patch:
commit 90de4a4ac96ef314e3af9c43c516d5aaf105777a
Author: Madhur Amilkanthwar <madhura@nvidia.com>
Date:   Mon Jul 28 12:08:43 2025 +0530

    [LoopFusion] Fix sink instructions (#147501)
    
    If we have instructions in second loop's preheader which can be sunk, we
    should also be adjusting PHI nodes to receive values from the fused loop's latch block.
    
    Fixes #128600

diff --git a/llvm/lib/Transforms/Scalar/LoopFuse.cpp b/llvm/lib/Transforms/Scalar/LoopFuse.cpp
index d6bd92d520e2..b5eb647a042b 100644
--- a/llvm/lib/Transforms/Scalar/LoopFuse.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopFuse.cpp
@@ -1176,6 +1176,28 @@ private:
     return true;
   }
 
+  /// This function fixes PHI nodes after fusion in \p SafeToSink.
+  /// \p SafeToSink instructions are the instructions that are to be moved past
+  /// the fused loop. Thus, the PHI nodes in \p SafeToSink should be updated to
+  /// receive values from the fused loop if they are currently taking values
+  /// from the first loop (i.e. FC0)'s latch.
+  void fixPHINodes(ArrayRef<Instruction *> SafeToSink,
+                   const FusionCandidate &FC0,
+                   const FusionCandidate &FC1) const {
+    for (Instruction *Inst : SafeToSink) {
+      // No update needed for non-PHI nodes.
+      PHINode *Phi = dyn_cast<PHINode>(Inst);
+      if (!Phi)
+        continue;
+      for (unsigned I = 0; I < Phi->getNumIncomingValues(); I++) {
+        if (Phi->getIncomingBlock(I) != FC0.Latch)
+          continue;
+        assert(FC1.Latch && "FC1 latch is not set");
+        Phi->setIncomingBlock(I, FC1.Latch);
+      }
+    }
+  }
+
   /// Collect instructions in the \p FC1 Preheader that can be hoisted
   /// to the \p FC0 Preheader or sunk into the \p FC1 Body
   bool collectMovablePreheaderInsts(
@@ -1481,6 +1503,9 @@ private:
       assert(I->getParent() == FC1.Preheader);
       I->moveBefore(*FC1.ExitBlock, FC1.ExitBlock->getFirstInsertionPt());
     }
+    // PHI nodes in SinkInsts need to be updated to receive values from the
+    // fused loop.
+    fixPHINodes(SinkInsts, FC0, FC1);
   }
 
   /// Determine if two fusion candidates have identical guards


Regression tests:
file: llvm/test/Transforms/LoopFusion/sunk-phi-nodes.ll
commands: opt -passes=loop-fusion -S < %s 2>&1
tests: test_name: <module>
test_body: define dso_local i32 @check_sunk_phi_nodes() {
;
entry:
  br label %for.body

for.body:                                         ; preds = %entry, %for.inc
  %sum1.02 = phi i32 [ 0, %entry ], [ %add, %for.inc ]
  %i.01 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
  %add = add nsw i32 %sum1.02, %i.01
  br label %for.inc

for.inc:                                          ; preds = %for.body
  %inc = add nsw i32 %i.01, 1
  %cmp = icmp slt i32 %inc, 10
  br i1 %cmp, label %for.body, label %for.end

for.end:                                          ; preds = %for.inc
  %sum1.0.lcssa = phi i32 [ %add, %for.inc ]
  br label %for.body4

for.body4:                                        ; preds = %for.end, %for.inc6
  %i1.04 = phi i32 [ 0, %for.end ], [ %inc7, %for.inc6 ]
  %sum2.03 = phi i32 [ 0, %for.end ], [ %add5, %for.inc6 ]
  %mul = mul nsw i32 %i1.04, %i1.04
  %add5 = add nsw i32 %sum2.03, %mul
  br label %for.inc6

for.inc6:                                         ; preds = %for.body4
  %inc7 = add nsw i32 %i1.04, 1
  %cmp3 = icmp slt i32 %inc7, 10
  br i1 %cmp3, label %for.body4, label %for.end8

for.end8:                                         ; preds = %for.inc6
  %sum2.0.lcssa = phi i32 [ %add5, %for.inc6 ]
  %0 = add i32 %sum1.0.lcssa, %sum2.0.lcssa
  ret i32 %0
}