Bug type: crash
Component: LoopPeel
Bug location: llvm/lib/Transforms/Utils/LoopPeel.cpp: llvm::peelLoop
Issue title: [LoopUnroll] Assertion `New && "Value::replaceAllUsesWith(<null>) is invalid!"' failed.
Labels: crash-on-valid
llvm:transforms
generated by fuzzer
Reported by: dtcxzyw

Reproducer: https://godbolt.org/z/ahxqn68Mn
```
; bin/opt -passes="loop-unroll<O3>" reduced.ll -S
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

define i32 @main() {
entry:
  br label %for.cond52.preheader.i.i

for.cond52.preheader.i.i:                         ; preds = %for.end213.i.i, %entry
  %p_158.addr.0380.i.i1 = phi i16 [ 0, %entry ], [ %inc215.i.i, %for.end213.i.i ]
  %0 = icmp eq i16 %p_158.addr.0380.i.i1, -1
  br label %for.body136.i.i

for.body136.i.i:                                  ; preds = %for.end54.preheader.peel.i.i.i, %for.cond52.preheader.i.i
  %1 = add i32 0, 0
  br i1 %0, label %for.end54.preheader.peel.i.i.i, label %for.end54.preheader.peel.i.i.i

for.end54.preheader.peel.i.i.i:                   ; preds = %for.body136.i.i, %for.body136.i.i
  br i1 true, label %for.end213.i.i, label %for.body136.i.i

for.end213.i.i:                                   ; preds = %for.end54.preheader.peel.i.i.i
  %inc215.i.i = add i16 %p_158.addr.0380.i.i1, 1
  %exitcond387.not.i.i = icmp eq i16 %inc215.i.i, 0
  br i1 %exitcond387.not.i.i, label %for.end141.peel.i.i, label %for.cond52.preheader.i.i

for.end141.peel.i.i:                              ; preds = %for.end213.i.i
  ret i32 %1
}
```
```
opt: /root/llvm-project/llvm/lib/IR/Value.cpp:516: void llvm::Value::doRAUW(llvm::Value*, llvm::Value::ReplaceMetadataUses): Assertion `New && "Value::replaceAllUsesWith(<null>) is invalid!"' 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=loop-unroll<O3> <source>
1.	Running pass "function(loop-unroll<O3>)" on module "<source>"
2.	Running pass "loop-unroll<O3>" on function "main"
 #0 0x00000000055c5a48 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x55c5a48)
 #1 0x00000000055c33d4 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x000078c7a1842520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x000078c7a18969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x000078c7a1842476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x000078c7a18287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x000078c7a182871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x000078c7a1839e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x00000000053f248a (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x53f248a)
 #9 0x0000000004830404 llvm::peelLoop(llvm::Loop*, unsigned int, bool, llvm::LoopInfo*, llvm::ScalarEvolution*, llvm::DominatorTree&, llvm::AssumptionCache*, bool, llvm::ValueMap<llvm::Value const*, llvm::WeakTrackingVH, llvm::ValueMapConfig<llvm::Value const*, llvm::sys::SmartMutex<false>>>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4830404)
#10 0x0000000004424eb9 tryToUnrollLoop(llvm::Loop*, llvm::DominatorTree&, llvm::LoopInfo*, llvm::ScalarEvolution&, llvm::TargetTransformInfo const&, llvm::AssumptionCache&, llvm::OptimizationRemarkEmitter&, llvm::BlockFrequencyInfo*, llvm::ProfileSummaryInfo*, bool, int, bool, bool, bool, std::optional<unsigned int>, std::optional<unsigned int>, std::optional<bool>, std::optional<bool>, std::optional<bool>, std::optional<bool>, std::optional<bool>, std::optional<unsigned int>, llvm::AAResults*) LoopUnrollPass.cpp:0:0
#11 0x0000000004427b27 llvm::LoopUnrollPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4427b27)
#12 0x0000000002d6a54e llvm::detail::PassModel<llvm::Function, llvm::LoopUnrollPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x2d6a54e)
#13 0x00000000053bcd00 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x53bcd00)
#14 0x0000000000e8bbee 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+0xe8bbee)
#15 0x00000000053bd213 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x53bd213)
#16 0x0000000000e8aa3e 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+0xe8aa3e)
#17 0x00000000053bae30 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x53bae30)
#18 0x000000000094c2aa 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+0x94c2aa)
#19 0x000000000093fa7c optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x93fa7c)
#20 0x000078c7a1829d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#21 0x000078c7a1829e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#22 0x0000000000937695 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x937695)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```
llvm version: 3ccb15d6caf57f2a866d496ada2fb52d14b179d2

Comments: author: fhahn
body: Probably related to 3fcfce4c5e5fd1c3072e8db1d692c93459e8cd74, taking a look

Fix patch:
commit 7e14161f49b32387988cf9d937bbfaa27d0fbdd5
Author: Florian Hahn <flo@fhahn.com>
Date:   Sun May 18 10:17:20 2025 +0100

    [LoopPeel] Handle constants when updating exit values when peeling last.
    
    Account for constant values when updating exit values after peeling an
    iteration from the end. This can happen if the inner loop gets unrolled
    and simplified.
    
    Fixes https://github.com/llvm/llvm-project/issues/140442.

diff --git a/llvm/lib/Transforms/Utils/LoopPeel.cpp b/llvm/lib/Transforms/Utils/LoopPeel.cpp
index c5c637ab6e20..646354bba9df 100644
--- a/llvm/lib/Transforms/Utils/LoopPeel.cpp
+++ b/llvm/lib/Transforms/Utils/LoopPeel.cpp
@@ -1214,7 +1214,7 @@ bool llvm::peelLoop(Loop *L, unsigned PeelCount, bool PeelLast, LoopInfo *LI,
     // Now adjust users of the original exit values by replacing them with the
     // exit value from the peeled iteration.
     for (const auto &[P, E] : ExitValues)
-      P->replaceAllUsesWith(VMap.lookup(E));
+      P->replaceAllUsesWith(isa<Constant>(E) ? E : &*VMap.lookup(E));
     formLCSSA(*L, DT, LI, SE);
   } else {
     // Now adjust the phi nodes in the loop header to get their initial values


Regression tests:
file: llvm/test/Transforms/LoopUnroll/unroll-and-peel-last-iteration.ll
commands: opt -p loop-unroll -S %s
tests: test_name: <module>
test_body: 
; Test case for https://github.com/llvm/llvm-project/issues/140442.
define i32 @peel_last_iter_of_outer_lcssa_phi_with_constant_after_unrolling_inner() {
;
entry:
  br label %outer.header

outer.header:
  %iv = phi i16 [ 0, %entry ], [ %iv.next, %outer.latch ]
  %0 = icmp eq i16 %iv, 999
  br label %inner.header

inner.header:
  %inner.iv = phi i32 [ 0, %outer.header ], [ %inner.iv.next, %inner.latch ]
  %1 = add i32 %inner.iv, 1
  br i1 %0, label %then, label %inner.latch

then:
  call void @foo(i32 %inner.iv)
  br label %inner.latch

inner.latch:
  %inner.iv.next = add i32 %inner.iv, 1
  %inner.ec = icmp eq i32 %inner.iv.next, 1
  br i1 %inner.ec, label %outer.latch, label %inner.header

outer.latch:
  %iv.next = add i16 %iv, 1
  %ec = icmp eq i16 %iv.next, 1000
  br i1 %ec, label %exit, label %outer.header

exit:
  ret i32 %1
}

declare void @foo(i32)
;.
;.