From: Nikita Popov Date: Wed, 23 Feb 2022 10:56:34 +0000 (+0100) Subject: [InstCombine] Fold sub of umin to usub.sat X-Git-Tag: upstream/15.0.7~15576 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e2f627e5e3855309f3a7421f6786b401efb6b7c7;p=platform%2Fupstream%2Fllvm.git [InstCombine] Fold sub of umin to usub.sat We were handling sub of umax, but not the conjugated umin case. https://alive2.llvm.org/ce/z/4fdZfy https://alive2.llvm.org/ce/z/BhUQBM --- diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 0598f75..8a88192 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2187,12 +2187,23 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { return replaceInstUsesWith( I, Builder.CreateIntrinsic(Intrinsic::usub_sat, {Ty}, {X, Op1})); + // Op0 - umin(X, Op0) --> usub.sat(Op0, X) + if (match(Op1, m_OneUse(m_c_UMin(m_Value(X), m_Specific(Op0))))) + return replaceInstUsesWith( + I, Builder.CreateIntrinsic(Intrinsic::usub_sat, {Ty}, {Op0, X})); + // Op0 - umax(X, Op0) --> 0 - usub.sat(X, Op0) if (match(Op1, m_OneUse(m_c_UMax(m_Value(X), m_Specific(Op0))))) { Value *USub = Builder.CreateIntrinsic(Intrinsic::usub_sat, {Ty}, {X, Op0}); return BinaryOperator::CreateNeg(USub); } + // umin(X, Op1) - Op1 --> 0 - usub.sat(Op1, X) + if (match(Op0, m_OneUse(m_c_UMin(m_Value(X), m_Specific(Op1))))) { + Value *USub = Builder.CreateIntrinsic(Intrinsic::usub_sat, {Ty}, {Op1, X}); + return BinaryOperator::CreateNeg(USub); + } + // C - ctpop(X) => ctpop(~X) if C is bitwidth if (match(Op0, m_SpecificInt(Ty->getScalarSizeInBits())) && match(Op1, m_OneUse(m_Intrinsic(m_Value(X))))) diff --git a/llvm/test/Transforms/InstCombine/sub-minmax.ll b/llvm/test/Transforms/InstCombine/sub-minmax.ll index 5dbf02c..339dd73 100644 --- a/llvm/test/Transforms/InstCombine/sub-minmax.ll +++ b/llvm/test/Transforms/InstCombine/sub-minmax.ll @@ -39,9 +39,8 @@ define i32 @na_minus_max_na_b(i32 %A, i32 %B) { define i5 @sub_umin(i5 %a, i5 %b) { ; CHECK-LABEL: @sub_umin( -; CHECK-NEXT: [[UMIN:%.*]] = call i5 @llvm.umin.i5(i5 [[A:%.*]], i5 [[B:%.*]]) -; CHECK-NEXT: [[R:%.*]] = sub i5 [[A]], [[UMIN]] -; CHECK-NEXT: ret i5 [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.usub.sat.i5(i5 [[A:%.*]], i5 [[B:%.*]]) +; CHECK-NEXT: ret i5 [[TMP1]] ; %umin = call i5 @llvm.umin.i5(i5 %a, i5 %b) %r = sub i5 %a, %umin @@ -50,9 +49,8 @@ define i5 @sub_umin(i5 %a, i5 %b) { define <2 x i8> @sub_umin_commute_vec(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @sub_umin_commute_vec( -; CHECK-NEXT: [[UMIN:%.*]] = call <2 x i8> @llvm.umin.v2i8(<2 x i8> [[B:%.*]], <2 x i8> [[A:%.*]]) -; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> [[B]], [[UMIN]] -; CHECK-NEXT: ret <2 x i8> [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[B:%.*]], <2 x i8> [[A:%.*]]) +; CHECK-NEXT: ret <2 x i8> [[TMP1]] ; %umin = call <2 x i8> @llvm.umin.v2i8(<2 x i8> %b, <2 x i8> %a) %r = sub <2 x i8> %b, %umin @@ -569,9 +567,8 @@ define i8 @umax_sub_op1_use(i8 %x, i8 %y) { define i8 @umin_sub_op1(i8 %x, i8 %y) { ; CHECK-LABEL: @umin_sub_op1( -; CHECK-NEXT: [[U:%.*]] = call i8 @llvm.umin.i8(i8 [[Y:%.*]], i8 [[X:%.*]]) -; CHECK-NEXT: [[R:%.*]] = sub i8 [[Y]], [[U]] -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y:%.*]], i8 [[X:%.*]]) +; CHECK-NEXT: ret i8 [[TMP1]] ; %u = call i8 @llvm.umin.i8(i8 %y, i8 %x) %r = sub i8 %y, %u @@ -580,9 +577,8 @@ define i8 @umin_sub_op1(i8 %x, i8 %y) { define i8 @umin_sub_op1_commute(i8 %x, i8 %y) { ; CHECK-LABEL: @umin_sub_op1_commute( -; CHECK-NEXT: [[U:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[R:%.*]] = sub i8 [[Y]], [[U]] -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y:%.*]], i8 [[X:%.*]]) +; CHECK-NEXT: ret i8 [[TMP1]] ; %u = call i8 @llvm.umin.i8(i8 %x, i8 %y) %r = sub i8 %y, %u @@ -591,8 +587,8 @@ define i8 @umin_sub_op1_commute(i8 %x, i8 %y) { define i8 @umin_sub_op0(i8 %x, i8 %y) { ; CHECK-LABEL: @umin_sub_op0( -; CHECK-NEXT: [[U:%.*]] = call i8 @llvm.umin.i8(i8 [[Y:%.*]], i8 [[X:%.*]]) -; CHECK-NEXT: [[R:%.*]] = sub i8 [[U]], [[Y]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y:%.*]], i8 [[X:%.*]]) +; CHECK-NEXT: [[R:%.*]] = sub i8 0, [[TMP1]] ; CHECK-NEXT: ret i8 [[R]] ; %u = call i8 @llvm.umin.i8(i8 %y, i8 %x) @@ -602,8 +598,8 @@ define i8 @umin_sub_op0(i8 %x, i8 %y) { define i8 @umin_sub_op0_commute(i8 %x, i8 %y) { ; CHECK-LABEL: @umin_sub_op0_commute( -; CHECK-NEXT: [[U:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[R:%.*]] = sub i8 [[U]], [[Y]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y:%.*]], i8 [[X:%.*]]) +; CHECK-NEXT: [[R:%.*]] = sub i8 0, [[TMP1]] ; CHECK-NEXT: ret i8 [[R]] ; %u = call i8 @llvm.umin.i8(i8 %x, i8 %y)