[InstCombine] fold icmp with sub and bool

This is the specific pattern seen in #53432, but it can be extended
in multiple ways:
1. The 'zext' could be an 'and'
2. The 'sub' could be some other binop with a similar ==0 property (udiv).

There might be some way to generalize using knownbits, but that
would require checking that the 'bool' value is created with
some instruction that can be replaced with new icmp+logic.

https://alive2.llvm.org/ce/z/-KCfpa
This commit is contained in:
Sanjay Patel
2022-05-22 11:02:28 -04:00
parent aa9acb51f6
commit 4069cccf3b
2 changed files with 36 additions and 7 deletions

View File

@@ -5631,6 +5631,29 @@ Instruction *InstCombinerImpl::foldICmpUsingKnownBits(ICmpInst &I) {
return nullptr;
}
/// If one operand of an icmp is effectively a bool (value range of {0,1}),
/// then try to reduce patterns based on that limit.
static Instruction *foldICmpUsingBoolRange(ICmpInst &I,
InstCombiner::BuilderTy &Builder) {
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
const ICmpInst::Predicate Pred = I.getPredicate();
Value *X, *Y, *Z;
if (Pred != ICmpInst::ICMP_ULT || !match(Op0, m_Sub(m_Value(X), m_Value(Y))))
return nullptr;
unsigned ExtraUses = !Op0->hasOneUse() + !Op1->hasOneUse();
// Sub must be 0 and bool must be true for "ULT":
// (sub X, Y) <u (zext i1 Z) --> (X == Y) && Z
if (match(Op1, m_ZExt(m_Value(Z))) && ExtraUses < 2) {
Value *EqXY = Builder.CreateICmpEQ(X, Y);
return BinaryOperator::CreateAnd(EqXY, Z);
}
return nullptr;
}
llvm::Optional<std::pair<CmpInst::Predicate, Constant *>>
InstCombiner::getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred,
Constant *C) {
@@ -6058,6 +6081,9 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
if (Instruction *Res = foldICmpWithDominatingICmp(I))
return Res;
if (Instruction *Res = foldICmpUsingBoolRange(I, Builder))
return Res;
if (Instruction *Res = foldICmpUsingKnownBits(I))
return Res;

View File

@@ -173,9 +173,8 @@ define i1 @test_two_ranges3(i32* nocapture readonly %arg1, i32* nocapture readon
define i1 @sub_ult_zext(i1 %b, i8 %x, i8 %y) {
; CHECK-LABEL: @sub_ult_zext(
; CHECK-NEXT: [[Z:%.*]] = zext i1 [[B:%.*]] to i8
; CHECK-NEXT: [[S:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[S]], [[Z]]
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%z = zext i1 %b to i8
@@ -188,8 +187,8 @@ define i1 @sub_ult_zext_use1(i1 %b, i8 %x, i8 %y) {
; CHECK-LABEL: @sub_ult_zext_use1(
; CHECK-NEXT: [[Z:%.*]] = zext i1 [[B:%.*]] to i8
; CHECK-NEXT: call void @use(i8 [[Z]])
; CHECK-NEXT: [[S:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[S]], [[Z]]
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[B]]
; CHECK-NEXT: ret i1 [[R]]
;
%z = zext i1 %b to i8
@@ -201,10 +200,10 @@ define i1 @sub_ult_zext_use1(i1 %b, i8 %x, i8 %y) {
define <2 x i1> @zext_ugt_sub_use2(<2 x i1> %b, <2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @zext_ugt_sub_use2(
; CHECK-NEXT: [[Z:%.*]] = zext <2 x i1> [[B:%.*]] to <2 x i8>
; CHECK-NEXT: [[S:%.*]] = sub <2 x i8> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: call void @use_vec(<2 x i8> [[S]])
; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i8> [[S]], [[Z]]
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i8> [[X]], [[Y]]
; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%z = zext <2 x i1> %b to <2 x i8>
@@ -214,6 +213,8 @@ define <2 x i1> @zext_ugt_sub_use2(<2 x i1> %b, <2 x i8> %x, <2 x i8> %y) {
ret <2 x i1> %r
}
; negative test - too many extra uses
define i1 @sub_ult_zext_use3(i1 %b, i8 %x, i8 %y) {
; CHECK-LABEL: @sub_ult_zext_use3(
; CHECK-NEXT: [[Z:%.*]] = zext i1 [[B:%.*]] to i8
@@ -231,6 +232,8 @@ define i1 @sub_ult_zext_use3(i1 %b, i8 %x, i8 %y) {
ret i1 %r
}
; negative test - wrong predicate
define i1 @sub_ule_zext(i1 %b, i8 %x, i8 %y) {
; CHECK-LABEL: @sub_ule_zext(
; CHECK-NEXT: [[Z:%.*]] = zext i1 [[B:%.*]] to i8