[llvm] [InstCombine] simplify `(X * C0) / (X * C1)` into `C0 / C1`. (PR #73204)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 23 22:03:56 PST 2023
https://github.com/Z572 updated https://github.com/llvm/llvm-project/pull/73204
>From 6a4b73675ea03e85ff2ba1f46620b9f2da8a0381 Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Thu, 23 Nov 2023 11:30:54 +0800
Subject: [PATCH 1/2] [InstCombine] Simplify `(X * C0) / (X * C1)` into `C0 /
C1`.
proof: https://alive2.llvm.org/ce/z/IIEKgf
---
.../InstCombine/InstCombineMulDivRem.cpp | 12 +++
llvm/test/Transforms/InstCombine/div.ll | 93 +++++++++++++++++++
2 files changed, 105 insertions(+)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 40156726c7038b9..0032422cd3ce7c7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1207,6 +1207,18 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
}
}
+ // (X * C0) / (X * C1) --> C0 / C1
+ Constant *C0, *C1;
+ if (match(Op0, m_c_Mul(m_Value(X), m_Constant(C0))) &&
+ match(Op1, m_c_Mul(m_Specific(X), m_Constant(C1)))) {
+ auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
+ auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();
+ if ((IsSigned && OB0HasNSW) || (!IsSigned && OB0HasNUW)) {
+ replaceOperand(I, 0, C0);
+ replaceOperand(I, 1, C1);
+ return &I;
+ };
+ }
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index cd17d10d0e1de07..2fb4873c72f5832 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1432,6 +1432,99 @@ define <2 x i8> @sdiv_sdiv_mul_nsw(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
ret <2 x i8> %r
}
+; (X * C0) / (X * C1) --> C0 / C1
+define i8 @sdiv_mul_nsw_mul(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_nsw_mul(
+; CHECK-NEXT: ret i8 2
+;
+ %add4 = mul i8 %x, 6
+ %add5 = mul nsw i8 %x, 12
+ %div = sdiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @sdiv_mul_nsw_mul_nsw(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw(
+; CHECK-NEXT: ret i8 2
+;
+ %add4 = mul nsw i8 %x, 5
+ %add5 = mul nsw i8 %x, 10
+ %div = sdiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @sdiv_mul_mul_nsw(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_mul_nsw(
+; CHECK-NEXT: [[ADD4:%.*]] = mul nsw i8 [[X:%.*]], 10
+; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], 20
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul nsw i8 %x, 10
+ %add5 = mul i8 %x, 20
+ %div = sdiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @sdiv_mul_mul(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_mul(
+; CHECK-NEXT: [[ADD4:%.*]] = mul i8 [[X:%.*]], 10
+; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], 20
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul i8 %x, 10
+ %add5 = mul i8 %x, 20
+ %div = sdiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @udiv_mul_mul(i8 %x) {
+; CHECK-LABEL: @udiv_mul_mul(
+; CHECK-NEXT: [[ADD4:%.*]] = mul i8 [[X:%.*]], 10
+; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], 20
+; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul i8 %x, 10
+ %add5 = mul i8 %x, 20
+ %div = udiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @udiv_mul_nuw_mul_nuw(i8 %x) {
+; CHECK-LABEL: @udiv_mul_nuw_mul_nuw(
+; CHECK-NEXT: ret i8 1
+;
+ %add4 = mul nuw i8 %x, 10
+ %add5 = mul nuw i8 %x, 10
+ %div = udiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @udiv_mul_mul_nuw(i8 %x) {
+; CHECK-LABEL: @udiv_mul_mul_nuw(
+; CHECK-NEXT: [[ADD4:%.*]] = mul nuw i8 [[X:%.*]], 10
+; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], 20
+; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul nuw i8 %x, 10
+ %add5 = mul i8 %x, 20
+ %div = udiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @udiv_mul_nuw_mul(i8 %x) {
+; CHECK-LABEL: @udiv_mul_nuw_mul(
+; CHECK-NEXT: ret i8 2
+;
+ %add4 = mul i8 %x, 10
+ %add5 = mul nuw i8 %x, 20
+ %div = udiv i8 %add5, %add4
+ ret i8 %div
+}
+
define i32 @sdiv_sub1(i32 %arg) {
; CHECK-LABEL: @sdiv_sub1(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG:%.*]], -2147483648
>From 3d5abb4a9cd981ec31d9659a5b2e959f62a5a3cd Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Fri, 24 Nov 2023 13:07:51 +0800
Subject: [PATCH 2/2] fixup! [InstCombine] Simplify `(X * C0) / (X * C1)` into
`C0 / C1`.
---
.../InstCombine/InstCombineMulDivRem.cpp | 56 +++++---
llvm/test/Transforms/InstCombine/div.ll | 132 ++++++++++++++++--
2 files changed, 152 insertions(+), 36 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 0032422cd3ce7c7..c6b0fc9b884cf10 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1207,17 +1207,44 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
}
}
- // (X * C0) / (X * C1) --> C0 / C1
- Constant *C0, *C1;
- if (match(Op0, m_c_Mul(m_Value(X), m_Constant(C0))) &&
- match(Op1, m_c_Mul(m_Specific(X), m_Constant(C1)))) {
+
+ // (X * Y) / (X * Z) --> Y / X (and commuted variants)
+ if (match(Op0, m_Mul(m_Value(X), m_Value(Y)))) {
auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();
- if ((IsSigned && OB0HasNSW) || (!IsSigned && OB0HasNUW)) {
- replaceOperand(I, 0, C0);
- replaceOperand(I, 1, C1);
- return &I;
+
+ auto CreateDivOrNull = [&](Value *A) -> Instruction * {
+ auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
+ auto OB1HasNUW =
+ cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
+
+ // if (IsSigned && OB0HasNSW && OB1HasNSW) {
+ // return BinaryOperator::CreateSDiv(A, Z);
+ // }
+ if (!IsSigned && OB0HasNUW && OB1HasNUW) {
+ return BinaryOperator::CreateUDiv(A, Z);
+ };
+ if (isa<Constant>(A) && isa<Constant>(Z)) {
+ if (IsSigned && OB0HasNSW) {
+ return BinaryOperator::CreateSDiv(A, Z);
+ }
+ if (!IsSigned && OB0HasNUW) {
+ return BinaryOperator::CreateUDiv(A, Z);
+ };
+ };
+ return nullptr;
};
+
+ if (match(Op1, m_c_Mul(m_Specific(X), m_Value(Z)))) {
+ auto *Val = CreateDivOrNull(Y);
+ if (Val)
+ return Val;
+ };
+ if (match(Op1, m_c_Mul(m_Specific(Y), m_Value(Z)))) {
+ auto *Val = CreateDivOrNull(X);
+ if (Val)
+ return Val;
+ }
}
return nullptr;
}
@@ -1389,20 +1416,7 @@ Instruction *InstCombinerImpl::visitUDiv(BinaryOperator &I) {
if (Instruction *NarrowDiv = narrowUDivURem(I, *this))
return NarrowDiv;
- // If the udiv operands are non-overflowing multiplies with a common operand,
- // then eliminate the common factor:
- // (A * B) / (A * X) --> B / X (and commuted variants)
- // TODO: The code would be reduced if we had m_c_NUWMul pattern matching.
- // TODO: If -reassociation handled this generally, we could remove this.
Value *A, *B;
- if (match(Op0, m_NUWMul(m_Value(A), m_Value(B)))) {
- if (match(Op1, m_NUWMul(m_Specific(A), m_Value(X))) ||
- match(Op1, m_NUWMul(m_Value(X), m_Specific(A))))
- return BinaryOperator::CreateUDiv(B, X);
- if (match(Op1, m_NUWMul(m_Specific(B), m_Value(X))) ||
- match(Op1, m_NUWMul(m_Value(X), m_Specific(B))))
- return BinaryOperator::CreateUDiv(A, X);
- }
// Look through a right-shift to find the common factor:
// ((Op1 *nuw A) >> B) / Op1 --> A >> B
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 2fb4873c72f5832..cd4a09e7f4dedb9 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1433,8 +1433,110 @@ define <2 x i8> @sdiv_sdiv_mul_nsw(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
}
; (X * C0) / (X * C1) --> C0 / C1
-define i8 @sdiv_mul_nsw_mul(i8 %x) {
+define i8 @sdiv_mul_nsw_mul(i8 %x,i8 %y,i8 %z) {
; CHECK-LABEL: @sdiv_mul_nsw_mul(
+; CHECK-NEXT: [[ADD4:%.*]] = mul i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[ADD5:%.*]] = mul nsw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul i8 %x, %z
+ %add5 = mul nsw i8 %x, %y
+ %div = sdiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @sdiv_mul_nsw_mul_nsw(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw(
+; CHECK-NEXT: [[ADD4:%.*]] = mul nsw i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[ADD5:%.*]] = mul nsw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul nsw i8 %x, %z
+ %add5 = mul nsw i8 %x, %y
+ %div = sdiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @sdiv_mul_mul_nsw(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @sdiv_mul_mul_nsw(
+; CHECK-NEXT: [[ADD4:%.*]] = mul nsw i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul nsw i8 %x, %z
+ %add5 = mul i8 %x, %y
+ %div = sdiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @sdiv_mul_mul(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @sdiv_mul_mul(
+; CHECK-NEXT: [[ADD4:%.*]] = mul i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul i8 %x, %z
+ %add5 = mul i8 %x, %y
+ %div = sdiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @udiv_mul_mul(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @udiv_mul_mul(
+; CHECK-NEXT: [[ADD4:%.*]] = mul i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul i8 %x, %z
+ %add5 = mul i8 %x, %y
+ %div = udiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @udiv_mul_nuw_mul_nuw(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @udiv_mul_nuw_mul_nuw(
+; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[Y:%.*]], [[Z:%.*]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul nuw i8 %x, %z
+ %add5 = mul nuw i8 %x, %y
+ %div = udiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @udiv_mul_mul_nuw(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @udiv_mul_mul_nuw(
+; CHECK-NEXT: [[ADD4:%.*]] = mul nuw i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul nuw i8 %x, %z
+ %add5 = mul i8 %x, %y
+ %div = udiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @udiv_mul_nuw_mul(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @udiv_mul_nuw_mul(
+; CHECK-NEXT: [[ADD4:%.*]] = mul i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[ADD5:%.*]] = mul nuw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i8 [[DIV]]
+;
+ %add4 = mul i8 %x, %z
+ %add5 = mul nuw i8 %x, %y
+ %div = udiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i8 @sdiv_mul_nsw_constant_mul_constant(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant(
; CHECK-NEXT: ret i8 2
;
%add4 = mul i8 %x, 6
@@ -1443,8 +1545,8 @@ define i8 @sdiv_mul_nsw_mul(i8 %x) {
ret i8 %div
}
-define i8 @sdiv_mul_nsw_mul_nsw(i8 %x) {
-; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw(
+define i8 @sdiv_mul_nsw_constant_mul_nsw_constant(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_nsw_constant(
; CHECK-NEXT: ret i8 2
;
%add4 = mul nsw i8 %x, 5
@@ -1453,8 +1555,8 @@ define i8 @sdiv_mul_nsw_mul_nsw(i8 %x) {
ret i8 %div
}
-define i8 @sdiv_mul_mul_nsw(i8 %x) {
-; CHECK-LABEL: @sdiv_mul_mul_nsw(
+define i8 @sdiv_mul_constant_mul_nsw_constant(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_constant_mul_nsw_constant(
; CHECK-NEXT: [[ADD4:%.*]] = mul nsw i8 [[X:%.*]], 10
; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], 20
; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
@@ -1466,8 +1568,8 @@ define i8 @sdiv_mul_mul_nsw(i8 %x) {
ret i8 %div
}
-define i8 @sdiv_mul_mul(i8 %x) {
-; CHECK-LABEL: @sdiv_mul_mul(
+define i8 @sdiv_mul_constant_mul_constant(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_constant_mul_constant(
; CHECK-NEXT: [[ADD4:%.*]] = mul i8 [[X:%.*]], 10
; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], 20
; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
@@ -1479,8 +1581,8 @@ define i8 @sdiv_mul_mul(i8 %x) {
ret i8 %div
}
-define i8 @udiv_mul_mul(i8 %x) {
-; CHECK-LABEL: @udiv_mul_mul(
+define i8 @udiv_mul_constant_mul_constant(i8 %x) {
+; CHECK-LABEL: @udiv_mul_constant_mul_constant(
; CHECK-NEXT: [[ADD4:%.*]] = mul i8 [[X:%.*]], 10
; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], 20
; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
@@ -1492,8 +1594,8 @@ define i8 @udiv_mul_mul(i8 %x) {
ret i8 %div
}
-define i8 @udiv_mul_nuw_mul_nuw(i8 %x) {
-; CHECK-LABEL: @udiv_mul_nuw_mul_nuw(
+define i8 @udiv_mul_nuw_constant_mul_nuw_constant(i8 %x) {
+; CHECK-LABEL: @udiv_mul_nuw_constant_mul_nuw_constant(
; CHECK-NEXT: ret i8 1
;
%add4 = mul nuw i8 %x, 10
@@ -1502,8 +1604,8 @@ define i8 @udiv_mul_nuw_mul_nuw(i8 %x) {
ret i8 %div
}
-define i8 @udiv_mul_mul_nuw(i8 %x) {
-; CHECK-LABEL: @udiv_mul_mul_nuw(
+define i8 @udiv_mul_constant_mul_nuw_constant(i8 %x) {
+; CHECK-LABEL: @udiv_mul_constant_mul_nuw_constant(
; CHECK-NEXT: [[ADD4:%.*]] = mul nuw i8 [[X:%.*]], 10
; CHECK-NEXT: [[ADD5:%.*]] = mul i8 [[X]], 20
; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
@@ -1515,8 +1617,8 @@ define i8 @udiv_mul_mul_nuw(i8 %x) {
ret i8 %div
}
-define i8 @udiv_mul_nuw_mul(i8 %x) {
-; CHECK-LABEL: @udiv_mul_nuw_mul(
+define i8 @udiv_mul_constant_nuw_mul_constant(i8 %x) {
+; CHECK-LABEL: @udiv_mul_constant_nuw_mul_constant(
; CHECK-NEXT: ret i8 2
;
%add4 = mul i8 %x, 10
More information about the llvm-commits
mailing list