Skip to content

Commit b584bc0

Browse files
el-evIanWood1
authored andcommitted
[InstCombine] Canonicalize max(min(X, MinC), MaxC) -> min(max(X, MaxC), MinC) (llvm#136665)
Closes llvm#121870. https://alive2.llvm.org/ce/z/WjmAjz https://alive2.llvm.org/ce/z/4KCjgL
1 parent 0234a09 commit b584bc0

File tree

8 files changed

+464
-74
lines changed

8 files changed

+464
-74
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

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

1927+
// smax(smin(X, MinC), MaxC) -> smin(smax(X, MaxC), MinC) if MinC s>= MaxC
1928+
// umax(umin(X, MinC), MaxC) -> umin(umax(X, MaxC), MinC) if MinC u>= MaxC
1929+
const APInt *MinC, *MaxC;
1930+
auto CreateCanonicalClampForm = [&](bool IsSigned) {
1931+
auto MaxIID = IsSigned ? Intrinsic::smax : Intrinsic::umax;
1932+
auto MinIID = IsSigned ? Intrinsic::smin : Intrinsic::umin;
1933+
Value *NewMax = Builder.CreateBinaryIntrinsic(
1934+
MaxIID, X, ConstantInt::get(X->getType(), *MaxC));
1935+
return replaceInstUsesWith(
1936+
*II, Builder.CreateBinaryIntrinsic(
1937+
MinIID, NewMax, ConstantInt::get(X->getType(), *MinC)));
1938+
};
1939+
if (IID == Intrinsic::smax &&
1940+
match(I0, m_OneUse(m_Intrinsic<Intrinsic::smin>(m_Value(X),
1941+
m_APInt(MinC)))) &&
1942+
match(I1, m_APInt(MaxC)) && MinC->sgt(*MaxC))
1943+
return CreateCanonicalClampForm(true);
1944+
if (IID == Intrinsic::umax &&
1945+
match(I0, m_OneUse(m_Intrinsic<Intrinsic::umin>(m_Value(X),
1946+
m_APInt(MinC)))) &&
1947+
match(I1, m_APInt(MaxC)) && MinC->ugt(*MaxC))
1948+
return CreateCanonicalClampForm(false);
1949+
19271950
// umin(i1 X, i1 Y) -> and i1 X, Y
19281951
// smax(i1 X, i1 Y) -> and i1 X, Y
19291952
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>

0 commit comments

Comments
 (0)