diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index a219dac7acfbe..9aea16b80fef9 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -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: { @@ -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: @@ -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) { diff --git a/llvm/test/Transforms/InstCombine/pr21199.ll b/llvm/test/Transforms/InstCombine/pr21199.ll index 54389768f1f9b..7c31638f369fa 100644 --- a/llvm/test/Transforms/InstCombine/pr21199.ll +++ b/llvm/test/Transforms/InstCombine/pr21199.ll @@ -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:%.*]] ] diff --git a/llvm/test/Transforms/InstCombine/smax-icmp.ll b/llvm/test/Transforms/InstCombine/smax-icmp.ll index f8df92d5470e1..0ccbef34889fd 100644 --- a/llvm/test/Transforms/InstCombine/smax-icmp.ll +++ b/llvm/test/Transforms/InstCombine/smax-icmp.ll @@ -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: @@ -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: @@ -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 @@ -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 diff --git a/llvm/test/Transforms/InstCombine/smin-icmp.ll b/llvm/test/Transforms/InstCombine/smin-icmp.ll index 244dad451022e..c97f29f5eff8d 100644 --- a/llvm/test/Transforms/InstCombine/smin-icmp.ll +++ b/llvm/test/Transforms/InstCombine/smin-icmp.ll @@ -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 @@ -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 @@ -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: @@ -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: @@ -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]], ; CHECK-NEXT: call void @use_v2i1(<2 x i1> [[CMP8]]) -; CHECK-NEXT: [[CMP9:%.*]] = icmp eq <2 x i32> [[COND]], +; CHECK-NEXT: [[CMP9:%.*]] = icmp eq <2 x i32> [[Y]], ; CHECK-NEXT: call void @use_v2i1(<2 x i1> [[CMP9]]) -; CHECK-NEXT: [[CMP10:%.*]] = icmp ne <2 x i32> [[COND]], +; CHECK-NEXT: [[CMP10:%.*]] = icmp ne <2 x i32> [[Y]], ; CHECK-NEXT: call void @use_v2i1(<2 x i1> [[CMP10]]) ; CHECK-NEXT: ret void ; @@ -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>) diff --git a/llvm/test/Transforms/InstCombine/umax-icmp.ll b/llvm/test/Transforms/InstCombine/umax-icmp.ll index d6706374c4989..9946f3c390f0f 100644 --- a/llvm/test/Transforms/InstCombine/umax-icmp.ll +++ b/llvm/test/Transforms/InstCombine/umax-icmp.ll @@ -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: @@ -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: @@ -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 @@ -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 diff --git a/llvm/test/Transforms/InstCombine/umin-icmp.ll b/llvm/test/Transforms/InstCombine/umin-icmp.ll index 88a391bf18ca1..da901c6c5e484 100644 --- a/llvm/test/Transforms/InstCombine/umin-icmp.ll +++ b/llvm/test/Transforms/InstCombine/umin-icmp.ll @@ -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 @@ -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 @@ -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: @@ -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: