Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/VPlanUnroll.cpp: cloneForLane
Issue title: Assertion in Vectorize/VPlan.cpp "trying to delete a VPValue with remaining users"
Labels: regression
vectorizers
crash
Reported by: eugeneepshteyn

```
$ clang -c -O2 repro.ll
clang: .../Linux_x86_64/llvm/lib/Transforms/Vectorize/VPlan.cpp:95: virtual llvm::VPValue::~VPValue(): Assertion `Us
ers.empty() && "trying to delete a VPValue with remaining users"' failed.                                                        PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, 
and associated run script.                                                                                                       
Stack dump:                                                                                                                      0.      Program arguments: ...//bin/clang -c -O2 repro.ll                                        1.      Optimizer 
2.      Running pass "function<eager-inv>(float2int,lower-constant-intrinsics,loop(loop-rotate<header-duplication;no-prepare-for-lto>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,infer
-alignment,loop-load-elim,instcombine<max-iterations=1;no-verify-fixpoint>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-inst
s;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,slp-vectorizer,vector-combine,instcombine<max-iterations=1;no-verify-fixpoint>,loop-unroll<O2>,transform-warning,sroa<preserve-cfg>,infer-alignment,instcombine<max-iterations=1;no-verify-fi
xpoint>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;hoist-l
oads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>)" on module "repro.ll"                                                                                                                        
3.      Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "_Qtest"                  
 #0 0x00000000046945a8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/.../bin/clang+0x4694
5a8)                                                                                                                             
 #1 0x00000000046919cc llvm::sys::CleanupOnSignal(unsigned long) (.../bin/clang+0x46919cc)
 #2 0x00000000045de438 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0     
 #3 0x00007fe4b29d7420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420)      
 #4 0x00007fe4b25ee00b raise /build/glibc-FcRMwW/glibc-2.31/signal/../sysdeps/unix/sysv/linux/raise.c:51:1
 #5 0x00007fe4b25cd859 abort /build/glibc-FcRMwW/glibc-2.31/stdlib/abort.c:81:7
 #6 0x00007fe4b25cd729 get_sysdep_segment_value /build/glibc-FcRMwW/glibc-2.31/intl/loadmsgcat.c:509:8
 #7 0x00007fe4b25cd729 _nl_load_domain /build/glibc-FcRMwW/glibc-2.31/intl/loadmsgcat.c:970:34
 #8 0x00007fe4b25defd6 (/lib/x86_64-linux-gnu/libc.so.6+0x33fd6) 
 #9 0x0000000005f1d824 llvm::VPValue::~VPValue() (.../bin/clang+0x5f1d824)
#10 0x0000000005f42356 llvm::VPReplicateRecipe::~VPReplicateRecipe() VPlanRecipes.cpp:0:0
#11 0x0000000005f476ce llvm::VPRecipeBase::eraseFromParent() (.../bin/clang+0x5f476ce)
#12 0x0000000005fc3514 llvm::VPlanTransforms::replicateByVF(llvm::VPlan&, llvm::ElementCount) (.../bin/clang+0x5fc3514)                                         
#13 0x0000000005f02594 llvm::LoopVectorizationPlanner::executePlan(llvm::ElementCount, unsigned int, llvm::VPlan&, llvm::InnerLoo
pVectorizer&, llvm::DominatorTree*, bool) (.../bin/clang+0x5f02594)
#14 0x0000000005f1691f llvm::LoopVectorizePass::processLoop(llvm::Loop*) (.../bin/clang+0x5f1691
f)
#15 0x0000000005f187c0 llvm::LoopVectorizePass::runImpl(llvm::Function&) (.../bin/clang+0x5f187c
0)
#16 0x0000000005f18e27 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (.../bin/clang+0x5f18e27)
#17 0x0000000005b0379e llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::r
un(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) PassBuilder.cpp:0:0
...
```
Reduced reproducer:
```
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 void @_Qtest(ptr %0, ptr %1, ptr %2, i64 %3, float %4) {
  br label %6

6:                                                ; preds = %37, %5
  %7 = phi float [ %.0, %37 ], [ 0.000000e+00, %5 ]
  %8 = phi i64 [ %38, %37 ], [ %3, %5 ]
  %9 = icmp sgt i64 %8, 0
  br i1 %9, label %.critedge, label %39

.critedge:                                        ; preds = %6
  %10 = call ptr @llvm.stacksave.p0()
  %11 = load float, ptr %2, align 4
  %12 = fcmp ogt float %11, 0.000000e+00
  br i1 %12, label %13, label %25

13:                                               ; preds = %.critedge
  %14 = load float, ptr %0, align 4
  %15 = fdiv float 0.000000e+00, %14
  %16 = load float, ptr %1, align 4
  %17 = fmul float %14, 0.000000e+00
  %18 = fdiv float %16, %17
  %19 = fadd float %4, %18
  %20 = call float @llvm.pow.f32(float 0.000000e+00, float %15)
  %21 = fmul float %20, 0.000000e+00
  %22 = fmul float %19, %4
  %23 = call float @llvm.exp.f32(float %22)
  %24 = fmul float %21, %23
  br label %37

25:                                               ; preds = %.critedge
  %26 = load float, ptr %1, align 4
  %27 = fdiv float 0.000000e+00, %26
  %28 = load float, ptr %0, align 4
  %29 = fmul float %26, 0.000000e+00
  %30 = fdiv float %28, %29
  %31 = fadd float %4, %30
  %32 = call float @llvm.pow.f32(float %4, float %27)
  %33 = fmul float %32, 0.000000e+00
  %34 = fmul float %31, %4
  %35 = call float @llvm.exp.f32(float %34)
  %36 = fmul float %33, %35
  br label %37

37:                                               ; preds = %25, %13
  %.0 = phi float [ %24, %13 ], [ %36, %25 ]
  call void @llvm.stackrestore.p0(ptr %10)
  %38 = add i64 %8, -1
  br label %6

39:                                               ; preds = %39, %6
  store float %7, ptr %0, align 4
  br label %39
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.pow.f32(float, float) #0

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.exp.f32(float) #0

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare ptr @llvm.stacksave.p0() #1

; Function Attrs: nocallback nofree nosync nounwind willreturn
declare void @llvm.stackrestore.p0(ptr) #1

; uselistorder directives
uselistorder ptr @llvm.pow.f32, { 1, 0 }
uselistorder ptr @llvm.exp.f32, { 1, 0 }

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #1 = { nocallback nofree nosync nounwind willreturn }
```
clang version:
```
clang version 22.0.0git (https://github.com/llvm/llvm-project 2f011ea37ad480fdf16e2364e0487409cb4d1c75)
Target: x86_64-unknown-linux-gnu
Thread model: posix
```

Comments: author: eugeneepshteyn
body: LLVM build at commit ID 9ddc043538329a0a1386d12e191de7b4c43051e9 is known to work. The issue was introduced sometime after that.
author: fhahn
body: Suspect this is caused by #151487 (7e9989390d95cbb382cb2dc9eb44b37717e23738). Taking a look
author: eugeneepshteyn
body: Thank you @fhahn , I can confirm that the larger use case that was the source of the reproducer also works now.

Fix patch:
commit d67dba5e8880bdd856b0d3812dcdccf8c7902aba
Author: Florian Hahn <flo@fhahn.com>
Date:   Thu Aug 21 11:34:49 2025 +0100

    [VPlan] Check Def2LaneDefs first in cloneForLane. (NFC)
    
    If we have entries in Def2LaneDefs, we always have to use it. Move the
    check before.
    
    Otherwise we may not pick the correct operand, e.g. if Op was a
    replicate recipe that got single-scalar after replicating it.
    
    Fixes https://github.com/llvm/llvm-project/issues/154330.

diff --git a/llvm/lib/Transforms/Vectorize/VPlanUnroll.cpp b/llvm/lib/Transforms/Vectorize/VPlanUnroll.cpp
index 62fd83a5e092..d47d76d20373 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanUnroll.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanUnroll.cpp
@@ -473,8 +473,11 @@ cloneForLane(VPlan &Plan, VPBuilder &Builder, Type *IdxTy,
   // Collect the operands at Lane, creating extracts as needed.
   SmallVector<VPValue *> NewOps;
   for (VPValue *Op : RepR->operands()) {
-    if (vputils::isSingleScalar(Op)) {
-      NewOps.push_back(Op);
+    // If Op is a definition that has been unrolled, directly use the clone for
+    // the corresponding lane.
+    auto LaneDefs = Def2LaneDefs.find(Op);
+    if (LaneDefs != Def2LaneDefs.end()) {
+      NewOps.push_back(LaneDefs->second[Lane.getKnownLane()]);
       continue;
     }
     if (Lane.getKind() == VPLane::Kind::ScalableLast) {
@@ -482,11 +485,8 @@ cloneForLane(VPlan &Plan, VPBuilder &Builder, Type *IdxTy,
           Builder.createNaryOp(VPInstruction::ExtractLastElement, {Op}));
       continue;
     }
-    // If Op is a definition that has been unrolled, directly use the clone for
-    // the corresponding lane.
-    auto LaneDefs = Def2LaneDefs.find(Op);
-    if (LaneDefs != Def2LaneDefs.end()) {
-      NewOps.push_back(LaneDefs->second[Lane.getKnownLane()]);
+    if (vputils::isSingleScalar(Op)) {
+      NewOps.push_back(Op);
       continue;
     }
 


Regression tests:
file: llvm/test/Transforms/LoopVectorize/X86/replicate-recipe-with-only-first-lane-used.ll
commands: opt -p loop-vectorize -force-vector-width=4 -force-vector-interleave=2 -S %s
tests: test_name: uniform_load_replicating_select
test_body: 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 float @uniform_load_replicating_select(ptr %A, ptr %B, i64 %0) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ %iv.next, %loop ], [ 0, %entry ]
  %l = load float, ptr %A, align 4
  %c = fcmp ogt float %l, 0.000000e+00
  %gep.B = getelementptr inbounds float, ptr %B, i64 %iv
  %sel.ptr = select i1 %c, ptr %A, ptr %gep.B
  %base = select i1 %c, float 1.000000e+01, float 1.000000e+00
  %l.2 = load float, ptr %sel.ptr, align 4
  %div = fdiv float 4.000000e+00, %l.2
  %pow = tail call float @llvm.pow.f32(float %base, float %div)
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv, %0
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret float %pow
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.pow.f32(float, float) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }