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

To reproduce run opt with the test below (-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 void @wombat(i32 %arg) #0 gc "statepoint-example" {
bb:
  br label %bb1

bb1:                                              ; preds = %bb
  %sub = sub i32 0, %arg
  %add = add i32 0, 0
  %add2 = add i32 0, 0
  %add3 = add i32 0, 0
  br i1 false, label %bb8, label %bb4

bb4:                                              ; preds = %bb1
  %add5 = add i32 %add3, 0
  %add6 = add i32 0, 0
  %add7 = add i32 0, 0
  br label %bb8

bb8:                                              ; preds = %bb4, %bb1
  %phi = phi i32 [ %sub, %bb4 ], [ %sub, %bb1 ]
  %phi9 = phi i32 [ %add5, %bb4 ], [ %add, %bb1 ]
  %phi10 = phi i32 [ %add6, %bb4 ], [ %add2, %bb1 ]
  %phi11 = phi i32 [ %add7, %bb4 ], [ %add3, %bb1 ]
  ret void
}

attributes #0 = { "target-features"="+prfchw,-cldemote,+avx,+aes,+sahf,+pclmul,-xop,+crc32,-amx-fp8,+xsaves,-avx512fp16,-usermsr,-sm4,-egpr,+sse4.1,-avx10.1,-avx512ifma,+xsave,+sse4.2,-tsxldtrk,-sm3,-ptwrite,-widekl,-movrs,-invpcid,+64bit,+xsavec,-avx512vpopcntdq,+cmov,-avx512vp2intersect,-avx512cd,+movbe,-avxvnniint8,-ccmp,-amx-int8,-kl,-sha512,-avxvnni,-rtm,+adx,+avx2,-hreset,-movdiri,-serialize,-vpclmulqdq,-avx512vl,-uintr,-cf,+clflushopt,-raoint,-cmpccxadd,+bmi,-amx-tile,+sse,-gfni,-avxvnniint16,-amx-fp16,-zu,-ndd,+xsaveopt,+rdrnd,-avx512f,-amx-bf16,-avx512bf16,-avx512vnni,-push2pop2,+cx8,-avx512bw,+sse3,-pku,-nf,-amx-tf32,-amx-avx512,+fsgsbase,+clzero,-mwaitx,-lwp,+lzcnt,+sha,-movdir64b,-ppx,+wbnoinvd,-enqcmd,-amx-transpose,-avxneconvert,-tbm,-pconfig,-amx-complex,+ssse3,+cx16,-avx10.2,+bmi2,+fma,+popcnt,-avxifma,+f16c,-avx512bitalg,-rdpru,+clwb,+mmx,+sse2,+rdseed,-avx512vbmi2,-prefetchi,-amx-movrs,+rdpid,-fma4,-avx512vbmi,-shstk,-vaes,-waitpkg,-sgx,+fxsr,-avx512dq,+sse4a" }
```
Reproducer: https://godbolt.org/z/1czjdsGz4

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 "verify" on module "<source>"
 #0 0x0000000005974be8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5974be8)
 #1 0x0000000005971a94 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x000079b58c842520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x000079b58c8969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x000079b58c842476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x000079b58c8287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00000000008362db llvm::json::operator==(llvm::json::Value const&, llvm::json::Value const&) (.cold) JSON.cpp:0:0
 #7 0x00000000058a24c1 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x58a24c1)
 #8 0x000000000578ee38 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x578ee38)
 #9 0x000000000097ba6e 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+0x97ba6e)
#10 0x000000000574c471 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x574c471)
#11 0x0000000000985c3a 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, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x985c3a)
#12 0x0000000000979eb1 optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x979eb1)
#13 0x000079b58c829d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#14 0x000079b58c829e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#15 0x00000000009712c5 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x9712c5)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```


Fix patch:
commit a7b188983fd804e05a15835c3f0df5fa7523c246
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Sun Oct 26 09:38:39 2025 -0700

    [SLP]Consider non-inst operands, when checking insts, used outside only
    
    If the instructions in the node do not require scheduling and used
    outside basic block only, still need to check, if their operands are
    non-inst too. Such nodes should be emitted in the beginning of the
    block.
    
    Fixes #165151

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index cdb9e7e38112..4fcaf6dabb51 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -17641,12 +17641,28 @@ Instruction &BoUpSLP::getLastInstructionInBundle(const TreeEntry *E) {
                 [](Value *V) {
                   return !isa<GetElementPtrInst>(V) && isa<Instruction>(V);
                 })) ||
-        all_of(E->Scalars, [&](Value *V) {
-          return isa<PoisonValue>(V) ||
-                 (E->Idx == 0 && isa<InsertElementInst>(V)) ||
-                 E->isCopyableElement(V) ||
-                 (!isVectorLikeInstWithConstOps(V) && isUsedOutsideBlock(V));
-        }))
+        (all_of(E->Scalars,
+                [&](Value *V) {
+                  return isa<PoisonValue>(V) ||
+                         (E->Idx == 0 && isa<InsertElementInst>(V)) ||
+                         E->isCopyableElement(V) ||
+                         (!isVectorLikeInstWithConstOps(V) &&
+                          isUsedOutsideBlock(V));
+                }) &&
+         (!E->doesNotNeedToSchedule() ||
+          any_of(E->Scalars,
+                 [&](Value *V) {
+                   if (!isa<Instruction>(V) ||
+                       (E->hasCopyableElements() && E->isCopyableElement(V)))
+                     return false;
+                   return !areAllOperandsNonInsts(V);
+                 }) ||
+          none_of(E->Scalars, [&](Value *V) {
+            if (!isa<Instruction>(V) ||
+                (E->hasCopyableElements() && E->isCopyableElement(V)))
+              return false;
+            return MustGather.contains(V);
+          }))))
       Res = FindLastInst();
     else
       Res = FindFirstInst();


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/buildvector-reused-with-bv-subvector.ll
commands: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu -mcpu=skylake < %s
tests: test_name: test
test_body: define void @test(ptr %0, i64 %1, i64 %2) {
  %4 = ptrtoint ptr %0 to i64
  %5 = ptrtoint ptr %0 to i64
  %6 = ptrtoint ptr %0 to i64
  %7 = ptrtoint ptr %0 to i64
  %8 = ptrtoint ptr %0 to i64
  br label %.preheader.lr.ph

.preheader.lr.ph:                                 ; preds = %3
  br label %.preheader.us.us.preheader

.preheader.us.us.preheader:                       ; preds = %.preheader.lr.ph
  %9 = or i64 %1, %7
  %10 = or i64 %2, %7
  %11 = or i64 %1, %4
  %12 = or i64 %1, %8
  %13 = or i64 %5, %8
  %14 = or i64 %8, %4
  %15 = or i64 %5, %6
  %16 = or i64 %6, %4
  br label %.preheader.us.us

.preheader.us.us:                                 ; preds = %.preheader.us.us, %.preheader.us.us.preheader
  %diff.check1 = icmp ult i64 %9, 32
  %diff.check2 = icmp ult i64 %10, 32
  %conflict.rdx3 = or i1 %diff.check1, %diff.check2
  %diff.check4 = icmp ult i64 %11, 32
  %conflict.rdx5 = or i1 %conflict.rdx3, %diff.check4
  %diff.check6 = icmp ult i64 %12, 32
  %conflict.rdx7 = or i1 %conflict.rdx5, %diff.check6
  %diff.check8 = icmp ult i64 %13, 32
  %conflict.rdx9 = or i1 %conflict.rdx7, %diff.check8
  %diff.check10 = icmp ult i64 %14, 32
  %conflict.rdx11 = or i1 %conflict.rdx9, %diff.check10
  %diff.check12 = icmp ult i64 %15, 32
  %conflict.rdx13 = or i1 %conflict.rdx11, %diff.check12
  %diff.check14 = icmp ult i64 %16, 32
  %conflict.rdx15 = or i1 %conflict.rdx13, %diff.check14
  br i1 %conflict.rdx15, label %scalar.ph, label %.preheader.us.us

scalar.ph:                                        ; preds = %.preheader.us.us
  ret void
}

file: llvm/test/Transforms/SLPVectorizer/X86/entry-no-bundle-but-extra-use-on-vec.ll
commands: opt -S --passes=slp-vectorizer -mtriple=x86_64-generic-linux-gnu < %s
tests: test_name: test
test_body: define void @test(ptr %nExp, float %0, i1 %cmp, float %1) {
entry:
  br i1 %cmp, label %if.then, label %if.end

if.then:                                          ; preds = %entry
  %div.i41 = fmul float %0, 0.000000e+00
  %2 = load float, ptr %nExp, align 4
  %div.1.i.i = fmul float %2, 0.000000e+00
  %div.2.i.i = fmul float %0, 0.000000e+00
  br label %if.end

if.end:                                           ; preds = %if.then, %entry
  %3 = phi float [ %1, %if.then ], [ %0, %entry ]
  %4 = phi float [ 0.000000e+00, %if.then ], [ %1, %entry ]
  %5 = phi float [ 0.000000e+00, %if.then ], [ 0x7FF8000000000000, %entry ]
  %6 = phi float [ 0.000000e+00, %if.then ], [ 1.000000e+00, %entry ]
  %fa.sroa.9.0 = phi float [ %div.2.i.i, %if.then ], [ 0.000000e+00, %entry ]
  %fa.sroa.7.0 = phi float [ %div.1.i.i, %if.then ], [ 0.000000e+00, %entry ]
  %fa.sroa.0.0 = phi float [ %div.i41, %if.then ], [ 0.000000e+00, %entry ]
  %mul.1.i.i58 = fmul float %fa.sroa.7.0, %6
  %mul.2.i.i60 = fmul float %fa.sroa.9.0, %6
  %mul.1.i.i.i63 = fmul float %fa.sroa.0.0, %5
  %mul.2.i.i.i65 = fmul float %fa.sroa.0.0, 0.000000e+00
  %mul.i66 = fmul float %fa.sroa.0.0, 0.000000e+00
  %add.1.i.i = fadd float %mul.1.i.i58, %mul.1.i.i.i63
  %add.2.i.i = fadd float %mul.2.i.i60, %mul.2.i.i.i65
  %mul.1.i.i74 = fmul float %add.1.i.i, 0.000000e+00
  %mul.2.i.i76 = fmul float %add.2.i.i, 0.000000e+00
  %mul.i.i.i78 = fmul float %mul.i66, 0.000000e+00
  %add.1.i.i85 = fadd float %mul.1.i.i74, 0.000000e+00
  %add.2.i.i86 = fadd float %mul.2.i.i76, 0.000000e+00
  %mul.i.i.i97 = fmul float %5, 0.000000e+00
  %mul.1.i.i.i99 = fmul float %4, 0.000000e+00
  %mul.2.i.i.i101 = fmul float %3, 0.000000e+00
  %add.i.i103 = fadd float %mul.i.i.i97, 0.000000e+00
  %add.1.i.i104 = fadd float %mul.1.i.i.i99, 0.000000e+00
  %add.2.i.i105 = fadd float %mul.2.i.i.i101, 0.000000e+00
  %add = fadd float %mul.i.i.i78, 0.000000e+00
  %add.i = fadd float %add.i.i103, 1.000000e+00
  %add.1.i = fadd float %add.1.i.i104, %add.1.i.i85
  %add.2.i = fadd float %add.2.i.i105, %add.2.i.i86
  %call25 = load volatile ptr, ptr null, align 8
  store float %add, ptr %call25, align 4
  %__trans_tmp_29.sroa.5.0.call25.sroa_idx = getelementptr i8, ptr %call25, i64 4
  store float %add.i, ptr %__trans_tmp_29.sroa.5.0.call25.sroa_idx, align 4
  %__trans_tmp_29.sroa.6.0.call25.sroa_idx = getelementptr i8, ptr %call25, i64 8
  store float %add.1.i, ptr %__trans_tmp_29.sroa.6.0.call25.sroa_idx, align 4
  %__trans_tmp_29.sroa.7.0.call25.sroa_idx = getelementptr i8, ptr %call25, i64 12
  store float %add.2.i, ptr %__trans_tmp_29.sroa.7.0.call25.sroa_idx, align 4
  ret void
}

file: llvm/test/Transforms/SLPVectorizer/X86/non-scheduled-inst-extern-use.ll
commands: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu -slp-threshold=-100 < %s
tests: test_name: <module>
test_body: 
define void @test(i32 %arg) {
;
bb:
  br label %bb1

bb1:
  %sub = sub i32 0, %arg
  %add = add i32 0, 0
  %add2 = add i32 0, 0
  %add3 = add i32 0, 0
  br i1 false, label %bb8, label %bb4

bb4:
  %add5 = add i32 %add3, 0
  %add6 = add i32 0, 0
  %add7 = add i32 0, 0
  br label %bb8

bb8:
  %phi = phi i32 [ %sub, %bb4 ], [ %sub, %bb1 ]
  %phi9 = phi i32 [ %add5, %bb4 ], [ %add, %bb1 ]
  %phi10 = phi i32 [ %add6, %bb4 ], [ %add2, %bb1 ]
  %phi11 = phi i32 [ %add7, %bb4 ], [ %add3, %bb1 ]
  ret void
}

file: llvm/test/Transforms/SLPVectorizer/X86/parent-node-non-schedulable.ll
commands: opt -S --passes=slp-vectorizer -S -mtriple=i686-unknown-linux-android29 -mattr=+sse2 < %s
tests: test_name: test
test_body: define void @test(ptr %0, i64 %1, i64 %2, i1 %3, i64 %4, i64 %5) {
  %7 = getelementptr i8, ptr %0, i32 248
  %8 = load i64, ptr %7, align 4
  %9 = getelementptr i8, ptr %0, i32 240
  %10 = load i64, ptr %9, align 4
  %11 = load i64, ptr null, align 4
  %12 = add i64 %1, 1
  %13 = add i64 %1, 1
  %14 = add i64 %1, %2
  %15 = getelementptr i8, ptr %0, i32 136
  %16 = load i64, ptr %15, align 4
  %17 = getelementptr i8, ptr %0, i32 128
  %18 = load i64, ptr %17, align 4
  %19 = add i64 %18, %1
  %20 = sub i64 0, %18
  %21 = sub i64 0, %16
  %22 = sub i64 0, %11
  %23 = add i64 %1, 1
  %24 = sub i64 0, %1
  %25 = sub i64 0, %1
  %26 = sub i64 0, %10
  %27 = sub i64 0, %8
  %28 = sub i64 0, %19
  %29 = add i64 %11, 1
  %30 = ashr i64 %29, 14
  %31 = add i64 %11, 1
  %32 = ashr i64 %31, 14
  br i1 %3, label %58, label %33

33:                                               ; preds = %6
  %34 = ashr i64 %2, 2
  %35 = ashr i64 %1, 2
  %36 = add i64 %1, 1
  %37 = ashr i64 %36, 2
  %38 = add i64 %1, 1
  %39 = lshr i64 %1, 1
  %40 = add i64 %38, %39
  %41 = ashr i64 %40, 2
  %42 = add i64 %1, 1
  %43 = lshr i64 %1, 1
  %44 = add i64 %42, %43
  %45 = ashr i64 %44, 2
  %46 = ashr i64 %5, 2
  %47 = ashr i64 %4, 2
  %48 = ashr i64 %1, 2
  %49 = ashr i64 %1, 2
  %50 = ashr i64 %1, 2
  %51 = ashr i64 %1, 2
  %52 = add i64 %1, 1
  %53 = ashr i64 %52, 2
  %54 = add i64 %1, 1
  %55 = ashr i64 %54, 2
  %56 = add i64 %1, 1
  %57 = ashr i64 %56, 2
  br label %58

58:                                               ; preds = %33, %6
  %59 = phi i64 [ %51, %33 ], [ %24, %6 ]
  %60 = phi i64 [ %50, %33 ], [ %32, %6 ]
  %61 = phi i64 [ %53, %33 ], [ %25, %6 ]
  %62 = phi i64 [ %55, %33 ], [ %26, %6 ]
  %63 = phi i64 [ %57, %33 ], [ %27, %6 ]
  %64 = phi i64 [ %49, %33 ], [ %30, %6 ]
  %65 = phi i64 [ %48, %33 ], [ %23, %6 ]
  %66 = phi i64 [ %47, %33 ], [ %22, %6 ]
  %67 = phi i64 [ %46, %33 ], [ %21, %6 ]
  %68 = phi i64 [ %45, %33 ], [ %20, %6 ]
  %69 = phi i64 [ %41, %33 ], [ %28, %6 ]
  %70 = phi i64 [ %34, %33 ], [ %12, %6 ]
  %71 = phi i64 [ %35, %33 ], [ %13, %6 ]
  %72 = phi i64 [ %37, %33 ], [ %14, %6 ]
  %73 = or i64 %65, %64
  %74 = or i64 %59, %60
  %75 = or i64 %70, %71
  %76 = or i64 %74, %73
  %77 = or i64 %61, %66
  %78 = or i64 %72, %75
  %79 = or i64 %67, %77
  %80 = or i64 %62, %79
  %81 = or i64 %76, %80
  %82 = or i64 %68, %81
  store i64 %78, ptr %0, align 4
  store i64 %69, ptr null, align 4
  store i64 %63, ptr %0, align 4
  store i64 %82, ptr null, align 4
  ret void
}

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: test
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:                                                ; preds = %2
  %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:                                                ; preds = %2
  br i1 false, label %15, label %10

10:                                               ; preds = %9
  %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:                                               ; preds = %10, %9
  %16 = phi double [ %12, %10 ], [ 0.000000e+00, %9 ]
  %17 = phi double [ %14, %10 ], [ 0.000000e+00, %9 ]
  br label %18

18:                                               ; preds = %15, %6
  %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
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare double @llvm.copysign.f64(double, double) #0

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare double @llvm.fmuladd.f64(double, double, double) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }