Bug type: crash
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: BoUpSLP::getLastInstructionInBundle
Issue title: [SLP] crash with -fprofile-generate: Instruction::PHI && "Expected PHI"
Labels: llvm:SLPVectorizer
crash
Reported by: gregbedwell

One of our internal tests picked up a new assertion failure since #131625

Here's a reduced test-case
https://godbolt.org/z/rKT64of5b
```
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"
target triple = "x86_64-unknown-unknown"

define void @_Z1sv() #0 {
entry:
  br label %"_ZZ1svEN3$_08__invokeEii.exit"

if.then.i.i:                                      ; No predecessors!
  br label %3

"_ZZ1svEN3$_08__invokeEii.exit":                  ; preds = %entry
  %0 = zext i1 false to i64
  %1 = add i64 0, %0
  %2 = add i64 0, 0
  br i1 false, label %3, label %while.cond.while.end_crit_edge

3:                                                ; preds = %"_ZZ1svEN3$_08__invokeEii.exit", %if.then.i.i
  %pgocount51962 = phi i64 [ 0, %"_ZZ1svEN3$_08__invokeEii.exit" ], [ 0, %if.then.i.i ]
  %pgocount62360 = phi i64 [ 0, %"_ZZ1svEN3$_08__invokeEii.exit" ], [ 0, %if.then.i.i ]
  %pgocount83056 = phi i64 [ %1, %"_ZZ1svEN3$_08__invokeEii.exit" ], [ 0, %if.then.i.i ]
  %pgocount93354 = phi i64 [ %2, %"_ZZ1svEN3$_08__invokeEii.exit" ], [ 0, %if.then.i.i ]
  br label %while.cond.while.end_crit_edge

while.cond.while.end_crit_edge:                   ; preds = %3, %"_ZZ1svEN3$_08__invokeEii.exit"
  %pgocount51961 = phi i64 [ %pgocount51962, %3 ], [ 0, %"_ZZ1svEN3$_08__invokeEii.exit" ]
  %pgocount62359 = phi i64 [ %pgocount62360, %3 ], [ 0, %"_ZZ1svEN3$_08__invokeEii.exit" ]
  %pgocount83055 = phi i64 [ %pgocount83056, %3 ], [ %1, %"_ZZ1svEN3$_08__invokeEii.exit" ]
  %pgocount93353 = phi i64 [ %pgocount93354, %3 ], [ %2, %"_ZZ1svEN3$_08__invokeEii.exit" ]
  store i64 %pgocount51961, ptr getelementptr inbounds nuw (i8, ptr null, i64 40), align 8
  store i64 %pgocount62359, ptr getelementptr inbounds nuw (i8, ptr null, i64 48), align 8
  store i64 %pgocount83055, ptr getelementptr inbounds nuw (i8, ptr null, i64 56), align 8
  store i64 %pgocount93353, ptr getelementptr inbounds nuw (i8, ptr null, i64 64), align 8
  ret void
}

; uselistorder directives
uselistorder ptr null, { 3, 2, 1, 0 }

attributes #0 = { "target-cpu"="znver2" }
```

```
opt: /root/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:15064: llvm::Instruction& llvm::slpvectorizer::BoUpSLP::getLastInstructionInBundle(const llvm::slpvectorizer::BoUpSLP::TreeEntry*): Assertion `E->getOpcode() == Instruction::PHI && "Expected PHI"' failed.
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 <source>
1.	Running pass "function(slp-vectorizer)" on module "<source>"
2.	Running pass "slp-vectorizer" on function "_Z1sv"
```

This is derived from the following reduced C++ code:

https://godbolt.org/z/aqYnvnGdj
```
int b, a, c, d, e, g, h, i;
int j(const char *, const char *);
int q();
struct ag {
  friend bool r(ag) {
    const char *f, *k = q() ? 0 : "";
    f = q() ? 0 : "";
    return j(k, f);
  }
} l;
bool m;
void s() {
  auto n = [](int, int) {
    if (c) {
      if (a)
        return true;
    } else if (a)
      if (d)
        if (e) {
          bool o = r(l);
          return o;
        }
    return m;
  };
  bool (*p)(int, int) = n;
  while (h)
    g = p(b, i) ?: g;
}
```

```
clang++: /root/llvm-project/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp:15064: llvm::Instruction& llvm::slpvectorizer::BoUpSLP::getLastInstructionInBundle(const llvm::slpvectorizer::BoUpSLP::TreeEntry*): Assertion `E->getOpcode() == Instruction::PHI && "Expected PHI"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/clang++ -gdwarf-4 -g -o /app/output.s -mllvm --x86-asm-syntax=intel -fno-verbose-asm -S --gcc-toolchain=/opt/compiler-explorer/gcc-snapshot -fcolor-diagnostics -fno-crash-diagnostics -O2 -fprofile-generate -march=znver2 <source>
1.	<eof> parser at end of file
2.	Optimizer
3.	Running pass "function<eager-inv>(float2int,lower-constant-intrinsics,loop(loop-rotate<header-duplication;no-prepare-for-lto>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>,infer-alignment,loop-load-elim,instcombine<max-iterations=1;no-verify-fixpoint>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,slp-vectorizer,vector-combine,instcombine<max-iterations=1;no-verify-fixpoint>,loop-unroll<O2>,transform-warning,sroa<preserve-cfg>,infer-alignment,instcombine<max-iterations=1;no-verify-fixpoint>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;no-switch-to-lookup;keep-loops;no-hoist-common-insts;hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>)" on module "<source>"
4.	Running pass "slp-vectorizer" on function "_Z1sv"

```


Fix patch:
commit 8122bb9dbe39a1dde77eb4aad76bf1c0e70b2d89
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Tue Mar 25 04:10:56 2025 -0700

    [SLP]Fix a check for non-schedulable instructions
    
    Need to fix a check for non-schedulable instructions in
    getLastInstructionInBundle function, because this check may not work
    correctly during the codegen. Instead, need to check that actually these
    instructions were never scheduled, since the scheduling analysis always
    performed before the codegen and is stable.
    
    Fixes #132841

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 4dc398f716b3..7741f96ee897 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -15071,7 +15071,18 @@ Instruction &BoUpSLP::getLastInstructionInBundle(const TreeEntry *E) {
 
   // Set the insert point to the beginning of the basic block if the entry
   // should not be scheduled.
-  if (doesNotNeedToSchedule(E->Scalars) ||
+  const auto *It = BlocksSchedules.find(BB);
+  auto IsNotScheduledEntry = [&](const TreeEntry *E) {
+    if (E->isGather())
+      return false;
+    // Found previously that the instruction do not need to be scheduled.
+    return It == BlocksSchedules.end() || all_of(E->Scalars, [&](Value *V) {
+             if (!isa<Instruction>(V))
+               return true;
+             return It->second->getScheduleBundles(V).empty();
+           });
+  };
+  if (IsNotScheduledEntry(E) ||
       (!E->isGather() && all_of(E->Scalars, isVectorLikeInstWithConstOps))) {
     if ((E->getOpcode() == Instruction::GetElementPtr &&
          any_of(E->Scalars,
@@ -15098,12 +15109,11 @@ Instruction &BoUpSLP::getLastInstructionInBundle(const TreeEntry *E) {
   // scheduled, and the last instruction is VL.back(). So we start with
   // VL.back() and iterate over schedule data until we reach the end of the
   // bundle. The end of the bundle is marked by null ScheduleData.
-  if (BlocksSchedules.count(BB) && !E->isGather()) {
+  if (It != BlocksSchedules.end() && !E->isGather()) {
     Value *V = E->isOneOf(E->Scalars.back());
     if (doesNotNeedToBeScheduled(V))
       V = *find_if_not(E->Scalars, doesNotNeedToBeScheduled);
-    if (ArrayRef<ScheduleBundle *> Bundles =
-            BlocksSchedules[BB]->getScheduleBundles(V);
+    if (ArrayRef<ScheduleBundle *> Bundles = It->second->getScheduleBundles(V);
         !Bundles.empty()) {
       const auto *It = find_if(
           Bundles, [&](ScheduleBundle *B) { return B->getTreeEntry() == E; });


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/non-schedulable-instructions-become-schedulable.ll
commands: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-unknown -mcpu=znver2 < %s
tests: test_name: <module>
test_body: 
define void @test() {
;
entry:
  br label %bb1

if.then.i.i:
  br label %3

bb1:
  %0 = zext i1 false to i64
  %1 = add i64 0, %0
  %2 = add i64 0, 0
  br i1 false, label %3, label %bb2

3:
  %pgocount51962 = phi i64 [ 0, %bb1 ], [ 0, %if.then.i.i ]
  %pgocount62360 = phi i64 [ 0, %bb1 ], [ 0, %if.then.i.i ]
  %pgocount83056 = phi i64 [ %1, %bb1 ], [ 0, %if.then.i.i ]
  %pgocount93354 = phi i64 [ %2, %bb1 ], [ 0, %if.then.i.i ]
  br label %bb2

bb2:
  %pgocount51961 = phi i64 [ %pgocount51962, %3 ], [ 0, %bb1 ]
  %pgocount62359 = phi i64 [ %pgocount62360, %3 ], [ 0, %bb1 ]
  %pgocount83055 = phi i64 [ %pgocount83056, %3 ], [ %1, %bb1 ]
  %pgocount93353 = phi i64 [ %pgocount93354, %3 ], [ %2, %bb1 ]
  store i64 %pgocount51961, ptr getelementptr inbounds nuw (i8, ptr null, i64 40), align 8
  store i64 %pgocount62359, ptr getelementptr inbounds nuw (i8, ptr null, i64 48), align 8
  store i64 %pgocount83055, ptr getelementptr inbounds nuw (i8, ptr null, i64 56), align 8
  store i64 %pgocount93353, ptr getelementptr inbounds nuw (i8, ptr null, i64 64), align 8
  ret void
}