Bug type: miscompilation
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: BoUpSLP::collectValuesToDemote
Issue title: [SLPVectorizer] Miscompile in slp vectorizer (shift produces poison)
Labels: miscompilation
llvm:SLPVectorizer
Reported by: danilaml

SLPVectorizer (`opt -passes=slp-vectorizer -slp-threshold=-99999`) turns the following IR:
```llvm
target triple = "x86_64-unknown-linux-gnu"

define float @foo(i8 %0) {
entry:
  %1 = sext i8 0 to i32
  %2 = lshr i32 %1, 27
  %3 = sext i8 %0 to i32
  %reass.add.epil = mul i32 %3, 2
  %4 = or i32 %reass.add.epil, %2
  switch i32 %4, label %exit [
    i32 0, label %exit
    i32 1, label %exit
  ]

exit:                                      ; preds = %body, %body, %body
  ret float 0.000000e+00
}
```
into
```llvm
define float @foo(i8 %0) {
entry:
  %1 = insertelement <2 x i8> <i8 poison, i8 0>, i8 %0, i32 0
  %2 = sext <2 x i8> %1 to <2 x i16>
  %3 = mul <2 x i16> %2, <i16 2, i16 27>
  %4 = lshr <2 x i16> %2, <i16 2, i16 27>
  %5 = shufflevector <2 x i16> %3, <2 x i16> %4, <2 x i32> <i32 0, i32 3>
  %6 = extractelement <2 x i16> %5, i32 0
  %7 = sext i16 %6 to i32
  %8 = extractelement <2 x i16> %5, i32 1
  %9 = zext i16 %8 to i32
  %10 = or i32 %7, %9
  switch i32 %10, label %exit [
    i32 0, label %exit
    i32 1, label %exit
  ]

exit:
  ret float 0.000000e+00
}
```

Note that it now has `i16` shifts by `27` which later get turned into poison.

Godbolt link: https://godbolt.org/z/shj5GK5nd
Alive2 link: https://alive2.llvm.org/ce/z/CM7Pmp


Fix patch:
commit 964c7711f4384b08f051d17da888d35d03a3024a
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Fri Oct 31 15:07:26 2025 -0700

    [SLP]Fix the minbitwidth analysis for slternate opcodes
    
    If the laternate operation is more stricter than the main operation, we
    cannot rely on the analysis of the main operation. In such case, better
    to avoid doing the analysis at all, since it may affect the overall
    result and lead to incorrect optimization
    
    Fixes #165878

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 1b55a3b23522..34b405ced8c0 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -22134,6 +22134,27 @@ bool BoUpSLP::collectValuesToDemote(
         {VectorizableTree[E.CombinedEntriesWithIndices.front().first].get(),
          VectorizableTree[E.CombinedEntriesWithIndices.back().first].get()});
 
+  if (E.isAltShuffle()) {
+    // Combining these opcodes may lead to incorrect analysis, skip for now.
+    auto IsDangerousOpcode = [](unsigned Opcode) {
+      switch (Opcode) {
+      case Instruction::Shl:
+      case Instruction::AShr:
+      case Instruction::LShr:
+      case Instruction::UDiv:
+      case Instruction::SDiv:
+      case Instruction::URem:
+      case Instruction::SRem:
+        return true;
+      default:
+        break;
+      }
+      return false;
+    };
+    if (IsDangerousOpcode(E.getAltOpcode()))
+      return FinalAnalysis();
+  }
+
   switch (E.getOpcode()) {
 
   // We can always demote truncations and extensions. Since truncations can


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/alternate-opcode-strict-bitwidth-than-main.ll
commands: opt -passes=slp-vectorizer -S -slp-threshold=-99999 -mtriple=x86_64-unknown-linux-gnu < %s
tests: test_name: test
test_body: define float @test(i8 %0) {
entry:
  %1 = sext i8 0 to i32
  %2 = lshr i32 %1, 27
  %3 = sext i8 %0 to i32
  %reass.add.epil = mul i32 %3, 2
  %4 = or i32 %reass.add.epil, %2
  switch i32 %4, label %exit [
    i32 0, label %exit
    i32 1, label %exit
  ]

exit:                                             ; preds = %entry, %entry, %entry
  ret float 0.000000e+00
}