Bug type: crash
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: BoUpSLP::BlockScheduling::tryScheduleBundle
BoUpSLP::isGatherShuffledSingleRegisterEntry
Issue title: Instruction does not dominate all uses!... LLVM ERROR: Broken module found, compilation aborted! (yet another)
Labels: llvm:SLPVectorizer
crash
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() #0 gc "statepoint-example" {
bb:
  br label %bb1

bb1:                                              ; preds = %bb14, %bb10, %bb
  %phi = phi i32 [ 0, %bb ], [ %or16, %bb14 ], [ 0, %bb10 ]
  %phi2 = phi i32 [ 0, %bb ], [ %or15, %bb14 ], [ 0, %bb10 ]
  br label %bb3

bb3:                                              ; preds = %bb1
  %phi4 = phi i32 [ poison, %bb1 ]
  %phi5 = phi float [ 0.000000e+00, %bb1 ]
  %phi6 = phi i32 [ poison, %bb1 ]
  %phi7 = phi i32 [ %phi, %bb1 ]
  %phi8 = phi float [ 0.000000e+00, %bb1 ]
  %phi9 = phi i32 [ %phi2, %bb1 ]
  br label %bb10

bb10:                                             ; preds = %bb14, %bb3
  %phi11 = phi i32 [ 0, %bb3 ], [ %phi11, %bb14 ]
  %phi12 = phi float [ 0.000000e+00, %bb3 ], [ 0.000000e+00, %bb14 ]
  %phi13 = phi i32 [ 0, %bb3 ], [ %or15, %bb14 ]
  switch i32 0, label %bb14 [
    i32 0, label %bb1
  ]

bb14:                                             ; preds = %bb10
  %or = or i32 %phi13, %phi11
  %or15 = or i32 %or, 0
  %or16 = or i32 %phi11, 0
  br i1 false, label %bb1, label %bb10
}

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/6bzdEoWb3

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 0x00000000059af7a8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x59af7a8)
 #1 0x00000000059ac654 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x000078a228842520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x000078a2288969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x000078a228842476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x000078a2288287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x0000000000839a0d llvm::json::operator==(llvm::json::Value const&, llvm::json::Value const&) (.cold) JSON.cpp:0:0
 #7 0x00000000058dc2d1 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x58dc2d1)
 #8 0x00000000057c8b88 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x57c8b88)
 #9 0x000000000097f88e 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+0x97f88e)
#10 0x00000000057860e1 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x57860e1)
#11 0x0000000000989a5a 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+0x989a5a)
#12 0x000000000097dcd1 optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x97dcd1)
#13 0x000078a228829d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#14 0x000078a228829e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#15 0x00000000009750e5 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x9750e5)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```


Fix patch:
commit 75ef0be0c3b6b0313d541b2af673ee4bb091572b
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Tue Nov 11 10:17:31 2025 -0800

    [SLP]Be careful when trying match/vectorize copyable nodes with external uses only
    
    Need to be careful when trying to match and/or build copyable node with
    the instructions, used outside the block only and if their operands
    immediately precede such instructions. In this case insertion point
    might be the same and it may cause broken def-use chain.
    
    Fixes #167366

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index ffba0bdbdbe8..cc53b0dd3577 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -16844,6 +16844,16 @@ BoUpSLP::isGatherShuffledSingleRegisterEntry(
     }
     return false;
   };
+  auto CheckNonSchedulableOrdering = [&](const TreeEntry *E,
+                                         Instruction *InsertPt) {
+    return TEUseEI && TEUseEI.UserTE && TEUseEI.UserTE->hasCopyableElements() &&
+           !TEUseEI.UserTE->isCopyableElement(
+               const_cast<Instruction *>(TEInsertPt)) &&
+           isUsedOutsideBlock(const_cast<Instruction *>(TEInsertPt)) &&
+           InsertPt->getNextNode() == TEInsertPt &&
+           (!E->hasCopyableElements() || !E->isCopyableElement(InsertPt) ||
+            !isUsedOutsideBlock(InsertPt));
+  };
   for (Value *V : VL) {
     if (isConstant(V) || !VisitedValue.insert(V).second)
       continue;
@@ -16926,6 +16936,11 @@ BoUpSLP::isGatherShuffledSingleRegisterEntry(
       // The node is reused - exit.
       if (CheckAndUseSameNode(TEPtr))
         break;
+      // The parent node is copyable with last inst used outside? And the last
+      // inst is the next inst for the lastinst of TEPtr? Exit, if yes, to
+      // preserve def-use chain.
+      if (CheckNonSchedulableOrdering(UseEI.UserTE, InsertPt))
+        continue;
       VToTEs.insert(TEPtr);
     }
     if (ArrayRef<TreeEntry *> VTEs = getSplitTreeEntries(V); !VTEs.empty()) {
@@ -16961,7 +16976,8 @@ BoUpSLP::isGatherShuffledSingleRegisterEntry(
       if (none_of(TE->CombinedEntriesWithIndices,
                   [&](const auto &P) { return P.first == VTE->Idx; })) {
         Instruction &LastBundleInst = getLastInstructionInBundle(VTE);
-        if (&LastBundleInst == TEInsertPt || !CheckOrdering(&LastBundleInst))
+        if (&LastBundleInst == TEInsertPt || !CheckOrdering(&LastBundleInst) ||
+            CheckNonSchedulableOrdering(VTE, &LastBundleInst))
           continue;
       }
       // The node is reused - exit.
@@ -21003,6 +21019,22 @@ BoUpSLP::BlockScheduling::tryScheduleBundle(ArrayRef<Value *> VL, BoUpSLP *SLP,
         return isUsedOutsideBlock(V);
       }))
     return std::nullopt;
+  // If any instruction is used outside block only and its operand is placed
+  // immediately before it, do not schedule, it may cause wrong def-use chain.
+  if (S.areInstructionsWithCopyableElements() && any_of(VL, [&](Value *V) {
+        if (isa<PoisonValue>(V) || S.isCopyableElement(V))
+          return false;
+        if (isUsedOutsideBlock(V)) {
+          for (Value *Op : cast<Instruction>(V)->operands()) {
+            auto *I = dyn_cast<Instruction>(Op);
+            if (!I)
+              continue;
+            return SLP->isVectorized(I) && I->getNextNode() == V;
+          }
+        }
+        return false;
+      }))
+    return std::nullopt;
   bool HasCopyables = S.areInstructionsWithCopyableElements();
   if (((!HasCopyables && doesNotNeedToSchedule(VL)) ||
        all_of(VL, [&](Value *V) { return S.isNonSchedulable(V); }))) {


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/copyable-used-outside-with-immediate-op.ll
commands: opt -passes=slp-vectorizer -S -mtriple=x86_64-unknown-linux-gnu -slp-threshold=-9999 < %s
tests: test_name: <module>
test_body: 
define void @test() {
;
bb:
  br label %bb1

bb1:
  %phi = phi i32 [ 0, %bb ], [ %or16, %bb14 ], [ 0, %bb10 ]
  %phi2 = phi i32 [ 0, %bb ], [ %or15, %bb14 ], [ 0, %bb10 ]
  br label %bb3

bb3:                                              ; preds = %bb1
  %phi4 = phi i32 [ poison, %bb1 ]
  %phi6 = phi i32 [ poison, %bb1 ]
  %phi7 = phi i32 [ %phi, %bb1 ]
  %phi9 = phi i32 [ %phi2, %bb1 ]
  %0 = phi <2 x float> [ zeroinitializer, %bb1 ]
  br label %bb10

bb10:
  %phi11 = phi i32 [ 0, %bb3 ], [ %phi11, %bb14 ]
  %phi12 = phi float [ 0.000000e+00, %bb3 ], [ 0.000000e+00, %bb14 ]
  %phi13 = phi i32 [ 0, %bb3 ], [ %or15, %bb14 ]
  switch i32 0, label %bb14 [
  i32 0, label %bb1
  ]

bb14:
  %or = or i32 %phi13, %phi11
  %or15 = or i32 %or, 0
  %or16 = or i32 %phi11, 0
  br i1 false, label %bb1, label %bb10
}