Bug type: crash
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: BoUpSLP::isGatherShuffledSingleRegisterEntry
Issue title: [clang] Crash at -O3: Instruction does not dominate all uses!
Labels: llvm:SLPVectorizer
crash-on-valid
Reported by: cardigan1008

This code crashes at `-O3`:

```c
int a;
double b;
long c;
int d(long f, long g) {
  if (f + g)
    return 1;
  for (long e = 0; e < g; e++)
    *(char *)e = 5;
  return 0;
}
int h(int f) {
  double i = 0.270112271089232341485679099e4;
  b = 0.1e1;
  for (; c; c--) {
    i = i * (80 + f) * (9 + f) + a;
    a = 0;
    b = b * f * (d(-42, f) + f) + 0.11623987080032122878585294e22;
  }
  return i / b;
}
void main() {}
```

Compiler Explorer: https://godbolt.org/z/b4YEsPMrq

Bisected to https://github.com/llvm/llvm-project/commit/d57884011e8c57b118b831614b692ba4bc8b5aca, which was committed by @alexey-bataev 

Crash:

```console
Instruction does not dominate all uses!
  %3 = insertelement <2 x i32> %2, i32 %f, i64 1
  %0 = insertelement <2 x i32> %3, i32 %add1, i64 0
in function h
fatal error: error in backend: Broken function found, compilation aborted!
```

Backtrace:

```console
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/clang -gdwarf-4 -g -o /app/output.s -mllvm --x86-asm-syntax=intel -fno-verbose-asm -S --gcc-toolchain=/opt/compiler-explorer/gcc-snapshot -fcolor-diagnostics -fno-crash-diagnostics -O3 -Wall -Wextra <source>
1.	<eof> parser at end of file
2.	Code generation
3.	Running pass 'Function Pass Manager' on module '<source>'.
4.	Running pass 'Module Verifier' on function '@h'
 #0 0x0000000003e87c38 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3e87c38)
 #1 0x0000000003e858c4 llvm::sys::CleanupOnSignal(unsigned long) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3e858c4)
 #2 0x0000000003dcacb6 llvm::CrashRecoveryContext::HandleExit(int) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3dcacb6)
 #3 0x0000000003e7cfee llvm::sys::Process::Exit(int, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3e7cfee)
 #4 0x0000000000d4e5a0 LLVMErrorHandler(void*, char const*, bool) cc1_main.cpp:0:0
 #5 0x0000000003dd5443 llvm::report_fatal_error(llvm::Twine const&, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3dd5443)
 #6 0x0000000003dd55a8 (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3dd55a8)
 #7 0x0000000003887952 (anonymous namespace)::VerifierLegacyPass::runOnFunction(llvm::Function&) Verifier.cpp:0:0
 #8 0x00000000037d28df llvm::FPPassManager::runOnFunction(llvm::Function&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x37d28df)
 #9 0x00000000037d2c91 llvm::FPPassManager::runOnModule(llvm::Module&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x37d2c91)
#10 0x00000000037d3531 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x37d3531)
#11 0x000000000413d67e clang::emitBackendOutput(clang::CompilerInstance&, clang::CodeGenOptions&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>, clang::BackendConsumer*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x413d67e)
#12 0x00000000048429a0 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x48429a0)
#13 0x00000000064aecac clang::ParseAST(clang::Sema&, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x64aecac)
#14 0x0000000004842da8 clang::CodeGenAction::ExecuteAction() (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x4842da8)
#15 0x0000000004b127f5 clang::FrontendAction::Execute() (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x4b127f5)
#16 0x0000000004a94a2e clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x4a94a2e)
#17 0x0000000004c024fe clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x4c024fe)
#18 0x0000000000d50baf cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0xd50baf)
#19 0x0000000000d4836a ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#20 0x000000000488b309 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const::'lambda'()>(long) Job.cpp:0:0
#21 0x0000000003dcabf4 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x3dcabf4)
#22 0x000000000488b91f clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const (.part.0) Job.cpp:0:0
#23 0x000000000484e38d clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x484e38d)
#24 0x000000000484f41e clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) const (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x484f41e)
#25 0x0000000004856af5 clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0x4856af5)
#26 0x0000000000d4d9a8 clang_main(int, char**, llvm::ToolContext const&) (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0xd4d9a8)
#27 0x0000000000c146c4 main (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0xc146c4)
#28 0x00007acc03029d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#29 0x00007acc03029e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#30 0x0000000000d47e15 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/clang+0xd47e15)
```


Fix patch:
commit 45090b3059562b32723cd25679db75d1574ab04e
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Tue Mar 18 09:32:23 2025 -0700

    [SLP]Check the whole def-use chain in the tree to find proper dominance, if the last instruction is the same
    
    If the insertion point (last instruction) of the user nodes is the same,
    need to check the whole def-use chain in the tree to find proper
    dominance to prevent a compiler crash.
    
    Fixes #131818

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 24171f1d9a06..4a835bc797ab 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -14086,11 +14086,18 @@ BoUpSLP::isGatherShuffledSingleRegisterEntry(
   auto CheckParentNodes = [&](const TreeEntry *User1, const TreeEntry *User2,
                               unsigned EdgeIdx) {
     const TreeEntry *Ptr1 = User1;
+    const TreeEntry *Ptr2 = User2;
+    SmallDenseMap<const TreeEntry *, unsigned> PtrToIdx;
+    while (Ptr2) {
+      PtrToIdx.try_emplace(Ptr2, EdgeIdx);
+      EdgeIdx = Ptr2->UserTreeIndex.EdgeIdx;
+      Ptr2 = Ptr2->UserTreeIndex.UserTE;
+    }
     while (Ptr1) {
       unsigned Idx = Ptr1->UserTreeIndex.EdgeIdx;
       Ptr1 = Ptr1->UserTreeIndex.UserTE;
-      if (Ptr1 == User2)
-        return Idx < EdgeIdx;
+      if (auto It = PtrToIdx.find(Ptr1); It != PtrToIdx.end())
+        return Idx < It->second;
     }
     return false;
   };


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/same-last-instruction-different-parents.ll
commands: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu < %s
tests: test_name: <module>
test_body: 
define i32 @test(i32 %0, i1 %1) {
;
  %3 = sitofp i32 %0 to double
  %4 = sitofp i32 %0 to double
  %5 = sitofp i32 %0 to double
  br i1 %1, label %6, label %9

6:
  %7 = tail call double @llvm.fmuladd.f64(double %4, double 0.000000e+00, double 0.000000e+00)
  %8 = tail call double @llvm.fmuladd.f64(double %5, double 0.000000e+00, double 0.000000e+00)
  br label %18

9:
  br i1 false, label %15, label %10

10:
  %11 = call double @llvm.copysign.f64(double 0.000000e+00, double %3)
  %12 = tail call double @llvm.fmuladd.f64(double %11, double %4, double 0.000000e+00)
  %13 = call double @llvm.copysign.f64(double 0.000000e+00, double %5)
  %14 = tail call double @llvm.fmuladd.f64(double %13, double 0.000000e+00, double 0.000000e+00)
  br label %15

15:
  %16 = phi double [ %12, %10 ], [ 0.000000e+00, %9 ]
  %17 = phi double [ %14, %10 ], [ 0.000000e+00, %9 ]
  br label %18

18:
  %19 = phi double [ %17, %15 ], [ %8, %6 ]
  %20 = phi double [ %16, %15 ], [ %7, %6 ]
  %21 = fmul double %20, %19
  %22 = fptosi double %21 to i32
  ret i32 %22
}