Skip to content

Commit ed285b0

Browse files
committed
[InstCombine] Canonicalize smax(smin(X, MinC), MaxC) -> smin(smax(X, MaxC), MinC)
1 parent 11f4f53 commit ed285b0

File tree

8 files changed

+111
-78
lines changed

8 files changed

+111
-78
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,40 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
19241924
}
19251925
}
19261926

1927+
// Canonicalize smax(smin(X, MinC), MaxC) to smin(smax(X, MaxC), MinC)
1928+
// if MinC s>= MaxC.
1929+
if (IID == Intrinsic::smax) {
1930+
Constant *MinC, *MaxC;
1931+
if (match(I0, m_OneUse(m_Intrinsic<Intrinsic::smin>(
1932+
m_Value(X), m_ImmConstant(MinC)))) &&
1933+
match(I1, m_ImmConstant(MaxC))) {
1934+
1935+
bool MinSgeMax = false;
1936+
1937+
ConstantInt *MinCI = dyn_cast<ConstantInt>(MinC);
1938+
ConstantInt *MaxCI = dyn_cast<ConstantInt>(MaxC);
1939+
if (MinCI && MaxCI && MinCI->getValue().sge(MaxCI->getValue())) {
1940+
MinSgeMax = true;
1941+
} else if (MinC->getType()->isVectorTy()) {
1942+
ConstantInt *MinSplat =
1943+
dyn_cast_or_null<ConstantInt>(MinC->getSplatValue());
1944+
ConstantInt *MaxSplat =
1945+
dyn_cast_or_null<ConstantInt>(MaxC->getSplatValue());
1946+
if (MinSplat && MaxSplat &&
1947+
MinSplat->getValue().sge(MaxSplat->getValue())) {
1948+
MinSgeMax = true;
1949+
}
1950+
}
1951+
1952+
if (MinSgeMax) {
1953+
Value *NewSMax =
1954+
Builder.CreateBinaryIntrinsic(Intrinsic::smax, X, MaxC);
1955+
return replaceInstUsesWith(*II, Builder.CreateBinaryIntrinsic(
1956+
Intrinsic::smin, NewSMax, MinC));
1957+
}
1958+
}
1959+
}
1960+
19271961
// umin(i1 X, i1 Y) -> and i1 X, Y
19281962
// smax(i1 X, i1 Y) -> and i1 X, Y
19291963
if ((IID == Intrinsic::umin || IID == Intrinsic::smax) &&

llvm/test/Transforms/InstCombine/clamp-to-minmax.ll

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ define float @clamp_float_fast_unordered_strict_maxmin(float %x) {
8383
; (X <= C1) ? C1 : MIN(X, C2)
8484
define float @clamp_float_fast_unordered_nonstrict_maxmin(float %x) {
8585
; CHECK-LABEL: @clamp_float_fast_unordered_nonstrict_maxmin(
86-
; CHECK-NEXT: [[MIN:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 2.550000e+02)
86+
; CHECK-NEXT: [[MIN:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 2.550000e+02)
8787
; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast ule float [[X]], 1.000000e+00
8888
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
8989
; CHECK-NEXT: ret float [[R]]
@@ -98,7 +98,7 @@ define float @clamp_float_fast_unordered_nonstrict_maxmin(float %x) {
9898
; (X > C1) ? C1 : MAX(X, C2)
9999
define float @clamp_float_fast_unordered_strict_minmax(float %x) {
100100
; CHECK-LABEL: @clamp_float_fast_unordered_strict_minmax(
101-
; CHECK-NEXT: [[MAX:%.*]] = call fast float @llvm.maxnum.f32(float [[X:%.*]], float 1.000000e+00)
101+
; CHECK-NEXT: [[MAX:%.*]] = call fast float @llvm.maxnum.f32(float [[X:%.*]], float 1.000000e+00)
102102
; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast ugt float [[X]], 2.550000e+02
103103
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
104104
; CHECK-NEXT: ret float [[R]]
@@ -113,7 +113,7 @@ define float @clamp_float_fast_unordered_strict_minmax(float %x) {
113113
; (X >= C1) ? C1 : MAX(X, C2)
114114
define float @clamp_float_fast_unordered_nonstrict_minmax(float %x) {
115115
; CHECK-LABEL: @clamp_float_fast_unordered_nonstrict_minmax(
116-
; CHECK-NEXT: [[MAX:%.*]] = call fast float @llvm.maxnum.f32(float [[X:%.*]], float 1.000000e+00)
116+
; CHECK-NEXT: [[MAX:%.*]] = call fast float @llvm.maxnum.f32(float [[X:%.*]], float 1.000000e+00)
117117
; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast uge float [[X]], 2.550000e+02
118118
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
119119
; CHECK-NEXT: ret float [[R]]
@@ -147,7 +147,7 @@ define float @clamp_test_1(float %x) {
147147
; Like @clamp_test_1 but HighConst < LowConst
148148
define float @clamp_negative_wrong_const(float %x) {
149149
; CHECK-LABEL: @clamp_negative_wrong_const(
150-
; CHECK-NEXT: [[INNER_SEL:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 2.550000e+02)
150+
; CHECK-NEXT: [[INNER_SEL:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 2.550000e+02)
151151
; CHECK-NEXT: [[OUTER_CMP:%.*]] = fcmp fast ugt float [[X]], 5.120000e+02
152152
; CHECK-NEXT: [[R:%.*]] = select i1 [[OUTER_CMP]], float [[INNER_SEL]], float 5.120000e+02
153153
; CHECK-NEXT: ret float [[R]]
@@ -162,7 +162,7 @@ define float @clamp_negative_wrong_const(float %x) {
162162
; Like @clamp_test_1 but both are min
163163
define float @clamp_negative_same_op(float %x) {
164164
; CHECK-LABEL: @clamp_negative_same_op(
165-
; CHECK-NEXT: [[INNER_SEL:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 2.550000e+02)
165+
; CHECK-NEXT: [[INNER_SEL:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 2.550000e+02)
166166
; CHECK-NEXT: [[OUTER_CMP:%.*]] = fcmp fast ult float [[X]], 1.000000e+00
167167
; CHECK-NEXT: [[R:%.*]] = select i1 [[OUTER_CMP]], float [[INNER_SEL]], float 1.000000e+00
168168
; CHECK-NEXT: ret float [[R]]
@@ -500,9 +500,9 @@ define float @ui64_clamp_and_cast_to_float(i64 %x) {
500500

501501
define float @mixed_clamp_to_float_1(i32 %x) {
502502
; CHECK-LABEL: @mixed_clamp_to_float_1(
503-
; CHECK-NEXT: [[SI_MIN:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 255)
504-
; CHECK-NEXT: [[R1:%.*]] = call i32 @llvm.smax.i32(i32 [[SI_MIN]], i32 1)
505-
; CHECK-NEXT: [[R:%.*]] = uitofp nneg i32 [[R1]] to float
503+
; CHECK-NEXT: [[R1:%.*]] = call i32 @llvm.smax.i32(i32 [[SI_MIN:%.*]], i32 1)
504+
; CHECK-NEXT: [[R2:%.*]] = call i32 @llvm.smin.i32(i32 [[R1]], i32 255)
505+
; CHECK-NEXT: [[R:%.*]] = uitofp nneg i32 [[R2]] to float
506506
; CHECK-NEXT: ret float [[R]]
507507
;
508508
%si_min_cmp = icmp sgt i32 %x, 255
@@ -535,9 +535,9 @@ define i32 @mixed_clamp_to_i32_1(float %x) {
535535

536536
define float @mixed_clamp_to_float_2(i32 %x) {
537537
; CHECK-LABEL: @mixed_clamp_to_float_2(
538-
; CHECK-NEXT: [[SI_MIN:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 255)
539-
; CHECK-NEXT: [[R1:%.*]] = call i32 @llvm.smax.i32(i32 [[SI_MIN]], i32 1)
540-
; CHECK-NEXT: [[R:%.*]] = uitofp nneg i32 [[R1]] to float
538+
; CHECK-NEXT: [[R1:%.*]] = call i32 @llvm.smax.i32(i32 [[SI_MIN:%.*]], i32 1)
539+
; CHECK-NEXT: [[R2:%.*]] = call i32 @llvm.smin.i32(i32 [[R1]], i32 255)
540+
; CHECK-NEXT: [[R:%.*]] = uitofp nneg i32 [[R2]] to float
541541
; CHECK-NEXT: ret float [[R]]
542542
;
543543
%si_min_cmp = icmp sgt i32 %x, 255
@@ -568,9 +568,9 @@ define i32 @mixed_clamp_to_i32_2(float %x) {
568568

569569
define <2 x float> @mixed_clamp_to_float_vec(<2 x i32> %x) {
570570
; CHECK-LABEL: @mixed_clamp_to_float_vec(
571-
; CHECK-NEXT: [[SI_MIN:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[X:%.*]], <2 x i32> splat (i32 255))
572-
; CHECK-NEXT: [[R1:%.*]] = call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[SI_MIN]], <2 x i32> splat (i32 1))
573-
; CHECK-NEXT: [[R:%.*]] = uitofp nneg <2 x i32> [[R1]] to <2 x float>
571+
; CHECK-NEXT: [[R1:%.*]] = call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[SI_MIN:%.*]], <2 x i32> splat (i32 1))
572+
; CHECK-NEXT: [[R2:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[R1]], <2 x i32> splat (i32 255))
573+
; CHECK-NEXT: [[R:%.*]] = uitofp nneg <2 x i32> [[R2]] to <2 x float>
574574
; CHECK-NEXT: ret <2 x float> [[R]]
575575
;
576576
%si_min_cmp = icmp sgt <2 x i32> %x, <i32 255, i32 255>

llvm/test/Transforms/InstCombine/max_known_bits.ll

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ define i16 @min_max_clamp(i16 %x) {
3535
; Same as above with min/max reversed.
3636
define i16 @min_max_clamp_2(i16 %x) {
3737
; CHECK-LABEL: @min_max_clamp_2(
38-
; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047)
39-
; CHECK-NEXT: [[D:%.*]] = call i16 @llvm.smax.i16(i16 [[B]], i16 -2048)
40-
; CHECK-NEXT: [[E:%.*]] = add nsw i16 [[D]], 1
38+
; CHECK-NEXT: [[D:%.*]] = call i16 @llvm.smax.i16(i16 [[B:%.*]], i16 -2048)
39+
; CHECK-NEXT: [[D1:%.*]] = call i16 @llvm.smin.i16(i16 [[D]], i16 2047)
40+
; CHECK-NEXT: [[E:%.*]] = add nsw i16 [[D1]], 1
4141
; CHECK-NEXT: ret i16 [[E]]
4242
;
4343
%a = icmp slt i16 %x, 2047
@@ -71,9 +71,9 @@ define i32 @min_max_clamp_3(i16 %x) {
7171
; Same as above with min/max order reversed
7272
define i32 @min_max_clamp_4(i16 %x) {
7373
; CHECK-LABEL: @min_max_clamp_4(
74-
; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047)
75-
; CHECK-NEXT: [[D:%.*]] = call i16 @llvm.smax.i16(i16 [[B]], i16 -2048)
76-
; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[D]] to i32
74+
; CHECK-NEXT: [[D:%.*]] = call i16 @llvm.smax.i16(i16 [[B:%.*]], i16 -2048)
75+
; CHECK-NEXT: [[D1:%.*]] = call i16 @llvm.smin.i16(i16 [[D]], i16 2047)
76+
; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[D1]] to i32
7777
; CHECK-NEXT: ret i32 [[TMP1]]
7878
;
7979
%a = icmp slt i16 %x, 2047
@@ -106,9 +106,9 @@ define i16 @min_max_clamp_intrinsic(i16 %x) {
106106

107107
define i16 @min_max_clamp_intrinsic_2(i16 %x) {
108108
; CHECK-LABEL: @min_max_clamp_intrinsic_2(
109-
; CHECK-NEXT: [[A:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047)
110-
; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[A]], i16 -2048)
111-
; CHECK-NEXT: [[C:%.*]] = add nsw i16 [[B]], 1
109+
; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[A:%.*]], i16 -2048)
110+
; CHECK-NEXT: [[B1:%.*]] = call i16 @llvm.smin.i16(i16 [[B]], i16 2047)
111+
; CHECK-NEXT: [[C:%.*]] = add nsw i16 [[B1]], 1
112112
; CHECK-NEXT: ret i16 [[C]]
113113
;
114114
%a = call i16 @llvm.smin.i16(i16 %x, i16 2047)
@@ -134,9 +134,9 @@ define i32 @min_max_clamp_intrinsic_3(i16 %x) {
134134

135135
define i32 @min_max_clamp_intrinsic_4(i16 %x) {
136136
; CHECK-LABEL: @min_max_clamp_intrinsic_4(
137-
; CHECK-NEXT: [[A:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047)
138-
; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[A]], i16 -2048)
139-
; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[B]] to i32
137+
; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[A:%.*]], i16 -2048)
138+
; CHECK-NEXT: [[B1:%.*]] = call i16 @llvm.smin.i16(i16 [[B]], i16 2047)
139+
; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[B1]] to i32
140140
; CHECK-NEXT: ret i32 [[TMP1]]
141141
;
142142
%a = call i16 @llvm.smin.i16(i16 %x, i16 2047)

llvm/test/Transforms/InstCombine/minmax-fold.ll

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,9 @@ define i32 @test75(i32 %x) {
346346

347347
define i32 @clamp_signed1(i32 %x) {
348348
; CHECK-LABEL: @clamp_signed1(
349-
; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 255)
350-
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smax.i32(i32 [[MIN]], i32 15)
351-
; CHECK-NEXT: ret i32 [[R]]
349+
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smax.i32(i32 [[MIN:%.*]], i32 15)
350+
; CHECK-NEXT: [[R1:%.*]] = call i32 @llvm.smin.i32(i32 [[R]], i32 255)
351+
; CHECK-NEXT: ret i32 [[R1]]
352352
;
353353
%cmp2 = icmp slt i32 %x, 255
354354
%min = select i1 %cmp2, i32 %x, i32 255
@@ -376,9 +376,9 @@ define i32 @clamp_signed2(i32 %x) {
376376

377377
define i32 @clamp_signed3(i32 %x) {
378378
; CHECK-LABEL: @clamp_signed3(
379-
; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 255)
380-
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smax.i32(i32 [[MIN]], i32 15)
381-
; CHECK-NEXT: ret i32 [[R]]
379+
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.smax.i32(i32 [[MIN:%.*]], i32 15)
380+
; CHECK-NEXT: [[R1:%.*]] = call i32 @llvm.smin.i32(i32 [[R]], i32 255)
381+
; CHECK-NEXT: ret i32 [[R1]]
382382
;
383383
%cmp2 = icmp slt i32 %x, 255
384384
%min = select i1 %cmp2, i32 %x, i32 255
@@ -467,9 +467,9 @@ define i32 @clamp_unsigned4(i32 %x) {
467467
; (icmp sgt smin(PositiveA, B) 0) -> (icmp sgt B 0)
468468
define i32 @clamp_check_for_no_infinite_loop1(i32 %i) {
469469
; CHECK-LABEL: @clamp_check_for_no_infinite_loop1(
470-
; CHECK-NEXT: [[SEL1:%.*]] = call i32 @llvm.smin.i32(i32 [[I:%.*]], i32 255)
471-
; CHECK-NEXT: [[RES:%.*]] = call i32 @llvm.smax.i32(i32 [[SEL1]], i32 0)
472-
; CHECK-NEXT: ret i32 [[RES]]
470+
; CHECK-NEXT: [[RES:%.*]] = call i32 @llvm.smax.i32(i32 [[SEL1:%.*]], i32 0)
471+
; CHECK-NEXT: [[RES1:%.*]] = call i32 @llvm.smin.i32(i32 [[RES]], i32 255)
472+
; CHECK-NEXT: ret i32 [[RES1]]
473473
;
474474
%cmp1 = icmp slt i32 %i, 255
475475
%sel1 = select i1 %cmp1, i32 %i, i32 255
@@ -1429,8 +1429,8 @@ define i8 @PR46271(<2 x i8> %x) {
14291429
define i32 @twoway_clamp_lt(i32 %num) {
14301430
; CHECK-LABEL: @twoway_clamp_lt(
14311431
; CHECK-NEXT: entry:
1432-
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[NUM:%.*]], 13767
1433-
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP0]], i32 13768, i32 13767
1432+
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[NUM:%.*]], 13768
1433+
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP0]], i32 13767, i32 13768
14341434
; CHECK-NEXT: ret i32 [[R]]
14351435
;
14361436
entry:

llvm/test/Transforms/InstCombine/minmax-intrinsics.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -774,8 +774,8 @@ define i8 @clamp_two_vals_smax_smin(i8 %x) {
774774

775775
define <3 x i8> @clamp_two_vals_smin_smax(<3 x i8> %x) {
776776
; CHECK-LABEL: @clamp_two_vals_smin_smax(
777-
; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt <3 x i8> [[X:%.*]], splat (i8 41)
778-
; CHECK-NEXT: [[R:%.*]] = select <3 x i1> [[TMP1]], <3 x i8> splat (i8 42), <3 x i8> splat (i8 41)
777+
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt <3 x i8> [[X:%.*]], splat (i8 42)
778+
; CHECK-NEXT: [[R:%.*]] = select <3 x i1> [[TMP1]], <3 x i8> splat (i8 41), <3 x i8> splat (i8 42)
779779
; CHECK-NEXT: ret <3 x i8> [[R]]
780780
;
781781
%m = call <3 x i8> @llvm.smin.v3i8(<3 x i8> %x, <3 x i8> <i8 42, i8 42, i8 42>)
@@ -2192,9 +2192,9 @@ define i8 @umin_umin_reassoc_constants(i8 %x) {
21922192

21932193
define i8 @smin_smax_reassoc_constants(i8 %x) {
21942194
; CHECK-LABEL: @smin_smax_reassoc_constants(
2195-
; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 97)
2196-
; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[M1]], i8 -3)
2197-
; CHECK-NEXT: ret i8 [[M2]]
2195+
; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[M1:%.*]], i8 -3)
2196+
; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.smin.i8(i8 [[M2]], i8 97)
2197+
; CHECK-NEXT: ret i8 [[M3]]
21982198
;
21992199
%m1 = call i8 @llvm.smin.i8(i8 %x, i8 97)
22002200
%m2 = call i8 @llvm.smax.i8(i8 %m1, i8 -3)

0 commit comments

Comments
 (0)