[llvm] [InstCombine]combine mul(abs(x), abs(y)) to abs(mul(x, y)) (PR #78395)

Congcong Cai via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 17 02:35:24 PST 2024


https://github.com/HerrCai0907 updated https://github.com/llvm/llvm-project/pull/78395

>From e2b34d60a73c23e2aff38f33e80b4f1e79c709f0 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 17 Jan 2024 13:22:56 +0800
Subject: [PATCH 1/3] [NFC][instCombine]Add mul(abs(x), abs(y))->abs(mul(x,y))
 test

---
 llvm/test/Transforms/InstCombine/mul.ll | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/mul.ll b/llvm/test/Transforms/InstCombine/mul.ll
index b404fcffbf4226..f6bd1368033d64 100644
--- a/llvm/test/Transforms/InstCombine/mul.ll
+++ b/llvm/test/Transforms/InstCombine/mul.ll
@@ -1649,6 +1649,20 @@ define <vscale x 2 x i64> @mul_scalable_splat_zero(<vscale x 2 x i64> %z) {
   ret <vscale x 2 x i64> %t3
 }
 
+; fold mul(abs(x),abs(y)) -> abs(mul(x,y))
+define i32 @combine_mul_abs_x_abs_y(i32 %x, i32 %y) {
+; CHECK-LABEL: @combine_mul_abs_x_abs_y(
+; CHECK-NEXT:    [[ABS_X:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
+; CHECK-NEXT:    [[ABS_Y:%.*]] = call i32 @llvm.abs.i32(i32 [[Y:%.*]], i1 false)
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS_X]], [[ABS_Y]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %abs_x = call i32 @llvm.abs.i32(i32 %x, i1 false)
+  %abs_y = call i32 @llvm.abs.i32(i32 %y, i1 false)
+  %mul = mul i32 %abs_x, %abs_y
+  ret i32 %mul
+}
+
 ;
 ; fold mul(sub(x,y),negpow2) -> shl(sub(y,x),log2(pow2))
 ;

>From c4b7a9d3069e93c7758dbd3d98ba175024188514 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 17 Jan 2024 13:24:28 +0800
Subject: [PATCH 2/3] [instCombine]combine mul(abs(x),abs(y)) to abs(mul(x,y))

Fixes: #78076
Alive2 Proof: https://alive2.llvm.org/ce/z/XEDy0f
---
 .../InstCombine/InstCombineMulDivRem.cpp        | 17 +++++++++++++++++
 llvm/test/Transforms/InstCombine/mul.ll         |  5 ++---
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index e7f983a00e3044..36930f24a542a2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -330,6 +330,23 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
       return BinaryOperator::CreateMul(X, X);
   }
 
+  {
+    Value *X, *Y, *Z;
+    // abs(X) * abs(Y) -> abs(X * Y)
+    // nabs(X) * nabs(Y) -> abs(X * Y)
+    SelectPatternFlavor SPF0 = matchSelectPattern(Op0, X, Z).Flavor;
+    SelectPatternFlavor SPF1 = matchSelectPattern(Op1, Y, Z).Flavor;
+    if ((SPF0 == SPF1) && (SPF0 == SPF_ABS || SPF0 == SPF_NABS))
+      return replaceInstUsesWith(
+          I, Builder.CreateBinaryIntrinsic(
+                 Intrinsic::abs, Builder.CreateMul(X, Y), Builder.getTrue()));
+    if (match(Op0, m_Intrinsic<Intrinsic::abs>(m_Value(X))) &&
+        match(Op1, m_Intrinsic<Intrinsic::abs>(m_Value(Y))))
+      return replaceInstUsesWith(
+          I, Builder.CreateBinaryIntrinsic(
+                 Intrinsic::abs, Builder.CreateMul(X, Y), Builder.getTrue()));
+  }
+
   // -X * C --> X * -C
   Value *X, *Y;
   Constant *Op1C;
diff --git a/llvm/test/Transforms/InstCombine/mul.ll b/llvm/test/Transforms/InstCombine/mul.ll
index f6bd1368033d64..0494091b038243 100644
--- a/llvm/test/Transforms/InstCombine/mul.ll
+++ b/llvm/test/Transforms/InstCombine/mul.ll
@@ -1652,9 +1652,8 @@ define <vscale x 2 x i64> @mul_scalable_splat_zero(<vscale x 2 x i64> %z) {
 ; fold mul(abs(x),abs(y)) -> abs(mul(x,y))
 define i32 @combine_mul_abs_x_abs_y(i32 %x, i32 %y) {
 ; CHECK-LABEL: @combine_mul_abs_x_abs_y(
-; CHECK-NEXT:    [[ABS_X:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
-; CHECK-NEXT:    [[ABS_Y:%.*]] = call i32 @llvm.abs.i32(i32 [[Y:%.*]], i1 false)
-; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS_X]], [[ABS_Y]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = call i32 @llvm.abs.i32(i32 [[TMP1]], i1 true)
 ; CHECK-NEXT:    ret i32 [[MUL]]
 ;
   %abs_x = call i32 @llvm.abs.i32(i32 %x, i1 false)

>From 73dbfcb1a5a944665ab817b334a75fe36110e442 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 17 Jan 2024 18:35:09 +0800
Subject: [PATCH 3/3] fix

---
 .../InstCombine/InstCombineMulDivRem.cpp      | 19 +++-----
 llvm/test/Transforms/InstCombine/mul.ll       | 43 ++++++++++++++++++-
 2 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 36930f24a542a2..b53764560734ec 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -331,20 +331,15 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
   }
 
   {
-    Value *X, *Y, *Z;
+    Value *X, *Y;
     // abs(X) * abs(Y) -> abs(X * Y)
-    // nabs(X) * nabs(Y) -> abs(X * Y)
-    SelectPatternFlavor SPF0 = matchSelectPattern(Op0, X, Z).Flavor;
-    SelectPatternFlavor SPF1 = matchSelectPattern(Op1, Y, Z).Flavor;
-    if ((SPF0 == SPF1) && (SPF0 == SPF_ABS || SPF0 == SPF_NABS))
-      return replaceInstUsesWith(
-          I, Builder.CreateBinaryIntrinsic(
-                 Intrinsic::abs, Builder.CreateMul(X, Y), Builder.getTrue()));
-    if (match(Op0, m_Intrinsic<Intrinsic::abs>(m_Value(X))) &&
-        match(Op1, m_Intrinsic<Intrinsic::abs>(m_Value(Y))))
+    if (I.hasNoSignedWrap() &&
+        match(Op0, m_Intrinsic<Intrinsic::abs>(m_Value(X), m_AllOnes())) &&
+        match(Op1, m_Intrinsic<Intrinsic::abs>(m_Value(Y), m_AllOnes())))
       return replaceInstUsesWith(
-          I, Builder.CreateBinaryIntrinsic(
-                 Intrinsic::abs, Builder.CreateMul(X, Y), Builder.getTrue()));
+          I, Builder.CreateBinaryIntrinsic(Intrinsic::abs,
+                                           Builder.CreateNSWMul(X, Y),
+                                           Builder.getTrue()));
   }
 
   // -X * C --> X * -C
diff --git a/llvm/test/Transforms/InstCombine/mul.ll b/llvm/test/Transforms/InstCombine/mul.ll
index 0494091b038243..9cf8b31cd5be0f 100644
--- a/llvm/test/Transforms/InstCombine/mul.ll
+++ b/llvm/test/Transforms/InstCombine/mul.ll
@@ -1652,13 +1652,52 @@ define <vscale x 2 x i64> @mul_scalable_splat_zero(<vscale x 2 x i64> %z) {
 ; fold mul(abs(x),abs(y)) -> abs(mul(x,y))
 define i32 @combine_mul_abs_x_abs_y(i32 %x, i32 %y) {
 ; CHECK-LABEL: @combine_mul_abs_x_abs_y(
-; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nsw i32 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    [[MUL:%.*]] = call i32 @llvm.abs.i32(i32 [[TMP1]], i1 true)
 ; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %abs_x = call i32 @llvm.abs.i32(i32 %x, i1 true)
+  %abs_y = call i32 @llvm.abs.i32(i32 %y, i1 true)
+  %mul = mul nsw i32 %abs_x, %abs_y
+  ret i32 %mul
+}
+
+define i32 @combine_mul_abs_x_abs_y_no_nsw(i32 %x, i32 %y) {
+; CHECK-LABEL: @combine_mul_abs_x_abs_y_no_nsw(
+; CHECK-NEXT:    [[ABS_X:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true)
+; CHECK-NEXT:    [[ABS_Y:%.*]] = call i32 @llvm.abs.i32(i32 [[Y:%.*]], i1 true)
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS_X]], [[ABS_Y]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %abs_x = call i32 @llvm.abs.i32(i32 %x, i1 true)
+  %abs_y = call i32 @llvm.abs.i32(i32 %y, i1 true)
+  %mul = mul i32 %abs_x, %abs_y
+  ret i32 %mul
+}
+
+define i32 @combine_mul_abs_x_abs_y_poison_1(i32 %x, i32 %y) {
+; CHECK-LABEL: @combine_mul_abs_x_abs_y_poison_1(
+; CHECK-NEXT:    [[ABS_X:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true)
+; CHECK-NEXT:    [[ABS_Y:%.*]] = call i32 @llvm.abs.i32(i32 [[Y:%.*]], i1 false)
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[ABS_X]], [[ABS_Y]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %abs_x = call i32 @llvm.abs.i32(i32 %x, i1 true)
+  %abs_y = call i32 @llvm.abs.i32(i32 %y, i1 false)
+  %mul = mul nsw i32 %abs_x, %abs_y
+  ret i32 %mul
+}
+
+define i32 @combine_mul_abs_x_abs_y_poison_2(i32 %x, i32 %y) {
+; CHECK-LABEL: @combine_mul_abs_x_abs_y_poison_2(
+; CHECK-NEXT:    [[ABS_X:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
+; CHECK-NEXT:    [[ABS_Y:%.*]] = call i32 @llvm.abs.i32(i32 [[Y:%.*]], i1 false)
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[ABS_X]], [[ABS_Y]]
+; CHECK-NEXT:    ret i32 [[MUL]]
 ;
   %abs_x = call i32 @llvm.abs.i32(i32 %x, i1 false)
   %abs_y = call i32 @llvm.abs.i32(i32 %y, i1 false)
-  %mul = mul i32 %abs_x, %abs_y
+  %mul = mul nsw i32 %abs_x, %abs_y
   ret i32 %mul
 }
 



More information about the llvm-commits mailing list