Bug type: crash
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: BoUpSLP::isGatherShuffledSingleRegisterEntry
Issue title: SLPVectorizer miscompilation
Labels: llvm:SLPVectorizer
crash-on-valid
Reported by: Zentrik

```llvm
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:10:11:12:13"
target triple = "x86_64-unknown-linux-gnu"

define swiftcc { ptr addrspace(10), i8 } @julia__dir2ori_404(float %0) {
  %2 = fdiv float 0.000000e+00, 0.000000e+00
  %3 = fdiv float 0.000000e+00, 0.000000e+00
  %4 = fdiv float %0, 0.000000e+00
  br label %5

5:                                                ; preds = %1
  %6 = fmul float %4, 0.000000e+00
  %7 = fsub float 0.000000e+00, %6
  %8 = fmul float %3, 0.000000e+00
  %9 = fsub float 0.000000e+00, %8
  br label %11

10:                                               ; No predecessors!
  br label %11

11:                                               ; preds = %10, %5
  %12 = phi float [ %7, %5 ], [ 0.000000e+00, %10 ]
  %13 = phi float [ %9, %5 ], [ 0.000000e+00, %10 ]
  br label %14

14:                                               ; preds = %11
  %15 = fmul float %2, 0.000000e+00
  %16 = fsub float %12, %15
  %17 = fmul float %4, 0.000000e+00
  %18 = fsub float %13, %17
  %19 = fadd float %16, %18
  %20 = call float @llvm.fabs.f32(float %19)
  ret { ptr addrspace(10), i8 } zeroinitializer
}

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

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
```
produces 
```
Instruction does not dominate all uses!
  %4 = insertelement <2 x float> <float poison, float 0.000000e+00>, float %0, i32 0
  %2 = shufflevector <2 x float> %4, <2 x float> <float 0.000000e+00, float poison>, <2 x i32> <i32 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 -mcpu=haswell <source>
1.	Running pass "verify" on module "<source>"
 #0 0x00000000054edec8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x54edec8)
 #1 0x00000000054eb884 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x00007faaea842520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007faaea8969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007faaea842476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007faaea8287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x000000000082790d llvm::json::operator==(llvm::json::Value const&, llvm::json::Value const&) (.cold) JSON.cpp:0:0
 #7 0x000000000542b6e8 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x542b6e8)
 #8 0x0000000005329278 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5329278)
 #9 0x000000000095605e 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+0x95605e)
#10 0x00000000052e7b50 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x52e7b50)
#11 0x000000000096174a 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+0x96174a)
#12 0x0000000000953c7c optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x953c7c)
#13 0x00007faaea829d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#14 0x00007faaea829e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#15 0x000000000094b555 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x94b555)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```
on 19 and trunk.
Godbolt: https://godbolt.org/z/qxKP6198T

Comments: author: Zentrik
body: Bisected thanks to manyclangs to 66775f8ccdcc8264ef349518e1c59d96d4227823 (8e2b2c4181506efc5b9321c203dd107bbd63392b seemed to be good) @alexey-bataev

Fix patch:
commit ac217ee389d63124432e5e6890851a678f7a676b
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Thu Feb 13 14:19:51 2025 -0800

    [SLP] Check for PHI nodes (potentially cycles!) when checking dependencies
    
    When checking for dependecies for gather nodes with users with the same
    last instruction, cannot rely on the index order, if there is (even
    potential!) cycle in the graph, which may cause order not work correctly
    and cause compiler crash.
    
    Fixes #127128

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index fb72a112b9ac..780cafe91d6b 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -13206,8 +13206,16 @@ BoUpSLP::isGatherShuffledSingleRegisterEntry(
           continue;
         // If the user instruction is used for some reason in different
         // vectorized nodes - make it depend on index.
+        // If any vector node is PHI node, this dependency might not work
+        // because of cycle dependencies, so disable it.
         if (TEUseEI.UserTE != UseEI.UserTE &&
-            TEUseEI.UserTE->Idx < UseEI.UserTE->Idx)
+            (TEUseEI.UserTE->Idx < UseEI.UserTE->Idx ||
+             any_of(
+                 VectorizableTree,
+                 [](const std::unique_ptr<TreeEntry> &TE) {
+                   return TE->State == TreeEntry::Vectorize &&
+                          TE->getOpcode() == Instruction::PHI;
+                 })))
           continue;
       }
 


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/delayed-gather-emission.ll
commands: opt -passes=slp-vectorizer -mtriple=x86_64 -mattr=+avx2 -S < %s
tests: test_name: test
test_body: define void @test() {
entry:
  %.pre.pre = load float, ptr poison, align 4
  br label %bb1

bb1:                                              ; preds = %bb2, %entry
  %.pre = phi float [ %.pre.pre, %entry ], [ %i2, %bb2 ]
  %foxtrot.0 = phi float [ undef, %entry ], [ %gulf.0, %bb2 ]
  br label %bb2

bb2:                                              ; preds = %bb2, %bb1
  %i = phi float [ %.pre, %bb1 ], [ %i2, %bb2 ]
  %gulf.0 = phi float [ %foxtrot.0, %bb1 ], [ %div, %bb2 ]
  %div = fdiv float %i, %gulf.0
  %i1 = load float, ptr poison, align 4
  %div1 = fdiv float %gulf.0, %i1
  %mul = fmul float %div, %div1
  tail call void @foo(float %mul)
  %i2 = load float, ptr poison, align 4
  %tobool = fcmp une float %i2, 0.000000e+00
  br i1 %tobool, label %bb1, label %bb2
}

declare void @foo(float)

file: llvm/test/Transforms/SLPVectorizer/X86/phi-node-with-cycle.ll
commands: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu -mcpu=haswell < %s
tests: test_name: <module>
test_body: 
define void @test(float %0) {
;
  %2 = fdiv float 0.000000e+00, 0.000000e+00
  %3 = fdiv float 0.000000e+00, 0.000000e+00
  %4 = fdiv float %0, 0.000000e+00
  br label %5

5:
  %6 = fmul float %4, 0.000000e+00
  %7 = fsub float 0.000000e+00, %6
  %8 = fmul float %3, 0.000000e+00
  %9 = fsub float 0.000000e+00, %8
  br label %11

10:
  br label %11

11:
  %12 = phi float [ %7, %5 ], [ 0.000000e+00, %10 ]
  %13 = phi float [ %9, %5 ], [ 0.000000e+00, %10 ]
  br label %14

14:
  %15 = fmul float %2, 0.000000e+00
  %16 = fsub float %12, %15
  %17 = fmul float %4, 0.000000e+00
  %18 = fsub float %13, %17
  %19 = fadd float %16, %18
  %20 = call float @llvm.fabs.f32(float %19)
  ret void
}