Bug type: crash
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: BoUpSLP::vectorizeTree
removeInstructionsAndOperands
tryToReduce
Issue title: Assertion `I->use_empty() && "trying to erase instruction with users."' failed.
Labels: llvm:SLPVectorizer
crash
Reported by: TatyanaDoubts

To reproduce run opt with the test below using -passes=slp-vectorizer.
```
; ModuleID = './reduced.ll'
source_filename = "./reduced.ll"
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-ni:1-p2:32:8:8:32-ni:2"
target triple = "x86_64-unknown-linux-gnu"

define i32 @wombat(i32 %arg) #0 gc "statepoint-example" {
bb:
  br label %bb1
  
bb1:                                              ; preds = %bb1, %bb
  %phi = phi i32 [ 0, %bb ], [ %mul37, %bb1 ]
  %mul = mul i64 0, 0
  %trunc = trunc i64 %mul to i32
  %or = or i32 0, %trunc
  %or2 = or i32 0, %or
  %or3 = or i32 %or2, 0
  %mul4 = mul i32 0, %or3
  %mul5 = mul i32 %or3, 0
  %mul6 = mul i32 %mul5, %mul4
  %mul7 = mul i32 %mul6, %mul4
  %mul8 = mul i32 %mul7, %or3
  %mul9 = mul i64 0, 0
  %trunc10 = trunc i64 %mul9 to i32
  %or11 = or i32 0, %trunc10
  %or12 = or i32 %arg, %or11
  %or13 = or i32 %or12, 0
  %mul14 = mul i32 %or13, %mul8
  %mul15 = mul i32 %mul14, 0
  %mul16 = mul i32 %mul15, 0
  %mul17 = mul i32 %mul16, %or13
  %shl = shl i64 0, 0
  %mul18 = mul i64 %shl, 0
  %trunc19 = trunc i64 %mul18 to i32
  %or20 = or i32 0, %trunc19
  %or21 = or i32 0, %or20
  %or22 = or i32 %or21, 0
  %mul23 = mul i32 %or22, %mul17
  %mul24 = mul i32 %mul23, 0
  %mul25 = mul i32 %mul24, 0
  %mul26 = mul i32 %mul25, %or22
  %shl27 = shl i64 0, 0
  %mul28 = mul i64 %shl27, 0
  %trunc29 = trunc i64 %mul28 to i32
  %or30 = or i32 0, %trunc29
  %or31 = or i32 0, %or30
  %or32 = or i32 %or31, 0
  %mul33 = mul i32 0, %or32
  %mul34 = mul i32 %or32, %mul26
 %mul35 = mul i32 %mul34, %mul33
  %mul36 = mul i32 %mul35, %mul33
  %mul37 = mul i32 %mul36, %or32
  br label %bb1
}

attributes #0 = { "target-cpu"="znver2" }
```

Reproducer: https://godbolt.org/z/4PPzsMbP3

Stack dump:
```
opt: /root/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:4570: llvm::slpvectorizer::BoUpSLP::~BoUpSLP(): Assertion `I->use_empty() && "trying to erase instruction with users."' 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=slp-vectorizer <source>
1.	Running pass "function(slp-vectorizer)" on module "<source>"
2.	Running pass "slp-vectorizer" on function "wombat"
 #0 0x00000000054546a8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x54546a8)
 #1 0x0000000005452064 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x00007b5c5f242520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007b5c5f2969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007b5c5f242476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007b5c5f2287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00007b5c5f22871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x00007b5c5f239e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x000000000440d177 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x440d177)
 #9 0x00000000044d46ae llvm::SLPVectorizerPass::runImpl(llvm::Function&, llvm::ScalarEvolution*, llvm::TargetTransformInfo*, llvm::TargetLibraryInfo*, llvm::AAResults*, llvm::LoopInfo*, llvm::DominatorTree*, llvm::AssumptionCache*, llvm::DemandedBits*, llvm::OptimizationRemarkEmitter*) (.part.0) SLPVectorizer.cpp:0:0
#10 0x00000000044d50cb llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x44d50cb)
#11 0x000000000318a35e llvm::detail::PassModel<llvm::Function, llvm::SLPVectorizerPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x318a35e)
#12 0x000000000524e9e0 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x524e9e0)
#13 0x0000000000e6f88e 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+0xe6f88e)
#14 0x000000000524d2fb llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x524d2fb)
#15 0x0000000000e6eb7e 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+0xe6eb7e)
#16 0x000000000524cd00 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x524cd00)
#17 0x0000000000935e7a 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+0x935e7a)
#18 0x00000000009294ec optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x9294ec)
#19 0x00007b5c5f229d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#20 0x00007b5c5f229e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#21 0x0000000000920dc5 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x920dc5)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```


Fix patch:
commit 39bab1de33333ee3c62b586c4e8d26f8c443bc60
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Wed Feb 26 14:12:05 2025 -0800

    [SLP]Check if the operand for removal is the reduction operand, awaiting for the reduction
    
    If the operand of the instruction-to-be-removed is a reduction value,
    which is not reduced yet, and, thus, it has no users, it may be removed
    during operands analysis.
    
    Fixes #128736

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index b25b09306aca..e8c91ebd508c 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -1389,9 +1389,10 @@ public:
   /// Vectorize the tree but with the list of externally used values \p
   /// ExternallyUsedValues. Values in this MapVector can be replaced but the
   /// generated extractvalue instructions.
-  Value *
-  vectorizeTree(const ExtraValueToDebugLocsMap &ExternallyUsedValues,
-                Instruction *ReductionRoot = nullptr);
+  Value *vectorizeTree(
+      const ExtraValueToDebugLocsMap &ExternallyUsedValues,
+      Instruction *ReductionRoot = nullptr,
+      ArrayRef<std::tuple<Value *, unsigned, bool>> VectorValuesAndScales = {});
 
   /// \returns the cost incurred by unwanted spills and fills, caused by
   /// holding live values over call sites.
@@ -2849,11 +2850,13 @@ public:
   /// Remove instructions from the parent function and clear the operands of \p
   /// DeadVals instructions, marking for deletion trivially dead operands.
   template <typename T>
-  void removeInstructionsAndOperands(ArrayRef<T *> DeadVals) {
+  void removeInstructionsAndOperands(
+      ArrayRef<T *> DeadVals,
+      ArrayRef<std::tuple<Value *, unsigned, bool>> VectorValuesAndScales) {
     SmallVector<WeakTrackingVH> DeadInsts;
     for (T *V : DeadVals) {
       auto *I = cast<Instruction>(V);
-      DeletedInstructions.insert(I);
+      eraseInstruction(I);
     }
     DenseSet<Value *> Processed;
     for (T *V : DeadVals) {
@@ -2915,12 +2918,17 @@ public:
         // loop iteration.
         if (auto *OpI = dyn_cast<Instruction>(OpV))
           if (!DeletedInstructions.contains(OpI) &&
+              (!OpI->getType()->isVectorTy() ||
+               none_of(VectorValuesAndScales,
+                       [&](const std::tuple<Value *, unsigned, bool> &V) {
+                         return std::get<0>(V) == OpI;
+                       })) &&
               isInstructionTriviallyDead(OpI, TLI))
             DeadInsts.push_back(OpI);
       }
 
       VI->removeFromParent();
-      DeletedInstructions.insert(VI);
+      eraseInstruction(VI);
       SE->forgetValue(VI);
     }
   }
@@ -16466,9 +16474,10 @@ Value *BoUpSLP::vectorizeTree() {
   return vectorizeTree(ExternallyUsedValues);
 }
 
-Value *
-BoUpSLP::vectorizeTree(const ExtraValueToDebugLocsMap &ExternallyUsedValues,
-                       Instruction *ReductionRoot) {
+Value *BoUpSLP::vectorizeTree(
+    const ExtraValueToDebugLocsMap &ExternallyUsedValues,
+    Instruction *ReductionRoot,
+    ArrayRef<std::tuple<Value *, unsigned, bool>> VectorValuesAndScales) {
   // All blocks must be scheduled before any instructions are inserted.
   for (auto &BSIter : BlocksSchedules) {
     scheduleBlock(BSIter.second.get());
@@ -17075,7 +17084,7 @@ BoUpSLP::vectorizeTree(const ExtraValueToDebugLocsMap &ExternallyUsedValues,
   // cache correctness.
   // NOTE: removeInstructionAndOperands only marks the instruction for deletion
   // - instructions are not deleted until later.
-  removeInstructionsAndOperands(ArrayRef(RemovedInsts));
+  removeInstructionsAndOperands(ArrayRef(RemovedInsts), VectorValuesAndScales);
 
   Builder.ClearInsertionPoint();
   InstrElementSize.clear();
@@ -20449,8 +20458,8 @@ public:
           InsertPt = GetCmpForMinMaxReduction(RdxRootInst);
 
         // Vectorize a tree.
-        Value *VectorizedRoot =
-            V.vectorizeTree(LocalExternallyUsedValues, InsertPt);
+        Value *VectorizedRoot = V.vectorizeTree(
+            LocalExternallyUsedValues, InsertPt, VectorValuesAndScales);
         // Update TrackedToOrig mapping, since the tracked values might be
         // updated.
         for (Value *RdxVal : Candidates) {
@@ -20678,7 +20687,7 @@ public:
             Ignore->replaceAllUsesWith(P);
           }
         }
-        V.removeInstructionsAndOperands(RdxOps);
+        V.removeInstructionsAndOperands(RdxOps, VectorValuesAndScales);
       }
     } else if (!CheckForReusedReductionOps) {
       for (ReductionOpsType &RdxOps : ReductionOps)


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/reduction-with-removed-extracts.ll
commands: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu -mcpu=znver2 < %s
tests: test_name: <module>
test_body: 
define i32 @test(i32 %arg) {
;
bb:
  br label %bb1

bb1:
  %phi = phi i32 [ 0, %bb ], [ %mul37, %bb1 ]
  %mul = mul i64 0, 0
  %trunc = trunc i64 %mul to i32
  %or = or i32 0, %trunc
  %or2 = or i32 0, %or
  %or3 = or i32 %or2, 0
  %mul4 = mul i32 0, %or3
  %mul5 = mul i32 %or3, 0
  %mul6 = mul i32 %mul5, %mul4
  %mul7 = mul i32 %mul6, %mul4
  %mul8 = mul i32 %mul7, %or3
  %mul9 = mul i64 0, 0
  %trunc10 = trunc i64 %mul9 to i32
  %or11 = or i32 0, %trunc10
  %or12 = or i32 %arg, %or11
  %or13 = or i32 %or12, 0
  %mul14 = mul i32 %or13, %mul8
  %mul15 = mul i32 %mul14, 0
  %mul16 = mul i32 %mul15, 0
  %mul17 = mul i32 %mul16, %or13
  %shl = shl i64 0, 0
  %mul18 = mul i64 %shl, 0
  %trunc19 = trunc i64 %mul18 to i32
  %or20 = or i32 0, %trunc19
  %or21 = or i32 0, %or20
  %or22 = or i32 %or21, 0
  %mul23 = mul i32 %or22, %mul17
  %mul24 = mul i32 %mul23, 0
  %mul25 = mul i32 %mul24, 0
  %mul26 = mul i32 %mul25, %or22
  %shl27 = shl i64 0, 0
  %mul28 = mul i64 %shl27, 0
  %trunc29 = trunc i64 %mul28 to i32
  %or30 = or i32 0, %trunc29
  %or31 = or i32 0, %or30
  %or32 = or i32 %or31, 0
  %mul33 = mul i32 0, %or32
  %mul34 = mul i32 %or32, %mul26
  %mul35 = mul i32 %mul34, %mul33
  %mul36 = mul i32 %mul35, %mul33
  %mul37 = mul i32 %mul36, %or32
  br label %bb1
}