-
Notifications
You must be signed in to change notification settings - Fork 12.4k
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] Simplify the pattern a ne/eq (zext/sext (a ne/eq c))
#65852
Conversation
@llvm/pr-subscribers-llvm-transforms ChangesThis patch folds the pattern Full diff: https://github.com/llvm/llvm-project/pull/65852.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index a219dac7acfbe16..d0b62c17ec94358 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6380,7 +6380,69 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
Y->getType()->isIntOrIntVectorTy(1) && Pred == ICmpInst::ICMP_ULE)
return BinaryOperator::CreateOr(Builder.CreateIsNull(X), Y);
+ ICmpInst::Predicate Pred1, Pred2;
const APInt *C;
+ // icmp eq/ne X, (zext (icmp eq/ne X, C))
+ if (match(&I, m_c_ICmp(Pred1, m_Value(X),
+ m_ZExt(m_ICmp(Pred2, m_Deferred(X), m_APInt(C))))) &&
+ ICmpInst::isEquality(Pred1) && ICmpInst::isEquality(Pred2)) {
+ if (C->isZero()) {
+ if (Pred2 == ICmpInst::ICMP_EQ) {
+ // icmp eq X, (zext (icmp eq X, 0)) --> false
+ // icmp ne X, (zext (icmp eq X, 0)) --> true
+ return replaceInstUsesWith(
+ I,
+ Constant::getIntegerValue(
+ I.getType(),
+ APInt(1U, static_cast<uint64_t>(Pred1 == ICmpInst::ICMP_NE))));
+ } else {
+ // icmp eq X, (zext (icmp ne X, 0)) --> icmp ult X, 2
+ // icmp ne X, (zext (icmp ne X, 0)) --> icmp ugt X, 1
+ return ICmpInst::Create(
+ Instruction::ICmp,
+ Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
+ : ICmpInst::ICMP_ULT,
+ X,
+ Constant::getIntegerValue(
+ X->getType(), APInt(X->getType()->getScalarSizeInBits(),
+ Pred1 == ICmpInst::ICMP_NE ? 1 : 2)));
+ }
+ } else if (C->isOne()) {
+ if (Pred2 == ICmpInst::ICMP_NE) {
+ // icmp eq X, (zext (icmp ne X, 1)) --> false
+ // icmp ne X, (zext (icmp ne X, 1)) --> true
+ return replaceInstUsesWith(
+ I,
+ Constant::getIntegerValue(
+ I.getType(),
+ APInt(1U, static_cast<uint64_t>(Pred1 == ICmpInst::ICMP_NE))));
+ } else {
+ // icmp eq X, (zext (icmp eq X, 1)) --> icmp ult X, 2
+ // icmp ne X, (zext (icmp eq X, 1)) --> icmp ugt X, 1
+ return ICmpInst::Create(
+ Instruction::ICmp,
+ Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
+ : ICmpInst::ICMP_ULT,
+ X,
+ Constant::getIntegerValue(
+ X->getType(), APInt(X->getType()->getScalarSizeInBits(),
+ Pred1 == ICmpInst::ICMP_NE ? 1 : 2)));
+ }
+ } else {
+ // C != 0 && C != 1
+ // icmp eq X, (zext (icmp eq X, C)) --> icmp eq X, 0
+ // icmp eq X, (zext (icmp ne X, C)) --> icmp eq X, 1
+ // icmp ne X, (zext (icmp eq X, C)) --> icmp ne X, 0
+ // icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, 1
+ return ICmpInst::Create(
+ Instruction::ICmp, Pred1, X,
+ Constant::getIntegerValue(
+ X->getType(),
+ APInt(X->getType()->getScalarSizeInBits(),
+ static_cast<uint64_t>(Pred2 == ICmpInst::ICMP_NE))));
+ }
+ }
+
if (match(I.getOperand(0), m_c_Add(m_ZExt(m_Value(X)), m_SExt(m_Value(Y)))) &&
match(I.getOperand(1), m_APInt(C)) &&
X->getType()->isIntOrIntVectorTy(1) &&
diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll
index a26e760059b43fe..88d5a723747ad5f 100644
--- a/llvm/test/Transforms/InstCombine/icmp-range.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-range.ll
@@ -1037,10 +1037,7 @@ define i1 @icmp_ne_bool_1(ptr %ptr) {
; Tests from PR65073
define i1 @icmp_ne_zext_eq_zero(i32 %a) {
; CHECK-LABEL: @icmp_ne_zext_eq_zero(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
-; CHECK-NEXT: ret i1 [[CMP1]]
+; CHECK-NEXT: ret i1 true
;
%cmp = icmp eq i32 %a, 0
%conv = zext i1 %cmp to i32
@@ -1050,9 +1047,7 @@ define i1 @icmp_ne_zext_eq_zero(i32 %a) {
define i1 @icmp_ne_zext_ne_zero(i32 %a) {
; CHECK-LABEL: @icmp_ne_zext_ne_zero(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 0
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp ne i32 %a, 0
@@ -1063,10 +1058,7 @@ define i1 @icmp_ne_zext_ne_zero(i32 %a) {
define i1 @icmp_eq_zext_eq_zero(i32 %a) {
; CHECK-LABEL: @icmp_eq_zext_eq_zero(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
-; CHECK-NEXT: ret i1 [[CMP1]]
+; CHECK-NEXT: ret i1 false
;
%cmp = icmp eq i32 %a, 0
%conv = zext i1 %cmp to i32
@@ -1076,9 +1068,7 @@ define i1 @icmp_eq_zext_eq_zero(i32 %a) {
define i1 @icmp_eq_zext_ne_zero(i32 %a) {
; CHECK-LABEL: @icmp_eq_zext_ne_zero(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 0
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], 2
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp ne i32 %a, 0
@@ -1089,9 +1079,7 @@ define i1 @icmp_eq_zext_ne_zero(i32 %a) {
define i1 @icmp_ne_zext_eq_one(i32 %a) {
; CHECK-LABEL: @icmp_ne_zext_eq_one(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 1
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp eq i32 %a, 1
@@ -1102,10 +1090,7 @@ define i1 @icmp_ne_zext_eq_one(i32 %a) {
define i1 @icmp_ne_zext_ne_one(i32 %a) {
; CHECK-LABEL: @icmp_ne_zext_ne_one(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 1
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
-; CHECK-NEXT: ret i1 [[CMP1]]
+; CHECK-NEXT: ret i1 true
;
%cmp = icmp ne i32 %a, 1
%conv = zext i1 %cmp to i32
@@ -1115,9 +1100,7 @@ define i1 @icmp_ne_zext_ne_one(i32 %a) {
define i1 @icmp_eq_zext_eq_one(i32 %a) {
; CHECK-LABEL: @icmp_eq_zext_eq_one(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 1
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], 2
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp eq i32 %a, 1
@@ -1128,10 +1111,7 @@ define i1 @icmp_eq_zext_eq_one(i32 %a) {
define i1 @icmp_eq_zext_ne_one(i32 %a) {
; CHECK-LABEL: @icmp_eq_zext_ne_one(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 1
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
-; CHECK-NEXT: ret i1 [[CMP1]]
+; CHECK-NEXT: ret i1 false
;
%cmp = icmp ne i32 %a, 1
%conv = zext i1 %cmp to i32
@@ -1141,9 +1121,7 @@ define i1 @icmp_eq_zext_ne_one(i32 %a) {
define i1 @icmp_ne_zext_eq_non_boolean(i32 %a) {
; CHECK-LABEL: @icmp_ne_zext_eq_non_boolean(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 2
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 0
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp eq i32 %a, 2
@@ -1154,9 +1132,7 @@ define i1 @icmp_ne_zext_eq_non_boolean(i32 %a) {
define i1 @icmp_ne_zext_ne_non_boolean(i32 %a) {
; CHECK-LABEL: @icmp_ne_zext_ne_non_boolean(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 2
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp ne i32 %a, 2
@@ -1167,9 +1143,7 @@ define i1 @icmp_ne_zext_ne_non_boolean(i32 %a) {
define i1 @icmp_eq_zext_eq_non_boolean(i32 %a) {
; CHECK-LABEL: @icmp_eq_zext_eq_non_boolean(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 2
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 0
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp eq i32 %a, 2
@@ -1180,9 +1154,7 @@ define i1 @icmp_eq_zext_eq_non_boolean(i32 %a) {
define i1 @icmp_eq_zext_ne_non_boolean(i32 %a) {
; CHECK-LABEL: @icmp_eq_zext_ne_non_boolean(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 2
-; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp ne i32 %a, 2
@@ -1192,11 +1164,8 @@ define i1 @icmp_eq_zext_ne_non_boolean(i32 %a) {
}
define <2 x i1> @icmp_ne_zext_eq_zero_vec(<2 x i32> %a) {
-; CHECK-LABEL: @icmp_ne_zext_eq_zero_vec(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], zeroinitializer
-; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
-; CHECK-NEXT: ret <2 x i1> [[CMP1]]
+; CHECK-LABEL: @icmp_ne_zext_eq_zero_vec
+; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%cmp = icmp eq <2 x i32> %a, <i32 0, i32 0>
%conv = zext <2 x i1> %cmp to <2 x i32>
@@ -1206,9 +1175,7 @@ define <2 x i1> @icmp_ne_zext_eq_zero_vec(<2 x i32> %a) {
define <2 x i1> @icmp_ne_zext_ne_zero_vec(<2 x i32> %a) {
; CHECK-LABEL: @icmp_ne_zext_ne_zero_vec(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[A:%.*]], zeroinitializer
-; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i32> [[A:%.*]], <i32 1, i32 1>
; CHECK-NEXT: ret <2 x i1> [[CMP1]]
;
%cmp = icmp ne <2 x i32> %a, <i32 0, i32 0>
@@ -1219,9 +1186,7 @@ define <2 x i1> @icmp_ne_zext_ne_zero_vec(<2 x i32> %a) {
define <2 x i1> @icmp_ne_zext_eq_one_vec(<2 x i32> %a) {
; CHECK-LABEL: @icmp_ne_zext_eq_one_vec(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 1, i32 1>
-; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt <2 x i32> [[A:%.*]], <i32 1, i32 1>
; CHECK-NEXT: ret <2 x i1> [[CMP1]]
;
%cmp = icmp eq <2 x i32> %a, <i32 1, i32 1>
@@ -1232,10 +1197,7 @@ define <2 x i1> @icmp_ne_zext_eq_one_vec(<2 x i32> %a) {
define <2 x i1> @icmp_ne_zext_ne_one_vec(<2 x i32> %a) {
; CHECK-LABEL: @icmp_ne_zext_ne_one_vec(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[A:%.*]], <i32 1, i32 1>
-; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
-; CHECK-NEXT: ret <2 x i1> [[CMP1]]
+; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%cmp = icmp ne <2 x i32> %a, <i32 1, i32 1>
%conv = zext <2 x i1> %cmp to <2 x i32>
@@ -1245,9 +1207,7 @@ define <2 x i1> @icmp_ne_zext_ne_one_vec(<2 x i32> %a) {
define <2 x i1> @icmp_ne_zext_eq_non_boolean_vec(<2 x i32> %a) {
; CHECK-LABEL: @icmp_ne_zext_eq_non_boolean_vec(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 2, i32 2>
-; CHECK-NEXT: [[CONV:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[A:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP1]]
;
%cmp = icmp eq <2 x i32> %a, <i32 2, i32 2>
|
a ne/eq (zext (a ne/eq c))
a ne/eq (zext/sext (a ne/eq c))
LGTM. |
Ping. |
Ping. |
Continue to LGTM... |
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.
Basically LGTM, but I think this is still missing negative tests for non-equality pred1/pred2?
Add negative tests
Looks like incorrect conflict resolution in the last merge. |
c9ce7de
to
7e81e63
Compare
The conflict resolution should be correct now. |
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.
Yeah, it looks correct now.
This patch folds the pattern
a ne/eq (zext/sext (a ne/eq c))
into a boolean constant or a compare.Clang vs GCC: https://godbolt.org/z/4ro817WE8
Proof for
zext
: https://alive2.llvm.org/ce/z/6z9NRFProof for
sext
: https://alive2.llvm.org/ce/z/tv5wuEFixes #65073.