diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index b6ed1dc4331d2..1920ee9e4c1aa 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1972,6 +1972,21 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { return BinaryOperator::CreateOr(I0, I1); } + // smin(smax(X, -1), 1) -> scmp(X, 0) + // smax(smin(X, 1), -1) -> scmp(X, 0) + // At this point, smax(smin(X, 1), -1) is changed to smin(smax(X, -1) + // And i1's have been changed to and/ors + // So we only need to check for smin + if (IID == Intrinsic::smin) { + if (match(I0, m_OneUse(m_SMax(m_Value(X), m_AllOnes()))) && + match(I1, m_One())) { + Value *Zero = ConstantInt::get(X->getType(), 0); + return replaceInstUsesWith( + CI, + Builder.CreateIntrinsic(II->getType(), Intrinsic::scmp, {X, Zero})); + } + } + if (IID == Intrinsic::smax || IID == Intrinsic::smin) { // smax (neg nsw X), (neg nsw Y) --> neg nsw (smin X, Y) // smin (neg nsw X), (neg nsw Y) --> neg nsw (smax X, Y) diff --git a/llvm/test/Transforms/InstCombine/compare-3way.ll b/llvm/test/Transforms/InstCombine/compare-3way.ll index 5d443cd45238c..f5bbe0c9efd28 100644 --- a/llvm/test/Transforms/InstCombine/compare-3way.ll +++ b/llvm/test/Transforms/InstCombine/compare-3way.ll @@ -3,7 +3,7 @@ declare void @use(i32) -; These 18 exercise all combinations of signed comparison +; These exercise all combinations of signed comparison ; for each of the three values produced by your typical ; 3way compare function (-1, 0, 1) @@ -81,8 +81,8 @@ unreached: define void @test_low_sle(i64 %a, i64 %b) { ; CHECK-LABEL: define void @test_low_sle ; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]] -; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[A]], [[B]] +; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] ; CHECK: normal: ; CHECK-NEXT: ret void ; CHECK: unreached: @@ -105,8 +105,8 @@ unreached: define void @test_low_ne(i64 %a, i64 %b) { ; CHECK-LABEL: define void @test_low_ne ; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]] -; CHECK-NEXT: br i1 [[TMP1]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]] +; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp slt i64 [[A]], [[B]] +; CHECK-NEXT: br i1 [[CMP_NOT]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]] ; CHECK: normal: ; CHECK-NEXT: ret void ; CHECK: unreached: @@ -130,8 +130,8 @@ unreached: define void @test_low_eq(i64 %a, i64 %b) { ; CHECK-LABEL: define void @test_low_eq ; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]] -; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[A]], [[B]] +; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] ; CHECK: normal: ; CHECK-NEXT: ret void ; CHECK: unreached: @@ -154,8 +154,8 @@ unreached: define void @test_mid_sgt(i64 %a, i64 %b) { ; CHECK-LABEL: define void @test_mid_sgt ; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]] -; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[A]], [[B]] +; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] ; CHECK: normal: ; CHECK-NEXT: ret void ; CHECK: unreached: @@ -178,8 +178,8 @@ unreached: define void @test_mid_slt(i64 %a, i64 %b) { ; CHECK-LABEL: define void @test_mid_slt ; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]] -; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[A]], [[B]] +; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] ; CHECK: normal: ; CHECK-NEXT: ret void ; CHECK: unreached: @@ -252,8 +252,8 @@ unreached: define void @test_mid_ne(i64 %a, i64 %b) { ; CHECK-LABEL: define void @test_mid_ne ; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) { -; CHECK-NEXT: [[EQ:%.*]] = icmp eq i64 [[A]], [[B]] -; CHECK-NEXT: br i1 [[EQ]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]] +; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i64 [[A]], [[B]] +; CHECK-NEXT: br i1 [[CMP_NOT]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]] ; CHECK: normal: ; CHECK-NEXT: ret void ; CHECK: unreached: @@ -277,8 +277,8 @@ unreached: define void @test_mid_eq(i64 %a, i64 %b) { ; CHECK-LABEL: define void @test_mid_eq ; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) { -; CHECK-NEXT: [[EQ:%.*]] = icmp eq i64 [[A]], [[B]] -; CHECK-NEXT: br i1 [[EQ]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[A]], [[B]] +; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] ; CHECK: normal: ; CHECK-NEXT: ret void ; CHECK: unreached: @@ -348,8 +348,8 @@ unreached: define void @test_high_sge(i64 %a, i64 %b) { ; CHECK-LABEL: define void @test_high_sge ; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]] -; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[A]], [[B]] +; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] ; CHECK: normal: ; CHECK-NEXT: ret void ; CHECK: unreached: @@ -396,8 +396,8 @@ unreached: define void @test_high_ne(i64 %a, i64 %b) { ; CHECK-LABEL: define void @test_high_ne ; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]] -; CHECK-NEXT: br i1 [[TMP1]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]] +; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sgt i64 [[A]], [[B]] +; CHECK-NEXT: br i1 [[CMP_NOT]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]] ; CHECK: normal: ; CHECK-NEXT: ret void ; CHECK: unreached: @@ -421,8 +421,8 @@ unreached: define void @test_high_eq(i64 %a, i64 %b) { ; CHECK-LABEL: define void @test_high_eq ; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]] -; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[A]], [[B]] +; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]] ; CHECK: normal: ; CHECK-NEXT: ret void ; CHECK: unreached: @@ -560,3 +560,75 @@ unreached: call void @use(i32 %result) ret void } + +define i32 @smax_smin_to_scmp(i32 %x) { +; CHECK-LABEL: define i32 @smax_smin_to_scmp +; CHECK-SAME: (i32 [[X:%.*]]) { +; CHECK-NEXT: [[COND5:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 0) +; CHECK-NEXT: ret i32 [[COND5]] +; + %cond = call i32 @llvm.smax.i32(i32 %x, i32 -1) + %cond5 = call i32 @llvm.smin.i32(i32 %cond, i32 1) + ret i32 %cond5 +} + +define i16 @smax_smin_to_scmp_i16(i16 %x) { +; CHECK-LABEL: define i16 @smax_smin_to_scmp_i16 +; CHECK-SAME: (i16 [[X:%.*]]) { +; CHECK-NEXT: [[COND5:%.*]] = call i16 @llvm.scmp.i16.i16(i16 [[X]], i16 0) +; CHECK-NEXT: ret i16 [[COND5]] +; + %cond = call i16 @llvm.smax.i16(i16 %x, i16 -1) + %cond5 = call i16 @llvm.smin.i16(i16 %cond, i16 1) + ret i16 %cond5 +} + +; Test the reversed pattern: smax(smin(X, 1), -1) -> scmp(X, 0) +define i32 @smin_smax_to_scmp(i32 %x) { +; CHECK-LABEL: define i32 @smin_smax_to_scmp +; CHECK-SAME: (i32 [[X:%.*]]) { +; CHECK-NEXT: [[COND5:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 0) +; CHECK-NEXT: ret i32 [[COND5]] +; + %cond = call i32 @llvm.smin.i32(i32 %x, i32 1) + %cond5 = call i32 @llvm.smax.i32(i32 %cond, i32 -1) + ret i32 %cond5 +} + +define i32 @test_max_min_neg(i32 %x) { +; CHECK-LABEL: define i32 @test_max_min_neg +; CHECK-SAME: (i32 [[X:%.*]]) { +; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smax.i32(i32 [[X]], i32 -2) +; CHECK-NEXT: [[COND5:%.*]] = call i32 @llvm.smin.i32(i32 [[COND]], i32 1) +; CHECK-NEXT: ret i32 [[COND5]] +; + %cond = call i32 @llvm.smax.i32(i32 %x, i32 -2) + %cond5 = call i32 @llvm.smin.i32(i32 %cond, i32 1) + ret i32 %cond5 +} + +define i32 @test_max_min_neg_2(i32 %x) { +; CHECK-LABEL: define i32 @test_max_min_neg_2 +; CHECK-SAME: (i32 [[X:%.*]]) { +; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smax.i32(i32 [[X]], i32 -1) +; CHECK-NEXT: [[COND5:%.*]] = call i32 @llvm.smin.i32(i32 [[COND]], i32 2) +; CHECK-NEXT: ret i32 [[COND5]] +; + %cond = call i32 @llvm.smax.i32(i32 %x, i32 -1) + %cond5 = call i32 @llvm.smin.i32(i32 %cond, i32 2) + ret i32 %cond5 +} + +define i32 @test_multiple_uses(i32 %x) { +; CHECK-LABEL: define i32 @test_multiple_uses +; CHECK-SAME: (i32 [[X:%.*]]) { +; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smax.i32(i32 [[X]], i32 -1) +; CHECK-NEXT: [[COND5:%.*]] = call i32 @llvm.smin.i32(i32 [[COND]], i32 1) +; CHECK-NEXT: [[SUM:%.*]] = add i32 [[COND]], [[COND5]] +; CHECK-NEXT: ret i32 [[SUM]] +; + %cond = call i32 @llvm.smax.i32(i32 %x, i32 -1) + %cond5 = call i32 @llvm.smin.i32(i32 %cond, i32 1) + %sum = add i32 %cond, %cond5 + ret i32 %sum +}