Skip to content

Commit

Permalink
[Reland][InstCombine] Fold icmp eq/ne min|max(X, Y), Z (#67087)
Browse files Browse the repository at this point in the history
This patch further improves the simplification of pattern `icmp eq/ne
min|max(X, Y), Z` as discussed in
[D156238](https://reviews.llvm.org/D156238).
When `X < Z`:
`min(X, Y) == Z -> false`
`min(X, Y) != Z -> true`
`max(X, Y) == Z -> Y == Z`
`max(Y, Z) != Z -> Y != Z`
When `X > Z`:
`max(X, Y) == Z -> false`
`max(X, Y) != Z -> true`
`min(X, Y) == Z -> Y == Z`
`min(Y, Z) != Z -> Y != Z`

Alive2:  https://alive2.llvm.org/ce/z/evkmaq
  • Loading branch information
dtcxzyw committed Sep 25, 2023
1 parent 7e5c267 commit 416e891
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 64 deletions.
48 changes: 35 additions & 13 deletions llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5022,6 +5022,12 @@ InstCombinerImpl::foldICmpWithMinMaxImpl(Instruction &I,
std::swap(CmpXZ, CmpYZ);
}

auto FoldIntoCmpYZ = [&]() -> Instruction * {
if (CmpYZ.has_value())
return replaceInstUsesWith(I, ConstantInt::getBool(I.getType(), *CmpYZ));
return ICmpInst::Create(Instruction::ICmp, Pred, Y, Z);
};

switch (Pred) {
case ICmpInst::ICMP_EQ:
case ICmpInst::ICMP_NE: {
Expand All @@ -5038,12 +5044,35 @@ InstCombinerImpl::foldICmpWithMinMaxImpl(Instruction &I,
NewPred = ICmpInst::getInversePredicate(NewPred);
return ICmpInst::Create(Instruction::ICmp, NewPred, X, Y);
}
// Otherwise (X != Z, nofold):
// Expr Result
// min(X, Y) == Z X > Y || Y == Z
// max(X, Y) == Z X < Y || Y == Z
// min(X, Y) != Z X <= Y && Y != Z
// max(X, Y) != Z X >= Y && Y != Z
// Otherwise (X != Z):
ICmpInst::Predicate NewPred = MinMax->getPredicate();
auto MinMaxCmpXZ = IsCondKnownTrue(simplifyICmpInst(NewPred, X, Z, Q));
if (!MinMaxCmpXZ.has_value()) {
std::swap(X, Y);
std::swap(CmpXZ, CmpYZ);
// Re-check pre-condition X != Z
if (!CmpXZ.has_value() || (Pred == ICmpInst::ICMP_EQ) == *CmpXZ)
break;
MinMaxCmpXZ = IsCondKnownTrue(simplifyICmpInst(NewPred, X, Z, Q));
}
if (!MinMaxCmpXZ.has_value())
break;
if (*MinMaxCmpXZ) {
// Expr Fact Result
// min(X, Y) == Z X < Z false
// max(X, Y) == Z X > Z false
// min(X, Y) != Z X < Z true
// max(X, Y) != Z X > Z true
return replaceInstUsesWith(
I, ConstantInt::getBool(I.getType(), Pred == ICmpInst::ICMP_NE));
} else {
// Expr Fact Result
// min(X, Y) == Z X > Z Y == Z
// max(X, Y) == Z X < Z Y == Z
// min(X, Y) != Z X > Z Y != Z
// max(X, Y) != Z X < Z Y != Z
return FoldIntoCmpYZ();
}
break;
}
case ICmpInst::ICMP_SLT:
Expand All @@ -5054,13 +5083,6 @@ InstCombinerImpl::foldICmpWithMinMaxImpl(Instruction &I,
case ICmpInst::ICMP_UGT:
case ICmpInst::ICMP_SGE:
case ICmpInst::ICMP_UGE: {
auto FoldIntoCmpYZ = [&]() -> Instruction * {
if (CmpYZ.has_value())
return replaceInstUsesWith(I,
ConstantInt::getBool(I.getType(), *CmpYZ));
return ICmpInst::Create(Instruction::ICmp, Pred, Y, Z);
};

bool IsSame = MinMax->getPredicate() == ICmpInst::getStrictPredicate(Pred);
if (*CmpXZ) {
if (IsSame) {
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Transforms/InstCombine/pr21199.ll
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ define void @test(i32 %len) {
; CHECK-LABEL: @test(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.umin.i32(i32 [[LEN:%.*]], i32 8)
; CHECK-NEXT: [[CMP11_NOT:%.*]] = icmp eq i32 [[COND]], 0
; CHECK-NEXT: [[CMP11_NOT:%.*]] = icmp eq i32 [[LEN]], 0
; CHECK-NEXT: br i1 [[CMP11_NOT]], label [[FOR_END:%.*]], label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_02:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]
Expand Down
20 changes: 8 additions & 12 deletions llvm/test/Transforms/InstCombine/smax-icmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -370,9 +370,9 @@ define void @slt_smax_contextual(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: ret void
; CHECK: end:
Expand Down Expand Up @@ -429,9 +429,9 @@ define void @slt_smax_contextual_commuted(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: ret void
; CHECK: end:
Expand Down Expand Up @@ -602,10 +602,8 @@ define void @sgt_smax_contextual(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: ret void
; CHECK: end:
; CHECK-NEXT: ret void
Expand Down Expand Up @@ -657,10 +655,8 @@ define void @sgt_smax_contextual_commuted(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: ret void
; CHECK: end:
; CHECK-NEXT: ret void
Expand Down
46 changes: 32 additions & 14 deletions llvm/test/Transforms/InstCombine/smin-icmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -465,10 +465,8 @@ define void @slt_smin_contextual(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: ret void
; CHECK: end:
; CHECK-NEXT: ret void
Expand Down Expand Up @@ -520,10 +518,8 @@ define void @slt_smin_contextual_commuted(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: ret void
; CHECK: end:
; CHECK-NEXT: ret void
Expand Down Expand Up @@ -693,9 +689,9 @@ define void @sgt_smin_contextual(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: ret void
; CHECK: end:
Expand Down Expand Up @@ -752,9 +748,9 @@ define void @sgt_smin_contextual_commuted(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: ret void
; CHECK: end:
Expand Down Expand Up @@ -1117,9 +1113,9 @@ define void @sgt_smin_v2i32_constant(<2 x i32> %y) {
; CHECK-NEXT: call void @use_v2i1(<2 x i1> [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp ugt <2 x i32> [[COND]], <i32 9, i32 9>
; CHECK-NEXT: call void @use_v2i1(<2 x i1> [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq <2 x i32> [[COND]], <i32 10, i32 10>
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq <2 x i32> [[Y]], <i32 10, i32 10>
; CHECK-NEXT: call void @use_v2i1(<2 x i1> [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne <2 x i32> [[COND]], <i32 10, i32 10>
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne <2 x i32> [[Y]], <i32 10, i32 10>
; CHECK-NEXT: call void @use_v2i1(<2 x i1> [[CMP10]])
; CHECK-NEXT: ret void
;
Expand Down Expand Up @@ -1275,5 +1271,27 @@ define i1 @smin_and_bitwise(i32 %x) {
ret i1 %tobool
}

; try to fold icmp eq smin(X, Y), Z
; pre-condition X != Z
; X < Z fail
; swap X and Y
; pre-condition Y != Z fail
; Y < Z fail
define i1 @eq_smin_nofold(i32 %x) {
; CHECK-LABEL: @eq_smin_nofold(
; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X:%.*]], 5
; CHECK-NEXT: call void @llvm.assume(i1 [[COND]])
; CHECK-NEXT: [[MINV:%.*]] = tail call i32 @llvm.smin.i32(i32 [[X]], i32 5)
; CHECK-NEXT: [[RET:%.*]] = icmp eq i32 [[MINV]], 5
; CHECK-NEXT: ret i1 [[RET]]
;
%cond = icmp ne i32 %x, 5
call void @llvm.assume(i1 %cond)
%minv = tail call i32 @llvm.smin.i32(i32 %x, i32 5)
%ret = icmp eq i32 %minv, 5
ret i1 %ret
}

declare void @llvm.assume(i1)
declare i32 @llvm.smin.i32(i32, i32)
declare <2 x i32> @llvm.smin.v2i32(<2 x i32>, <2 x i32>)
20 changes: 8 additions & 12 deletions llvm/test/Transforms/InstCombine/umax-icmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -370,9 +370,9 @@ define void @ult_umax_contextual(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: ret void
; CHECK: end:
Expand Down Expand Up @@ -429,9 +429,9 @@ define void @ult_umax_contextual_commuted(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: ret void
; CHECK: end:
Expand Down Expand Up @@ -602,10 +602,8 @@ define void @ugt_umax_contextual(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: ret void
; CHECK: end:
; CHECK-NEXT: ret void
Expand Down Expand Up @@ -657,10 +655,8 @@ define void @ugt_umax_contextual_commuted(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: ret void
; CHECK: end:
; CHECK-NEXT: ret void
Expand Down
20 changes: 8 additions & 12 deletions llvm/test/Transforms/InstCombine/umin-icmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,8 @@ define void @ult_umin_contextual(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: ret void
; CHECK: end:
; CHECK-NEXT: ret void
Expand Down Expand Up @@ -421,10 +419,8 @@ define void @ult_umin_contextual_commuted(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: ret void
; CHECK: end:
; CHECK-NEXT: ret void
Expand Down Expand Up @@ -594,9 +590,9 @@ define void @ugt_umin_contextual(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: ret void
; CHECK: end:
Expand Down Expand Up @@ -653,9 +649,9 @@ define void @ugt_umin_contextual_commuted(i32 %x, i32 %y, i32 %z) {
; CHECK-NEXT: call void @use(i1 [[CMP7]])
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP8]])
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP9]])
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
; CHECK-NEXT: call void @use(i1 [[CMP10]])
; CHECK-NEXT: ret void
; CHECK: end:
Expand Down

0 comments on commit 416e891

Please sign in to comment.