[llvm-branch-commits] [llvm] ed39621 - [InstCombine] Transform abs pattern using multiplication to abs intrinsic (PR45691)

Dávid Bolvanský via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Jan 17 08:10:27 PST 2021


Author: Dávid Bolvanský
Date: 2021-01-17T17:06:14+01:00
New Revision: ed396212da41feed9bffb8cc1ca6518ab031a3c7

URL: https://github.com/llvm/llvm-project/commit/ed396212da41feed9bffb8cc1ca6518ab031a3c7
DIFF: https://github.com/llvm/llvm-project/commit/ed396212da41feed9bffb8cc1ca6518ab031a3c7.diff

LOG: [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

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
    llvm/test/Transforms/InstCombine/ashr-or-mul-abs.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 2da7415b908b..4b485a0ad85e 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 1874378f1f1f..ab390a209340 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:%.*]], <i32 31, i32 31, i32 31, i32 31>
-; CHECK-NEXT:    [[I1:%.*]] = or <4 x i32> [[I]], <i32 1, i32 1, i32 1, i32 1>
-; 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, <i32 31, i32 31, i32 31, i32 31>
@@ -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:%.*]], <i32 31, i32 31, i32 31, i32 31>
-; CHECK-NEXT:    [[I1:%.*]] = or <4 x i32> [[I]], <i32 1, i32 1, i32 1, i32 1>
-; 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, <i32 31, i32 31, i32 31, i32 31>
@@ -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:%.*]], <i32 31, i32 undef, i32 31, i32 31>
-; CHECK-NEXT:    [[I1:%.*]] = or <4 x i32> [[I]], <i32 1, i32 1, i32 1, i32 undef>
-; 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, <i32 31, i32 undef, i32 31, i32 31>
@@ -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
+}


        


More information about the llvm-branch-commits mailing list