Skip to content

Commit 5272762

Browse files
committed
[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
1 parent 3cf4a50 commit 5272762

File tree

2 files changed

+51
-9
lines changed

2 files changed

+51
-9
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,45 @@ Value *InstCombinerImpl::simplifyRangeCheck(ICmpInst *Cmp0, ICmpInst *Cmp1,
701701
return Builder.CreateICmp(NewPred, Input, RangeEnd);
702702
}
703703

704+
// (or (icmp eq X, 0), (icmp eq X, Pow2OrZero))
705+
// -> (icmp eq (and X, Pow2OrZero), X)
706+
// (and (icmp ne X, 0), (icmp ne X, Pow2OrZero))
707+
// -> (icmp ne (and X, Pow2OrZero), X)
708+
static Value *
709+
foldAndOrOfICmpsWithPow2AndWithZero(InstCombiner::BuilderTy &Builder,
710+
ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
711+
const SimplifyQuery &Q) {
712+
CmpInst::Predicate Pred = IsAnd ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ;
713+
// Make sure we have right compares for our op.
714+
if (LHS->getPredicate() != Pred || RHS->getPredicate() != Pred)
715+
return nullptr;
716+
717+
// Make it so we can match LHS against the (icmp eq/ne X, 0) just for
718+
// simplicity.
719+
if (match(RHS->getOperand(1), m_Zero()))
720+
std::swap(LHS, RHS);
721+
722+
Value *Pow2, *Op;
723+
// Match the desired pattern:
724+
// LHS: (icmp eq/ne X, 0)
725+
// RHS: (icmp eq/ne X, Pow2OrZero)
726+
// Skip if Pow2OrZero is 1. Either way it gets folded to (icmp ugt X, 1) but
727+
// this form ends up slightly less canonical.
728+
// We could potentially be more sophisticated than requiring LHS/RHS
729+
// be one-use. We don't create additional instructions if only one
730+
// of them is one-use. So cases where one is one-use and the other
731+
// is two-use might be profitable.
732+
if (!match(LHS, m_OneUse(m_ICmp(Pred, m_Value(Op), m_Zero()))) ||
733+
!match(RHS, m_OneUse(m_c_ICmp(Pred, m_Specific(Op), m_Value(Pow2)))) ||
734+
match(Pow2, m_One()) ||
735+
!isKnownToBeAPowerOfTwo(Pow2, Q.DL, /*OrZero=*/true, /*Depth=*/0, Q.AC,
736+
Q.CxtI, Q.DT))
737+
return nullptr;
738+
739+
Value *And = Builder.CreateAnd(Op, Pow2);
740+
return Builder.CreateICmp(Pred, And, Op);
741+
}
742+
704743
// Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2)
705744
// Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2)
706745
Value *InstCombinerImpl::foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS,
@@ -3240,6 +3279,7 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
32403279
ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate();
32413280
Value *LHS0 = LHS->getOperand(0), *RHS0 = RHS->getOperand(0);
32423281
Value *LHS1 = LHS->getOperand(1), *RHS1 = RHS->getOperand(1);
3282+
32433283
const APInt *LHSC = nullptr, *RHSC = nullptr;
32443284
match(LHS1, m_APInt(LHSC));
32453285
match(RHS1, m_APInt(RHSC));
@@ -3345,6 +3385,11 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
33453385
Constant::getAllOnesValue(LHS0->getType()));
33463386
}
33473387

3388+
if (!IsLogical)
3389+
if (Value *V =
3390+
foldAndOrOfICmpsWithPow2AndWithZero(Builder, LHS, RHS, IsAnd, Q))
3391+
return V;
3392+
33483393
// This only handles icmp of constants: (icmp1 A, C1) | (icmp2 B, C2).
33493394
if (!LHSC || !RHSC)
33503395
return nullptr;

llvm/test/Transforms/InstCombine/and-or-icmps.ll

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3119,9 +3119,8 @@ define i1 @icmp_eq_or_z_or_pow2orz(i8 %x, i8 %y) {
31193119
; CHECK-LABEL: @icmp_eq_or_z_or_pow2orz(
31203120
; CHECK-NEXT: [[NY:%.*]] = sub i8 0, [[Y:%.*]]
31213121
; CHECK-NEXT: [[POW2ORZ:%.*]] = and i8 [[NY]], [[Y]]
3122-
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[X:%.*]], 0
3123-
; CHECK-NEXT: [[CP2:%.*]] = icmp eq i8 [[POW2ORZ]], [[X]]
3124-
; CHECK-NEXT: [[R:%.*]] = or i1 [[CP2]], [[C0]]
3122+
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[POW2ORZ]], [[X:%.*]]
3123+
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[TMP1]], [[X]]
31253124
; CHECK-NEXT: ret i1 [[R]]
31263125
;
31273126
%ny = sub i8 0, %y
@@ -3138,9 +3137,8 @@ define i1 @icmp_eq_or_z_or_pow2orz_logical(i8 %x, i8 %y) {
31383137
; CHECK-LABEL: @icmp_eq_or_z_or_pow2orz_logical(
31393138
; CHECK-NEXT: [[NY:%.*]] = sub i8 0, [[Y:%.*]]
31403139
; CHECK-NEXT: [[POW2ORZ:%.*]] = and i8 [[NY]], [[Y]]
3141-
; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[X:%.*]], 0
3142-
; CHECK-NEXT: [[CP2:%.*]] = icmp eq i8 [[POW2ORZ]], [[X]]
3143-
; CHECK-NEXT: [[R:%.*]] = or i1 [[CP2]], [[C0]]
3140+
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[POW2ORZ]], [[X:%.*]]
3141+
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[TMP1]], [[X]]
31443142
; CHECK-NEXT: ret i1 [[R]]
31453143
;
31463144
%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) {
31983196
; CHECK-LABEL: @icmp_ne_and_z_and_pow2orz(
31993197
; CHECK-NEXT: [[NY:%.*]] = sub <2 x i8> zeroinitializer, [[Y:%.*]]
32003198
; CHECK-NEXT: [[POW2ORZ:%.*]] = and <2 x i8> [[NY]], [[Y]]
3201-
; CHECK-NEXT: [[C0:%.*]] = icmp ne <2 x i8> [[X:%.*]], zeroinitializer
3202-
; CHECK-NEXT: [[CP2:%.*]] = icmp ne <2 x i8> [[POW2ORZ]], [[X]]
3203-
; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[C0]], [[CP2]]
3199+
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[POW2ORZ]], [[X:%.*]]
3200+
; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[TMP1]], [[X]]
32043201
; CHECK-NEXT: ret <2 x i1> [[R]]
32053202
;
32063203
%ny = sub <2 x i8> zeroinitializer, %y

0 commit comments

Comments
 (0)