[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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user