Skip to content

Commit d2abe8d

Browse files
authored
[InstCombine] Fold icmp eq/ne min|max(X, Y), Z (#67087)
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
1 parent dd8902a commit d2abe8d

File tree

6 files changed

+67
-64
lines changed

6 files changed

+67
-64
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5022,6 +5022,12 @@ InstCombinerImpl::foldICmpWithMinMaxImpl(Instruction &I,
50225022
std::swap(CmpXZ, CmpYZ);
50235023
}
50245024

5025+
auto FoldIntoCmpYZ = [&]() -> Instruction * {
5026+
if (CmpYZ.has_value())
5027+
return replaceInstUsesWith(I, ConstantInt::getBool(I.getType(), *CmpYZ));
5028+
return ICmpInst::Create(Instruction::ICmp, Pred, Y, Z);
5029+
};
5030+
50255031
switch (Pred) {
50265032
case ICmpInst::ICMP_EQ:
50275033
case ICmpInst::ICMP_NE: {
@@ -5038,12 +5044,32 @@ InstCombinerImpl::foldICmpWithMinMaxImpl(Instruction &I,
50385044
NewPred = ICmpInst::getInversePredicate(NewPred);
50395045
return ICmpInst::Create(Instruction::ICmp, NewPred, X, Y);
50405046
}
5041-
// Otherwise (X != Z, nofold):
5042-
// Expr Result
5043-
// min(X, Y) == Z X > Y || Y == Z
5044-
// max(X, Y) == Z X < Y || Y == Z
5045-
// min(X, Y) != Z X <= Y && Y != Z
5046-
// max(X, Y) != Z X >= Y && Y != Z
5047+
// Otherwise (X != Z):
5048+
ICmpInst::Predicate NewPred = MinMax->getPredicate();
5049+
auto MinMaxCmpXZ = IsCondKnownTrue(simplifyICmpInst(NewPred, X, Z, Q));
5050+
if (!MinMaxCmpXZ.has_value()) {
5051+
std::swap(X, Y);
5052+
std::swap(CmpXZ, CmpYZ);
5053+
MinMaxCmpXZ = IsCondKnownTrue(simplifyICmpInst(NewPred, X, Z, Q));
5054+
}
5055+
if (!MinMaxCmpXZ.has_value())
5056+
break;
5057+
if (*MinMaxCmpXZ) {
5058+
// Expr Fact Result
5059+
// min(X, Y) == Z X < Z false
5060+
// max(X, Y) == Z X > Z false
5061+
// min(X, Y) != Z X < Z true
5062+
// max(X, Y) != Z X > Z true
5063+
return replaceInstUsesWith(
5064+
I, ConstantInt::getBool(I.getType(), Pred == ICmpInst::ICMP_NE));
5065+
} else {
5066+
// Expr Fact Result
5067+
// min(X, Y) == Z X > Z Y == Z
5068+
// max(X, Y) == Z X < Z Y == Z
5069+
// min(X, Y) != Z X > Z Y != Z
5070+
// max(X, Y) != Z X < Z Y != Z
5071+
return FoldIntoCmpYZ();
5072+
}
50475073
break;
50485074
}
50495075
case ICmpInst::ICMP_SLT:
@@ -5054,13 +5080,6 @@ InstCombinerImpl::foldICmpWithMinMaxImpl(Instruction &I,
50545080
case ICmpInst::ICMP_UGT:
50555081
case ICmpInst::ICMP_SGE:
50565082
case ICmpInst::ICMP_UGE: {
5057-
auto FoldIntoCmpYZ = [&]() -> Instruction * {
5058-
if (CmpYZ.has_value())
5059-
return replaceInstUsesWith(I,
5060-
ConstantInt::getBool(I.getType(), *CmpYZ));
5061-
return ICmpInst::Create(Instruction::ICmp, Pred, Y, Z);
5062-
};
5063-
50645083
bool IsSame = MinMax->getPredicate() == ICmpInst::getStrictPredicate(Pred);
50655084
if (*CmpXZ) {
50665085
if (IsSame) {

llvm/test/Transforms/InstCombine/pr21199.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ define void @test(i32 %len) {
1010
; CHECK-LABEL: @test(
1111
; CHECK-NEXT: entry:
1212
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.umin.i32(i32 [[LEN:%.*]], i32 8)
13-
; CHECK-NEXT: [[CMP11_NOT:%.*]] = icmp eq i32 [[COND]], 0
13+
; CHECK-NEXT: [[CMP11_NOT:%.*]] = icmp eq i32 [[LEN]], 0
1414
; CHECK-NEXT: br i1 [[CMP11_NOT]], label [[FOR_END:%.*]], label [[FOR_BODY:%.*]]
1515
; CHECK: for.body:
1616
; CHECK-NEXT: [[I_02:%.*]] = phi i32 [ [[INC:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ]

llvm/test/Transforms/InstCombine/smax-icmp.ll

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -370,9 +370,9 @@ define void @slt_smax_contextual(i32 %x, i32 %y, i32 %z) {
370370
; CHECK-NEXT: call void @use(i1 [[CMP7]])
371371
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
372372
; CHECK-NEXT: call void @use(i1 [[CMP8]])
373-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
373+
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
374374
; CHECK-NEXT: call void @use(i1 [[CMP9]])
375-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
375+
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
376376
; CHECK-NEXT: call void @use(i1 [[CMP10]])
377377
; CHECK-NEXT: ret void
378378
; CHECK: end:
@@ -429,9 +429,9 @@ define void @slt_smax_contextual_commuted(i32 %x, i32 %y, i32 %z) {
429429
; CHECK-NEXT: call void @use(i1 [[CMP7]])
430430
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
431431
; CHECK-NEXT: call void @use(i1 [[CMP8]])
432-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
432+
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
433433
; CHECK-NEXT: call void @use(i1 [[CMP9]])
434-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
434+
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
435435
; CHECK-NEXT: call void @use(i1 [[CMP10]])
436436
; CHECK-NEXT: ret void
437437
; CHECK: end:
@@ -602,10 +602,8 @@ define void @sgt_smax_contextual(i32 %x, i32 %y, i32 %z) {
602602
; CHECK-NEXT: call void @use(i1 [[CMP7]])
603603
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
604604
; CHECK-NEXT: call void @use(i1 [[CMP8]])
605-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
606-
; CHECK-NEXT: call void @use(i1 [[CMP9]])
607-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
608-
; CHECK-NEXT: call void @use(i1 [[CMP10]])
605+
; CHECK-NEXT: call void @use(i1 false)
606+
; CHECK-NEXT: call void @use(i1 true)
609607
; CHECK-NEXT: ret void
610608
; CHECK: end:
611609
; CHECK-NEXT: ret void
@@ -657,10 +655,8 @@ define void @sgt_smax_contextual_commuted(i32 %x, i32 %y, i32 %z) {
657655
; CHECK-NEXT: call void @use(i1 [[CMP7]])
658656
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
659657
; CHECK-NEXT: call void @use(i1 [[CMP8]])
660-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
661-
; CHECK-NEXT: call void @use(i1 [[CMP9]])
662-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
663-
; CHECK-NEXT: call void @use(i1 [[CMP10]])
658+
; CHECK-NEXT: call void @use(i1 false)
659+
; CHECK-NEXT: call void @use(i1 true)
664660
; CHECK-NEXT: ret void
665661
; CHECK: end:
666662
; CHECK-NEXT: ret void

llvm/test/Transforms/InstCombine/smin-icmp.ll

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -465,10 +465,8 @@ define void @slt_smin_contextual(i32 %x, i32 %y, i32 %z) {
465465
; CHECK-NEXT: call void @use(i1 [[CMP7]])
466466
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
467467
; CHECK-NEXT: call void @use(i1 [[CMP8]])
468-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
469-
; CHECK-NEXT: call void @use(i1 [[CMP9]])
470-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
471-
; CHECK-NEXT: call void @use(i1 [[CMP10]])
468+
; CHECK-NEXT: call void @use(i1 false)
469+
; CHECK-NEXT: call void @use(i1 true)
472470
; CHECK-NEXT: ret void
473471
; CHECK: end:
474472
; CHECK-NEXT: ret void
@@ -520,10 +518,8 @@ define void @slt_smin_contextual_commuted(i32 %x, i32 %y, i32 %z) {
520518
; CHECK-NEXT: call void @use(i1 [[CMP7]])
521519
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
522520
; CHECK-NEXT: call void @use(i1 [[CMP8]])
523-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
524-
; CHECK-NEXT: call void @use(i1 [[CMP9]])
525-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
526-
; CHECK-NEXT: call void @use(i1 [[CMP10]])
521+
; CHECK-NEXT: call void @use(i1 false)
522+
; CHECK-NEXT: call void @use(i1 true)
527523
; CHECK-NEXT: ret void
528524
; CHECK: end:
529525
; CHECK-NEXT: ret void
@@ -693,9 +689,9 @@ define void @sgt_smin_contextual(i32 %x, i32 %y, i32 %z) {
693689
; CHECK-NEXT: call void @use(i1 [[CMP7]])
694690
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
695691
; CHECK-NEXT: call void @use(i1 [[CMP8]])
696-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
692+
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
697693
; CHECK-NEXT: call void @use(i1 [[CMP9]])
698-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
694+
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
699695
; CHECK-NEXT: call void @use(i1 [[CMP10]])
700696
; CHECK-NEXT: ret void
701697
; CHECK: end:
@@ -752,9 +748,9 @@ define void @sgt_smin_contextual_commuted(i32 %x, i32 %y, i32 %z) {
752748
; CHECK-NEXT: call void @use(i1 [[CMP7]])
753749
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[COND]], [[Z]]
754750
; CHECK-NEXT: call void @use(i1 [[CMP8]])
755-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
751+
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
756752
; CHECK-NEXT: call void @use(i1 [[CMP9]])
757-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
753+
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
758754
; CHECK-NEXT: call void @use(i1 [[CMP10]])
759755
; CHECK-NEXT: ret void
760756
; CHECK: end:
@@ -1117,9 +1113,9 @@ define void @sgt_smin_v2i32_constant(<2 x i32> %y) {
11171113
; CHECK-NEXT: call void @use_v2i1(<2 x i1> [[CMP7]])
11181114
; CHECK-NEXT: [[CMP8:%.*]] = icmp ugt <2 x i32> [[COND]], <i32 9, i32 9>
11191115
; CHECK-NEXT: call void @use_v2i1(<2 x i1> [[CMP8]])
1120-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq <2 x i32> [[COND]], <i32 10, i32 10>
1116+
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq <2 x i32> [[Y]], <i32 10, i32 10>
11211117
; CHECK-NEXT: call void @use_v2i1(<2 x i1> [[CMP9]])
1122-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne <2 x i32> [[COND]], <i32 10, i32 10>
1118+
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne <2 x i32> [[Y]], <i32 10, i32 10>
11231119
; CHECK-NEXT: call void @use_v2i1(<2 x i1> [[CMP10]])
11241120
; CHECK-NEXT: ret void
11251121
;

llvm/test/Transforms/InstCombine/umax-icmp.ll

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -370,9 +370,9 @@ define void @ult_umax_contextual(i32 %x, i32 %y, i32 %z) {
370370
; CHECK-NEXT: call void @use(i1 [[CMP7]])
371371
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[Y]], [[Z]]
372372
; CHECK-NEXT: call void @use(i1 [[CMP8]])
373-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
373+
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
374374
; CHECK-NEXT: call void @use(i1 [[CMP9]])
375-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
375+
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
376376
; CHECK-NEXT: call void @use(i1 [[CMP10]])
377377
; CHECK-NEXT: ret void
378378
; CHECK: end:
@@ -429,9 +429,9 @@ define void @ult_umax_contextual_commuted(i32 %x, i32 %y, i32 %z) {
429429
; CHECK-NEXT: call void @use(i1 [[CMP7]])
430430
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[Y]], [[Z]]
431431
; CHECK-NEXT: call void @use(i1 [[CMP8]])
432-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
432+
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
433433
; CHECK-NEXT: call void @use(i1 [[CMP9]])
434-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
434+
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
435435
; CHECK-NEXT: call void @use(i1 [[CMP10]])
436436
; CHECK-NEXT: ret void
437437
; CHECK: end:
@@ -602,10 +602,8 @@ define void @ugt_umax_contextual(i32 %x, i32 %y, i32 %z) {
602602
; CHECK-NEXT: call void @use(i1 false)
603603
; CHECK-NEXT: call void @use(i1 true)
604604
; CHECK-NEXT: call void @use(i1 true)
605-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
606-
; CHECK-NEXT: call void @use(i1 [[CMP9]])
607-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
608-
; CHECK-NEXT: call void @use(i1 [[CMP10]])
605+
; CHECK-NEXT: call void @use(i1 false)
606+
; CHECK-NEXT: call void @use(i1 true)
609607
; CHECK-NEXT: ret void
610608
; CHECK: end:
611609
; CHECK-NEXT: ret void
@@ -657,10 +655,8 @@ define void @ugt_umax_contextual_commuted(i32 %x, i32 %y, i32 %z) {
657655
; CHECK-NEXT: call void @use(i1 false)
658656
; CHECK-NEXT: call void @use(i1 true)
659657
; CHECK-NEXT: call void @use(i1 true)
660-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
661-
; CHECK-NEXT: call void @use(i1 [[CMP9]])
662-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
663-
; CHECK-NEXT: call void @use(i1 [[CMP10]])
658+
; CHECK-NEXT: call void @use(i1 false)
659+
; CHECK-NEXT: call void @use(i1 true)
664660
; CHECK-NEXT: ret void
665661
; CHECK: end:
666662
; CHECK-NEXT: ret void

llvm/test/Transforms/InstCombine/umin-icmp.ll

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -366,10 +366,8 @@ define void @ult_umin_contextual(i32 %x, i32 %y, i32 %z) {
366366
; CHECK-NEXT: call void @use(i1 true)
367367
; CHECK-NEXT: call void @use(i1 false)
368368
; CHECK-NEXT: call void @use(i1 false)
369-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
370-
; CHECK-NEXT: call void @use(i1 [[CMP9]])
371-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
372-
; CHECK-NEXT: call void @use(i1 [[CMP10]])
369+
; CHECK-NEXT: call void @use(i1 false)
370+
; CHECK-NEXT: call void @use(i1 true)
373371
; CHECK-NEXT: ret void
374372
; CHECK: end:
375373
; CHECK-NEXT: ret void
@@ -421,10 +419,8 @@ define void @ult_umin_contextual_commuted(i32 %x, i32 %y, i32 %z) {
421419
; CHECK-NEXT: call void @use(i1 true)
422420
; CHECK-NEXT: call void @use(i1 false)
423421
; CHECK-NEXT: call void @use(i1 false)
424-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
425-
; CHECK-NEXT: call void @use(i1 [[CMP9]])
426-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
427-
; CHECK-NEXT: call void @use(i1 [[CMP10]])
422+
; CHECK-NEXT: call void @use(i1 false)
423+
; CHECK-NEXT: call void @use(i1 true)
428424
; CHECK-NEXT: ret void
429425
; CHECK: end:
430426
; CHECK-NEXT: ret void
@@ -594,9 +590,9 @@ define void @ugt_umin_contextual(i32 %x, i32 %y, i32 %z) {
594590
; CHECK-NEXT: call void @use(i1 [[CMP7]])
595591
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[Y]], [[Z]]
596592
; CHECK-NEXT: call void @use(i1 [[CMP8]])
597-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
593+
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
598594
; CHECK-NEXT: call void @use(i1 [[CMP9]])
599-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
595+
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
600596
; CHECK-NEXT: call void @use(i1 [[CMP10]])
601597
; CHECK-NEXT: ret void
602598
; CHECK: end:
@@ -653,9 +649,9 @@ define void @ugt_umin_contextual_commuted(i32 %x, i32 %y, i32 %z) {
653649
; CHECK-NEXT: call void @use(i1 [[CMP7]])
654650
; CHECK-NEXT: [[CMP8:%.*]] = icmp uge i32 [[Y]], [[Z]]
655651
; CHECK-NEXT: call void @use(i1 [[CMP8]])
656-
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[COND]], [[Z]]
652+
; CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[Y]], [[Z]]
657653
; CHECK-NEXT: call void @use(i1 [[CMP9]])
658-
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[COND]], [[Z]]
654+
; CHECK-NEXT: [[CMP10:%.*]] = icmp ne i32 [[Y]], [[Z]]
659655
; CHECK-NEXT: call void @use(i1 [[CMP10]])
660656
; CHECK-NEXT: ret void
661657
; CHECK: end:

0 commit comments

Comments
 (0)