[llvm] [InstCombine] Simplifiy `(-x * y * -x)` into `(x * y * x)` (PR #72953)

via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 6 02:03:59 PST 2023


https://github.com/Z572 updated https://github.com/llvm/llvm-project/pull/72953

>From b07ca5fca430424d074146032b3d49f87d7bbec2 Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Tue, 21 Nov 2023 11:41:20 +0800
Subject: [PATCH 1/5] [InstCombine] Simplifiy `(-x * y * -x)` into `(x * y *
 x)`

proof: https://alive2.llvm.org/ce/z/B9kej-
---
 .../InstCombine/InstCombineMulDivRem.cpp      |  2 +-
 .../InstCombine/mul-inseltpoison.ll           |  5 +-
 llvm/test/Transforms/InstCombine/mul.ll       | 53 +++++++++++++++++--
 .../sub-of-negatible-inseltpoison.ll          |  5 +-
 .../InstCombine/sub-of-negatible.ll           |  5 +-
 5 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 40156726c7038..458341b8900ca 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -349,7 +349,7 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
 
   // -X * Y --> -(X * Y)
   // X * -Y --> -(X * Y)
-  if (match(&I, m_c_Mul(m_OneUse(m_Neg(m_Value(X))), m_Value(Y))))
+  if (match(&I, m_c_Mul(m_Neg(m_Value(X)), m_Value(Y))))
     return BinaryOperator::CreateNeg(Builder.CreateMul(X, Y));
 
   // (X / Y) *  Y = X - (X % Y)
diff --git a/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll b/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
index 448558d755a57..ed0b74d44ace1 100644
--- a/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
@@ -672,9 +672,8 @@ define <2 x i32> @test_mul_canonicalize_vec(<2 x i32> %x, <2 x i32> %y) {
 
 define i32 @test_mul_canonicalize_multiple_uses(i32 %x, i32 %y) {
 ; CHECK-LABEL: @test_mul_canonicalize_multiple_uses(
-; CHECK-NEXT:    [[NEG:%.*]] = sub i32 0, [[X:%.*]]
-; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[NEG]], [[Y:%.*]]
-; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[MUL]], [[NEG]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
 ; CHECK-NEXT:    ret i32 [[MUL2]]
 ;
   %neg = sub i32 0, %x
diff --git a/llvm/test/Transforms/InstCombine/mul.ll b/llvm/test/Transforms/InstCombine/mul.ll
index 42698b5102bc5..3b610cf1cf4dd 100644
--- a/llvm/test/Transforms/InstCombine/mul.ll
+++ b/llvm/test/Transforms/InstCombine/mul.ll
@@ -1233,9 +1233,8 @@ define <2 x i32> @test_mul_canonicalize_vec(<2 x i32> %x, <2 x i32> %y) {
 
 define i32 @test_mul_canonicalize_multiple_uses(i32 %x, i32 %y) {
 ; CHECK-LABEL: @test_mul_canonicalize_multiple_uses(
-; CHECK-NEXT:    [[NEG:%.*]] = sub i32 0, [[X:%.*]]
-; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[NEG]], [[Y:%.*]]
-; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[MUL]], [[NEG]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
 ; CHECK-NEXT:    ret i32 [[MUL2]]
 ;
   %neg = sub i32 0, %x
@@ -1244,6 +1243,54 @@ define i32 @test_mul_canonicalize_multiple_uses(i32 %x, i32 %y) {
   ret i32 %mul2
 }
 
+define i32 @mul_nsw_mul_nsw_neg(i32 %x, i32 %y) {
+; CHECK-LABEL: @mul_nsw_mul_nsw_neg(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i32 [[MUL2]]
+;
+  %neg = sub i32 0, %x
+  %mul = mul nsw i32 %neg, %y
+  %mul2 = mul nsw i32 %mul, %neg
+  ret i32 %mul2
+}
+
+define i32 @mul_mul_nsw_neg(i32 %x,i32 %y) {
+; CHECK-LABEL: @mul_mul_nsw_neg(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i32 [[MUL2]]
+;
+  %neg = sub i32 0, %x
+  %mul = mul nsw i32 %neg, %y
+  %mul2 = mul i32 %mul, %neg
+  ret i32 %mul2
+}
+
+define i32 @mul_nsw_mul_neg(i32 %x,i32 %y) {
+; CHECK-LABEL: @mul_nsw_mul_neg(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i32 [[MUL2]]
+;
+  %neg = sub i32 0, %x
+  %mul = mul i32 %neg, %y
+  %mul2 = mul nsw i32 %mul, %neg
+  ret i32 %mul2
+}
+
+define i32 @mul_mul_neg(i32 %x) {
+; CHECK-LABEL: @mul_mul_neg(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i32 [[MUL2]]
+;
+  %neg = sub i32 0, %x
+  %mul = mul i32 %neg, %x
+  %mul2 = mul i32 %mul, %neg
+  ret i32 %mul2
+}
+
 @X = global i32 5
 
 define i64 @test_mul_canonicalize_neg_is_not_undone(i64 %L1) {
diff --git a/llvm/test/Transforms/InstCombine/sub-of-negatible-inseltpoison.ll b/llvm/test/Transforms/InstCombine/sub-of-negatible-inseltpoison.ll
index d76564dd7a67e..dfed19f7ba1e4 100644
--- a/llvm/test/Transforms/InstCombine/sub-of-negatible-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/sub-of-negatible-inseltpoison.ll
@@ -399,9 +399,10 @@ define i8 @n16(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @n16(
 ; CHECK-NEXT:    [[T0:%.*]] = sub i8 0, [[Y:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
-; CHECK-NEXT:    [[T1:%.*]] = mul i8 [[T0]], [[Z:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i8 [[Y]], [[Z:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = sub i8 0, [[TMP1]]
 ; CHECK-NEXT:    call void @use8(i8 [[T1]])
-; CHECK-NEXT:    [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
+; CHECK-NEXT:    [[T2:%.*]] = add i8 [[TMP1]], [[X:%.*]]
 ; CHECK-NEXT:    ret i8 [[T2]]
 ;
   %t0 = sub i8 0, %y
diff --git a/llvm/test/Transforms/InstCombine/sub-of-negatible.ll b/llvm/test/Transforms/InstCombine/sub-of-negatible.ll
index aacc83eba0061..7fcc7020785e6 100644
--- a/llvm/test/Transforms/InstCombine/sub-of-negatible.ll
+++ b/llvm/test/Transforms/InstCombine/sub-of-negatible.ll
@@ -423,9 +423,10 @@ define i8 @n16(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @n16(
 ; CHECK-NEXT:    [[T0:%.*]] = sub i8 0, [[Y:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
-; CHECK-NEXT:    [[T1:%.*]] = mul i8 [[T0]], [[Z:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul i8 [[Y]], [[Z:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = sub i8 0, [[TMP1]]
 ; CHECK-NEXT:    call void @use8(i8 [[T1]])
-; CHECK-NEXT:    [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
+; CHECK-NEXT:    [[T2:%.*]] = add i8 [[TMP1]], [[X:%.*]]
 ; CHECK-NEXT:    ret i8 [[T2]]
 ;
   %t0 = sub i8 0, %y

>From 31c560cb90b65cf1c649c3652f44f8828dbab194 Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Tue, 21 Nov 2023 17:35:08 +0800
Subject: [PATCH 2/5] fixup! [InstCombine] Simplifiy `(-x * y * -x)` into `(x *
 y * x)`

---
 .../InstCombine/InstCombineMulDivRem.cpp      | 15 ++++++++-
 llvm/test/Transforms/InstCombine/mul.ll       | 32 ++++++++++++++++---
 .../sub-of-negatible-inseltpoison.ll          |  5 ++-
 .../InstCombine/sub-of-negatible.ll           |  5 ++-
 4 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 458341b8900ca..6a36083b8993e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -349,9 +349,22 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
 
   // -X * Y --> -(X * Y)
   // X * -Y --> -(X * Y)
-  if (match(&I, m_c_Mul(m_Neg(m_Value(X)), m_Value(Y))))
+  if (match(&I, m_c_Mul(m_OneUse(m_Neg(m_Value(X))), m_Value(Y))))
     return BinaryOperator::CreateNeg(Builder.CreateMul(X, Y));
 
+  // -X * Y * -X --> X * Y * X
+  if (match(&I, m_c_Mul(m_Neg(m_Value(X)),
+                        m_c_Mul(m_Value(Y), m_Neg(m_Deferred(X)))))) {
+    if (X == Y) {
+      auto *Mul = BinaryOperator::CreateMul(
+          X, Builder.CreateMul(
+                 X, Y, "", /*HasNUW*/ false,
+                 cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap()));
+      Mul->setHasNoSignedWrap(HasNSW);
+      return Mul;
+    }
+    return BinaryOperator::CreateMul(X, Builder.CreateMul(X, Y));
+  }
   // (X / Y) *  Y = X - (X % Y)
   // (X / Y) * -Y = (X % Y) - X
   {
diff --git a/llvm/test/Transforms/InstCombine/mul.ll b/llvm/test/Transforms/InstCombine/mul.ll
index 3b610cf1cf4dd..33a2503810650 100644
--- a/llvm/test/Transforms/InstCombine/mul.ll
+++ b/llvm/test/Transforms/InstCombine/mul.ll
@@ -1279,15 +1279,39 @@ define i32 @mul_nsw_mul_neg(i32 %x,i32 %y) {
   ret i32 %mul2
 }
 
-define i32 @mul_mul_neg(i32 %x) {
-; CHECK-LABEL: @mul_mul_neg(
+define i32 @mul_mul_neg_onearg(i32 %x) {
+; CHECK-LABEL: @mul_mul_neg_onearg(
 ; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[X]]
-; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul nsw i32 [[TMP1]], [[X]]
 ; CHECK-NEXT:    ret i32 [[MUL2]]
 ;
   %neg = sub i32 0, %x
   %mul = mul i32 %neg, %x
-  %mul2 = mul i32 %mul, %neg
+  %mul2 = mul nsw i32 %mul, %neg
+  ret i32 %mul2
+}
+
+define i8 @mul_mul_nsw_neg_onearg(i8 %x) {
+; CHECK-LABEL: @mul_mul_nsw_neg_onearg(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nsw i8 [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i8 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i8 [[MUL2]]
+;
+  %neg = sub i8 0, %x
+  %mul = mul nsw i8 %neg, %x
+  %mul2 = mul i8 %mul, %neg
+  ret i8 %mul2
+}
+
+define i32 @mul_nsw_mul_nsw_neg_onearg(i32 %x) {
+; CHECK-LABEL: @mul_nsw_mul_nsw_neg_onearg(
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nsw i32 [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul nsw i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    ret i32 [[MUL2]]
+;
+  %neg = sub i32 0, %x
+  %mul = mul nsw i32 %neg, %x
+  %mul2 = mul nsw i32 %mul, %neg
   ret i32 %mul2
 }
 
diff --git a/llvm/test/Transforms/InstCombine/sub-of-negatible-inseltpoison.ll b/llvm/test/Transforms/InstCombine/sub-of-negatible-inseltpoison.ll
index dfed19f7ba1e4..d76564dd7a67e 100644
--- a/llvm/test/Transforms/InstCombine/sub-of-negatible-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/sub-of-negatible-inseltpoison.ll
@@ -399,10 +399,9 @@ define i8 @n16(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @n16(
 ; CHECK-NEXT:    [[T0:%.*]] = sub i8 0, [[Y:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
-; CHECK-NEXT:    [[TMP1:%.*]] = mul i8 [[Y]], [[Z:%.*]]
-; CHECK-NEXT:    [[T1:%.*]] = sub i8 0, [[TMP1]]
+; CHECK-NEXT:    [[T1:%.*]] = mul i8 [[T0]], [[Z:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[T1]])
-; CHECK-NEXT:    [[T2:%.*]] = add i8 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
 ; CHECK-NEXT:    ret i8 [[T2]]
 ;
   %t0 = sub i8 0, %y
diff --git a/llvm/test/Transforms/InstCombine/sub-of-negatible.ll b/llvm/test/Transforms/InstCombine/sub-of-negatible.ll
index 7fcc7020785e6..aacc83eba0061 100644
--- a/llvm/test/Transforms/InstCombine/sub-of-negatible.ll
+++ b/llvm/test/Transforms/InstCombine/sub-of-negatible.ll
@@ -423,10 +423,9 @@ define i8 @n16(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @n16(
 ; CHECK-NEXT:    [[T0:%.*]] = sub i8 0, [[Y:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
-; CHECK-NEXT:    [[TMP1:%.*]] = mul i8 [[Y]], [[Z:%.*]]
-; CHECK-NEXT:    [[T1:%.*]] = sub i8 0, [[TMP1]]
+; CHECK-NEXT:    [[T1:%.*]] = mul i8 [[T0]], [[Z:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[T1]])
-; CHECK-NEXT:    [[T2:%.*]] = add i8 [[TMP1]], [[X:%.*]]
+; CHECK-NEXT:    [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
 ; CHECK-NEXT:    ret i8 [[T2]]
 ;
   %t0 = sub i8 0, %y

>From d0065673184ee75bb10a11718b5c533763fb99ca Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Wed, 22 Nov 2023 08:59:46 +0800
Subject: [PATCH 3/5] fixup! fixup! [InstCombine] Simplifiy `(-x * y * -x)`
 into `(x * y * x)`

---
 llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 6a36083b8993e..4c54f929042b2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -356,10 +356,10 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
   if (match(&I, m_c_Mul(m_Neg(m_Value(X)),
                         m_c_Mul(m_Value(Y), m_Neg(m_Deferred(X)))))) {
     if (X == Y) {
-      auto *Mul = BinaryOperator::CreateMul(
-          X, Builder.CreateMul(
-                 X, Y, "", /*HasNUW*/ false,
-                 cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap()));
+      Value *MulXY = Builder.CreateMul(X, Y);
+      bool BO0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
+      cast<BinaryOperator>(MulXY)->setHasNoSignedWrap(BO0HasNSW);
+      auto *Mul = BinaryOperator::CreateMul(X, MulXY);
       Mul->setHasNoSignedWrap(HasNSW);
       return Mul;
     }

>From 9bc1fffd402c50bc942eb677dd00528b86cd2053 Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Tue, 5 Dec 2023 11:26:37 +0800
Subject: [PATCH 4/5] fixup! fixup! fixup! [InstCombine] Simplifiy `(-x * y *
 -x)` into `(x * y * x)`

---
 llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 4c54f929042b2..e8f976634f7e7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -353,8 +353,8 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
     return BinaryOperator::CreateNeg(Builder.CreateMul(X, Y));
 
   // -X * Y * -X --> X * Y * X
-  if (match(&I, m_c_Mul(m_Neg(m_Value(X)),
-                        m_c_Mul(m_Value(Y), m_Neg(m_Deferred(X)))))) {
+  if (match(&I, m_Mul(m_c_Mul(m_Value(Y), m_Neg(m_Value(X))),
+                      m_Neg(m_Deferred(X))))) {
     if (X == Y) {
       Value *MulXY = Builder.CreateMul(X, Y);
       bool BO0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();

>From dc1af0df489d32ba69de51fdc38bb2307ce45917 Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Wed, 6 Dec 2023 17:42:39 +0800
Subject: [PATCH 5/5] fixup! fixup! fixup! fixup! [InstCombine] Simplifiy `(-x
 * y * -x)` into `(x * y * x)`

---
 .../InstCombine/InstCombineMulDivRem.cpp      |  30 ++--
 .../InstCombine/mul-inseltpoison.ll           |   4 +-
 llvm/test/Transforms/InstCombine/mul.ll       | 134 +++++++++++++++---
 3 files changed, 138 insertions(+), 30 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index e8f976634f7e7..859b8ec7484a5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -351,19 +351,25 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
   // X * -Y --> -(X * Y)
   if (match(&I, m_c_Mul(m_OneUse(m_Neg(m_Value(X))), m_Value(Y))))
     return BinaryOperator::CreateNeg(Builder.CreateMul(X, Y));
-
-  // -X * Y * -X --> X * Y * X
-  if (match(&I, m_Mul(m_c_Mul(m_Value(Y), m_Neg(m_Value(X))),
-                      m_Neg(m_Deferred(X))))) {
-    if (X == Y) {
-      Value *MulXY = Builder.CreateMul(X, Y);
-      bool BO0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
-      cast<BinaryOperator>(MulXY)->setHasNoSignedWrap(BO0HasNSW);
-      auto *Mul = BinaryOperator::CreateMul(X, MulXY);
-      Mul->setHasNoSignedWrap(HasNSW);
-      return Mul;
+  // (-X * Y) * -X --> (X * Y) * X
+  // (-X << Y) * -X --> (X << Y) * X
+  {
+    bool IsShl = false;
+    if ((match(Op0, m_c_Mul(m_Neg(m_Value(X)), m_Value(Y))) ||
+         (match(Op0, m_Shl(m_Neg(m_Value(X)), m_Value(Y))) &&
+          (IsShl = true))) &&
+        match(Op1, m_Neg(m_Specific(X)))) {
+      auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
+      if (Value *NegOp0 = Negator::Negate(
+              true,
+              /*IsNSW*/ ((X == Y) ? OB0HasNSW : (IsShl && HasNSW && OB0HasNSW)),
+              Op0, *this)) {
+        auto *Mul = BinaryOperator::CreateMul(NegOp0, Builder.CreateNeg(Op1));
+        Mul->setHasNoSignedWrap((X == Y) ? HasNSW
+                                         : (IsShl && HasNSW && OB0HasNSW));
+        return Mul;
+      }
     }
-    return BinaryOperator::CreateMul(X, Builder.CreateMul(X, Y));
   }
   // (X / Y) *  Y = X - (X % Y)
   // (X / Y) * -Y = (X % Y) - X
diff --git a/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll b/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
index ed0b74d44ace1..8fe4261bbf009 100644
--- a/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
@@ -672,8 +672,8 @@ define <2 x i32> @test_mul_canonicalize_vec(<2 x i32> %x, <2 x i32> %y) {
 
 define i32 @test_mul_canonicalize_multiple_uses(i32 %x, i32 %y) {
 ; CHECK-LABEL: @test_mul_canonicalize_multiple_uses(
-; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
 ; CHECK-NEXT:    ret i32 [[MUL2]]
 ;
   %neg = sub i32 0, %x
diff --git a/llvm/test/Transforms/InstCombine/mul.ll b/llvm/test/Transforms/InstCombine/mul.ll
index 33a2503810650..164cdda83ced8 100644
--- a/llvm/test/Transforms/InstCombine/mul.ll
+++ b/llvm/test/Transforms/InstCombine/mul.ll
@@ -1233,8 +1233,8 @@ define <2 x i32> @test_mul_canonicalize_vec(<2 x i32> %x, <2 x i32> %y) {
 
 define i32 @test_mul_canonicalize_multiple_uses(i32 %x, i32 %y) {
 ; CHECK-LABEL: @test_mul_canonicalize_multiple_uses(
-; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
 ; CHECK-NEXT:    ret i32 [[MUL2]]
 ;
   %neg = sub i32 0, %x
@@ -1245,8 +1245,8 @@ define i32 @test_mul_canonicalize_multiple_uses(i32 %x, i32 %y) {
 
 define i32 @mul_nsw_mul_nsw_neg(i32 %x, i32 %y) {
 ; CHECK-LABEL: @mul_nsw_mul_nsw_neg(
-; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
 ; CHECK-NEXT:    ret i32 [[MUL2]]
 ;
   %neg = sub i32 0, %x
@@ -1257,8 +1257,8 @@ define i32 @mul_nsw_mul_nsw_neg(i32 %x, i32 %y) {
 
 define i32 @mul_mul_nsw_neg(i32 %x,i32 %y) {
 ; CHECK-LABEL: @mul_mul_nsw_neg(
-; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
 ; CHECK-NEXT:    ret i32 [[MUL2]]
 ;
   %neg = sub i32 0, %x
@@ -1269,8 +1269,8 @@ define i32 @mul_mul_nsw_neg(i32 %x,i32 %y) {
 
 define i32 @mul_nsw_mul_neg(i32 %x,i32 %y) {
 ; CHECK-LABEL: @mul_nsw_mul_neg(
-; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
 ; CHECK-NEXT:    ret i32 [[MUL2]]
 ;
   %neg = sub i32 0, %x
@@ -1279,10 +1279,10 @@ define i32 @mul_nsw_mul_neg(i32 %x,i32 %y) {
   ret i32 %mul2
 }
 
-define i32 @mul_mul_neg_onearg(i32 %x) {
-; CHECK-LABEL: @mul_mul_neg_onearg(
-; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[X:%.*]], [[X]]
-; CHECK-NEXT:    [[MUL2:%.*]] = mul nsw i32 [[TMP1]], [[X]]
+define i32 @mul_nsw_mul_neg_onearg(i32 %x) {
+; CHECK-LABEL: @mul_nsw_mul_neg_onearg(
+; CHECK-NEXT:    [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul nsw i32 [[MUL_NEG]], [[X]]
 ; CHECK-NEXT:    ret i32 [[MUL2]]
 ;
   %neg = sub i32 0, %x
@@ -1293,8 +1293,8 @@ define i32 @mul_mul_neg_onearg(i32 %x) {
 
 define i8 @mul_mul_nsw_neg_onearg(i8 %x) {
 ; CHECK-LABEL: @mul_mul_nsw_neg_onearg(
-; CHECK-NEXT:    [[TMP1:%.*]] = mul nsw i8 [[X:%.*]], [[X]]
-; CHECK-NEXT:    [[MUL2:%.*]] = mul i8 [[TMP1]], [[X]]
+; CHECK-NEXT:    [[MUL_NEG:%.*]] = mul nsw i8 [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i8 [[MUL_NEG]], [[X]]
 ; CHECK-NEXT:    ret i8 [[MUL2]]
 ;
   %neg = sub i8 0, %x
@@ -1305,8 +1305,8 @@ define i8 @mul_mul_nsw_neg_onearg(i8 %x) {
 
 define i32 @mul_nsw_mul_nsw_neg_onearg(i32 %x) {
 ; CHECK-LABEL: @mul_nsw_mul_nsw_neg_onearg(
-; CHECK-NEXT:    [[TMP1:%.*]] = mul nsw i32 [[X:%.*]], [[X]]
-; CHECK-NEXT:    [[MUL2:%.*]] = mul nsw i32 [[TMP1]], [[X]]
+; CHECK-NEXT:    [[MUL_NEG:%.*]] = mul nsw i32 [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL2:%.*]] = mul nsw i32 [[MUL_NEG]], [[X]]
 ; CHECK-NEXT:    ret i32 [[MUL2]]
 ;
   %neg = sub i32 0, %x
@@ -1315,6 +1315,108 @@ define i32 @mul_nsw_mul_nsw_neg_onearg(i32 %x) {
   ret i32 %mul2
 }
 
+define i32 @mul_nsw_shl_nsw_neg(i32 %x, i32 %y) {
+; CHECK-LABEL: @mul_nsw_shl_nsw_neg(
+; CHECK-NEXT:    [[SHL_NEG:%.*]] = shl nsw i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[SHL_NEG]], [[X]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %neg = sub i32 0, %x
+  %shl = shl nsw i32 %neg, %y
+  %mul = mul nsw i32 %shl, %neg
+  ret i32 %mul
+}
+
+define i32 @mul_shl_nsw_neg(i32 %x,i32 %y) {
+; CHECK-LABEL: @mul_shl_nsw_neg(
+; CHECK-NEXT:    [[SHL_NEG:%.*]] = shl i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[SHL_NEG]], [[X]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %neg = sub i32 0, %x
+  %shl = shl nsw i32 %neg, %y
+  %mul = mul i32 %shl, %neg
+  ret i32 %mul
+}
+
+define i32 @mul_nsw_shl_neg(i32 %x,i32 %y) {
+; CHECK-LABEL: @mul_nsw_shl_neg(
+; CHECK-NEXT:    [[SHL_NEG:%.*]] = shl i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[SHL_NEG]], [[X]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %neg = sub i32 0, %x
+  %shl = shl i32 %neg, %y
+  %mul = mul nsw i32 %shl, %neg
+  ret i32 %mul
+}
+
+define i32 @mul_nsw_shl_neg_onearg(i32 %x) {
+; CHECK-LABEL: @mul_nsw_shl_neg_onearg(
+; CHECK-NEXT:    [[SHL_NEG:%.*]] = shl i32 [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[SHL_NEG]], [[X]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %neg = sub i32 0, %x
+  %shl = shl i32 %neg, %x
+  %mul = mul nsw i32 %shl, %neg
+  ret i32 %mul
+}
+
+define i8 @mul_shl_nsw_neg_onearg(i8 %x) {
+; CHECK-LABEL: @mul_shl_nsw_neg_onearg(
+; CHECK-NEXT:    [[SHL_NEG:%.*]] = shl nsw i8 [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[SHL_NEG]], [[X]]
+; CHECK-NEXT:    ret i8 [[MUL]]
+;
+  %neg = sub i8 0, %x
+  %shl = shl nsw i8 %neg, %x
+  %mul = mul i8 %shl, %neg
+  ret i8 %mul
+}
+
+define i32 @mul_nsw_shl_nsw_neg_onearg(i32 %x) {
+; CHECK-LABEL: @mul_nsw_shl_nsw_neg_onearg(
+; CHECK-NEXT:    [[SHL_NEG:%.*]] = mul nsw i32 [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[SHL_NEG]], [[X]]
+; CHECK-NEXT:    ret i32 [[MUL]]
+;
+  %neg = sub i32 0, %x
+  %shl = mul nsw i32 %neg, %x
+  %mul = mul nsw i32 %shl, %neg
+  ret i32 %mul
+}
+
+define i32 @mul_use_mul_neg(i32 %x,i32 %y) {
+; CHECK-LABEL: @mul_use_mul_neg(
+; CHECK-NEXT:    [[NEG:%.*]] = sub i32 0, [[X:%.*]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    call void @use32(i32 [[MUL]])
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[MUL]], [[NEG]]
+; CHECK-NEXT:    ret i32 [[MUL2]]
+;
+  %neg = sub i32 0, %x
+  %mul = mul i32 %neg, %y
+  call void @use32(i32 %mul)
+  %mul2 = mul i32 %mul, %neg
+  ret i32 %mul2
+}
+
+define i32 @mul_shl_use_mul_neg(i32 %x,i32 %y) {
+; CHECK-LABEL: @mul_shl_use_mul_neg(
+; CHECK-NEXT:    [[NEG:%.*]] = sub i32 0, [[X:%.*]]
+; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[NEG]], [[Y:%.*]]
+; CHECK-NEXT:    call void @use32(i32 [[SHL]])
+; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 [[SHL]], [[NEG]]
+; CHECK-NEXT:    ret i32 [[MUL2]]
+;
+  %neg = sub i32 0, %x
+  %shl = shl i32 %neg, %y
+  call void @use32(i32 %shl)
+  %mul2 = mul i32 %shl, %neg
+  ret i32 %mul2
+}
+
 @X = global i32 5
 
 define i64 @test_mul_canonicalize_neg_is_not_undone(i64 %L1) {



More information about the llvm-commits mailing list