Bug type: miscompilation
Component: VectorCombine
Bug location: llvm/lib/Transforms/Vectorize/VectorCombine.cpp: VectorCombine::foldShuffleOfBinops
Issue title: [clang] Miscompilation at -Os
Labels: miscompilation
vectorizers
Reported by: cardigan1008

This code prints 9 at `-Os` and 0 at `-O0/1/2/3`:

```c
int printf(const char *, ...);
char a = 9, c, d;
int b, e;
unsigned short f;
char *g = &a;
void h(int i) {
  for (; b; b++)
    c &= 0 <= i;
}
static short j(unsigned long i) {
  int k;
  for (; e + d + 4 > 0;) {
    k = i + 49;
    h(k + i - 52 + i);
    *g = 0;
    return 0;
  }
  return 0;
}
int main() {
  j(6 < (unsigned short)(f - 7) + f);
  printf("%d\n", a);
}
```

Compiler Explorer: https://godbolt.org/z/Mo5TEKh8r

Bisected to https://github.com/llvm/llvm-project/commit/5287299f8809ae927a0acafb179c4b37ce9ff21d, which was committed by @RKSimon 

Comments: author: RKSimon
body: I'm not convinced the patch is responsible, it's more likely exposed something else.  I'll take a look after the Christmas break.
author: dtcxzyw
body: Reproducer: https://alive2.llvm.org/ce/z/jdkwFh
```
; bin/opt -passes=vector-combine test.ll -S
target triple = "x86_64-unknown-linux-gnu"

define <2 x i1> @src() {
entry:
  %0 = icmp samesign ugt <2 x i32> zeroinitializer, zeroinitializer
  %1 = icmp sgt <2 x i32> zeroinitializer, <i32 6, i32 -4>
  %2 = shufflevector <2 x i1> %0, <2 x i1> %1, <2 x i32> <i32 0, i32 3>
  ret <2 x i1> %2
}
```
```
define <2 x i1> @tgt() {
entry:
  ret <2 x i1> zeroinitializer
}
```
```

----------------------------------------
define <2 x i1> @src() {
entry:
  %#0 = icmp samesign ugt <2 x i32> { 0, 0 }, { 0, 0 }
  %#1 = icmp sgt <2 x i32> { 0, 0 }, { 6, 4294967292 }
  %#2 = shufflevector <2 x i1> %#0, <2 x i1> %#1, 0, 3
  ret <2 x i1> %#2
}
=>
define <2 x i1> @tgt() {
entry:
  ret <2 x i1> { 0, 0 }
}
Transformation doesn't verify!

ERROR: Value mismatch

Example:

Source:
<2 x i1> %#0 = < #x0 (0), #x0 (0) >
<2 x i1> %#1 = < #x0 (0), #x1 (1) >
<2 x i1> %#2 = < #x0 (0), #x1 (1) >

Target:
Source value: < #x0 (0), #x1 (1) >
Target value: < #x0 (0), #x0 (0) >
```


Fix patch:
commit f2f02b21cd581057e3c9b4a7a27e0014eeb9ba15
Author: Simon Pilgrim <llvm-dev@redking.me.uk>
Date:   Sat Dec 28 09:21:22 2024 +0000

    [VectorCombine] foldShuffleOfBinops - only accept exact matching cmp predicates
    
    m_SpecificCmp allowed equivalent predicate+flags which don't necessarily work after being folded from "shuffle (cmpop), (cmpop)" into "cmpop (shuffle), (shuffle)"
    
    Fixes #121110

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index ecbc13d489eb..2460ccc61d84 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1669,7 +1669,8 @@ bool VectorCombine::foldShuffleOfBinops(Instruction &I) {
 
   Value *X, *Y, *Z, *W;
   bool IsCommutative = false;
-  CmpPredicate Pred = CmpInst::BAD_ICMP_PREDICATE;
+  CmpPredicate PredLHS = CmpInst::BAD_ICMP_PREDICATE;
+  CmpPredicate PredRHS = CmpInst::BAD_ICMP_PREDICATE;
   if (match(LHS, m_BinOp(m_Value(X), m_Value(Y))) &&
       match(RHS, m_BinOp(m_Value(Z), m_Value(W)))) {
     auto *BO = cast<BinaryOperator>(LHS);
@@ -1677,8 +1678,9 @@ bool VectorCombine::foldShuffleOfBinops(Instruction &I) {
     if (llvm::is_contained(OldMask, PoisonMaskElem) && BO->isIntDivRem())
       return false;
     IsCommutative = BinaryOperator::isCommutative(BO->getOpcode());
-  } else if (match(LHS, m_Cmp(Pred, m_Value(X), m_Value(Y))) &&
-             match(RHS, m_SpecificCmp(Pred, m_Value(Z), m_Value(W)))) {
+  } else if (match(LHS, m_Cmp(PredLHS, m_Value(X), m_Value(Y))) &&
+             match(RHS, m_Cmp(PredRHS, m_Value(Z), m_Value(W))) &&
+             (CmpInst::Predicate)PredLHS == (CmpInst::Predicate)PredRHS) {
     IsCommutative = cast<CmpInst>(LHS)->isCommutative();
   } else
     return false;
@@ -1727,14 +1729,14 @@ bool VectorCombine::foldShuffleOfBinops(Instruction &I) {
       TTI.getShuffleCost(SK0, BinOpTy, NewMask0, CostKind, 0, nullptr, {X, Z}) +
       TTI.getShuffleCost(SK1, BinOpTy, NewMask1, CostKind, 0, nullptr, {Y, W});
 
-  if (Pred == CmpInst::BAD_ICMP_PREDICATE) {
+  if (PredLHS == CmpInst::BAD_ICMP_PREDICATE) {
     NewCost +=
         TTI.getArithmeticInstrCost(LHS->getOpcode(), ShuffleDstTy, CostKind);
   } else {
     auto *ShuffleCmpTy =
         FixedVectorType::get(BinOpTy->getElementType(), ShuffleDstTy);
     NewCost += TTI.getCmpSelInstrCost(LHS->getOpcode(), ShuffleCmpTy,
-                                      ShuffleDstTy, Pred, CostKind);
+                                      ShuffleDstTy, PredLHS, CostKind);
   }
 
   LLVM_DEBUG(dbgs() << "Found a shuffle feeding two binops: " << I
@@ -1750,10 +1752,10 @@ bool VectorCombine::foldShuffleOfBinops(Instruction &I) {
 
   Value *Shuf0 = Builder.CreateShuffleVector(X, Z, NewMask0);
   Value *Shuf1 = Builder.CreateShuffleVector(Y, W, NewMask1);
-  Value *NewBO = Pred == CmpInst::BAD_ICMP_PREDICATE
+  Value *NewBO = PredLHS == CmpInst::BAD_ICMP_PREDICATE
                      ? Builder.CreateBinOp(
                            cast<BinaryOperator>(LHS)->getOpcode(), Shuf0, Shuf1)
-                     : Builder.CreateCmp(Pred, Shuf0, Shuf1);
+                     : Builder.CreateCmp(PredLHS, Shuf0, Shuf1);
 
   // Intersect flags from the old binops.
   if (auto *NewInst = dyn_cast<Instruction>(NewBO)) {


Regression tests:
file: llvm/test/Transforms/VectorCombine/X86/shuffle-of-cmps.ll
commands: opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mattr=sse2
opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mattr=sse4.2
opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mattr=avx2
opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mattr=avx512vl
tests: test_name: shuf_icmp_ugt_v4i32_use
test_body: declare void @use(<4 x i1>)

define <4 x i32> @shuf_icmp_ugt_v4i32_use(<4 x i32> %x, <4 x i32> %y, <4 x i32> %z, <4 x i32> %w) {
  %c0 = icmp ugt <4 x i32> %x, %y
  %c1 = icmp ugt <4 x i32> %z, %w
  call void @use(<4 x i1> %c0)
  %s = shufflevector <4 x i1> %c0, <4 x i1> %c1, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
  %r = sext <4 x i1> %s to <4 x i32>
  ret <4 x i32> %r
}

test_name: PR121110
test_body: define <2 x i1> @PR121110() {
  %ugt = icmp samesign ugt <2 x i32> zeroinitializer, zeroinitializer
  %sgt = icmp sgt <2 x i32> zeroinitializer, <i32 6, i32 -4>
  %res = shufflevector <2 x i1> %ugt, <2 x i1> %sgt, <2 x i32> <i32 0, i32 3>
  ret <2 x i1> %res
}