<div dir="ltr"><div>Yes - we wouldn't reduce instruction count if one operand is a constant, but it would be a canonicalization:</div><div><a href="https://alive2.llvm.org/ce/z/TSMHcc">https://alive2.llvm.org/ce/z/TSMHcc</a></div><div><br></div><div>I'll add a TODO note for now. Trying to squash some other known min/max regressions currently.<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Aug 17, 2021 at 12:06 PM Philip Reames <<a href="mailto:listmail@philipreames.com">listmail@philipreames.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">It looks like this should be legal for anything which can be cheaply <br>
negated. Have you looked at cases such as smax (neg nsw X), C1?<br>
<br>
Philip<br>
<br>
On 8/17/21 5:16 AM, Sanjay Patel via llvm-commits wrote:<br>
> Author: Sanjay Patel<br>
> Date: 2021-08-17T08:10:42-04:00<br>
> New Revision: d0975b7cb0e184e8e5f3975183c51937dfa4043a<br>
><br>
> URL: <a href="https://github.com/llvm/llvm-project/commit/d0975b7cb0e184e8e5f3975183c51937dfa4043a" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/d0975b7cb0e184e8e5f3975183c51937dfa4043a</a><br>
> DIFF: <a href="https://github.com/llvm/llvm-project/commit/d0975b7cb0e184e8e5f3975183c51937dfa4043a.diff" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/d0975b7cb0e184e8e5f3975183c51937dfa4043a.diff</a><br>
><br>
> LOG: [InstCombine] fold signed min/max intrinsics with negated operands<br>
><br>
> If both operands are negated, we can invert the min/max and do<br>
> the negation after:<br>
> smax (neg nsw X), (neg nsw Y) --> neg nsw (smin X, Y)<br>
> smin (neg nsw X), (neg nsw Y) --> neg nsw (smax X, Y)<br>
><br>
> This is visible as a remaining regression in D98152. I don't see<br>
> a way to generalize this for 'unsigned' or adapt Negator to<br>
> handle it. This only appears to be safe with 'nsw':<br>
> <a href="https://alive2.llvm.org/ce/z/GUy1zJ" rel="noreferrer" target="_blank">https://alive2.llvm.org/ce/z/GUy1zJ</a><br>
><br>
> Differential Revision: <a href="https://reviews.llvm.org/D108165" rel="noreferrer" target="_blank">https://reviews.llvm.org/D108165</a><br>
><br>
> Added:<br>
> <br>
><br>
> Modified:<br>
> llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp<br>
> llvm/test/Transforms/InstCombine/minmax-intrinsics.ll<br>
><br>
> Removed:<br>
> <br>
><br>
><br>
> ################################################################################<br>
> diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp<br>
> index 25597840cad3..e3dd12c0c773 100644<br>
> --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp<br>
> +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp<br>
> @@ -1065,6 +1065,17 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {<br>
> }<br>
> }<br>
> <br>
> + if (IID == Intrinsic::smax || IID == Intrinsic::smin) {<br>
> + // smax (neg nsw X), (neg nsw Y) --> neg nsw (smin X, Y)<br>
> + // smin (neg nsw X), (neg nsw Y) --> neg nsw (smax X, Y)<br>
> + if (match(I0, m_NSWNeg(m_Value(X))) && match(I1, m_NSWNeg(m_Value(Y))) &&<br>
> + (I0->hasOneUse() || I1->hasOneUse())) {<br>
> + Intrinsic::ID InvID = getInverseMinMaxIntrinsic(IID);<br>
> + Value *InvMaxMin = Builder.CreateBinaryIntrinsic(InvID, X, Y);<br>
> + return BinaryOperator::CreateNSWNeg(InvMaxMin);<br>
> + }<br>
> + }<br>
> +<br>
> if (match(I0, m_Not(m_Value(X)))) {<br>
> // max (not X), (not Y) --> not (min X, Y)<br>
> Intrinsic::ID InvID = getInverseMinMaxIntrinsic(IID);<br>
><br>
> diff --git a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll<br>
> index a3dbbc9dcbde..b46ddabffd95 100644<br>
> --- a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll<br>
> +++ b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll<br>
> @@ -1033,9 +1033,8 @@ define i8 @umin_demand_and_7_8(i8 %x) {<br>
> <br>
> define i8 @neg_neg_nsw_smax(i8 %x, i8 %y) {<br>
> ; CHECK-LABEL: @neg_neg_nsw_smax(<br>
> -; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]<br>
> -; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]]<br>
> -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[NX]], i8 [[NY]])<br>
> +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 [[Y:%.*]])<br>
> +; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]]<br>
> ; CHECK-NEXT: ret i8 [[M]]<br>
> ;<br>
> %nx = sub nsw i8 0, %x<br>
> @@ -1046,9 +1045,8 @@ define i8 @neg_neg_nsw_smax(i8 %x, i8 %y) {<br>
> <br>
> define <3 x i8> @neg_neg_nsw_smin(<3 x i8> %x, <3 x i8> %y) {<br>
> ; CHECK-LABEL: @neg_neg_nsw_smin(<br>
> -; CHECK-NEXT: [[NX:%.*]] = sub nsw <3 x i8> zeroinitializer, [[X:%.*]]<br>
> -; CHECK-NEXT: [[NY:%.*]] = sub nsw <3 x i8> zeroinitializer, [[Y:%.*]]<br>
> -; CHECK-NEXT: [[M:%.*]] = call <3 x i8> @llvm.smin.v3i8(<3 x i8> [[NX]], <3 x i8> [[NY]])<br>
> +; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> [[Y:%.*]])<br>
> +; CHECK-NEXT: [[M:%.*]] = sub nsw <3 x i8> zeroinitializer, [[TMP1]]<br>
> ; CHECK-NEXT: ret <3 x i8> [[M]]<br>
> ;<br>
> %nx = sub nsw <3 x i8> zeroinitializer, %x<br>
> @@ -1061,8 +1059,8 @@ define i8 @neg_neg_nsw_smax_use0(i8 %x, i8 %y) {<br>
> ; CHECK-LABEL: @neg_neg_nsw_smax_use0(<br>
> ; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]<br>
> ; CHECK-NEXT: call void @use(i8 [[NX]])<br>
> -; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]]<br>
> -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[NX]], i8 [[NY]])<br>
> +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y:%.*]])<br>
> +; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]]<br>
> ; CHECK-NEXT: ret i8 [[M]]<br>
> ;<br>
> %nx = sub nsw i8 0, %x<br>
> @@ -1074,10 +1072,10 @@ define i8 @neg_neg_nsw_smax_use0(i8 %x, i8 %y) {<br>
> <br>
> define i8 @neg_neg_nsw_smin_use1(i8 %x, i8 %y) {<br>
> ; CHECK-LABEL: @neg_neg_nsw_smin_use1(<br>
> -; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]<br>
> ; CHECK-NEXT: [[NY:%.*]] = sub nsw i8 0, [[Y:%.*]]<br>
> ; CHECK-NEXT: call void @use(i8 [[NY]])<br>
> -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[NX]], i8 [[NY]])<br>
> +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y]])<br>
> +; CHECK-NEXT: [[M:%.*]] = sub nsw i8 0, [[TMP1]]<br>
> ; CHECK-NEXT: ret i8 [[M]]<br>
> ;<br>
> %nx = sub nsw i8 0, %x<br>
> @@ -1087,6 +1085,8 @@ define i8 @neg_neg_nsw_smin_use1(i8 %x, i8 %y) {<br>
> ret i8 %m<br>
> }<br>
> <br>
> +; negative test - too many uses<br>
> +<br>
> define i8 @neg_neg_nsw_smin_use2(i8 %x, i8 %y) {<br>
> ; CHECK-LABEL: @neg_neg_nsw_smin_use2(<br>
> ; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]<br>
> @@ -1104,6 +1104,8 @@ define i8 @neg_neg_nsw_smin_use2(i8 %x, i8 %y) {<br>
> ret i8 %m<br>
> }<br>
> <br>
> +; negative test - need nsw on both ops<br>
> +<br>
> define i8 @neg_neg_smax(i8 %x, i8 %y) {<br>
> ; CHECK-LABEL: @neg_neg_smax(<br>
> ; CHECK-NEXT: [[NX:%.*]] = sub i8 0, [[X:%.*]]<br>
> @@ -1117,6 +1119,8 @@ define i8 @neg_neg_smax(i8 %x, i8 %y) {<br>
> ret i8 %m<br>
> }<br>
> <br>
> +; negative test - need nsw on both ops<br>
> +<br>
> define i8 @neg_neg_smin(i8 %x, i8 %y) {<br>
> ; CHECK-LABEL: @neg_neg_smin(<br>
> ; CHECK-NEXT: [[NX:%.*]] = sub i8 0, [[X:%.*]]<br>
> @@ -1130,6 +1134,8 @@ define i8 @neg_neg_smin(i8 %x, i8 %y) {<br>
> ret i8 %m<br>
> }<br>
> <br>
> +; negative test - need signed min/max<br>
> +<br>
> define i8 @neg_neg_nsw_umin(i8 %x, i8 %y) {<br>
> ; CHECK-LABEL: @neg_neg_nsw_umin(<br>
> ; CHECK-NEXT: [[NX:%.*]] = sub nsw i8 0, [[X:%.*]]<br>
><br>
><br>
> <br>
> _______________________________________________<br>
> llvm-commits mailing list<br>
> <a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>