[llvm] 5272762 - [InstCombine] Add transforms for `(or/and (icmp eq/ne X,0),(icmp eq/ne X,Pow2OrZero))`
Noah Goldstein via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 12 11:34:59 PDT 2024
Author: Noah Goldstein
Date: 2024-07-13T02:34:38+08:00
New Revision: 52727626afb7ea702a41c1754a7d45924f9fecb2
URL: https://github.com/llvm/llvm-project/commit/52727626afb7ea702a41c1754a7d45924f9fecb2
DIFF: https://github.com/llvm/llvm-project/commit/52727626afb7ea702a41c1754a7d45924f9fecb2.diff
LOG: [InstCombine] Add transforms for `(or/and (icmp eq/ne X,0),(icmp eq/ne X,Pow2OrZero))`
`(or (icmp eq X, 0), (icmp eq X, Pow2OrZero))`
--> `(icmp eq (and X, Pow2OrZero), X)`
`(and (icmp ne X, 0), (icmp ne X, Pow2OrZero))`
--> `(icmp ne (and X, Pow2OrZero), X)`
Proofs: https://alive2.llvm.org/ce/z/nPo2BN
Closes #94648
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/test/Transforms/InstCombine/and-or-icmps.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 7f52a3ea95f73..f9caa4da44931 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -701,6 +701,45 @@ Value *InstCombinerImpl::simplifyRangeCheck(ICmpInst *Cmp0, ICmpInst *Cmp1,
return Builder.CreateICmp(NewPred, Input, RangeEnd);
}
+// (or (icmp eq X, 0), (icmp eq X, Pow2OrZero))
+// -> (icmp eq (and X, Pow2OrZero), X)
+// (and (icmp ne X, 0), (icmp ne X, Pow2OrZero))
+// -> (icmp ne (and X, Pow2OrZero), X)
+static Value *
+foldAndOrOfICmpsWithPow2AndWithZero(InstCombiner::BuilderTy &Builder,
+ ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
+ const SimplifyQuery &Q) {
+ CmpInst::Predicate Pred = IsAnd ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ;
+ // Make sure we have right compares for our op.
+ if (LHS->getPredicate() != Pred || RHS->getPredicate() != Pred)
+ return nullptr;
+
+ // Make it so we can match LHS against the (icmp eq/ne X, 0) just for
+ // simplicity.
+ if (match(RHS->getOperand(1), m_Zero()))
+ std::swap(LHS, RHS);
+
+ Value *Pow2, *Op;
+ // Match the desired pattern:
+ // LHS: (icmp eq/ne X, 0)
+ // RHS: (icmp eq/ne X, Pow2OrZero)
+ // Skip if Pow2OrZero is 1. Either way it gets folded to (icmp ugt X, 1) but
+ // this form ends up slightly less canonical.
+ // We could potentially be more sophisticated than requiring LHS/RHS
+ // be one-use. We don't create additional instructions if only one
+ // of them is one-use. So cases where one is one-use and the other
+ // is two-use might be profitable.
+ if (!match(LHS, m_OneUse(m_ICmp(Pred, m_Value(Op), m_Zero()))) ||
+ !match(RHS, m_OneUse(m_c_ICmp(Pred, m_Specific(Op), m_Value(Pow2)))) ||
+ match(Pow2, m_One()) ||
+ !isKnownToBeAPowerOfTwo(Pow2, Q.DL, /*OrZero=*/true, /*Depth=*/0, Q.AC,
+ Q.CxtI, Q.DT))
+ return nullptr;
+
+ Value *And = Builder.CreateAnd(Op, Pow2);
+ return Builder.CreateICmp(Pred, And, Op);
+}
+
// Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2)
// Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2)
Value *InstCombinerImpl::foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS,
@@ -3240,6 +3279,7 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate();
Value *LHS0 = LHS->getOperand(0), *RHS0 = RHS->getOperand(0);
Value *LHS1 = LHS->getOperand(1), *RHS1 = RHS->getOperand(1);
+
const APInt *LHSC = nullptr, *RHSC = nullptr;
match(LHS1, m_APInt(LHSC));
match(RHS1, m_APInt(RHSC));
@@ -3345,6 +3385,11 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
Constant::getAllOnesValue(LHS0->getType()));
}
+ if (!IsLogical)
+ if (Value *V =
+ foldAndOrOfICmpsWithPow2AndWithZero(Builder, LHS, RHS, IsAnd, Q))
+ return V;
+
// This only handles icmp of constants: (icmp1 A, C1) | (icmp2 B, C2).
if (!LHSC || !RHSC)
return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
index 2ee0cf98d032a..7d4fddc1563fe 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
@@ -3119,9 +3119,8 @@ define i1 @icmp_eq_or_z_or_pow2orz(i8 %x, i8 %y) {
; CHECK-LABEL: @icmp_eq_or_z_or_pow2orz(
; CHECK-NEXT: [[NY:%.*]] = sub i8 0, [[Y:%.*]]
; CHECK-NEXT: [[POW2ORZ:%.*]] = and i8 [[NY]], [[Y]]
-; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[CP2:%.*]] = icmp eq i8 [[POW2ORZ]], [[X]]
-; CHECK-NEXT: [[R:%.*]] = or i1 [[CP2]], [[C0]]
+; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[POW2ORZ]], [[X:%.*]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[TMP1]], [[X]]
; CHECK-NEXT: ret i1 [[R]]
;
%ny = sub i8 0, %y
@@ -3138,9 +3137,8 @@ define i1 @icmp_eq_or_z_or_pow2orz_logical(i8 %x, i8 %y) {
; CHECK-LABEL: @icmp_eq_or_z_or_pow2orz_logical(
; CHECK-NEXT: [[NY:%.*]] = sub i8 0, [[Y:%.*]]
; CHECK-NEXT: [[POW2ORZ:%.*]] = and i8 [[NY]], [[Y]]
-; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[CP2:%.*]] = icmp eq i8 [[POW2ORZ]], [[X]]
-; CHECK-NEXT: [[R:%.*]] = or i1 [[CP2]], [[C0]]
+; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[POW2ORZ]], [[X:%.*]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[TMP1]], [[X]]
; CHECK-NEXT: ret i1 [[R]]
;
%ny = sub i8 0, %y
@@ -3198,9 +3196,8 @@ define <2 x i1> @icmp_ne_and_z_and_pow2orz(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @icmp_ne_and_z_and_pow2orz(
; CHECK-NEXT: [[NY:%.*]] = sub <2 x i8> zeroinitializer, [[Y:%.*]]
; CHECK-NEXT: [[POW2ORZ:%.*]] = and <2 x i8> [[NY]], [[Y]]
-; CHECK-NEXT: [[C0:%.*]] = icmp ne <2 x i8> [[X:%.*]], zeroinitializer
-; CHECK-NEXT: [[CP2:%.*]] = icmp ne <2 x i8> [[POW2ORZ]], [[X]]
-; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[C0]], [[CP2]]
+; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[POW2ORZ]], [[X:%.*]]
+; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[TMP1]], [[X]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%ny = sub <2 x i8> zeroinitializer, %y
More information about the llvm-commits
mailing list