[llvm] [InstCombine] simplify `(X * C0) / (X * C1)` into `C0 / C1`. (PR #73204)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 12 22:49:52 PST 2023
https://github.com/Z572 updated https://github.com/llvm/llvm-project/pull/73204
>From 619f8728e971c6acf326934e422ba43456eb4301 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 | 54 ++++++--
llvm/test/Transforms/InstCombine/div.ll | 121 ++++++++++++++++++
2 files changed, 162 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 40156726c7038b..7ae36a1bbfa6b4 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1207,6 +1207,47 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
}
}
+ // (X * Y) / (X * Z) --> Y / Z (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();
+
+ auto CreateDivOrNull = [&](Value *A, Value *B, Value *C) -> Instruction * {
+ auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
+ auto OB1HasNUW =
+ cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
+ const APInt *C1, *C2;
+ if (IsSigned && OB0HasNSW) {
+ if (OB1HasNSW && match(B, m_APInt(C1)) && !C1->isAllOnes())
+ return BinaryOperator::CreateSDiv(A, B);
+ if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)))
+ if (auto *V = simplifyMulInst(C, B, OB1HasNSW, OB1HasNUW,
+ SQ.getWithInstruction(&I))) {
+ const APInt *AV;
+ APInt Q, R;
+ APInt::sdivrem(*C1, *C2, Q, R);
+ if (match(V, m_APInt(AV)) && !AV->isSignMask() && R.isZero())
+ return replaceInstUsesWith(I, ConstantInt::get(A->getType(), Q));
+ }
+ }
+ if (!IsSigned && OB0HasNUW) {
+ if (OB1HasNUW)
+ return BinaryOperator::CreateUDiv(A, B);
+ if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)) && C2->ule(*C1))
+ return BinaryOperator::CreateUDiv(A, B);
+ }
+ return nullptr;
+ };
+
+ if (match(Op1, m_c_Mul(m_Specific(X), m_Value(Z)))) {
+ if (auto *Val = CreateDivOrNull(Y, Z, X))
+ return Val;
+ }
+ if (match(Op1, m_c_Mul(m_Specific(Y), m_Value(Z)))) {
+ if (auto *Val = CreateDivOrNull(X, Z, Y))
+ return Val;
+ }
+ }
return nullptr;
}
@@ -1377,20 +1418,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 cd17d10d0e1de0..f2ba36bb8dec8e 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1432,6 +1432,127 @@ 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_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 @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 @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
+ %add5 = mul nsw i8 %x, 10
+ %div = sdiv i8 %add5, %add4
+ ret i8 %div
+}
+
+define i4 @sdiv_mul_nsw_constant_mul_constant(i4 %a) {
+; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant(
+; CHECK-NEXT: [[ADD4:%.*]] = mul i4 [[A:%.*]], 3
+; CHECK-NEXT: [[ADD5:%.*]] = mul nsw i4 [[A]], 6
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i4 [[DIV]]
+;
+ %add4 = mul i4 %a, 3
+ %add5 = mul nsw i4 %a, 6
+ %div = sdiv i4 %add5, %add4
+ ret i4 %div
+}
+define i4 @sdiv_mul_nsw_constant_mul_constant2(i4 %a) {
+; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant2(
+; CHECK-NEXT: [[ADD4:%.*]] = sub i4 0, [[A:%.*]]
+; CHECK-NEXT: [[ADD5:%.*]] = shl i4 [[A]], 3
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i4 [[DIV]]
+;
+ %add4 = mul i4 %a, 15
+ %add5 = mul nsw i4 %a, 8
+ %div = sdiv i4 %add5, %add4
+ ret i4 %div
+}
+
+define i4 @sdiv_mul_nsw_constant_mul_constant3(i4 %a) {
+; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant3(
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i4 [[A:%.*]], -8
+; CHECK-NEXT: [[DIV:%.*]] = select i1 [[TMP1]], i4 1, i4 -1
+; CHECK-NEXT: ret i4 [[DIV]]
+;
+ %add4 = mul i4 %a, 15
+ %add5 = mul nsw i4 %a, 1
+ %div = sdiv i4 %add5, %add4
+ ret i4 %div
+}
+
+define i4 @sdiv_mul_nsw_mul(i4 %a) {
+; CHECK-LABEL: @sdiv_mul_nsw_mul(
+; CHECK-NEXT: [[ADD4:%.*]] = sub i4 0, [[A:%.*]]
+; CHECK-NEXT: [[ADD5:%.*]] = shl i4 [[A]], 3
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i4 [[DIV]]
+;
+ %add4 = mul i4 %a, -1
+ %add5 = mul nsw i4 %a, -8
+ %div = sdiv i4 %add5, %add4
+ ret i4 %div
+}
+
+define i4 @udiv_mul_nuw_constant_mul_constant(i4 %a) {
+; CHECK-LABEL: @udiv_mul_nuw_constant_mul_constant(
+; CHECK-NEXT: ret i4 2
+;
+ %add4 = mul i4 %a, 3
+ %add5 = mul nuw i4 %a, 6
+ %div = udiv i4 %add5, %add4
+ ret i4 %div
+}
+
+define i4 @sdiv_mul_nsw_mul_nsw_allones(i4 %a) {
+; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw_allones(
+; CHECK-NEXT: [[ADD4:%.*]] = sub nsw i4 0, [[A:%.*]]
+; CHECK-NEXT: [[ADD5:%.*]] = shl i4 [[A]], 3
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i4 [[DIV]]
+;
+ %add4 = mul nsw i4 %a, -1
+ %add5 = mul nsw i4 %a, -8
+ %div = sdiv i4 %add5, %add4
+ ret i4 %div
+}
+
+define i4 @sdiv_mul_nsw_mul_signmask(i4 %a, i4 %c2) {
+; CHECK-LABEL: @sdiv_mul_nsw_mul_signmask(
+; CHECK-NEXT: [[ADD4:%.*]] = shl i4 [[A:%.*]], 3
+; CHECK-NEXT: [[ADD5:%.*]] = mul nsw i4 [[A]], [[C2:%.*]]
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i4 [[DIV]]
+;
+ %add4 = mul nsw i4 %a, -8
+ %add5 = mul nsw i4 %a, %c2
+ %div = sdiv i4 %add5, %add4
+ ret i4 %div
+}
+
define i32 @sdiv_sub1(i32 %arg) {
; CHECK-LABEL: @sdiv_sub1(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG:%.*]], -2147483648
>From dd17dec60f88a50db87e25395d63396ce0b2b9c9 Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Wed, 13 Dec 2023 14:49:17 +0800
Subject: [PATCH 2/2] fixup! [InstCombine] Simplify `(X * C0) / (X * C1)` into
`C0 / C1`.
---
.../InstCombine/InstCombineMulDivRem.cpp | 15 +++------------
llvm/test/Transforms/InstCombine/div.ll | 13 +++++++++++++
2 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 7ae36a1bbfa6b4..c981a0f7de19e9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1212,7 +1212,7 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();
- auto CreateDivOrNull = [&](Value *A, Value *B, Value *C) -> Instruction * {
+ auto CreateDivOrNull = [&](Value *A, Value *B) -> Instruction * {
auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
auto OB1HasNUW =
cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
@@ -1220,15 +1220,6 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
if (IsSigned && OB0HasNSW) {
if (OB1HasNSW && match(B, m_APInt(C1)) && !C1->isAllOnes())
return BinaryOperator::CreateSDiv(A, B);
- if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)))
- if (auto *V = simplifyMulInst(C, B, OB1HasNSW, OB1HasNUW,
- SQ.getWithInstruction(&I))) {
- const APInt *AV;
- APInt Q, R;
- APInt::sdivrem(*C1, *C2, Q, R);
- if (match(V, m_APInt(AV)) && !AV->isSignMask() && R.isZero())
- return replaceInstUsesWith(I, ConstantInt::get(A->getType(), Q));
- }
}
if (!IsSigned && OB0HasNUW) {
if (OB1HasNUW)
@@ -1240,11 +1231,11 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
};
if (match(Op1, m_c_Mul(m_Specific(X), m_Value(Z)))) {
- if (auto *Val = CreateDivOrNull(Y, Z, X))
+ if (auto *Val = CreateDivOrNull(Y, Z))
return Val;
}
if (match(Op1, m_c_Mul(m_Specific(Y), m_Value(Z)))) {
- if (auto *Val = CreateDivOrNull(X, Z, Y))
+ if (auto *Val = CreateDivOrNull(X, Z))
return Val;
}
}
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index f2ba36bb8dec8e..80847dd588ea92 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1527,6 +1527,19 @@ define i4 @udiv_mul_nuw_constant_mul_constant(i4 %a) {
ret i4 %div
}
+define i4 @udiv_mul_nuw_mul_negative(i4 %a) {
+; CHECK-LABEL: @udiv_mul_nuw_mul_negative(
+; CHECK-NEXT: [[ADD4:%.*]] = mul i4 [[A:%.*]], -3
+; CHECK-NEXT: [[ADD5:%.*]] = shl nuw i4 [[A]], 2
+; CHECK-NEXT: [[DIV:%.*]] = udiv i4 [[ADD5]], [[ADD4]]
+; CHECK-NEXT: ret i4 [[DIV]]
+;
+ %add4 = mul i4 %a, 13
+ %add5 = mul nuw i4 %a, 4
+ %div = udiv i4 %add5, %add4
+ ret i4 %div
+}
+
define i4 @sdiv_mul_nsw_mul_nsw_allones(i4 %a) {
; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw_allones(
; CHECK-NEXT: [[ADD4:%.*]] = sub nsw i4 0, [[A:%.*]]
More information about the llvm-commits
mailing list