Skip to content

Commit

Permalink
[InstCombine] fold icmp of zext bool based on limited range
Browse files Browse the repository at this point in the history
X <u (zext i1 Y) --> (X == 0) && Y

https://alive2.llvm.org/ce/z/avQDRY

This is a generalization of 4069ccc based on the post-commit suggestion.
This also adds the i1 type check and tests that were missing from the earlier
attempt; that commit caused several bot fails and was reverted.

Differential Revision: https://reviews.llvm.org/D126171
  • Loading branch information
rotateright committed May 23, 2022
1 parent 6793c63 commit 1ebad98
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 13 deletions.
21 changes: 21 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Expand Up @@ -5631,6 +5631,24 @@ 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 *X, *Y;
ICmpInst::Predicate Pred;

// X must be 0 and bool must be true for "ULT":
// X <u (zext i1 Y) --> (X == 0) && Y
if (match(&I, m_c_ICmp(Pred, m_Value(X), m_OneUse(m_ZExt(m_Value(Y))))) &&
Y->getType()->isIntOrIntVectorTy(1) && Pred == ICmpInst::ICMP_ULT)
return BinaryOperator::CreateAnd(Builder.CreateIsNull(X), Y);

// TODO: Handle the related pattern with UGE/sext.

return nullptr;
}

llvm::Optional<std::pair<CmpInst::Predicate, Constant *>>
InstCombiner::getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred,
Constant *C) {
Expand Down Expand Up @@ -6058,6 +6076,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;

Expand Down
41 changes: 28 additions & 13 deletions llvm/test/Transforms/InstCombine/icmp-range.ll
Expand Up @@ -173,8 +173,8 @@ define i1 @test_two_ranges3(i32* nocapture readonly %arg1, i32* nocapture readon

define i1 @ugt_zext(i1 %b, i8 %x) {
; CHECK-LABEL: @ugt_zext(
; CHECK-NEXT: [[Z:%.*]] = zext i1 [[B:%.*]] to i8
; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[Z]], [[X:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%z = zext i1 %b to i8
Expand All @@ -185,8 +185,8 @@ define i1 @ugt_zext(i1 %b, i8 %x) {
define <2 x i1> @ult_zext(<2 x i1> %b, <2 x i8> %p) {
; CHECK-LABEL: @ult_zext(
; CHECK-NEXT: [[X:%.*]] = mul <2 x i8> [[P:%.*]], [[P]]
; CHECK-NEXT: [[Z:%.*]] = zext <2 x i1> [[B:%.*]] to <2 x i8>
; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i8> [[X]], [[Z]]
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i8> [[X]], zeroinitializer
; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%x = mul <2 x i8> %p, %p ; thwart complexity-based canonicalization
Expand All @@ -195,6 +195,8 @@ define <2 x i1> @ult_zext(<2 x i1> %b, <2 x i8> %p) {
ret <2 x i1> %r
}

; negative test - need ult/ugt

define i1 @uge_zext(i1 %b, i8 %x) {
; CHECK-LABEL: @uge_zext(
; CHECK-NEXT: [[Z:%.*]] = zext i1 [[B:%.*]] to i8
Expand All @@ -206,6 +208,8 @@ define i1 @uge_zext(i1 %b, i8 %x) {
ret i1 %r
}

; negative test - need ult/ugt

define i1 @ule_zext(i1 %b, i8 %p) {
; CHECK-LABEL: @ule_zext(
; CHECK-NEXT: [[X:%.*]] = mul i8 [[P:%.*]], [[P]]
Expand All @@ -219,6 +223,8 @@ define i1 @ule_zext(i1 %b, i8 %p) {
ret i1 %r
}

; negative test - extra use

define i1 @ugt_zext_use(i1 %b, i8 %x) {
; CHECK-LABEL: @ugt_zext_use(
; CHECK-NEXT: [[Z:%.*]] = zext i1 [[B:%.*]] to i8
Expand All @@ -232,6 +238,8 @@ define i1 @ugt_zext_use(i1 %b, i8 %x) {
ret i1 %r
}

; negative test - must be zext of i1

define i1 @ult_zext_not_i1(i2 %b, i8 %x) {
; CHECK-LABEL: @ult_zext_not_i1(
; CHECK-NEXT: [[Z:%.*]] = zext i2 [[B:%.*]] to i8
Expand All @@ -243,11 +251,12 @@ define i1 @ult_zext_not_i1(i2 %b, i8 %x) {
ret i1 %r
}

; sub is eliminated

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
Expand All @@ -259,8 +268,8 @@ define i1 @sub_ult_zext(i1 %b, i8 %x, i8 %y) {
define i1 @zext_ult_zext(i1 %b, i8 %p) {
; CHECK-LABEL: @zext_ult_zext(
; CHECK-NEXT: [[X:%.*]] = mul i8 [[P:%.*]], [[P]]
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[B:%.*]] to i8
; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[X]], [[TMP1]]
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%x = mul i8 %p, %p ; thwart complexity-based canonicalization
Expand All @@ -270,12 +279,14 @@ define i1 @zext_ult_zext(i1 %b, i8 %p) {
ret i1 %r
}

; match and fold even if both sides are zexts (from different source types)

define i1 @zext_ugt_zext(i1 %b, i4 %x) {
; CHECK-LABEL: @zext_ugt_zext(
; CHECK-NEXT: [[ZX:%.*]] = zext i4 [[X:%.*]] to i8
; CHECK-NEXT: call void @use(i8 [[ZX]])
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[B:%.*]] to i4
; CHECK-NEXT: [[R:%.*]] = icmp ugt i4 [[TMP1]], [[X]]
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i4 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%z = zext i1 %b to i8
Expand All @@ -285,6 +296,8 @@ define i1 @zext_ugt_zext(i1 %b, i4 %x) {
ret i1 %r
}

; negative test - must be zext of i1

define i1 @sub_ult_zext_not_i1(i2 %b, i8 %x, i8 %y) {
; CHECK-LABEL: @sub_ult_zext_not_i1(
; CHECK-NEXT: [[Z:%.*]] = zext i2 [[B:%.*]] to i8
Expand All @@ -298,6 +311,8 @@ define i1 @sub_ult_zext_not_i1(i2 %b, i8 %x, i8 %y) {
ret i1 %r
}

; negative test - extra use (but we could try harder to fold this)

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
Expand All @@ -315,10 +330,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>
Expand Down

0 comments on commit 1ebad98

Please sign in to comment.