Bug type: crash
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: adjustExtracts
Issue title: [SLPVectorizer] Assertion failure: "trying to erase instruction with users" in BoUpSLP destructor
Labels: llvm:SLPVectorizer
crash-on-valid
Reported by: saurabhk

**Description**

The SLP Vectorizer crashes with an assertion failure when vectorizing code containing a specific pattern of extractelement → fpext → fmul → select → fcmp chains.
The assertion I->use_empty() && "trying to erase instruction with users." fails in BoUpSLP::~BoUpSLP() because an extractelement instruction is marked for deletion but still has live users (an insertelement instruction that was not marked for deletion).

When assertions are disabled, this leads to a segfault in the VectorCombine pass.

**Reproducer**
Minimal LLVM IR (75 lines):
```
; Minimal reproducer for SLP Vectorizer assertion failure
; Run: opt -passes='slp-vectorizer' crash.ll -o /dev/null

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 i1 @slp_crash() {
entry:
  %e0 = extractelement <4 x float> splat (float 0.0), i64 0
  %c1 = fpext float %e0 to double
  %m1 = fmul double 0.0, %c1
  %s1 = select i1 false, double %m1, double 0.0
  %r1 = fcmp olt double %s1, 0.0

  %c2 = fpext float 0.0 to double
  %m2 = fmul double 0.0, %c2
  %s2 = select i1 false, double %m2, double 0.0
  %r2 = fcmp olt double %s2, 0.0

  %e1 = extractelement <4 x float> splat (float 1.0), i64 0
  %c3 = fpext float %e1 to double
  %m3 = fmul double 0.0, %c3
  %s3 = select i1 false, double %m3, double 0.0
  %r3 = fcmp olt double %s3, 0.0

  %e2 = extractelement <4 x float> splat (float 2.0), i64 0
  %c4 = fpext float %e2 to double
  %m4 = fmul double 0.0, %c4
  %s4 = select i1 false, double %m4, double 0.0
  %r4 = fcmp olt double %s4, 0.0

  %e3 = extractelement <4 x float> splat (float 3.0), i64 0
  %c5 = fpext float %e3 to double
  %m5 = fmul double 0.0, %c5
  %s5 = select i1 false, double %m5, double 0.0
  %r5 = fcmp olt double %s5, 0.0

  %e4 = extractelement <4 x float> splat (float 4.0), i64 0
  %c6 = fpext float %e4 to double
  %m6 = fmul double 0.0, %c6
  %s6 = select i1 false, double %m6, double 0.0
  %r6 = fcmp olt double %s6, 0.0

  %e5 = extractelement <4 x float> splat (float 5.0), i64 0
  %c7 = fpext float %e5 to double
  %m7 = fmul double 0.0, %c7
  %s7 = select i1 false, double %m7, double 0.0
  %r7 = fcmp olt double %s7, 0.0

  %m8 = fmul double 0.0, %c1
  %s8 = select i1 false, double %m8, double 0.0
  %r8 = fcmp olt double %s8, 0.0

  ret i1 %r8
}
```
**Steps to Reproduce**
```opt -passes='slp-vectorizer' crash.ll -o /dev/null```

**Stack Trace**
```opt: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:6230: 
  llvm::slpvectorizer::BoUpSLP::~BoUpSLP(): 
  Assertion `I->use_empty() && "trying to erase instruction with users."' failed.

Stack dump:
0.  Program arguments: opt -passes=slp-vectorizer crash.ll -o /dev/null
1.  Running pass "function(slp-vectorizer)" on module "crash.ll"
2.  Running pass "slp-vectorizer" on function "slp_crash"
 #9  llvm::slpvectorizer::BoUpSLP::~BoUpSLP()
#10  llvm::SLPVectorizerPass::runImpl(...)
#11  llvm::SLPVectorizerPass::run(...)
```

**Environment**
LLVM version: trunk (commit 96891b73a95c)
Target: x86_64-unknown-linux-gnu

Comments: author: saurabhk
body: FYI @RKSimon @alexey-bataev 

Fix patch:
commit b9885558120c0a825d3ecc9dfa4d79a816060ef4
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Mon Dec 15 08:22:24 2025 -0800

    [SLP]Check if the extractelement is part of other buildvector node before marking for erasing
    
    Need to check if the extractelement instruction is part of other
    buildvector node, before trying to mark it for the deletion, otherwise
    the compiler may reuse the deleted instruction.
    
    Fixes #172221

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index a56edc67f28e..83faa89218bc 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -14108,6 +14108,11 @@ public:
         ArrayRef<TreeEntry *> VEs = R.getTreeEntries(V);
         if (!CheckedExtracts.insert(V).second ||
             !R.areAllUsersVectorized(cast<Instruction>(V), &VectorizedVals) ||
+            (E->UserTreeIndex && E->UserTreeIndex.EdgeIdx == UINT_MAX &&
+             !R.isVectorized(EE) &&
+             count_if(E->Scalars, [&](Value *V) { return V == EE; }) !=
+                 count_if(E->UserTreeIndex.UserTE->Scalars,
+                          [&](Value *V) { return V == EE; })) ||
             any_of(EE->users(),
                    [&](User *U) {
                      return isa<GetElementPtrInst>(U) &&
@@ -18283,6 +18288,11 @@ public:
       // If the only one use is vectorized - can delete the extractelement
       // itself.
       if (!EI->hasOneUse() || R.ExternalUsesAsOriginalScalar.contains(EI) ||
+          (E->UserTreeIndex && E->UserTreeIndex.EdgeIdx == UINT_MAX &&
+           !R.isVectorized(EI) &&
+           count_if(E->Scalars, [&](Value *V) { return V == EI; }) !=
+               count_if(E->UserTreeIndex.UserTE->Scalars,
+                        [&](Value *V) { return V == EI; })) ||
           (NumParts != 1 && count(VL, EI) > 1) ||
           any_of(EI->users(), [&](User *U) {
             ArrayRef<TreeEntry *> UTEs = R.getTreeEntries(U);


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/extract-used-in-many-nodes.ll
commands: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu < %s
tests: test_name: <module>
test_body: 
define i1 @test() {
;
entry:
  %e0 = extractelement <4 x float> splat (float 0.0), i64 0
  %c1 = fpext float %e0 to double
  %m1 = fmul double 0.0, %c1
  %s1 = select i1 false, double %m1, double 0.0
  %r1 = fcmp olt double %s1, 0.0

  %c2 = fpext float 0.0 to double
  %m2 = fmul double 0.0, %c2
  %s2 = select i1 false, double %m2, double 0.0
  %r2 = fcmp olt double %s2, 0.0

  %e1 = extractelement <4 x float> splat (float 1.0), i64 0
  %c3 = fpext float %e1 to double
  %m3 = fmul double 0.0, %c3
  %s3 = select i1 false, double %m3, double 0.0
  %r3 = fcmp olt double %s3, 0.0

  %e2 = extractelement <4 x float> splat (float 2.0), i64 0
  %c4 = fpext float %e2 to double
  %m4 = fmul double 0.0, %c4
  %s4 = select i1 false, double %m4, double 0.0
  %r4 = fcmp olt double %s4, 0.0

  %e3 = extractelement <4 x float> splat (float 3.0), i64 0
  %c5 = fpext float %e3 to double
  %m5 = fmul double 0.0, %c5
  %s5 = select i1 false, double %m5, double 0.0
  %r5 = fcmp olt double %s5, 0.0

  %e4 = extractelement <4 x float> splat (float 4.0), i64 0
  %c6 = fpext float %e4 to double
  %m6 = fmul double 0.0, %c6
  %s6 = select i1 false, double %m6, double 0.0
  %r6 = fcmp olt double %s6, 0.0

  %e5 = extractelement <4 x float> splat (float 5.0), i64 0
  %c7 = fpext float %e5 to double
  %m7 = fmul double 0.0, %c7
  %s7 = select i1 false, double %m7, double 0.0
  %r7 = fcmp olt double %s7, 0.0

  %m8 = fmul double 0.0, %c1
  %s8 = select i1 false, double %m8, double 0.0
  %r8 = fcmp olt double %s8, 0.0

  ret i1 %r8
}