Bug type: crash
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: BoUpSLP::vectorizeTree
Issue title: [SLPVectorizer] Instruction does not dominate all uses! LLVM ERROR: Broken module found, compilation aborted!
Labels: llvm:SLPVectorizer
llvm:crash
Reported by: TatyanaDoubts

To reproduce run the following test with -passes slp-vectorizer -slp-threshold=-99999
[Test.ll.tgz](https://github.com/user-attachments/files/16431764/Test.ll.tgz)

Reproducer : https://godbolt.org/z/GW41a7WP6

Stack dump:
```
Instruction does not dominate all uses!
  %2 = shufflevector <2 x ptr addrspace(1)> %0, <2 x ptr addrspace(1)> poison, <2 x i32> <i32 1, i32 0>
  %1 = extractelement <2 x ptr addrspace(1)> %2, i32 0
LLVM ERROR: Broken module found, compilation aborted!
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 -slp-threshold=-99999 <source>
1.	Running pass "verify" on module "<source>"
 #0 0x0000000004eff778 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4eff778)
 #1 0x0000000004efceec SignalHandler(int) Signals.cpp:0:0
 #2 0x00007c0269e42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007c0269e969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007c0269e42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007c0269e287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00000000007b3ff7 llvm::json::operator==(llvm::json::Value const&, llvm::json::Value const&) (.cold) JSON.cpp:0:0
 #7 0x0000000004e396a8 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4e396a8)
 #8 0x0000000004d360f0 llvm::VerifierPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4d360f0)
 #9 0x00000000008d865e llvm::detail::PassModel<llvm::Module, llvm::VerifierPass, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8d865e)
#10 0x0000000004cf9c90 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4cf9c90)
#11 0x00000000008e33d2 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+0x8e33d2)
#12 0x00000000008d62fc optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8d62fc)
#13 0x00007c0269e29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#14 0x00007c0269e29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#15 0x00000000008cd75e _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8cd75e)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```


Comments: author: Zentrik
body: @alexey-bataev Hi, is there a way to backport this fix for llvm 19, I tried just cherry picking f70f1228035c9610de38e0e376afdacb647c4ad9 but I ended up getting assertion failures of the form `/workspace/srcdir/llvm-project/llvm/lib/IR/Instruction.cpp:321: bool llvm::Instruction::comesBefore(const llvm::Instruction*) const: Assertion 'getParent() == Other->getParent() && "cross-BB instruction order comparison"' failed.'`. 
I can create an IR reproducer for that failure if need be.
Thank you.

EDIT: Would just adding a check that they're in the same basic block work?
author: alexey-bataev
body: > @alexey-bataev Hi, is there a way to backport this fix for llvm 19, I tried just cherry picking [f70f122](https://github.com/llvm/llvm-project/commit/f70f1228035c9610de38e0e376afdacb647c4ad9) but I ended up getting assertion failures of the form `/workspace/srcdir/llvm-project/llvm/lib/IR/Instruction.cpp:321: bool llvm::Instruction::comesBefore(const llvm::Instruction*) const: Assertion 'getParent() == Other->getParent() && "cross-BB instruction order comparison"' failed.'`. I can create an IR reproducer for that failure if need be. Thank you.
> 
> EDIT: Would just adding a check that they're in the same basic block work?

Yes, check for the same parent should fix it

Fix patch:
commit f70f1228035c9610de38e0e376afdacb647c4ad9
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Tue Jul 30 14:02:51 2024 -0700

    [SLP]Fix PR101213: Reuse extractelement, only if its vector operand comes before new vector value.
    
    When trying to reuse extractelement instruction, need to check that it
    is inserted into proper position. Its original vector operand should
    come before new vector value, otherwise new extractelement instruction
    must be generated.
    
    Fixes https://github.com/llvm/llvm-project/issues/101213

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 6501a14d8778..cf87b8621027 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -13909,11 +13909,16 @@ Value *BoUpSLP::vectorizeTree(
         }
         if (!Ex) {
           // "Reuse" the existing extract to improve final codegen.
-          if (auto *ES = dyn_cast<ExtractElementInst>(Scalar)) {
+          if (auto *ES = dyn_cast<ExtractElementInst>(Scalar);
+              ES && isa<Instruction>(Vec)) {
             Value *V = ES->getVectorOperand();
             if (const TreeEntry *ETE = getTreeEntry(V))
               V = ETE->VectorizedValue;
-            Ex = Builder.CreateExtractElement(V, ES->getIndexOperand());
+            if (auto *IV = dyn_cast<Instruction>(V);
+                !IV || IV == Vec || IV->comesBefore(cast<Instruction>(Vec)))
+              Ex = Builder.CreateExtractElement(V, ES->getIndexOperand());
+            else
+              Ex = Builder.CreateExtractElement(Vec, Lane);
           } else if (ReplaceGEP) {
             // Leave the GEPs as is, they are free in most cases and better to
             // keep them as GEPs.


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/extract-vectorized-operand.ll
commands: opt -S --passes=slp-vectorizer -slp-threshold=-99999 < %s -mtriple=x86_64-unknown-linux-gnu
tests: test_name: test
test_body: define void @test() {
bb:
  %0 = shufflevector <2 x ptr addrspace(1)> zeroinitializer, <2 x ptr addrspace(1)> zeroinitializer, <2 x i32> <i32 1, i32 0>
  %1 = extractelement <2 x ptr addrspace(1)> %0, i32 0
  %2 = extractelement <2 x ptr addrspace(1)> %0, i32 1
  br label %bb43

bb20:                                             ; No predecessors!
  br label %bb105

bb43:                                             ; preds = %bb51, %bb
  %phi441 = phi ptr addrspace(1) [ %4, %bb51 ], [ %2, %bb ]
  %phi452 = phi ptr addrspace(1) [ %5, %bb51 ], [ %1, %bb ]
  br i1 false, label %bb105, label %bb51

bb51:                                             ; preds = %bb54, %bb43
  %3 = phi <2 x ptr addrspace(1)> [ poison, %bb54 ], [ zeroinitializer, %bb43 ]
  %4 = extractelement <2 x ptr addrspace(1)> %3, i32 0
  %5 = extractelement <2 x ptr addrspace(1)> %3, i32 1
  br label %bb43

bb54:                                             ; No predecessors!
  br label %bb51

bb105:                                            ; preds = %bb43, %bb20
  %phi106 = phi ptr addrspace(1) [ %1, %bb20 ], [ null, %bb43 ]
  ret void
}