Skip to content

Commit

Permalink
[InstCombine] fold signed min/max intrinsics with negated operands
Browse files Browse the repository at this point in the history
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
  • Loading branch information
rotateright committed Aug 17, 2021
1 parent 8fb269d commit d0975b7
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 10 deletions.
11 changes: 11 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
Expand Up @@ -1065,6 +1065,17 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
}
}

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)
if (match(I0, m_NSWNeg(m_Value(X))) && match(I1, m_NSWNeg(m_Value(Y))) &&
(I0->hasOneUse() || I1->hasOneUse())) {
Intrinsic::ID InvID = getInverseMinMaxIntrinsic(IID);
Value *InvMaxMin = Builder.CreateBinaryIntrinsic(InvID, X, Y);
return BinaryOperator::CreateNSWNeg(InvMaxMin);
}
}

if (match(I0, m_Not(m_Value(X)))) {
// max (not X), (not Y) --> not (min X, Y)
Intrinsic::ID InvID = getInverseMinMaxIntrinsic(IID);
Expand Down
26 changes: 16 additions & 10 deletions llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
Expand Up @@ -1033,9 +1033,8 @@ define i8 @umin_demand_and_7_8(i8 %x) {

define i8 @neg_neg_nsw_smax(i8 %x, i8 %y) {
; CHECK-LABEL: @neg_neg_nsw_smax(
; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]
; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]]
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[NX]], i8 [[NY]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]]
; CHECK-NEXT: ret i8 [[M]]
;
%nx = sub nsw i8 0, %x
Expand All @@ -1046,9 +1045,8 @@ define i8 @neg_neg_nsw_smax(i8 %x, i8 %y) {

define <3 x i8> @neg_neg_nsw_smin(<3 x i8> %x, <3 x i8> %y) {
; CHECK-LABEL: @neg_neg_nsw_smin(
; CHECK-NEXT: [[NX:%.*]] = sub nsw <3 x i8> zeroinitializer, [[X:%.*]]
; CHECK-NEXT: [[NY:%.*]] = sub nsw <3 x i8> zeroinitializer, [[Y:%.*]]
; CHECK-NEXT: [[M:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[NX]], <3 x i8> [[NY]])
; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]])
; CHECK-NEXT: [[M:%.*]] = sub nsw <3 x i8> zeroinitializer, [[TMP1]]
; CHECK-NEXT: ret <3 x i8> [[M]]
;
%nx = sub nsw <3 x i8> zeroinitializer, %x
Expand All @@ -1061,8 +1059,8 @@ define i8 @neg_neg_nsw_smax_use0(i8 %x, i8 %y) {
; CHECK-LABEL: @neg_neg_nsw_smax_use0(
; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]
; CHECK-NEXT: call void @use(i8 [[NX]])
; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]]
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[NX]], i8 [[NY]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y:%.*]])
; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]]
; CHECK-NEXT: ret i8 [[M]]
;
%nx = sub nsw i8 0, %x
Expand All @@ -1074,10 +1072,10 @@ define i8 @neg_neg_nsw_smax_use0(i8 %x, i8 %y) {

define i8 @neg_neg_nsw_smin_use1(i8 %x, i8 %y) {
; CHECK-LABEL: @neg_neg_nsw_smin_use1(
; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]
; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]]
; CHECK-NEXT: call void @use(i8 [[NY]])
; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[NX]], i8 [[NY]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y]])
; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]]
; CHECK-NEXT: ret i8 [[M]]
;
%nx = sub nsw i8 0, %x
Expand All @@ -1087,6 +1085,8 @@ define i8 @neg_neg_nsw_smin_use1(i8 %x, i8 %y) {
ret i8 %m
}

; negative test - too many uses

define i8 @neg_neg_nsw_smin_use2(i8 %x, i8 %y) {
; CHECK-LABEL: @neg_neg_nsw_smin_use2(
; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]
Expand All @@ -1104,6 +1104,8 @@ define i8 @neg_neg_nsw_smin_use2(i8 %x, i8 %y) {
ret i8 %m
}

; negative test - need nsw on both ops

define i8 @neg_neg_smax(i8 %x, i8 %y) {
; CHECK-LABEL: @neg_neg_smax(
; CHECK-NEXT: [[NX:%.*]] = sub i8 0, [[X:%.*]]
Expand All @@ -1117,6 +1119,8 @@ define i8 @neg_neg_smax(i8 %x, i8 %y) {
ret i8 %m
}

; negative test - need nsw on both ops

define i8 @neg_neg_smin(i8 %x, i8 %y) {
; CHECK-LABEL: @neg_neg_smin(
; CHECK-NEXT: [[NX:%.*]] = sub i8 0, [[X:%.*]]
Expand All @@ -1130,6 +1134,8 @@ define i8 @neg_neg_smin(i8 %x, i8 %y) {
ret i8 %m
}

; negative test - need signed min/max

define i8 @neg_neg_nsw_umin(i8 %x, i8 %y) {
; CHECK-LABEL: @neg_neg_nsw_umin(
; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]
Expand Down

0 comments on commit d0975b7

Please sign in to comment.