[llvm] [InstCombine] Simplify the pattern `a ne/eq (zext/sext (a ne/eq c))` (PR #65852)
Matthias Springer via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 6 02:57:43 PDT 2023
https://github.com/matthias-springer updated https://github.com/llvm/llvm-project/pull/65852
>From d9d8bcbb98e8f5aecb9733329389d61a489bd731 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 9 Sep 2023 23:07:29 +0800
Subject: [PATCH 01/10] [InstCombine] Simplify the pattern `a ne/eq (zext (a
ne/eq c))`
---
.../InstCombine/InstCombineCompares.cpp | 62 ++++++
.../test/Transforms/InstCombine/icmp-range.ll | 181 ++++++++++++++++++
2 files changed, 243 insertions(+)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 9fdc46fec631679..837b8e6d2619989 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6309,7 +6309,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 4281e09cb0309c8..15424fce33fdeea 100644
--- a/llvm/test/Transforms/InstCombine/icmp-range.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-range.ll
@@ -1034,6 +1034,187 @@ define i1 @icmp_ne_bool_1(ptr %ptr) {
ret i1 %cmp
}
+define i1 @icmp_ne_zext_eq_zero(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_eq_zero(
+; CHECK-NEXT: ret i1 true
+;
+ %cmp = icmp eq i32 %a, 0
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp ne i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_ne_zext_ne_zero(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_ne_zero(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 1
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp ne i32 %a, 0
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp ne i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_eq_zero(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_eq_zero(
+; CHECK-NEXT: ret i1 false
+;
+ %cmp = icmp eq i32 %a, 0
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp eq i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_ne_zero(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_ne_zero(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], 2
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp ne i32 %a, 0
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp eq i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_ne_zext_eq_one(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_eq_one(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 1
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp eq i32 %a, 1
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp ne i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_ne_zext_ne_one(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_ne_one(
+; CHECK-NEXT: ret i1 true
+;
+ %cmp = icmp ne i32 %a, 1
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp ne i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_eq_one(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_eq_one(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], 2
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp eq i32 %a, 1
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp eq i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_ne_one(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_ne_one(
+; CHECK-NEXT: ret i1 false
+;
+ %cmp = icmp ne i32 %a, 1
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp eq i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_ne_zext_eq_non_boolean(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_eq_non_boolean(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp eq i32 %a, 2
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp ne i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_ne_zext_ne_non_boolean(i32 %a) {
+; CHECK-LABEL: @icmp_ne_zext_ne_non_boolean(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 1
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp ne i32 %a, 2
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp ne i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_eq_non_boolean(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_eq_non_boolean(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp eq i32 %a, 2
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp eq i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_eq_zext_ne_non_boolean(i32 %a) {
+; CHECK-LABEL: @icmp_eq_zext_ne_non_boolean(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 1
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp ne i32 %a, 2
+ %conv = zext i1 %cmp to i32
+ %cmp1 = icmp eq i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define <2 x i1> @icmp_ne_zext_eq_zero_vec(<2 x i32> %a) {
+; 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>
+ %cmp1 = icmp ne <2 x i32> %conv, %a
+ ret <2 x i1> %cmp1
+}
+
+define <2 x i1> @icmp_ne_zext_ne_zero_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_ne_zext_ne_zero_vec(
+; 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>
+ %conv = zext <2 x i1> %cmp to <2 x i32>
+ %cmp1 = icmp ne <2 x i32> %conv, %a
+ ret <2 x i1> %cmp1
+}
+
+define <2 x i1> @icmp_ne_zext_eq_one_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_ne_zext_eq_one_vec(
+; 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>
+ %conv = zext <2 x i1> %cmp to <2 x i32>
+ %cmp1 = icmp ne <2 x i32> %conv, %a
+ ret <2 x i1> %cmp1
+}
+
+define <2 x i1> @icmp_ne_zext_ne_one_vec(<2 x i32> %a) {
+; CHECK-LABEL: @icmp_ne_zext_ne_one_vec(
+; 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>
+ %cmp1 = icmp ne <2 x i32> %conv, %a
+ ret <2 x i1> %cmp1
+}
+
+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: [[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>
+ %conv = zext <2 x i1> %cmp to <2 x i32>
+ %cmp1 = icmp ne <2 x i32> %conv, %a
+ ret <2 x i1> %cmp1
+}
+
!0 = !{i32 1, i32 6}
!1 = !{i32 0, i32 6}
!2 = !{i8 0, i8 1}
>From bf79e8624a1578c65ca3adc4c3c95512c0e18d53 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 18 Sep 2023 22:36:02 +0800
Subject: [PATCH 02/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
(zext (a ne/eq c))`
---
.../lib/Transforms/InstCombine/InstCombineCompares.cpp | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index d0b62c17ec94358..d1f141bcf0e7df7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6391,10 +6391,7 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
// 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))));
+ I, ConstantInt::getBool(I.getType(), 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
@@ -6412,10 +6409,7 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
// 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))));
+ I, ConstantInt::getBool(I.getType(), 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
>From ba475e31713758724305acbff496cbe605888da8 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 18 Sep 2023 23:00:17 +0800
Subject: [PATCH 03/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
(zext (a ne/eq c))`
---
.../Transforms/InstCombine/InstCombineCompares.cpp | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index d1f141bcf0e7df7..c5e3ad8a55741fb 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6400,9 +6400,7 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
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)));
+ ConstantInt::get(X->getType(), Pred1 == ICmpInst::ICMP_NE ? 1 : 2));
}
} else if (C->isOne()) {
if (Pred2 == ICmpInst::ICMP_NE) {
@@ -6418,9 +6416,7 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
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)));
+ ConstantInt::get(X->getType(), Pred1 == ICmpInst::ICMP_NE ? 1 : 2));
}
} else {
// C != 0 && C != 1
@@ -6430,10 +6426,7 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
// 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))));
+ ConstantInt::get(X->getType(), Pred2 == ICmpInst::ICMP_NE ? 1 : 0));
}
}
>From 70a70fb44d0e628a1cf485e1767ada3eaaa26b0f Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 19 Sep 2023 03:30:11 +0800
Subject: [PATCH 04/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
(zext (a ne/eq c))`
---
llvm/include/llvm/IR/PatternMatch.h | 22 ++++++++
.../InstCombine/InstCombineCompares.cpp | 50 +++++++++++++------
2 files changed, 56 insertions(+), 16 deletions(-)
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 13877538f79de6d..38d40d1ec9a839e 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -767,6 +767,28 @@ m_ImmConstant(Constant *&C) {
return m_CombineAnd(m_Constant(C), m_Unless(m_ConstantExpr()));
}
+/// Match a pattern, capturing the value if we match.
+template <typename SubPattern_t, typename Class> struct capture_ty {
+ SubPattern_t SubPattern;
+ Class *&VR;
+
+ capture_ty(const SubPattern_t &SP, Class *&V) : SubPattern(SP), VR(V) {}
+
+ template <typename ITy> bool match(ITy *V) {
+ if (auto *CV = dyn_cast<Class>(V)) {
+ VR = CV;
+ return SubPattern.match(V);
+ }
+ return false;
+ }
+};
+
+template <typename T>
+inline capture_ty<T, Instruction> m_Instruction(Instruction *&I,
+ const T &SubPattern) {
+ return capture_ty<T, Instruction>(SubPattern, I);
+}
+
/// Match a specified Value*.
struct specificval_ty {
const Value *Val;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c5e3ad8a55741fb..aca8611026ef1ca 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6380,53 +6380,71 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
Y->getType()->isIntOrIntVectorTy(1) && Pred == ICmpInst::ICMP_ULE)
return BinaryOperator::CreateOr(Builder.CreateIsNull(X), Y);
+ // icmp eq/ne X, (zext/sext (icmp eq/ne X, C))
ICmpInst::Predicate Pred1, Pred2;
const APInt *C;
- // icmp eq/ne X, (zext (icmp eq/ne X, C))
+ Instruction *ExtI;
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)) {
+ m_Instruction(ExtI,
+ m_ZExtOrSExt(m_ICmp(Pred2, m_Deferred(X),
+ m_APInt(C))))))) {
+ bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
+ bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
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
+ // icmp eq X, (zext/sext (icmp eq X, 0)) --> false
+ // icmp ne X, (zext/sext (icmp eq X, 0)) --> true
return replaceInstUsesWith(
I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
- } else {
+ } else if (!IsSExt || HasOneUse) {
// icmp eq X, (zext (icmp ne X, 0)) --> icmp ult X, 2
// icmp ne X, (zext (icmp ne X, 0)) --> icmp ugt X, 1
+ // icmp eq X, (sext (icmp ne X, 0)) --> icmp ult (X + 1), 2
+ // icmp ne X, (sext (icmp ne X, 0)) --> icmp ugt (X + 1), 1
return ICmpInst::Create(
Instruction::ICmp,
Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
: ICmpInst::ICMP_ULT,
- X,
+ IsSExt ? Builder.CreateAdd(X, ConstantInt::get(X->getType(), 1))
+ : X,
ConstantInt::get(X->getType(), Pred1 == ICmpInst::ICMP_NE ? 1 : 2));
}
- } else if (C->isOne()) {
+ } else if (IsSExt ? C->isAllOnes() : 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
+ // icmp eq X, (sext (icmp ne X, -1)) --> false
+ // icmp ne X, (sext (icmp ne X, -1)) --> true
return replaceInstUsesWith(
I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
- } else {
+ } else if (!IsSExt || HasOneUse) {
// icmp eq X, (zext (icmp eq X, 1)) --> icmp ult X, 2
// icmp ne X, (zext (icmp eq X, 1)) --> icmp ugt X, 1
+ // icmp eq X, (sext (icmp eq X, -1)) --> icmp ult (X + 1), 2
+ // icmp ne X, (sext (icmp eq X, -1)) --> icmp ugt (X + 1), 1
return ICmpInst::Create(
Instruction::ICmp,
Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
: ICmpInst::ICMP_ULT,
- X,
+ IsSExt ? Builder.CreateAdd(X, ConstantInt::get(X->getType(), 1))
+ : X,
ConstantInt::get(X->getType(), 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
+ // when 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
+ // when 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,
- ConstantInt::get(X->getType(), Pred2 == ICmpInst::ICMP_NE ? 1 : 0));
+ ConstantInt::get(X->getType(),
+ Pred2 == ICmpInst::ICMP_NE ? (IsSExt ? -1 : 1) : 0));
}
}
>From 418562d5dbd25167d3f9b2c61fb7265581ee99d4 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 19 Sep 2023 03:39:23 +0800
Subject: [PATCH 05/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
(zext (a ne/eq c))`
---
llvm/include/llvm/IR/PatternMatch.h | 22 -----
.../InstCombine/InstCombineCompares.cpp | 6 +-
.../Transforms/InstCombine/and-or-icmps.ll | 17 +---
.../test/Transforms/InstCombine/icmp-range.ll | 82 ++++++-------------
4 files changed, 31 insertions(+), 96 deletions(-)
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 38d40d1ec9a839e..13877538f79de6d 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -767,28 +767,6 @@ m_ImmConstant(Constant *&C) {
return m_CombineAnd(m_Constant(C), m_Unless(m_ConstantExpr()));
}
-/// Match a pattern, capturing the value if we match.
-template <typename SubPattern_t, typename Class> struct capture_ty {
- SubPattern_t SubPattern;
- Class *&VR;
-
- capture_ty(const SubPattern_t &SP, Class *&V) : SubPattern(SP), VR(V) {}
-
- template <typename ITy> bool match(ITy *V) {
- if (auto *CV = dyn_cast<Class>(V)) {
- VR = CV;
- return SubPattern.match(V);
- }
- return false;
- }
-};
-
-template <typename T>
-inline capture_ty<T, Instruction> m_Instruction(Instruction *&I,
- const T &SubPattern) {
- return capture_ty<T, Instruction>(SubPattern, I);
-}
-
/// Match a specified Value*.
struct specificval_ty {
const Value *Val;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index aca8611026ef1ca..b72bde885de124b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6385,9 +6385,9 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
const APInt *C;
Instruction *ExtI;
if (match(&I, m_c_ICmp(Pred1, m_Value(X),
- m_Instruction(ExtI,
- m_ZExtOrSExt(m_ICmp(Pred2, m_Deferred(X),
- m_APInt(C))))))) {
+ m_CombineAnd(m_Instruction(ExtI),
+ m_ZExtOrSExt(m_ICmp(Pred2, m_Deferred(X),
+ m_APInt(C))))))) {
bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
if (C->isZero()) {
diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
index 065dbf261e131bf..2c887d574d397f6 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
@@ -366,19 +366,10 @@ define void @simplify_before_foldAndOfICmps(ptr %p) {
; CHECK-LABEL: @simplify_before_foldAndOfICmps(
; CHECK-NEXT: [[A8:%.*]] = alloca i16, align 2
; CHECK-NEXT: [[L7:%.*]] = load i16, ptr [[A8]], align 2
-; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[L7]], -1
-; CHECK-NEXT: [[B11:%.*]] = zext i1 [[TMP1]] to i16
-; CHECK-NEXT: [[C10:%.*]] = icmp ugt i16 [[L7]], [[B11]]
-; CHECK-NEXT: [[C5:%.*]] = icmp slt i16 [[L7]], 1
-; CHECK-NEXT: [[C7:%.*]] = icmp slt i16 [[L7]], 0
-; CHECK-NEXT: [[B15:%.*]] = xor i1 [[C7]], [[C10]]
-; CHECK-NEXT: [[C6:%.*]] = xor i1 [[B15]], true
-; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[C5]], [[C6]]
-; CHECK-NEXT: [[C3:%.*]] = and i1 [[TMP2]], [[C10]]
-; CHECK-NEXT: [[TMP3:%.*]] = xor i1 [[C10]], true
-; CHECK-NEXT: [[C18:%.*]] = or i1 [[C7]], [[TMP3]]
-; CHECK-NEXT: [[TMP4:%.*]] = sext i1 [[C3]] to i64
-; CHECK-NEXT: [[G26:%.*]] = getelementptr i1, ptr null, i64 [[TMP4]]
+; CHECK-NEXT: [[C18:%.*]] = icmp slt i16 [[L7]], 1
+; CHECK-NEXT: [[L7_LOBIT:%.*]] = ashr i16 [[L7]], 15
+; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[L7_LOBIT]] to i64
+; CHECK-NEXT: [[G26:%.*]] = getelementptr i1, ptr null, i64 [[TMP1]]
; CHECK-NEXT: store i16 [[L7]], ptr [[P:%.*]], align 2
; CHECK-NEXT: store i1 [[C18]], ptr [[P]], align 1
; CHECK-NEXT: store ptr [[G26]], ptr [[P]], align 8
diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll
index f7efff9f675373a..3a40755384f2a21 100644
--- a/llvm/test/Transforms/InstCombine/icmp-range.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-range.ll
@@ -1164,7 +1164,7 @@ 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-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>
@@ -1218,10 +1218,7 @@ define <2 x i1> @icmp_ne_zext_eq_non_boolean_vec(<2 x i32> %a) {
define i1 @icmp_ne_sext_eq_zero(i32 %a) {
; CHECK-LABEL: @icmp_ne_sext_eq_zero(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
-; CHECK-NEXT: [[CONV:%.*]] = sext 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 = sext i1 %cmp to i32
@@ -1231,9 +1228,8 @@ define i1 @icmp_ne_sext_eq_zero(i32 %a) {
define i1 @icmp_ne_sext_ne_zero(i32 %a) {
; CHECK-LABEL: @icmp_ne_sext_ne_zero(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 0
-; CHECK-NEXT: [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A:%.*]], -1
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[TMP1]], -2
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp ne i32 %a, 0
@@ -1244,10 +1240,7 @@ define i1 @icmp_ne_sext_ne_zero(i32 %a) {
define i1 @icmp_eq_sext_eq_zero(i32 %a) {
; CHECK-LABEL: @icmp_eq_sext_eq_zero(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
-; CHECK-NEXT: [[CONV:%.*]] = sext 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 = sext i1 %cmp to i32
@@ -1257,9 +1250,8 @@ define i1 @icmp_eq_sext_eq_zero(i32 %a) {
define i1 @icmp_eq_sext_ne_zero(i32 %a) {
; CHECK-LABEL: @icmp_eq_sext_ne_zero(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 0
-; CHECK-NEXT: [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A:%.*]], 1
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[TMP1]], 2
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp ne i32 %a, 0
@@ -1270,9 +1262,8 @@ define i1 @icmp_eq_sext_ne_zero(i32 %a) {
define i1 @icmp_ne_sext_eq_allones(i32 %a) {
; CHECK-LABEL: @icmp_ne_sext_eq_allones(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], -1
-; CHECK-NEXT: [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A:%.*]], -1
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[TMP1]], -2
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp eq i32 %a, -1
@@ -1283,10 +1274,7 @@ define i1 @icmp_ne_sext_eq_allones(i32 %a) {
define i1 @icmp_ne_sext_ne_allones(i32 %a) {
; CHECK-LABEL: @icmp_ne_sext_ne_allones(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], -1
-; CHECK-NEXT: [[CONV:%.*]] = sext 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 = sext i1 %cmp to i32
@@ -1296,9 +1284,8 @@ define i1 @icmp_ne_sext_ne_allones(i32 %a) {
define i1 @icmp_eq_sext_eq_allones(i32 %a) {
; CHECK-LABEL: @icmp_eq_sext_eq_allones(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], -1
-; CHECK-NEXT: [[CONV:%.*]] = sext i1 [[CMP]] to i32
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[CONV]], [[A]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[A:%.*]], 1
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[TMP1]], 2
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp = icmp eq i32 %a, -1
@@ -1309,10 +1296,7 @@ define i1 @icmp_eq_sext_eq_allones(i32 %a) {
define i1 @icmp_eq_sext_ne_allones(i32 %a) {
; CHECK-LABEL: @icmp_eq_sext_ne_allones(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], -1
-; CHECK-NEXT: [[CONV:%.*]] = sext 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 = sext i1 %cmp to i32
@@ -1322,9 +1306,7 @@ define i1 @icmp_eq_sext_ne_allones(i32 %a) {
define i1 @icmp_ne_sext_eq_otherwise(i32 %a) {
; CHECK-LABEL: @icmp_ne_sext_eq_otherwise(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 2
-; CHECK-NEXT: [[CONV:%.*]] = sext 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
@@ -1335,9 +1317,7 @@ define i1 @icmp_ne_sext_eq_otherwise(i32 %a) {
define i1 @icmp_ne_sext_ne_otherwise(i32 %a) {
; CHECK-LABEL: @icmp_ne_sext_ne_otherwise(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 2
-; CHECK-NEXT: [[CONV:%.*]] = sext 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
@@ -1348,9 +1328,7 @@ define i1 @icmp_ne_sext_ne_otherwise(i32 %a) {
define i1 @icmp_eq_sext_eq_otherwise(i32 %a) {
; CHECK-LABEL: @icmp_eq_sext_eq_otherwise(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 2
-; CHECK-NEXT: [[CONV:%.*]] = sext 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
@@ -1361,9 +1339,7 @@ define i1 @icmp_eq_sext_eq_otherwise(i32 %a) {
define i1 @icmp_eq_sext_ne_otherwise(i32 %a) {
; CHECK-LABEL: @icmp_eq_sext_ne_otherwise(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 2
-; CHECK-NEXT: [[CONV:%.*]] = sext 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
@@ -1374,10 +1350,7 @@ define i1 @icmp_eq_sext_ne_otherwise(i32 %a) {
define <2 x i1> @icmp_ne_sext_eq_zero_vec(<2 x i32> %a) {
; CHECK-LABEL: @icmp_ne_sext_eq_zero_vec(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], zeroinitializer
-; CHECK-NEXT: [[CONV:%.*]] = sext <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 eq <2 x i32> %a, <i32 0, i32 0>
%conv = sext <2 x i1> %cmp to <2 x i32>
@@ -1387,9 +1360,8 @@ define <2 x i1> @icmp_ne_sext_eq_zero_vec(<2 x i32> %a) {
define <2 x i1> @icmp_ne_sext_ne_zero_vec(<2 x i32> %a) {
; CHECK-LABEL: @icmp_ne_sext_ne_zero_vec(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[A:%.*]], zeroinitializer
-; CHECK-NEXT: [[CONV:%.*]] = sext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
+; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[A:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult <2 x i32> [[TMP1]], <i32 -2, i32 -2>
; CHECK-NEXT: ret <2 x i1> [[CMP1]]
;
%cmp = icmp ne <2 x i32> %a, <i32 0, i32 0>
@@ -1400,9 +1372,8 @@ define <2 x i1> @icmp_ne_sext_ne_zero_vec(<2 x i32> %a) {
define <2 x i1> @icmp_ne_sext_eq_allones_vec(<2 x i32> %a) {
; CHECK-LABEL: @icmp_ne_sext_eq_allones_vec(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 -1, i32 -1>
-; CHECK-NEXT: [[CONV:%.*]] = sext <2 x i1> [[CMP]] to <2 x i32>
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne <2 x i32> [[CONV]], [[A]]
+; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[A:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult <2 x i32> [[TMP1]], <i32 -2, i32 -2>
; CHECK-NEXT: ret <2 x i1> [[CMP1]]
;
%cmp = icmp eq <2 x i32> %a, <i32 -1, i32 -1>
@@ -1413,10 +1384,7 @@ define <2 x i1> @icmp_ne_sext_eq_allones_vec(<2 x i32> %a) {
define <2 x i1> @icmp_ne_sext_ne_allones_vec(<2 x i32> %a) {
; CHECK-LABEL: @icmp_ne_sext_ne_allones_vec(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[A:%.*]], <i32 -1, i32 -1>
-; CHECK-NEXT: [[CONV:%.*]] = sext <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 = sext <2 x i1> %cmp to <2 x i32>
@@ -1426,9 +1394,7 @@ define <2 x i1> @icmp_ne_sext_ne_allones_vec(<2 x i32> %a) {
define <2 x i1> @icmp_ne_sext_eq_otherwise_vec(<2 x i32> %a) {
; CHECK-LABEL: @icmp_ne_sext_eq_otherwise_vec(
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 2, i32 2>
-; CHECK-NEXT: [[CONV:%.*]] = sext <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>
>From b7565ccc7090e15f6330da274225420691a4160d Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 19 Sep 2023 10:24:50 +0800
Subject: [PATCH 06/10] [InstCombine] Fix comments `zext` -> `sext`. NFC.
---
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index b72bde885de124b..c7b9366bfd45e41 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6437,10 +6437,10 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
// icmp ne X, (zext (icmp eq X, C)) --> icmp ne X, 0
// icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, 1
// when 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
+ // icmp eq X, (sext (icmp eq X, C)) --> icmp eq X, 0
+ // icmp eq X, (sext (icmp ne X, C)) --> icmp eq X, -1
+ // icmp ne X, (sext (icmp eq X, C)) --> icmp ne X, 0
+ // icmp ne X, (sext (icmp ne X, C)) --> icmp ne X, -1
return ICmpInst::Create(
Instruction::ICmp, Pred1, X,
ConstantInt::get(X->getType(),
>From 5b5052403968d4b394b30779c8912a1e732e9998 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 24 Sep 2023 17:59:26 +0800
Subject: [PATCH 07/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
(zext (a ne/eq c))`
---
.../InstCombine/InstCombineCompares.cpp | 39 ++++++++-----------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c7b9366bfd45e41..7c7ab62c64dac89 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6390,6 +6390,13 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
m_APInt(C))))))) {
bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
+ auto CreateRangeCheck = [&] {
+ Value *V1 = Constant::getNullValue(X->getType());
+ Value *V2 = ConstantInt::get(X->getType(), IsSExt ? -1 : 1);
+ return BinaryOperator::Create(
+ Pred1 == ICmpInst::ICMP_EQ ? Instruction::Or : Instruction::And,
+ Builder.CreateICmp(Pred1, X, V1), Builder.CreateICmp(Pred1, X, V2));
+ };
if (C->isZero()) {
if (Pred2 == ICmpInst::ICMP_EQ) {
// icmp eq X, (zext/sext (icmp eq X, 0)) --> false
@@ -6397,17 +6404,11 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
return replaceInstUsesWith(
I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
} else if (!IsSExt || HasOneUse) {
- // icmp eq X, (zext (icmp ne X, 0)) --> icmp ult X, 2
- // icmp ne X, (zext (icmp ne X, 0)) --> icmp ugt X, 1
- // icmp eq X, (sext (icmp ne X, 0)) --> icmp ult (X + 1), 2
- // icmp ne X, (sext (icmp ne X, 0)) --> icmp ugt (X + 1), 1
- return ICmpInst::Create(
- Instruction::ICmp,
- Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
- : ICmpInst::ICMP_ULT,
- IsSExt ? Builder.CreateAdd(X, ConstantInt::get(X->getType(), 1))
- : X,
- ConstantInt::get(X->getType(), Pred1 == ICmpInst::ICMP_NE ? 1 : 2));
+ // icmp eq X, (zext (icmp ne X, 0)) --> X == 0 || X == 1
+ // icmp ne X, (zext (icmp ne X, 0)) --> X != 0 && X != 1
+ // icmp eq X, (sext (icmp ne X, 0)) --> X == 0 || X == -1
+ // icmp ne X, (sext (icmp ne X, 0)) --> X != 0 && X == -1
+ return CreateRangeCheck();
}
} else if (IsSExt ? C->isAllOnes() : C->isOne()) {
if (Pred2 == ICmpInst::ICMP_NE) {
@@ -6418,17 +6419,11 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
return replaceInstUsesWith(
I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
} else if (!IsSExt || HasOneUse) {
- // icmp eq X, (zext (icmp eq X, 1)) --> icmp ult X, 2
- // icmp ne X, (zext (icmp eq X, 1)) --> icmp ugt X, 1
- // icmp eq X, (sext (icmp eq X, -1)) --> icmp ult (X + 1), 2
- // icmp ne X, (sext (icmp eq X, -1)) --> icmp ugt (X + 1), 1
- return ICmpInst::Create(
- Instruction::ICmp,
- Pred1 == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGT
- : ICmpInst::ICMP_ULT,
- IsSExt ? Builder.CreateAdd(X, ConstantInt::get(X->getType(), 1))
- : X,
- ConstantInt::get(X->getType(), Pred1 == ICmpInst::ICMP_NE ? 1 : 2));
+ // icmp eq X, (zext (icmp eq X, 1)) --> X == 0 || X == 1
+ // icmp ne X, (zext (icmp eq X, 1)) --> X != 0 && X != 1
+ // icmp eq X, (sext (icmp eq X, -1)) --> X == 0 || X == -1
+ // icmp ne X, (sext (icmp eq X, -1)) --> X != 0 && X == -1
+ return CreateRangeCheck();
}
} else {
// when C != 0 && C != 1:
>From 55d52b1f05004abe6c4187dc07437580c7f5aa73 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 24 Sep 2023 21:49:47 +0800
Subject: [PATCH 08/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
(zext (a ne/eq c))`
---
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 7c7ab62c64dac89..9f2d0c8110f79e0 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6391,11 +6391,13 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
auto CreateRangeCheck = [&] {
- Value *V1 = Constant::getNullValue(X->getType());
- Value *V2 = ConstantInt::get(X->getType(), IsSExt ? -1 : 1);
+ Value *CmpV1 =
+ Builder.CreateICmp(Pred1, X, Constant::getNullValue(X->getType()));
+ Value *CmpV2 = Builder.CreateICmp(
+ Pred1, X, ConstantInt::get(X->getType(), IsSExt ? -1 : 1));
return BinaryOperator::Create(
Pred1 == ICmpInst::ICMP_EQ ? Instruction::Or : Instruction::And,
- Builder.CreateICmp(Pred1, X, V1), Builder.CreateICmp(Pred1, X, V2));
+ CmpV1, CmpV2);
};
if (C->isZero()) {
if (Pred2 == ICmpInst::ICMP_EQ) {
>From c0d8f8193fa1620db1f84379f2316fcf4b401e4c Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 1 Oct 2023 20:10:57 +0800
Subject: [PATCH 09/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
(zext (a ne/eq c))`
---
.../InstCombine/InstCombineCompares.cpp | 10 ++++----
.../Transforms/InstCombine/and-or-icmps.ll | 17 ++++++++++----
.../test/Transforms/InstCombine/icmp-range.ll | 23 +++++++++++++++++++
3 files changed, 42 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 9f2d0c8110f79e0..4fca8859dea7acc 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6387,14 +6387,15 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
if (match(&I, m_c_ICmp(Pred1, m_Value(X),
m_CombineAnd(m_Instruction(ExtI),
m_ZExtOrSExt(m_ICmp(Pred2, m_Deferred(X),
- m_APInt(C))))))) {
+ m_APInt(C)))))) &&
+ ICmpInst::isEquality(Pred1) && ICmpInst::isEquality(Pred2)) {
bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
auto CreateRangeCheck = [&] {
Value *CmpV1 =
Builder.CreateICmp(Pred1, X, Constant::getNullValue(X->getType()));
Value *CmpV2 = Builder.CreateICmp(
- Pred1, X, ConstantInt::get(X->getType(), IsSExt ? -1 : 1));
+ Pred1, X, ConstantInt::getSigned(X->getType(), IsSExt ? -1 : 1));
return BinaryOperator::Create(
Pred1 == ICmpInst::ICMP_EQ ? Instruction::Or : Instruction::And,
CmpV1, CmpV2);
@@ -6440,8 +6441,9 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
// icmp ne X, (sext (icmp ne X, C)) --> icmp ne X, -1
return ICmpInst::Create(
Instruction::ICmp, Pred1, X,
- ConstantInt::get(X->getType(),
- Pred2 == ICmpInst::ICMP_NE ? (IsSExt ? -1 : 1) : 0));
+ ConstantInt::getSigned(X->getType(), Pred2 == ICmpInst::ICMP_NE
+ ? (IsSExt ? -1 : 1)
+ : 0));
}
}
diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
index 2c887d574d397f6..065dbf261e131bf 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
@@ -366,10 +366,19 @@ define void @simplify_before_foldAndOfICmps(ptr %p) {
; CHECK-LABEL: @simplify_before_foldAndOfICmps(
; CHECK-NEXT: [[A8:%.*]] = alloca i16, align 2
; CHECK-NEXT: [[L7:%.*]] = load i16, ptr [[A8]], align 2
-; CHECK-NEXT: [[C18:%.*]] = icmp slt i16 [[L7]], 1
-; CHECK-NEXT: [[L7_LOBIT:%.*]] = ashr i16 [[L7]], 15
-; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[L7_LOBIT]] to i64
-; CHECK-NEXT: [[G26:%.*]] = getelementptr i1, ptr null, i64 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i16 [[L7]], -1
+; CHECK-NEXT: [[B11:%.*]] = zext i1 [[TMP1]] to i16
+; CHECK-NEXT: [[C10:%.*]] = icmp ugt i16 [[L7]], [[B11]]
+; CHECK-NEXT: [[C5:%.*]] = icmp slt i16 [[L7]], 1
+; CHECK-NEXT: [[C7:%.*]] = icmp slt i16 [[L7]], 0
+; CHECK-NEXT: [[B15:%.*]] = xor i1 [[C7]], [[C10]]
+; CHECK-NEXT: [[C6:%.*]] = xor i1 [[B15]], true
+; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[C5]], [[C6]]
+; CHECK-NEXT: [[C3:%.*]] = and i1 [[TMP2]], [[C10]]
+; CHECK-NEXT: [[TMP3:%.*]] = xor i1 [[C10]], true
+; CHECK-NEXT: [[C18:%.*]] = or i1 [[C7]], [[TMP3]]
+; CHECK-NEXT: [[TMP4:%.*]] = sext i1 [[C3]] to i64
+; CHECK-NEXT: [[G26:%.*]] = getelementptr i1, ptr null, i64 [[TMP4]]
; CHECK-NEXT: store i16 [[L7]], ptr [[P:%.*]], align 2
; CHECK-NEXT: store i1 [[C18]], ptr [[P]], align 1
; CHECK-NEXT: store ptr [[G26]], ptr [[P]], align 8
diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll
index 3a40755384f2a21..79790b7458d4219 100644
--- a/llvm/test/Transforms/InstCombine/icmp-range.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-range.ll
@@ -1403,6 +1403,29 @@ define <2 x i1> @icmp_ne_sext_eq_otherwise_vec(<2 x i32> %a) {
ret <2 x i1> %cmp1
}
+define i1 @icmp_ne_sext_ne_zero_i128(i128 %a) {
+; CHECK-LABEL: @icmp_ne_sext_ne_zero_i128(
+; CHECK-NEXT: [[TMP1:%.*]] = add i128 [[A:%.*]], -1
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i128 [[TMP1]], -2
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp ne i128 %a, 0
+ %conv = sext i1 %cmp to i128
+ %cmp1 = icmp ne i128 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_ne_sext_ne_otherwise_i128(i128 %a) {
+; CHECK-LABEL: @icmp_ne_sext_ne_otherwise_i128(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i128 [[A:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp ne i128 %a, 2
+ %conv = sext i1 %cmp to i128
+ %cmp1 = icmp ne i128 %conv, %a
+ ret i1 %cmp1
+}
+
!0 = !{i32 1, i32 6}
!1 = !{i32 0, i32 6}
!2 = !{i8 0, i8 1}
>From 2285a2c6b8e66cf35aed6151c61e841f1349817f Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 6 Oct 2023 17:17:53 +0800
Subject: [PATCH 10/10] fixup! [InstCombine] Simplify the pattern `a ne/eq
(zext (a ne/eq c))`
Add negative tests
---
.../test/Transforms/InstCombine/icmp-range.ll | 79 +++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll
index 17903be937057ab..7af06e03fd4b2a9 100644
--- a/llvm/test/Transforms/InstCombine/icmp-range.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-range.ll
@@ -1426,6 +1426,85 @@ define i1 @icmp_ne_sext_ne_otherwise_i128(i128 %a) {
ret i1 %cmp1
}
+; Negative tests with non-equality predicates
+define i1 @icmp_ne_sext_sgt_zero_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_ne_sext_sgt_zero_nofold(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 0
+; CHECK-NEXT: [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp sgt i32 %a, 0
+ %conv = sext i1 %cmp to i32
+ %cmp1 = icmp ne i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_slt_sext_ne_zero_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_slt_sext_ne_zero_nofold(
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 0
+; CHECK-NEXT: [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[CONV]], [[A]]
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp ne i32 %a, 0
+ %conv = sext i1 %cmp to i32
+ %cmp1 = icmp slt i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_ne_sext_slt_allones_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_ne_sext_slt_allones_nofold(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A:%.*]], -1
+; CHECK-NEXT: [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp slt i32 %a, -1
+ %conv = sext i1 %cmp to i32
+ %cmp1 = icmp ne i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_slt_sext_ne_allones_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_slt_sext_ne_allones_nofold(
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], -1
+; CHECK-NEXT: [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[CONV]], [[A]]
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp ne i32 %a, -1
+ %conv = sext i1 %cmp to i32
+ %cmp1 = icmp slt i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_ne_sext_slt_otherwise_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_ne_sext_slt_otherwise_nofold(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A:%.*]], 2
+; CHECK-NEXT: [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[CONV]], [[A]]
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp slt i32 %a, 2
+ %conv = sext i1 %cmp to i32
+ %cmp1 = icmp ne i32 %conv, %a
+ ret i1 %cmp1
+}
+
+define i1 @icmp_slt_sext_ne_otherwise_nofold(i32 %a) {
+; CHECK-LABEL: @icmp_slt_sext_ne_otherwise_nofold(
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], 2
+; CHECK-NEXT: [[CONV:%.*]] = sext i1 [[CMP]] to i32
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[CONV]], [[A]]
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+ %cmp = icmp ne i32 %a, 2
+ %conv = sext i1 %cmp to i32
+ %cmp1 = icmp slt i32 %conv, %a
+ ret i1 %cmp1
+}
+
; tests from PR59555
define i1 @isFloat(i64 %0) {
; CHECK-LABEL: @isFloat(
More information about the llvm-commits
mailing list