[llvm] [InstCombine] Fold abs(a * abs(b)) --> abs(a * b) (PR #78110)

via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 5 18:58:27 PST 2024


https://github.com/elhewaty updated https://github.com/llvm/llvm-project/pull/78110

>From 067ea5b3045304ed838d687a747d671da49b5aeb Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Sun, 14 Jan 2024 18:36:27 +0200
Subject: [PATCH 1/2] [InstCombine] Add test coverage for abs(b * abs(a)) -->
 abs(a * b) (NFC)

---
 .../Transforms/InstCombine/abs-intrinsic.ll   | 110 ++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
index 7fe34d92376485..d814439f67d7a9 100644
--- a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
+++ b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
@@ -5,7 +5,117 @@ declare i8 @llvm.abs.i8(i8, i1)
 declare i32 @llvm.abs.i32(i32, i1)
 declare <4 x i32> @llvm.abs.v4i32(<4 x i32>, i1)
 declare <3 x i82> @llvm.abs.v3i82(<3 x i82>, i1)
+declare <2 x i8> @llvm.abs.v2i8(<2 x i8>, i1)
 declare void @llvm.assume(i1)
+declare void @use(i32)
+
+define i8 @test_abs_abs_a_mul_b_i8(i8 %a, i8 %b) {
+; CHECK-LABEL: @test_abs_abs_a_mul_b_i8(
+; CHECK-NEXT:    [[ABS1:%.*]] = call i8 @llvm.abs.i8(i8 [[A:%.*]], i1 true)
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[ABS1]], [[B:%.*]]
+; CHECK-NEXT:    [[ABS2:%.*]] = call i8 @llvm.abs.i8(i8 [[MUL]], i1 true)
+; CHECK-NEXT:    ret i8 [[ABS2]]
+;
+  %abs1 = call i8 @llvm.abs.i8(i8 %a, i1 true)
+  %mul = mul i8 %abs1, %b
+  %abs2 = call i8 @llvm.abs.i8(i8 %mul, i1 true)
+  ret i8 %abs2
+}
+
+define i8 @test_abs_a_mul_abs_b_i8(i8 %a, i8 %b) {
+; CHECK-LABEL: @test_abs_a_mul_abs_b_i8(
+; CHECK-NEXT:    [[A1:%.*]] = urem i8 123, [[A:%.*]]
+; CHECK-NEXT:    [[ABS1:%.*]] = call i8 @llvm.abs.i8(i8 [[B:%.*]], i1 true)
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[A1]], [[ABS1]]
+; CHECK-NEXT:    [[ABS2:%.*]] = call i8 @llvm.abs.i8(i8 [[MUL]], i1 true)
+; CHECK-NEXT:    ret i8 [[ABS2]]
+;
+  %a1 = urem i8 123, %a
+  %abs1 = call i8 @llvm.abs.i8(i8 %b, i1 true)
+  %mul = mul i8 %a1, %abs1  ; thwart complexity-based canonicalization
+  %abs2 = call i8 @llvm.abs.i8(i8 %mul, i1 true)
+  ret i8 %abs2
+}
+
+define i32 @test_abs_abs_a_mul_b_i32(i32 %a, i32 %b) {
+; CHECK-LABEL: @test_abs_abs_a_mul_b_i32(
+; CHECK-NEXT:    [[ABS1:%.*]] = call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true)
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS1]], [[B:%.*]]
+; CHECK-NEXT:    [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[MUL]], i1 true)
+; CHECK-NEXT:    ret i32 [[ABS2]]
+;
+  %abs1 = call i32 @llvm.abs.i32(i32 %a, i1 true)
+  %mul = mul i32 %abs1, %b
+  %abs2 = call i32 @llvm.abs.i32(i32 %mul, i1 true)
+  ret i32 %abs2
+}
+
+define i32 @test_abs_abs_a_mul_b_i32_abs_false_true(i32 %a, i32 %b) {
+; CHECK-LABEL: @test_abs_abs_a_mul_b_i32_abs_false_true(
+; CHECK-NEXT:    [[ABS1:%.*]] = call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false)
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS1]], [[B:%.*]]
+; CHECK-NEXT:    [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[MUL]], i1 true)
+; CHECK-NEXT:    ret i32 [[ABS2]]
+;
+  %abs1 = call i32 @llvm.abs.i32(i32 %a, i1 false)
+  %mul = mul i32 %abs1, %b
+  %abs2 = call i32 @llvm.abs.i32(i32 %mul, i1 true)
+  ret i32 %abs2
+}
+
+define i32 @test_abs_abs_a_mul_b_i32_abs_true_false(i32 %a, i32 %b) {
+; CHECK-LABEL: @test_abs_abs_a_mul_b_i32_abs_true_false(
+; CHECK-NEXT:    [[ABS1:%.*]] = call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true)
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS1]], [[B:%.*]]
+; CHECK-NEXT:    [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[MUL]], i1 false)
+; CHECK-NEXT:    ret i32 [[ABS2]]
+;
+  %abs1 = call i32 @llvm.abs.i32(i32 %a, i1 true)
+  %mul = mul i32 %abs1, %b
+  %abs2 = call i32 @llvm.abs.i32(i32 %mul, i1 false)
+  ret i32 %abs2
+}
+
+define i32 @test_abs_abs_a_mul_b_i32_abs_false_false(i32 %a, i32 %b) {
+; CHECK-LABEL: @test_abs_abs_a_mul_b_i32_abs_false_false(
+; CHECK-NEXT:    [[ABS1:%.*]] = call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false)
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS1]], [[B:%.*]]
+; CHECK-NEXT:    [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[MUL]], i1 false)
+; CHECK-NEXT:    ret i32 [[ABS2]]
+;
+  %abs1 = call i32 @llvm.abs.i32(i32 %a, i1 false)
+  %mul = mul i32 %abs1, %b
+  %abs2 = call i32 @llvm.abs.i32(i32 %mul, i1 false)
+  ret i32 %abs2
+}
+
+define i32 @test_abs_abs_a_mul_b_more_one_use(i32 %a, i32 %b) {
+; CHECK-LABEL: @test_abs_abs_a_mul_b_more_one_use(
+; CHECK-NEXT:    [[ABS1:%.*]] = call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true)
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS1]], [[B:%.*]]
+; CHECK-NEXT:    [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[MUL]], i1 false)
+; CHECK-NEXT:    call void @use(i32 [[MUL]])
+; CHECK-NEXT:    ret i32 [[ABS2]]
+;
+  %abs1 = call i32 @llvm.abs.i32(i32 %a, i1 true)
+  %mul = mul i32 %abs1, %b
+  %abs2 = call i32 @llvm.abs.i32(i32 %mul, i1 false)
+  call void @use(i32 %mul)
+  ret i32 %abs2
+}
+
+define <2 x i8> @test_abs_abs_a_mul_b_vector_i8(<2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: @test_abs_abs_a_mul_b_vector_i8(
+; CHECK-NEXT:    [[ABS:%.*]] = call <2 x i8> @llvm.abs.v2i8(<2 x i8> [[A:%.*]], i1 true)
+; CHECK-NEXT:    [[MUL:%.*]] = mul <2 x i8> [[ABS]], [[B:%.*]]
+; CHECK-NEXT:    [[ABS2:%.*]] = call <2 x i8> @llvm.abs.v2i8(<2 x i8> [[MUL]], i1 true)
+; CHECK-NEXT:    ret <2 x i8> [[ABS2]]
+;
+  %abs = call <2 x i8> @llvm.abs.v2i8(<2 x i8> %a, i1 true)
+  %mul = mul <2 x i8> %abs, %b
+  %abs2 = call <2 x i8> @llvm.abs.v2i8(<2 x i8> %mul, i1 true)
+  ret <2 x i8> %abs2
+}
 
 ; abs preserves trailing zeros so the second and is unneeded
 define i32 @abs_trailing_zeros(i32 %x) {

>From dd376d8145da4eafe0f861fdf39efb8e0c111b08 Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Tue, 6 Feb 2024 04:54:43 +0200
Subject: [PATCH 2/2] [InstCombine] Fold abs(b * abs(a)) --> abs(a * b)

---
 .../InstCombine/InstCombineMulDivRem.cpp      | 10 +++++++++
 .../Transforms/InstCombine/abs-intrinsic.ll   | 21 +++++++------------
 2 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index e7f983a00e3044..060b3a6a8becec 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -218,6 +218,16 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
                   : BinaryOperator::CreateNeg(Op0);
   }
 
+  {
+    // abs(a * abs(b)) --> abs(a * b)
+    Value *A, *B;
+    if (match(&I, m_OneUse(m_c_Mul(m_Value(A),
+                                   m_Intrinsic<Intrinsic::abs>(m_Value(B)))))) {
+      Value *New = Builder.CreateMul(A, B);
+      return replaceInstUsesWith(I, New);
+    }
+  }
+
   // Also allow combining multiply instructions on vectors.
   {
     Value *NewOp;
diff --git a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
index d814439f67d7a9..0cdfef24e50d31 100644
--- a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
+++ b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
@@ -11,8 +11,7 @@ declare void @use(i32)
 
 define i8 @test_abs_abs_a_mul_b_i8(i8 %a, i8 %b) {
 ; CHECK-LABEL: @test_abs_abs_a_mul_b_i8(
-; CHECK-NEXT:    [[ABS1:%.*]] = call i8 @llvm.abs.i8(i8 [[A:%.*]], i1 true)
-; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[ABS1]], [[B:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    [[ABS2:%.*]] = call i8 @llvm.abs.i8(i8 [[MUL]], i1 true)
 ; CHECK-NEXT:    ret i8 [[ABS2]]
 ;
@@ -25,8 +24,7 @@ define i8 @test_abs_abs_a_mul_b_i8(i8 %a, i8 %b) {
 define i8 @test_abs_a_mul_abs_b_i8(i8 %a, i8 %b) {
 ; CHECK-LABEL: @test_abs_a_mul_abs_b_i8(
 ; CHECK-NEXT:    [[A1:%.*]] = urem i8 123, [[A:%.*]]
-; CHECK-NEXT:    [[ABS1:%.*]] = call i8 @llvm.abs.i8(i8 [[B:%.*]], i1 true)
-; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[A1]], [[ABS1]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[A1]], [[B:%.*]]
 ; CHECK-NEXT:    [[ABS2:%.*]] = call i8 @llvm.abs.i8(i8 [[MUL]], i1 true)
 ; CHECK-NEXT:    ret i8 [[ABS2]]
 ;
@@ -39,8 +37,7 @@ define i8 @test_abs_a_mul_abs_b_i8(i8 %a, i8 %b) {
 
 define i32 @test_abs_abs_a_mul_b_i32(i32 %a, i32 %b) {
 ; CHECK-LABEL: @test_abs_abs_a_mul_b_i32(
-; CHECK-NEXT:    [[ABS1:%.*]] = call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true)
-; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS1]], [[B:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[MUL]], i1 true)
 ; CHECK-NEXT:    ret i32 [[ABS2]]
 ;
@@ -52,8 +49,7 @@ define i32 @test_abs_abs_a_mul_b_i32(i32 %a, i32 %b) {
 
 define i32 @test_abs_abs_a_mul_b_i32_abs_false_true(i32 %a, i32 %b) {
 ; CHECK-LABEL: @test_abs_abs_a_mul_b_i32_abs_false_true(
-; CHECK-NEXT:    [[ABS1:%.*]] = call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false)
-; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS1]], [[B:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[MUL]], i1 true)
 ; CHECK-NEXT:    ret i32 [[ABS2]]
 ;
@@ -65,8 +61,7 @@ define i32 @test_abs_abs_a_mul_b_i32_abs_false_true(i32 %a, i32 %b) {
 
 define i32 @test_abs_abs_a_mul_b_i32_abs_true_false(i32 %a, i32 %b) {
 ; CHECK-LABEL: @test_abs_abs_a_mul_b_i32_abs_true_false(
-; CHECK-NEXT:    [[ABS1:%.*]] = call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true)
-; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS1]], [[B:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[MUL]], i1 false)
 ; CHECK-NEXT:    ret i32 [[ABS2]]
 ;
@@ -78,8 +73,7 @@ define i32 @test_abs_abs_a_mul_b_i32_abs_true_false(i32 %a, i32 %b) {
 
 define i32 @test_abs_abs_a_mul_b_i32_abs_false_false(i32 %a, i32 %b) {
 ; CHECK-LABEL: @test_abs_abs_a_mul_b_i32_abs_false_false(
-; CHECK-NEXT:    [[ABS1:%.*]] = call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false)
-; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[ABS1]], [[B:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    [[ABS2:%.*]] = call i32 @llvm.abs.i32(i32 [[MUL]], i1 false)
 ; CHECK-NEXT:    ret i32 [[ABS2]]
 ;
@@ -106,8 +100,7 @@ define i32 @test_abs_abs_a_mul_b_more_one_use(i32 %a, i32 %b) {
 
 define <2 x i8> @test_abs_abs_a_mul_b_vector_i8(<2 x i8> %a, <2 x i8> %b) {
 ; CHECK-LABEL: @test_abs_abs_a_mul_b_vector_i8(
-; CHECK-NEXT:    [[ABS:%.*]] = call <2 x i8> @llvm.abs.v2i8(<2 x i8> [[A:%.*]], i1 true)
-; CHECK-NEXT:    [[MUL:%.*]] = mul <2 x i8> [[ABS]], [[B:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul <2 x i8> [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    [[ABS2:%.*]] = call <2 x i8> @llvm.abs.v2i8(<2 x i8> [[MUL]], i1 true)
 ; CHECK-NEXT:    ret <2 x i8> [[ABS2]]
 ;



More information about the llvm-commits mailing list