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

bb1:                                              ; preds = %bb24, %bb
  %phi = phi i32 [ %lshr25, %bb24 ], [ 0, %bb ]
  %phi2 = phi i32 [ %or26, %bb24 ], [ 0, %bb ]
  %phi3 = phi i32 [ 0, %bb24 ], [ 0, %bb ]
  br i1 false, label %bb4, label %bb11

bb4:                                              ; preds = %bb1
  %phi5 = phi double [ 0.000000e+00, %bb1 ]
  %phi6 = phi i32 [ poison, %bb1 ]
  %phi7 = phi i32 [ poison, %bb1 ]
  %phi8 = phi double [ 0.000000e+00, %bb1 ]
  %phi9 = phi i32 [ %phi2, %bb1 ]
  %phi10 = phi i32 [ %phi, %bb1 ]
  br label %bb19

bb11:                                             ; preds = %bb1
  br i1 false, label %bb12, label %bb16

bb12:                                             ; preds = %bb11
  %or = or i32 0, %phi3
  br label %bb13

bb13:                                             ; preds = %bb12
  %phi14 = phi i32 [ %phi, %bb12 ]
  %phi15 = phi i32 [ %or, %bb12 ]
  br label %bb16

bb16:                                             ; preds = %bb13, %bb11
  %phi17 = phi i32 [ 0, %bb11 ], [ %phi14, %bb13 ]
  %phi18 = phi i32 [ 0, %bb11 ], [ %phi15, %bb13 ]
  br label %bb19

bb19:                                             ; preds = %bb16, %bb4
  %phi20 = phi i32 [ 0, %bb4 ], [ %phi17, %bb16 ]
  %phi21 = phi i32 [ 0, %bb4 ], [ %phi18, %bb16 ]
  %phi22 = phi double [ 0.000000e+00, %bb4 ], [ 0.000000e+00, %bb16 ]
  %or23 = or i32 %phi21, 0
  br label %bb24

bb24:                                             ; preds = %bb19
  %lshr = lshr i32 %phi20, 0
  %and = and i32 %lshr, 0
  %lshr25 = lshr i32 %phi, %and
  %or26 = or i32 0, %or23
  br label %bb1
}

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/3GjPaK9b8

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 0x0000000005977768 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5977768)
 #1 0x0000000005974614 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x000073d16ec42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x000073d16ec969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x000073d16ec42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x000073d16ec287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x000000000082da77 llvm::json::operator==(llvm::json::Value const&, llvm::json::Value const&) (.cold) JSON.cpp:0:0
 #7 0x00000000058abe41 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x58abe41)
 #8 0x0000000005797b68 (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5797b68)
 #9 0x000000000097321e 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+0x97321e)
#10 0x0000000005756121 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5756121)
#11 0x000000000097d4a8 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::RTLIB::RuntimeLibcallsInfo&, 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+0x97d4a8)
#12 0x00000000009714fd optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x9714fd)
#13 0x000073d16ec29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#14 0x000073d16ec29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#15 0x0000000000968745 _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x968745)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```


Fix patch:
commit 2c3aa92089695713a1fd4264e80941fd9679150b
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Wed Nov 19 11:42:18 2025 -0800

    [SLP]Fix insertion point for setting for the nodes
    
    The problem with the many def-use chain problems in SLP vectorizer are
    related to the fact that some nodes reuse the same instruction as
    insertion point. Insertion point is not the instruction, but the place
    between instructions. To set it correctly, better to generate pseudo
    instruction immediately after the last instruction, and use it as
    insertion point. It resolves the issues in most cases.
    
    Fixes #168512 #168576

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 4b9ac52748e7..22253f5118a1 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -2082,6 +2082,7 @@ public:
     MustGather.clear();
     NonScheduledFirst.clear();
     EntryToLastInstruction.clear();
+    LastInstructionToPos.clear();
     LoadEntriesToVectorize.clear();
     IsGraphTransformMode = false;
     GatheredLoadsEntriesFirst.reset();
@@ -4593,6 +4594,10 @@ private:
   /// pre-gather them before.
   SmallDenseMap<const TreeEntry *, WeakTrackingVH> EntryToLastInstruction;
 
+  /// Keeps the mapping between the last instructions and their insertion
+  /// points, which is an instruction-after-the-last-instruction.
+  SmallDenseMap<const Instruction *, Instruction *> LastInstructionToPos;
+
   /// List of gather nodes, depending on other gather/vector nodes, which should
   /// be emitted after the vector instruction emission process to correctly
   /// handle order of the vector instructions and shuffles.
@@ -17894,6 +17899,16 @@ void BoUpSLP::setInsertPointAfterBundle(const TreeEntry *E) {
     Builder.SetInsertPoint(
         LastInst->getParent(),
         LastInst->getNextNode()->getIterator());
+    if (Instruction *Res = LastInstructionToPos.lookup(LastInst)) {
+      Builder.SetInsertPoint(LastInst->getParent(), Res->getIterator());
+    } else {
+      Res = Builder.CreateAlignedLoad(Builder.getPtrTy(),
+                                      PoisonValue::get(Builder.getPtrTy()),
+                                      MaybeAlign());
+      Builder.SetInsertPoint(LastInst->getParent(), Res->getIterator());
+      eraseInstruction(Res);
+      LastInstructionToPos.try_emplace(LastInst, Res);
+    }
   }
   Builder.SetCurrentDebugLocation(Front->getDebugLoc());
 }


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/gathered-node-with-in-order-parent.ll
commands: opt -passes=slp-vectorizer -S -slp-threshold=-99999 -mtriple=x86_64-unknown-linux-gnu < %s
tests: test_name: test
test_body: define double @test() {
bb:
  br label %bb1

bb1:                                              ; preds = %bb4, %bb
  %phi = phi i32 [ 0, %bb ], [ 0, %bb4 ]
  %phi2 = phi i32 [ 0, %bb ], [ 0, %bb4 ]
  %phi3 = phi i32 [ 0, %bb ], [ %or5, %bb4 ]
  br label %bb4

bb4:                                              ; preds = %bb1
  %or = or i32 %phi2, 0
  %mul = mul i32 0, 1
  %or5 = or i32 %phi3, %mul
  %and = and i32 %or, 0
  %or6 = or i32 %phi2, 1
  br i1 false, label %bb7, label %bb1

bb7:                                              ; preds = %bb4
  %phi8 = phi i32 [ %phi, %bb4 ]
  %phi9 = phi i32 [ %or, %bb4 ]
  %phi10 = phi i32 [ %or5, %bb4 ]
  %phi11 = phi i32 [ %or6, %bb4 ]
  ret double 0.000000e+00
}

file: llvm/test/Transforms/SLPVectorizer/X86/matching-insert-point-for-nodes.ll
commands: opt -passes=slp-vectorizer -S -slp-threshold=-99999 -mtriple=x86_64-unknown-linux-gnu < %s
tests: test_name: <module>
test_body: 
define i32 @test() {
;
bb:
  br label %bb1

bb1:
  %phi = phi i32 [ %lshr25, %bb24 ], [ 0, %bb ]
  %phi2 = phi i32 [ %or26, %bb24 ], [ 0, %bb ]
  %phi3 = phi i32 [ 0, %bb24 ], [ 0, %bb ]
  br i1 false, label %bb4, label %bb11

bb4:
  %phi6 = phi i32 [ poison, %bb1 ]
  %phi7 = phi i32 [ poison, %bb1 ]
  %phi9 = phi i32 [ %phi2, %bb1 ]
  %phi10 = phi i32 [ %phi, %bb1 ]
  %0 = phi <2 x double> [ zeroinitializer, %bb1 ]
  br label %bb19

bb11:
  br i1 false, label %bb12, label %bb16

bb12:
  %or = or i32 0, %phi3
  br label %bb13

bb13:
  %phi14 = phi i32 [ %phi, %bb12 ]
  %phi15 = phi i32 [ %or, %bb12 ]
  br label %bb16

bb16:
  %phi17 = phi i32 [ 0, %bb11 ], [ %phi14, %bb13 ]
  %phi18 = phi i32 [ 0, %bb11 ], [ %phi15, %bb13 ]
  br label %bb19

bb19:
  %phi20 = phi i32 [ 0, %bb4 ], [ %phi17, %bb16 ]
  %phi21 = phi i32 [ 0, %bb4 ], [ %phi18, %bb16 ]
  %phi22 = phi double [ 0.000000e+00, %bb4 ], [ 0.000000e+00, %bb16 ]
  %or23 = or i32 %phi21, 0
  br label %bb24

bb24:
  %lshr = lshr i32 %phi20, 0
  %and = and i32 %lshr, 0
  %lshr25 = lshr i32 %phi, %and
  %or26 = or i32 0, %or23
  br label %bb1
}

file: llvm/test/Transforms/SLPVectorizer/X86/reused-last-instruction-in-split-node.ll
commands: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu < %s
tests: test_name: <module>
test_body: 
define float @test() {
;
label:
  %tmp.0.4.vec.extract = extractelement <4 x float> zeroinitializer, i64 0
  %tmp.0.0.vec.extract = extractelement <4 x float> zeroinitializer, i64 0
  %tmp.12.36.vec.extract = extractelement <4 x float> zeroinitializer, i64 0
  %tmp.7.28.vec.extract = extractelement <4 x float> zeroinitializer, i64 0
  %tmp.0.12.vec.extract = extractelement <4 x float> zeroinitializer, i64 0
  %mul3.i128.i = fmul float 0.000000e+00, 0.000000e+00
  %mul3.i138.i = fmul float 0.000000e+00, 0.000000e+00
  %sub.i102.i = fsub float 0.000000e+00, 0.000000e+00
  %mul.i136.i = fmul float %sub.i102.i, 0.000000e+00
  %v.0.4.vec.extract = extractelement <8 x float> zeroinitializer, i64 0
  %v.0.24.vec.extract = extractelement <8 x float> zeroinitializer, i64 0
  %v.0.28.vec.extract = extractelement <8 x float> zeroinitializer, i64 0
  %v.11.48.vec.extract = extractelement <8 x float> zeroinitializer, i64 0
  %v.20.72.vec.extract = extractelement <8 x float> zeroinitializer, i64 0
  %v.20.76.vec.extract = extractelement <8 x float> zeroinitializer, i64 0
  %0 = fmul float %v.0.4.vec.extract, %tmp.0.0.vec.extract
  %1 = fadd float %0, 0.000000e+00
  %2 = fmul float %v.0.28.vec.extract, 0.000000e+00
  %3 = fmul float %v.0.28.vec.extract, %tmp.0.0.vec.extract
  %4 = fadd float %3, 0.000000e+00
  %5 = fmul float %tmp.0.4.vec.extract, %v.11.48.vec.extract
  %6 = fadd float 0.000000e+00, %5
  %7 = fmul float %v.20.76.vec.extract, %tmp.0.0.vec.extract
  %8 = fadd float %7, 0.000000e+00
  %9 = fmul float 0.000000e+00, %tmp.0.12.vec.extract
  %10 = fadd float %2, %9
  %11 = fadd float %10, 0.000000e+00
  %12 = fsub float 0.000000e+00, %11
  %13 = fadd float 0.000000e+00, %1
  %14 = fadd float 0.000000e+00, %4
  %15 = fadd float 0.000000e+00, %6
  %16 = fadd float 0.000000e+00, %8
  %17 = fmul float 0.000000e+00, 0.000000e+00
  %18 = fmul float 0.000000e+00, %tmp.7.28.vec.extract
  %19 = fmul float 0.000000e+00, 0.000000e+00
  %20 = fmul float 0.000000e+00, 0.000000e+00
  %21 = fmul float 0.000000e+00, %tmp.7.28.vec.extract
  %22 = fmul float 0.000000e+00, 0.000000e+00
  %23 = fmul float 0.000000e+00, %tmp.12.36.vec.extract
  %24 = fadd float %18, %23
  %25 = fmul float 0.000000e+00, %tmp.12.36.vec.extract
  %26 = fadd float %21, %25
  %27 = fsub float 0.000000e+00, poison
  %28 = fadd float %24, 0.000000e+00
  %29 = fsub float 0.000000e+00, %28
  %30 = fadd float %26, 0.000000e+00
  %31 = fsub float 0.000000e+00, %30
  %32 = fadd float 0.000000e+00, %17
  %33 = fadd float 0.000000e+00, %19
  %34 = fadd float 0.000000e+00, %20
  %35 = fadd float 0.000000e+00, %22
  %36 = fmul float 0.000000e+00, %mul3.i138.i
  %37 = fmul float %v.0.4.vec.extract, %mul.i136.i
  %38 = fadd float %37, 0.000000e+00
  %39 = fmul float 0.000000e+00, %mul3.i138.i
  %40 = fmul float %mul3.i138.i, %v.0.24.vec.extract
  %41 = fadd float 0.000000e+00, %40
  %42 = fmul float 0.000000e+00, %mul3.i138.i
  %43 = fmul float 0.000000e+00, %mul3.i138.i
  %44 = fmul float %mul3.i138.i, %v.20.72.vec.extract
  %45 = fadd float 0.000000e+00, %44
  %46 = fmul float 0.000000e+00, 1.000000e+00
  %47 = fmul float 0.000000e+00, %mul3.i128.i
  %48 = fadd float %36, %47
  %49 = fmul float 0.000000e+00, %mul3.i128.i
  %50 = fadd float %39, %49
  %51 = fmul float 0.000000e+00, %mul3.i128.i
  %52 = fadd float %42, %51
  %53 = fmul float 0.000000e+00, %mul3.i128.i
  %54 = fadd float %43, %53
  %55 = fadd float %46, 0.000000e+00
  %56 = fadd float %48, 0.000000e+00
  %57 = fsub float %55, %56
  %58 = fadd float %50, 0.000000e+00
  %59 = fsub float 0.000000e+00, %58
  %60 = fadd float %52, 0.000000e+00
  %61 = fsub float 0.000000e+00, %60
  %62 = fadd float %mul.i136.i, 0.000000e+00
  %63 = fadd float %54, 0.000000e+00
  %64 = fsub float %62, %63
  %65 = fadd float 0.000000e+00, %38
  %66 = fadd float 0.000000e+00, %41
  %67 = fadd float 0.000000e+00, %45
  br label %region.30

region.30:
  %68 = phi float [ %29, %label ]
  %69 = phi float [ %66, %label ]
  %70 = phi float [ %59, %label ]
  %71 = phi float [ %15, %label ]
  %72 = phi float [ %34, %label ]
  %73 = phi float [ poison, %label ]
  %74 = phi float [ %61, %label ]
  %75 = phi float [ %16, %label ]
  %76 = phi float [ %35, %label ]
  %77 = phi float [ %31, %label ]
  %78 = phi float [ %67, %label ]
  %79 = phi float [ %64, %label ]
  %80 = phi float [ %33, %label ]
  %81 = phi float [ %12, %label ]
  %82 = phi float [ %14, %label ]
  %83 = phi float [ %57, %label ]
  %84 = phi float [ %65, %label ]
  %85 = phi float [ %27, %label ]
  %86 = phi float [ %32, %label ]
  %87 = phi float [ %13, %label ]
  ret float %87
}
file: llvm/test/Transforms/SLPVectorizer/X86/shuffle-mask-emission.ll
commands: opt -S -passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu < %s
tests: test_name: test
test_body: define i1 @test() {
entry:
  %h.promoted118.i.fr = freeze i32 1
  %invariant.op.i51 = add i32 %h.promoted118.i.fr, 0
  %conv25.i = xor i32 0, 0
  %add.i.i = add i32 %conv25.i, %h.promoted118.i.fr
  %sext.i.mask = and i32 %add.i.i, 0
  %cmp27.i = icmp eq i32 %sext.i.mask, 1
  %0 = or i1 %cmp27.i, false
  %conv25.i.1 = add i32 0, 0
  %add.i.i.1 = add i32 %conv25.i.1, %h.promoted118.i.fr
  %sext.i.1.mask = and i32 %add.i.i.1, 1
  %cmp27.i.1 = icmp eq i32 %sext.i.1.mask, 0
  %conv25.1.i.1 = xor i32 0, 0
  %add.i.1.i.1 = add i32 %conv25.1.i.1, %h.promoted118.i.fr
  %sext.1.i.1.mask = and i32 %add.i.1.i.1, 1
  %cmp27.1.i.1 = icmp eq i32 %sext.1.i.1.mask, 0
  %add.i.2.reass.i.1 = add i32 %invariant.op.i51, %conv25.i.1
  %sext.2.i.1.mask = and i32 %add.i.2.reass.i.1, 1
  %cmp27.2.i.1 = icmp eq i32 %sext.2.i.1.mask, 0
  %1 = or i1 %cmp27.1.i.1, %cmp27.2.i.1
  %2 = or i1 %cmp27.i.1, %1
  %3 = or i1 %0, %2
  ret i1 %3
}