From: Dávid Bolvanský Date: Sun, 17 Jan 2021 16:06:06 +0000 (+0100) Subject: [InstCombine] Transform abs pattern using multiplication to abs intrinsic (PR45691) X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=ed396212da41feed9bffb8cc1ca6518ab031a3c7;p=android-x86%2Fexternal-llvm-project.git [InstCombine] Transform abs pattern using multiplication to abs intrinsic (PR45691) ``` unsigned r(int v) { return (1 | -(v < 0)) * v; } `r` is equivalent to `abs(v)`. ``` ``` define <4 x i8> @src(<4 x i8> %0) { %1: %2 = ashr <4 x i8> %0, { 31, undef, 31, 31 } %3 = or <4 x i8> %2, { 1, 1, 1, undef } %4 = mul nsw <4 x i8> %3, %0 ret <4 x i8> %4 } => define <4 x i8> @tgt(<4 x i8> %0) { %1: %2 = icmp slt <4 x i8> %0, { 0, 0, 0, 0 } %3 = sub nsw <4 x i8> { 0, 0, 0, 0 }, %0 %4 = select <4 x i1> %2, <4 x i8> %3, <4 x i8> %0 ret <4 x i8> %4 } Transformation seems to be correct! ``` Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D94874 --- diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index 2da7415b908..4b485a0ad85 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -153,8 +153,10 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) { if (Value *V = SimplifyUsingDistributiveLaws(I)) return replaceInstUsesWith(I, V); - // X * -1 == 0 - X Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + unsigned BitWidth = I.getType()->getScalarSizeInBits(); + + // X * -1 == 0 - X if (match(Op1, m_AllOnes())) { BinaryOperator *BO = BinaryOperator::CreateNeg(Op0, I.getName()); if (I.hasNoSignedWrap()) @@ -360,6 +362,19 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) { if (match(Op1, m_LShr(m_Value(X), m_APInt(C))) && *C == C->getBitWidth() - 1) return BinaryOperator::CreateAnd(Builder.CreateAShr(X, *C), Op0); + // ((ashr X, 31) | 1) * X --> abs(X) + // X * ((ashr X, 31) | 1) --> abs(X) + if (match(&I, m_c_BinOp(m_Or(m_AShr(m_Value(X), + m_SpecificIntAllowUndef(BitWidth - 1)), + m_One()), + m_Deferred(X)))) { + Value *Abs = Builder.CreateBinaryIntrinsic( + Intrinsic::abs, X, + ConstantInt::getBool(I.getContext(), I.hasNoSignedWrap())); + Abs->takeName(&I); + return replaceInstUsesWith(I, Abs); + } + if (Instruction *Ext = narrowMathIfNoOverflow(I)) return Ext; diff --git a/llvm/test/Transforms/InstCombine/ashr-or-mul-abs.ll b/llvm/test/Transforms/InstCombine/ashr-or-mul-abs.ll index 1874378f1f1..ab390a20934 100644 --- a/llvm/test/Transforms/InstCombine/ashr-or-mul-abs.ll +++ b/llvm/test/Transforms/InstCombine/ashr-or-mul-abs.ll @@ -6,9 +6,7 @@ define i32 @ashr_or_mul_to_abs(i32 %X) { ; CHECK-LABEL: @ashr_or_mul_to_abs( -; CHECK-NEXT: [[I:%.*]] = ashr i32 [[X:%.*]], 31 -; CHECK-NEXT: [[I1:%.*]] = or i32 [[I]], 1 -; CHECK-NEXT: [[I2:%.*]] = mul nsw i32 [[I1]], [[X]] +; CHECK-NEXT: [[I2:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true) ; CHECK-NEXT: ret i32 [[I2]] ; %i = ashr i32 %X, 31 @@ -19,9 +17,7 @@ define i32 @ashr_or_mul_to_abs(i32 %X) { define i32 @ashr_or_mul_to_abs2(i32 %X) { ; CHECK-LABEL: @ashr_or_mul_to_abs2( -; CHECK-NEXT: [[I:%.*]] = ashr i32 [[X:%.*]], 31 -; CHECK-NEXT: [[I1:%.*]] = or i32 [[I]], 1 -; CHECK-NEXT: [[I2:%.*]] = mul i32 [[I1]], [[X]] +; CHECK-NEXT: [[I2:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false) ; CHECK-NEXT: ret i32 [[I2]] ; %i = ashr i32 %X, 31 @@ -30,13 +26,13 @@ define i32 @ashr_or_mul_to_abs2(i32 %X) { ret i32 %i2 } -define i32 @ashr_or_mul_to_abs3(i32 %X) { +define i32 @ashr_or_mul_to_abs3(i32 %PX) { ; CHECK-LABEL: @ashr_or_mul_to_abs3( -; CHECK-NEXT: [[I:%.*]] = ashr i32 [[X:%.*]], 31 -; CHECK-NEXT: [[I1:%.*]] = or i32 [[I]], 1 -; CHECK-NEXT: [[I2:%.*]] = mul i32 [[I1]], [[X]] +; CHECK-NEXT: [[X:%.*]] = sdiv i32 42, [[PX:%.*]] +; CHECK-NEXT: [[I2:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false) ; CHECK-NEXT: ret i32 [[I2]] ; + %X = sdiv i32 42, %PX ; thwart complexity-based canonicalization %i = ashr i32 %X, 31 %i1 = or i32 %i, 1 %i2 = mul i32 %X, %i1 @@ -46,9 +42,7 @@ define i32 @ashr_or_mul_to_abs3(i32 %X) { define <4 x i32> @ashr_or_mul_to_abs_vec(<4 x i32> %X) { ; CHECK-LABEL: @ashr_or_mul_to_abs_vec( -; CHECK-NEXT: [[I:%.*]] = ashr <4 x i32> [[X:%.*]], -; CHECK-NEXT: [[I1:%.*]] = or <4 x i32> [[I]], -; CHECK-NEXT: [[I2:%.*]] = mul <4 x i32> [[I1]], [[X]] +; CHECK-NEXT: [[I2:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[X:%.*]], i1 false) ; CHECK-NEXT: ret <4 x i32> [[I2]] ; %i = ashr <4 x i32> %X, @@ -59,9 +53,7 @@ define <4 x i32> @ashr_or_mul_to_abs_vec(<4 x i32> %X) { define <4 x i32> @ashr_or_mul_to_abs_vec2(<4 x i32> %X) { ; CHECK-LABEL: @ashr_or_mul_to_abs_vec2( -; CHECK-NEXT: [[I:%.*]] = ashr <4 x i32> [[X:%.*]], -; CHECK-NEXT: [[I1:%.*]] = or <4 x i32> [[I]], -; CHECK-NEXT: [[I2:%.*]] = mul nsw <4 x i32> [[I1]], [[X]] +; CHECK-NEXT: [[I2:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[X:%.*]], i1 true) ; CHECK-NEXT: ret <4 x i32> [[I2]] ; %i = ashr <4 x i32> %X, @@ -72,9 +64,7 @@ define <4 x i32> @ashr_or_mul_to_abs_vec2(<4 x i32> %X) { define <4 x i32> @ashr_or_mul_to_abs_vec3_undef(<4 x i32> %X) { ; CHECK-LABEL: @ashr_or_mul_to_abs_vec3_undef( -; CHECK-NEXT: [[I:%.*]] = ashr <4 x i32> [[X:%.*]], -; CHECK-NEXT: [[I1:%.*]] = or <4 x i32> [[I]], -; CHECK-NEXT: [[I2:%.*]] = mul <4 x i32> [[I1]], [[X]] +; CHECK-NEXT: [[I2:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[X:%.*]], i1 false) ; CHECK-NEXT: ret <4 x i32> [[I2]] ; %i = ashr <4 x i32> %X, @@ -110,3 +100,16 @@ define i32 @ashr_or_mul_to_abs_neg2(i32 %X) { %i2 = mul nsw i32 %i1, %X ret i32 %i2 } + +define i32 @ashr_or_mul_to_abs_neg3(i32 %X, i32 %Y) { +; CHECK-LABEL: @ashr_or_mul_to_abs_neg3( +; CHECK-NEXT: [[I:%.*]] = ashr i32 [[X:%.*]], 31 +; CHECK-NEXT: [[I1:%.*]] = or i32 [[I]], 1 +; CHECK-NEXT: [[I2:%.*]] = mul nsw i32 [[I1]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[I2]] +; + %i = ashr i32 %X, 31 + %i1 = or i32 %i, 1 + %i2 = mul nsw i32 %i1, %Y + ret i32 %i2 +}