Skip to content

Commit d0975b7

Browse files
committed
[InstCombine] fold signed min/max intrinsics with negated operands
If both operands are negated, we can invert the min/max and do the negation after: smax (neg nsw X), (neg nsw Y) --> neg nsw (smin X, Y) smin (neg nsw X), (neg nsw Y) --> neg nsw (smax X, Y) This is visible as a remaining regression in D98152. I don't see a way to generalize this for 'unsigned' or adapt Negator to handle it. This only appears to be safe with 'nsw': https://alive2.llvm.org/ce/z/GUy1zJ Differential Revision: https://reviews.llvm.org/D108165
1 parent 8fb269d commit d0975b7

File tree

2 files changed

+27
-10
lines changed

2 files changed

+27
-10
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,17 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
10651065
}
10661066
}
10671067

1068+
if (IID == Intrinsic::smax || IID == Intrinsic::smin) {
1069+
// smax (neg nsw X), (neg nsw Y) --> neg nsw (smin X, Y)
1070+
// smin (neg nsw X), (neg nsw Y) --> neg nsw (smax X, Y)
1071+
if (match(I0, m_NSWNeg(m_Value(X))) && match(I1, m_NSWNeg(m_Value(Y))) &&
1072+
(I0->hasOneUse() || I1->hasOneUse())) {
1073+
Intrinsic::ID InvID = getInverseMinMaxIntrinsic(IID);
1074+
Value *InvMaxMin = Builder.CreateBinaryIntrinsic(InvID, X, Y);
1075+
return BinaryOperator::CreateNSWNeg(InvMaxMin);
1076+
}
1077+
}
1078+
10681079
if (match(I0, m_Not(m_Value(X)))) {
10691080
// max (not X), (not Y) --> not (min X, Y)
10701081
Intrinsic::ID InvID = getInverseMinMaxIntrinsic(IID);

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

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,9 +1033,8 @@ define i8 @umin_demand_and_7_8(i8 %x) {
10331033

10341034
define i8 @neg_neg_nsw_smax(i8 %x, i8 %y) {
10351035
; CHECK-LABEL: @neg_neg_nsw_smax(
1036-
; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]
1037-
; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]]
1038-
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[NX]], i8 [[NY]])
1036+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
1037+
; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]]
10391038
; CHECK-NEXT: ret i8 [[M]]
10401039
;
10411040
%nx = sub nsw i8 0, %x
@@ -1046,9 +1045,8 @@ define i8 @neg_neg_nsw_smax(i8 %x, i8 %y) {
10461045

10471046
define <3 x i8> @neg_neg_nsw_smin(<3 x i8> %x, <3 x i8> %y) {
10481047
; CHECK-LABEL: @neg_neg_nsw_smin(
1049-
; CHECK-NEXT: [[NX:%.*]] = sub nsw <3 x i8> zeroinitializer, [[X:%.*]]
1050-
; CHECK-NEXT: [[NY:%.*]] = sub nsw <3 x i8> zeroinitializer, [[Y:%.*]]
1051-
; CHECK-NEXT: [[M:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[NX]], <3 x i8> [[NY]])
1048+
; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]])
1049+
; CHECK-NEXT: [[M:%.*]] = sub nsw <3 x i8> zeroinitializer, [[TMP1]]
10521050
; CHECK-NEXT: ret <3 x i8> [[M]]
10531051
;
10541052
%nx = sub nsw <3 x i8> zeroinitializer, %x
@@ -1061,8 +1059,8 @@ define i8 @neg_neg_nsw_smax_use0(i8 %x, i8 %y) {
10611059
; CHECK-LABEL: @neg_neg_nsw_smax_use0(
10621060
; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]
10631061
; CHECK-NEXT: call void @use(i8 [[NX]])
1064-
; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]]
1065-
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[NX]], i8 [[NY]])
1062+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y:%.*]])
1063+
; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]]
10661064
; CHECK-NEXT: ret i8 [[M]]
10671065
;
10681066
%nx = sub nsw i8 0, %x
@@ -1074,10 +1072,10 @@ define i8 @neg_neg_nsw_smax_use0(i8 %x, i8 %y) {
10741072

10751073
define i8 @neg_neg_nsw_smin_use1(i8 %x, i8 %y) {
10761074
; CHECK-LABEL: @neg_neg_nsw_smin_use1(
1077-
; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]
10781075
; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]]
10791076
; CHECK-NEXT: call void @use(i8 [[NY]])
1080-
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[NX]], i8 [[NY]])
1077+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y]])
1078+
; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]]
10811079
; CHECK-NEXT: ret i8 [[M]]
10821080
;
10831081
%nx = sub nsw i8 0, %x
@@ -1087,6 +1085,8 @@ define i8 @neg_neg_nsw_smin_use1(i8 %x, i8 %y) {
10871085
ret i8 %m
10881086
}
10891087

1088+
; negative test - too many uses
1089+
10901090
define i8 @neg_neg_nsw_smin_use2(i8 %x, i8 %y) {
10911091
; CHECK-LABEL: @neg_neg_nsw_smin_use2(
10921092
; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]
@@ -1104,6 +1104,8 @@ define i8 @neg_neg_nsw_smin_use2(i8 %x, i8 %y) {
11041104
ret i8 %m
11051105
}
11061106

1107+
; negative test - need nsw on both ops
1108+
11071109
define i8 @neg_neg_smax(i8 %x, i8 %y) {
11081110
; CHECK-LABEL: @neg_neg_smax(
11091111
; CHECK-NEXT: [[NX:%.*]] = sub i8 0, [[X:%.*]]
@@ -1117,6 +1119,8 @@ define i8 @neg_neg_smax(i8 %x, i8 %y) {
11171119
ret i8 %m
11181120
}
11191121

1122+
; negative test - need nsw on both ops
1123+
11201124
define i8 @neg_neg_smin(i8 %x, i8 %y) {
11211125
; CHECK-LABEL: @neg_neg_smin(
11221126
; CHECK-NEXT: [[NX:%.*]] = sub i8 0, [[X:%.*]]
@@ -1130,6 +1134,8 @@ define i8 @neg_neg_smin(i8 %x, i8 %y) {
11301134
ret i8 %m
11311135
}
11321136

1137+
; negative test - need signed min/max
1138+
11331139
define i8 @neg_neg_nsw_umin(i8 %x, i8 %y) {
11341140
; CHECK-LABEL: @neg_neg_nsw_umin(
11351141
; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]

0 commit comments

Comments
 (0)