Bug type: crash
Component: SCCP
Bug location: llvm/lib/Transforms/IPO/SCCP.cpp: runIPSCCP
Issue title: [IPSCCP] Use still stuck around after Def is destroyed
Labels: ipo
crash-on-valid
generated by fuzzer
Reported by: dtcxzyw

Reproducer:
```
; bin/opt -passes=ipsccp --funcspec-min-function-size=1 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"

@g_315 = internal global ptr null

define i8 @func_123() {
entry:
  %call2 = call i8 @func_152(i32 1)
  %call2991 = call i8 @func_152(i32 0)
  ret i8 %call2991
}

define internal i8 @func_152(i32 %p_153) {
entry:
  %tobool268 = icmp ne i32 %p_153, 0
  br label %cleanup424

cleanup424:                                       ; preds = %cleanup424, %entry
  br label %cleanup424

for.end453:                                       ; No predecessors!
  %0 = load ptr, ptr @g_315, align 8
  %1 = load ptr, ptr %0, align 8
  ret i8 0
}
```
```
While deleting: ptr %
Use still stuck around after Def is destroyed:  %0 = load ptr, ptr <badref>, align 8
Uses remain when a value is destroyed!
UNREACHABLE executed at /home/dtcxzyw/WorkSpace/Projects/compilers/llvm-project/llvm/lib/IR/Value.cpp:102!
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: bin/opt -passes=ipsccp --funcspec-min-function-size=1 reduced.ll -S
1.      Running pass "ipsccp" on module "reduced.ll"
 #0 0x000078deeee306f2 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMSupport.so.22.0git+0x2306f2)
 #1 0x000078deeee2ccbf llvm::sys::RunSignalHandlers() (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMSupport.so.22.0git+0x22ccbf)
 #2 0x000078deeee2ce0c SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #3 0x000078deee845330 (/lib/x86_64-linux-gnu/libc.so.6+0x45330)
 #4 0x000078deee89eb2c __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x000078deee89eb2c __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x000078deee89eb2c pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x000078deee84527e raise ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x000078deee8288ff abort ./stdlib/abort.c:81:7
 #9 0x000078deeed2a33e (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMSupport.so.22.0git+0x12a33e)
#10 0x000078dee6761699 llvm::Value::~Value() (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.22.0git+0x361699)
#11 0x000078dee6761882 llvm::Value::deleteValue() (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.22.0git+0x361882)
#12 0x000078dee667ffce llvm::Instruction::eraseFromParent() (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.22.0git+0x27ffce)
#13 0x000078dee97c0d45 runIPSCCP(llvm::Module&, llvm::DataLayout const&, llvm::AnalysisManager<llvm::Function>*, std::function<llvm::TargetLibraryInfo const& (llvm::Function&)>, std::function<llvm::TargetTransformInfo& (llvm::Function&)>, std::function<llvm::AssumptionCache& (llvm::Function&)>, std::function<llvm::DominatorTree& (llvm::Function&)>, std::function<llvm::BlockFrequencyInfo& (llvm::Function&)>, bool) SCCP.cpp:0:0
#14 0x000078dee97c122b llvm::IPSCCPPass::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMipo.so.22.0git+0x3c122b)
#15 0x000078dee9aec7f5 llvm::detail::PassModel<llvm::Module, llvm::IPSCCPPass, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMPasses.so.22.0git+0xec7f5)
#16 0x000078dee6724ddd llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.22.0git+0x324ddd)
#17 0x000078deef124185 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, bool) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMOptDriver.so.22.0git+0x2d185)
#18 0x000078deef12f5ea optMain (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMOptDriver.so.22.0git+0x385ea)
#19 0x000078deee82a1ca __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:74:3
#20 0x000078deee82a28b call_init ./csu/../csu/libc-start.c:128:20
#21 0x000078deee82a28b __libc_start_main ./csu/../csu/libc-start.c:347:5
#22 0x0000641d94919095 _start (bin/opt+0x1095)
Aborted (core dumped)
```
llvm version: 3c94613ae98fd9e9846fa77268b59d884b35cf60

Reverting 6bd844812385dd5cb65e08fe9561be9f91ace876 solves the issue. cc @XChy 


Comments: author: XChy
body: The assumption is incorrect after https://github.com/llvm/llvm-project/commit/6bd844812385dd5cb65e08fe9561be9f91ace876:
https://github.com/llvm/llvm-project/blob/5a9f1039c7732920dd1f4374074fdf09b58184ea/llvm/lib/Transforms/IPO/SCCP.cpp#L332-L339
The users in the dead functions are not replaced.

Fix patch:
commit 0ace96cca79c03c668b260dd01996e3d693e3f4f
Author: XChy <xxs_chy@outlook.com>
Date:   Thu Aug 28 19:13:27 2025 +0800

    [SCCP][FuncSpec] Poison unreachable constant global variable user (#155753)
    
    Fixes #155738.
    The original assumption "we already replaced its users with a constant"
    for the global variable becomes incorrect after #154668. The users in
    the dead function are not simplified, in fact.
    This patch poisons all the unsimplified constant global variable users.

diff --git a/llvm/lib/Transforms/IPO/SCCP.cpp b/llvm/lib/Transforms/IPO/SCCP.cpp
index e98a70f228ad..f4961faf7ad1 100644
--- a/llvm/lib/Transforms/IPO/SCCP.cpp
+++ b/llvm/lib/Transforms/IPO/SCCP.cpp
@@ -330,12 +330,15 @@ static bool runIPSCCP(
     LLVM_DEBUG(dbgs() << "Found that GV '" << GV->getName()
                       << "' is constant!\n");
     for (User *U : make_early_inc_range(GV->users())) {
-      // We can remove LoadInst here, because we already replaced its users
-      // with a constant.
+      // We can remove LoadInst here. The LoadInsts in dead functions marked by
+      // FuncSpec are not simplified to constants, thus poison them.
       assert((isa<StoreInst>(U) || isa<LoadInst>(U)) &&
              "Only Store|Load Instruction can be user of GlobalVariable at "
              "reaching here.");
-      cast<Instruction>(U)->eraseFromParent();
+      Instruction *I = cast<Instruction>(U);
+      if (isa<LoadInst>(I))
+        I->replaceAllUsesWith(PoisonValue::get(I->getType()));
+      I->eraseFromParent();
     }
 
     // Try to create a debug constant expression for the global variable


Regression tests:
file: llvm/test/Transforms/FunctionSpecialization/dead-gv-load.ll
commands: opt -passes=ipsccp  --funcspec-min-function-size=1 -S < %s
tests: test_name: <module>
test_body: 
@gv = internal global ptr null

define i8 @caller() {
;
entry:
  %call1 = call i8 @callee(i32 1)
  %call2 = call i8 @callee(i32 0)
  ret i8 %call2
}

define internal i8 @callee(i32 %arg) {
entry:
  %useless = icmp ne i32 %arg, 0
  br label %loop

loop:                                       ; preds = %loop, %entry
  br label %loop

dead_bb:                                       ; No predecessors!
  %l1 = load ptr, ptr @gv, align 8
  %l2 = load ptr, ptr %l1, align 8
  ret i8 0
}