Skip to content

Commit 8c77191

Browse files
authored
[InstCombine] smin(smax(X, -1), 1) -> scmp(X, 0) and smax(smin(X, 1), -1) -> scmp(X, 0) (#145736)
Motivating case: https://godbolt.org/z/Wxcc51jcj Alive2: https://alive2.llvm.org/ce/z/-bPPAg
1 parent 10445ac commit 8c77191

File tree

2 files changed

+108
-21
lines changed

2 files changed

+108
-21
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,6 +1967,21 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
19671967
return BinaryOperator::CreateOr(I0, I1);
19681968
}
19691969

1970+
// smin(smax(X, -1), 1) -> scmp(X, 0)
1971+
// smax(smin(X, 1), -1) -> scmp(X, 0)
1972+
// At this point, smax(smin(X, 1), -1) is changed to smin(smax(X, -1)
1973+
// And i1's have been changed to and/ors
1974+
// So we only need to check for smin
1975+
if (IID == Intrinsic::smin) {
1976+
if (match(I0, m_OneUse(m_SMax(m_Value(X), m_AllOnes()))) &&
1977+
match(I1, m_One())) {
1978+
Value *Zero = ConstantInt::get(X->getType(), 0);
1979+
return replaceInstUsesWith(
1980+
CI,
1981+
Builder.CreateIntrinsic(II->getType(), Intrinsic::scmp, {X, Zero}));
1982+
}
1983+
}
1984+
19701985
if (IID == Intrinsic::smax || IID == Intrinsic::smin) {
19711986
// smax (neg nsw X), (neg nsw Y) --> neg nsw (smin X, Y)
19721987
// smin (neg nsw X), (neg nsw Y) --> neg nsw (smax X, Y)

llvm/test/Transforms/InstCombine/compare-3way.ll

Lines changed: 93 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
declare void @use(i32)
55

6-
; These 18 exercise all combinations of signed comparison
6+
; These exercise all combinations of signed comparison
77
; for each of the three values produced by your typical
88
; 3way compare function (-1, 0, 1)
99

@@ -81,8 +81,8 @@ unreached:
8181
define void @test_low_sle(i64 %a, i64 %b) {
8282
; CHECK-LABEL: define void @test_low_sle
8383
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
84-
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]]
85-
; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
84+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[A]], [[B]]
85+
; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
8686
; CHECK: normal:
8787
; CHECK-NEXT: ret void
8888
; CHECK: unreached:
@@ -105,8 +105,8 @@ unreached:
105105
define void @test_low_ne(i64 %a, i64 %b) {
106106
; CHECK-LABEL: define void @test_low_ne
107107
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
108-
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]]
109-
; CHECK-NEXT: br i1 [[TMP1]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
108+
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp slt i64 [[A]], [[B]]
109+
; CHECK-NEXT: br i1 [[CMP_NOT]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
110110
; CHECK: normal:
111111
; CHECK-NEXT: ret void
112112
; CHECK: unreached:
@@ -130,8 +130,8 @@ unreached:
130130
define void @test_low_eq(i64 %a, i64 %b) {
131131
; CHECK-LABEL: define void @test_low_eq
132132
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
133-
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]]
134-
; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
133+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[A]], [[B]]
134+
; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
135135
; CHECK: normal:
136136
; CHECK-NEXT: ret void
137137
; CHECK: unreached:
@@ -154,8 +154,8 @@ unreached:
154154
define void @test_mid_sgt(i64 %a, i64 %b) {
155155
; CHECK-LABEL: define void @test_mid_sgt
156156
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
157-
; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]]
158-
; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
157+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[A]], [[B]]
158+
; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
159159
; CHECK: normal:
160160
; CHECK-NEXT: ret void
161161
; CHECK: unreached:
@@ -178,8 +178,8 @@ unreached:
178178
define void @test_mid_slt(i64 %a, i64 %b) {
179179
; CHECK-LABEL: define void @test_mid_slt
180180
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
181-
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]]
182-
; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
181+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[A]], [[B]]
182+
; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
183183
; CHECK: normal:
184184
; CHECK-NEXT: ret void
185185
; CHECK: unreached:
@@ -252,8 +252,8 @@ unreached:
252252
define void @test_mid_ne(i64 %a, i64 %b) {
253253
; CHECK-LABEL: define void @test_mid_ne
254254
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
255-
; CHECK-NEXT: [[EQ:%.*]] = icmp eq i64 [[A]], [[B]]
256-
; CHECK-NEXT: br i1 [[EQ]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
255+
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i64 [[A]], [[B]]
256+
; CHECK-NEXT: br i1 [[CMP_NOT]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
257257
; CHECK: normal:
258258
; CHECK-NEXT: ret void
259259
; CHECK: unreached:
@@ -277,8 +277,8 @@ unreached:
277277
define void @test_mid_eq(i64 %a, i64 %b) {
278278
; CHECK-LABEL: define void @test_mid_eq
279279
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
280-
; CHECK-NEXT: [[EQ:%.*]] = icmp eq i64 [[A]], [[B]]
281-
; CHECK-NEXT: br i1 [[EQ]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
280+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[A]], [[B]]
281+
; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
282282
; CHECK: normal:
283283
; CHECK-NEXT: ret void
284284
; CHECK: unreached:
@@ -348,8 +348,8 @@ unreached:
348348
define void @test_high_sge(i64 %a, i64 %b) {
349349
; CHECK-LABEL: define void @test_high_sge
350350
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
351-
; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]]
352-
; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
351+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[A]], [[B]]
352+
; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
353353
; CHECK: normal:
354354
; CHECK-NEXT: ret void
355355
; CHECK: unreached:
@@ -396,8 +396,8 @@ unreached:
396396
define void @test_high_ne(i64 %a, i64 %b) {
397397
; CHECK-LABEL: define void @test_high_ne
398398
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
399-
; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]]
400-
; CHECK-NEXT: br i1 [[TMP1]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
399+
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sgt i64 [[A]], [[B]]
400+
; CHECK-NEXT: br i1 [[CMP_NOT]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
401401
; CHECK: normal:
402402
; CHECK-NEXT: ret void
403403
; CHECK: unreached:
@@ -421,8 +421,8 @@ unreached:
421421
define void @test_high_eq(i64 %a, i64 %b) {
422422
; CHECK-LABEL: define void @test_high_eq
423423
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
424-
; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]]
425-
; CHECK-NEXT: br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
424+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[A]], [[B]]
425+
; CHECK-NEXT: br i1 [[CMP]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
426426
; CHECK: normal:
427427
; CHECK-NEXT: ret void
428428
; CHECK: unreached:
@@ -560,3 +560,75 @@ unreached:
560560
call void @use(i32 %result)
561561
ret void
562562
}
563+
564+
define i32 @smax_smin_to_scmp(i32 %x) {
565+
; CHECK-LABEL: define i32 @smax_smin_to_scmp
566+
; CHECK-SAME: (i32 [[X:%.*]]) {
567+
; CHECK-NEXT: [[COND5:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 0)
568+
; CHECK-NEXT: ret i32 [[COND5]]
569+
;
570+
%cond = call i32 @llvm.smax.i32(i32 %x, i32 -1)
571+
%cond5 = call i32 @llvm.smin.i32(i32 %cond, i32 1)
572+
ret i32 %cond5
573+
}
574+
575+
define i16 @smax_smin_to_scmp_i16(i16 %x) {
576+
; CHECK-LABEL: define i16 @smax_smin_to_scmp_i16
577+
; CHECK-SAME: (i16 [[X:%.*]]) {
578+
; CHECK-NEXT: [[COND5:%.*]] = call i16 @llvm.scmp.i16.i16(i16 [[X]], i16 0)
579+
; CHECK-NEXT: ret i16 [[COND5]]
580+
;
581+
%cond = call i16 @llvm.smax.i16(i16 %x, i16 -1)
582+
%cond5 = call i16 @llvm.smin.i16(i16 %cond, i16 1)
583+
ret i16 %cond5
584+
}
585+
586+
; Test the reversed pattern: smax(smin(X, 1), -1) -> scmp(X, 0)
587+
define i32 @smin_smax_to_scmp(i32 %x) {
588+
; CHECK-LABEL: define i32 @smin_smax_to_scmp
589+
; CHECK-SAME: (i32 [[X:%.*]]) {
590+
; CHECK-NEXT: [[COND5:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 0)
591+
; CHECK-NEXT: ret i32 [[COND5]]
592+
;
593+
%cond = call i32 @llvm.smin.i32(i32 %x, i32 1)
594+
%cond5 = call i32 @llvm.smax.i32(i32 %cond, i32 -1)
595+
ret i32 %cond5
596+
}
597+
598+
define i32 @test_max_min_neg(i32 %x) {
599+
; CHECK-LABEL: define i32 @test_max_min_neg
600+
; CHECK-SAME: (i32 [[X:%.*]]) {
601+
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smax.i32(i32 [[X]], i32 -2)
602+
; CHECK-NEXT: [[COND5:%.*]] = call i32 @llvm.smin.i32(i32 [[COND]], i32 1)
603+
; CHECK-NEXT: ret i32 [[COND5]]
604+
;
605+
%cond = call i32 @llvm.smax.i32(i32 %x, i32 -2)
606+
%cond5 = call i32 @llvm.smin.i32(i32 %cond, i32 1)
607+
ret i32 %cond5
608+
}
609+
610+
define i32 @test_max_min_neg_2(i32 %x) {
611+
; CHECK-LABEL: define i32 @test_max_min_neg_2
612+
; CHECK-SAME: (i32 [[X:%.*]]) {
613+
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smax.i32(i32 [[X]], i32 -1)
614+
; CHECK-NEXT: [[COND5:%.*]] = call i32 @llvm.smin.i32(i32 [[COND]], i32 2)
615+
; CHECK-NEXT: ret i32 [[COND5]]
616+
;
617+
%cond = call i32 @llvm.smax.i32(i32 %x, i32 -1)
618+
%cond5 = call i32 @llvm.smin.i32(i32 %cond, i32 2)
619+
ret i32 %cond5
620+
}
621+
622+
define i32 @test_multiple_uses(i32 %x) {
623+
; CHECK-LABEL: define i32 @test_multiple_uses
624+
; CHECK-SAME: (i32 [[X:%.*]]) {
625+
; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.smax.i32(i32 [[X]], i32 -1)
626+
; CHECK-NEXT: [[COND5:%.*]] = call i32 @llvm.smin.i32(i32 [[COND]], i32 1)
627+
; CHECK-NEXT: [[SUM:%.*]] = add i32 [[COND]], [[COND5]]
628+
; CHECK-NEXT: ret i32 [[SUM]]
629+
;
630+
%cond = call i32 @llvm.smax.i32(i32 %x, i32 -1)
631+
%cond5 = call i32 @llvm.smin.i32(i32 %cond, i32 1)
632+
%sum = add i32 %cond, %cond5
633+
ret i32 %sum
634+
}

0 commit comments

Comments
 (0)