Bug type: miscompilation
Component: InstCombine
Bug location: llvm/include/llvm/IR/PatternMatch.h: isValue
m_AllOnes
m_Not
m_c_SMin
match
llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp: foldSelectICmpEq
Issue title: [InstCombine] Miscompilation with poison vectors in `src_and_eq_C_xor_OrAndNotC` 
Labels: miscompilation
llvm:instcombine
Reported by: dtcxzyw

Alive2: https://alive2.llvm.org/ce/z/yB3oAx
```ll
define <2 x i32> @src_and_eq_C_xor_OrAndNotC(<2 x i32> %0, <2 x i32> %1, <2 x i32> %2) {
entry:
  %and = and <2 x i32> %1, %0
  %cmp = icmp eq <2 x i32> %and, %2
  %xor = xor <2 x i32> %1, %0
  %or = or <2 x i32> %1, %0
  %not = xor <2 x i32> %2, <i32 -1, i32 poison>
  %and1 = and <2 x i32> %or, %not
  %cond = select <2 x i1> %cmp, <2 x i32> %xor, <2 x i32> %and1
  ret <2 x i32> %cond
}
```
```ll

----------------------------------------
define <2 x i32> @src_and_eq_C_xor_OrAndNotC(<2 x i32> %#0, <2 x i32> %#1, <2 x i32> %#2) {
entry:
  %and = and <2 x i32> %#1, %#0
  %cmp = icmp eq <2 x i32> %and, %#2
  %xor = xor <2 x i32> %#1, %#0
  %or = or <2 x i32> %#1, %#0
  %not = xor <2 x i32> %#2, { 4294967295, poison }
  %and1 = and <2 x i32> %or, %not
  %cond = select <2 x i1> %cmp, <2 x i32> %xor, <2 x i32> %and1
  ret <2 x i32> %cond
}
=>
define <2 x i32> @src_and_eq_C_xor_OrAndNotC(<2 x i32> %#0, <2 x i32> %#1, <2 x i32> %#2) nofree willreturn memory(none) {
entry:
  %or = or <2 x i32> %#1, %#0
  %not = xor <2 x i32> %#2, { 4294967295, poison }
  %and1 = and <2 x i32> %or, %not
  ret <2 x i32> %and1
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
<2 x i32> %#0 = < poison, #x00000000 (0) >
<2 x i32> %#1 = < poison, #x00000000 (0) >
<2 x i32> %#2 = < poison, #x00000000 (0) >

Source:
<2 x i32> %and = < poison, #x00000000 (0) >
<2 x i1> %cmp = < poison, #x1 (1) >
<2 x i32> %xor = < poison, #x00000000 (0) >
<2 x i32> %or = < poison, #x00000000 (0) >
<2 x i32> %not = < poison, poison >
<2 x i32> %and1 = < poison, poison >
<2 x i32> %cond = < poison, #x00000000 (0) >

Target:
<2 x i32> %or = < poison, #x00000000 (0) >
<2 x i32> %not = < poison, poison >
<2 x i32> %and1 = < poison, poison >
Source value: < poison, #x00000000 (0) >
Target value: < poison, poison >

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
```

Found with https://github.com/dtcxzyw/llvm-tools.
cc @nikic

Comments: author: nikic
body: Looks like a recent issue introduced with https://github.com/llvm/llvm-project/pull/73362.
author: ParkHanbum
body: I'll not forget to create a testcase with poison.


Fix patch:
commit 7339f7ba3053db7595ece1ca5f49bd2e4c3c8305
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Apr 24 10:57:17 2024 +0900

    [InstCombine] Fix poison propagation in select of bitwise fold (#89701)
    
    We're replacing the select with the false value here, but it may be more
    poisonous if m_Not contains poison elements. Fix this by introducing a
    m_NotForbidPoison matcher and using it here.
    
    Fixes https://github.com/llvm/llvm-project/issues/89500.

diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 1fee1901fabb..0b13b4aad9c3 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -350,8 +350,9 @@ template <int64_t Val> inline constantint_match<Val> m_ConstantInt() {
 
 /// This helper class is used to match constant scalars, vector splats,
 /// and fixed width vectors that satisfy a specified predicate.
-/// For fixed width vector constants, poison elements are ignored.
-template <typename Predicate, typename ConstantVal>
+/// For fixed width vector constants, poison elements are ignored if AllowPoison
+/// is true.
+template <typename Predicate, typename ConstantVal, bool AllowPoison>
 struct cstval_pred_ty : public Predicate {
   template <typename ITy> bool match(ITy *V) {
     if (const auto *CV = dyn_cast<ConstantVal>(V))
@@ -374,7 +375,7 @@ struct cstval_pred_ty : public Predicate {
           Constant *Elt = C->getAggregateElement(i);
           if (!Elt)
             return false;
-          if (isa<PoisonValue>(Elt))
+          if (AllowPoison && isa<PoisonValue>(Elt))
             continue;
           auto *CV = dyn_cast<ConstantVal>(Elt);
           if (!CV || !this->isValue(CV->getValue()))
@@ -389,12 +390,13 @@ struct cstval_pred_ty : public Predicate {
 };
 
 /// specialization of cstval_pred_ty for ConstantInt
-template <typename Predicate>
-using cst_pred_ty = cstval_pred_ty<Predicate, ConstantInt>;
+template <typename Predicate, bool AllowPoison = true>
+using cst_pred_ty = cstval_pred_ty<Predicate, ConstantInt, AllowPoison>;
 
 /// specialization of cstval_pred_ty for ConstantFP
 template <typename Predicate>
-using cstfp_pred_ty = cstval_pred_ty<Predicate, ConstantFP>;
+using cstfp_pred_ty = cstval_pred_ty<Predicate, ConstantFP,
+                                     /*AllowPoison=*/true>;
 
 /// This helper class is used to match scalar and vector constants that
 /// satisfy a specified predicate, and bind them to an APInt.
@@ -484,6 +486,10 @@ inline cst_pred_ty<is_all_ones> m_AllOnes() {
   return cst_pred_ty<is_all_ones>();
 }
 
+inline cst_pred_ty<is_all_ones, false> m_AllOnesForbidPoison() {
+  return cst_pred_ty<is_all_ones, false>();
+}
+
 struct is_maxsignedvalue {
   bool isValue(const APInt &C) { return C.isMaxSignedValue(); }
 };
@@ -2596,6 +2602,13 @@ m_Not(const ValTy &V) {
   return m_c_Xor(m_AllOnes(), V);
 }
 
+template <typename ValTy>
+inline BinaryOp_match<cst_pred_ty<is_all_ones, false>, ValTy, Instruction::Xor,
+                      true>
+m_NotForbidPoison(const ValTy &V) {
+  return m_c_Xor(m_AllOnesForbidPoison(), V);
+}
+
 /// Matches an SMin with LHS and RHS in either order.
 template <typename LHS, typename RHS>
 inline MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty, true>
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 73600206a55c..117eb7a1dcc9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1722,11 +1722,11 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
       return match(CmpRHS, m_Zero()) && match(FalseVal, matchInner);
 
     if (NotMask == NotInner) {
-      return match(FalseVal,
-                   m_c_BinOp(OuterOpc, m_Not(matchInner), m_Specific(CmpRHS)));
+      return match(FalseVal, m_c_BinOp(OuterOpc, m_NotForbidPoison(matchInner),
+                                       m_Specific(CmpRHS)));
     } else if (NotMask == NotRHS) {
-      return match(FalseVal,
-                   m_c_BinOp(OuterOpc, matchInner, m_Not(m_Specific(CmpRHS))));
+      return match(FalseVal, m_c_BinOp(OuterOpc, matchInner,
+                                       m_NotForbidPoison(m_Specific(CmpRHS))));
     } else {
       return match(FalseVal,
                    m_c_BinOp(OuterOpc, matchInner, m_Specific(CmpRHS)));


Regression tests:
file: llvm/test/Transforms/InstCombine/select.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: src_and_eq_C_xor_OrAndNotC_vec_poison
test_body: target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"

define <2 x i32> @src_and_eq_C_xor_OrAndNotC_vec_poison(<2 x i32> %0, <2 x i32> %1, <2 x i32> %2) {
entry:
  %and = and <2 x i32> %1, %0
  %cmp = icmp eq <2 x i32> %and, %2
  %xor = xor <2 x i32> %1, %0
  %or = or <2 x i32> %1, %0
  %not = xor <2 x i32> %2, <i32 -1, i32 poison>
  %and1 = and <2 x i32> %or, %not
  %cond = select <2 x i1> %cmp, <2 x i32> %xor, <2 x i32> %and1
  ret <2 x i32> %cond
}