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

To reproduce run opt with the test below (-passes=slp-vectorizer -slp-threshold=-99999):
```
; 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 7, 0
  %icmp = icmp ult i32 %add, 0
  br i1 false, label %bb2, label %bb3

bb2:                                              ; preds = %bb1
  br label %bb3

bb3:                                              ; preds = %bb2, %bb1
  %phi = phi i32 [ 7, %bb2 ], [ 0, %bb1 ]
  %phi4 = phi i32 [ %sub, %bb2 ], [ %sub, %bb1 ]
  %phi5 = phi i32 [ %add, %bb2 ], [ %add, %bb1 ]
  %phi6 = phi i32 [ %add, %bb2 ], [ 0, %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,-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/zG7fPh7sa

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 0x00000000059f2228 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x59f2228)
 #1 0x00000000059ef0d4 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x000074bb71c42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x000074bb71c969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x000074bb71c42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x000074bb71c287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x000000000082fd6b llvm::json::operator==(llvm::json::Value const&, llvm::json::Value const&) (.cold) JSON.cpp:0:0
 #7 0x0000000005926781 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5926781)
 #8 0x0000000005811438 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5811438)
 #9 0x00000000009795be 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+0x9795be)
#10 0x00000000057cd9c1 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x57cd9c1)
#11 0x000000000098390a 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+0x98390a)
#12 0x00000000009777a8 optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x9777a8)
#13 0x000074bb71c29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#14 0x000074bb71c29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#15 0x000000000096e255 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x96e255)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```


Fix patch:
commit f8d0c355f5f8d373b1c31161d31d490b771aa03e
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Mon Dec 8 08:11:48 2025 -0800

    [SLP]Prefer instructions, ued outside the block, as the initial main copyable instructions
    
    Instructions, used outside the block, must be considered the first
    choice for the main instructionsin the copyable nodes, to avoid
    use-before-def.
    
    Fixes #171055

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 91f58bdc0686..6da11a2796d6 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -10930,13 +10930,21 @@ class InstructionsCompatibilityAnalysis {
     }
     unsigned BestOpcodeNum = 0;
     MainOp = nullptr;
+    bool UsedOutside = false;
     for (const auto &P : Candidates) {
+      bool PUsedOutside = all_of(P.second, isUsedOutsideBlock);
+      if (UsedOutside && !PUsedOutside)
+        continue;
+      if (!UsedOutside && PUsedOutside)
+        BestOpcodeNum = 0;
       if (P.second.size() < BestOpcodeNum)
         continue;
       // If have inner dependencies - skip.
-      if (any_of(P.second,
-                 [&](Instruction *I) { return Operands.contains(I); }))
+      if (!PUsedOutside && any_of(P.second, [&](Instruction *I) {
+            return Operands.contains(I);
+          }))
         continue;
+      UsedOutside = PUsedOutside;
       for (Instruction *I : P.second) {
         if (IsSupportedInstruction(I, AnyUndef)) {
           MainOp = I;


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/copyable-child-node-used-outside.ll
commands: opt -passes=slp-vectorizer -S -slp-threshold=-99999 -mtriple=x86_64-unknown-linux-gnu < %s
tests: test_name: test
test_body: define <4 x i32> @test() {
bb:
  %trunc = trunc i64 0 to i32
  br label %bb1

bb1:                                              ; preds = %bb
  %or = or i32 %trunc, 0
  %zext = zext i32 %or to i64
  %and = and i32 0, 0
  %or2 = or i32 %trunc, 0
  br label %bb3

bb3:                                              ; preds = %bb1
  %0 = insertelement <4 x i32> zeroinitializer, i32 %trunc, i32 0
  %1 = insertelement <4 x i32> %0, i32 %and, i32 1
  %2 = insertelement <4 x i32> %1, i32 %or2, i32 2
  %3 = insertelement <4 x i32> %2, i32 %or, i32 3
  ret <4 x i32> %3
}

file: llvm/test/Transforms/SLPVectorizer/X86/copyable-with-used-outside-bb.ll
commands: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu -slp-threshold=-99999 < %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 7, 0
  %icmp = icmp ult i32 %add, 0
  br i1 false, label %bb2, label %bb3

bb2:
  br label %bb3

bb3:
  %phi = phi i32 [ 7, %bb2 ], [ 0, %bb1 ]
  %phi4 = phi i32 [ %sub, %bb2 ], [ %sub, %bb1 ]
  %phi5 = phi i32 [ %add, %bb2 ], [ %add, %bb1 ]
  %phi6 = phi i32 [ %add, %bb2 ], [ 0, %bb1 ]
  ret void
}