-
Notifications
You must be signed in to change notification settings - Fork 10.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[InstCombine] Fix poison propagation in select of bitwise fold #89701
Conversation
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-llvm-ir Author: Nikita Popov (nikic) ChangesWe'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 #89500. Full diff: https://github.com/llvm/llvm-project/pull/89701.diff 3 Files Affected:
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 1fee1901fabb65..0b13b4aad9c326 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 73600206a55c14..117eb7a1dcc933 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)));
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 2ec092a745c52c..87e9d1779e30ba 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -3830,14 +3830,17 @@ entry:
ret i32 %cond
}
-; FIXME: This is a miscompile.
define <2 x i32> @src_and_eq_C_xor_OrAndNotC_vec_poison(<2 x i32> %0, <2 x i32> %1, <2 x i32> %2) {
; CHECK-LABEL: @src_and_eq_C_xor_OrAndNotC_vec_poison(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[TMP1:%.*]], [[TMP0:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i32> [[TMP2:%.*]], <i32 -1, i32 poison>
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[TMP1:%.*]], [[TMP0:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[AND]], [[TMP2:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i32> [[TMP1]], [[TMP0]]
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[TMP1]], [[TMP0]]
+; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i32> [[TMP2]], <i32 -1, i32 poison>
; CHECK-NEXT: [[AND1:%.*]] = and <2 x i32> [[OR]], [[NOT]]
-; CHECK-NEXT: ret <2 x i32> [[AND1]]
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i32> [[XOR]], <2 x i32> [[AND1]]
+; CHECK-NEXT: ret <2 x i32> [[COND]]
;
entry:
%and = and <2 x i32> %1, %0
|
true> | ||
m_NotForbidPoison(const ValTy &V) { | ||
return m_c_Xor(m_AllOnesForbidPoison(), V); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing unit tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer not to have unit tests for anything that has lit test coverage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Except for exhaustive unit tests.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Err I was confusing, not the m_NotForbidPoison
, but for the AllowPoison
template arg in the cstval_pred_ty
unittests.
Either way though.
LGTM w/ preference for unit tests for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
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 llvm#89500.
This is kind of the replacement for the m_NotForbidUndef matcher we used to have.
e672bb0
to
a387126
Compare
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 #89500.