[llvm] [InstCombine] Support division of numbers that can be converted to a shift (PR #88220)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 13 10:21:58 PDT 2024
https://github.com/AtariDreams updated https://github.com/llvm/llvm-project/pull/88220
>From 3c456e4cd46b56c1e2031470af5f789451b44e8a Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Tue, 9 Apr 2024 21:04:26 -0400
Subject: [PATCH 1/5] Pre-commit tests (NFC)
---
llvm/test/Transforms/InstCombine/div.ll | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index e8a25ff44d0296..a44731daf81ef7 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1638,6 +1638,30 @@ define i32 @sdiv_mul_sub_nsw(i32 %x, i32 %y) {
ret i32 %d
}
+ define i32 @mul_by_150_udiv_by_100 (i32 %0) {
+; CHECK-LABEL: @mul_by_150_udiv_by_100(
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw i32 [[TMP0:%.*]], 150
+; CHECK-NEXT: [[TMP3:%.*]] = udiv i32 [[TMP2]], 100
+; CHECK-NEXT: ret i32 [[TMP3]]
+;
+ %2 = mul nuw i32 %0, 150
+ %3 = udiv i32 %2, 100
+ ret i32 %3
+}
+
+;negative case, no nuw
+
+ define i32 @mul_by_150_sdiv_by_100 (i32 %0) {
+; CHECK-LABEL: @mul_by_150_sdiv_by_100(
+; CHECK-NEXT: [[TMP2:%.*]] = mul nsw i32 [[TMP0:%.*]], 150
+; CHECK-NEXT: [[TMP3:%.*]] = sdiv i32 [[TMP2]], 100
+; CHECK-NEXT: ret i32 [[TMP3]]
+;
+ %2 = mul nsw i32 %0, 150
+ %3 = sdiv i32 %2, 100
+ ret i32 %3
+}
+
define i32 @sdiv_mul_nsw_sub_nsw(i32 %x, i32 %y) {
; CHECK-LABEL: @sdiv_mul_nsw_sub_nsw(
; CHECK-NEXT: ret i32 -1
>From f4c46443860fe3bdf7b57c1b7a659ad6d10fedff Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Tue, 9 Apr 2024 20:32:12 -0400
Subject: [PATCH 2/5] [InstCombine] Support division of numbers that can be
converted to a shift
---
.../InstCombine/InstCombineMulDivRem.cpp | 38 +++++++++++++++++++
llvm/test/Transforms/InstCombine/div.ll | 4 +-
2 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 8c698e52b5a0e6..4121f3c5b4b1ad 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1149,6 +1149,44 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
Mul->setHasNoSignedWrap(OBO->hasNoSignedWrap());
return Mul;
}
+
+ // If we can reduce these functions so they can factor out to a shift or
+ // something similar (i.e Reduce (X * 150/100) -> (X * 3) >> 1)
+ //
+ // (X * C1)/C2 -> X * (C1/C3) >> log2(C2/C3) where C3 divides exactly C1
+ // and C2 and C2/C3 is a power of 2.
+ // This WILL require NUW, and if it is sdiv then it also requires NSW
+ // TODO: Can we expand this for negative powers of 2? Is it even
+ // profitable or worth it?
+ if (Op0->hasOneUse() && C1->isStrictlyPositive() &&
+ C2->isStrictlyPositive()) {
+ APInt C3 = APIntOps::GreatestCommonDivisor(*C1, *C2);
+ APInt Q(C2->getBitWidth(), /*val=*/0ULL, IsSigned);
+
+ // Returns false if division by 0
+ if (isMultiple(*C2, C3, Q, IsSigned) && Q.isPowerOf2()) {
+ auto *OBO = cast<OverflowingBinaryOperator>(Op0);
+ if ((!IsSigned && OBO->hasNoUnsignedWrap()) ||
+ (IsSigned && OBO->hasNoSignedWrap())) {
+
+ APInt C4 = IsSigned ? C1->sdiv(C3) : C1->udiv(C3);
+ auto *Mul = Builder.CreateMul(
+ X, ConstantInt::get(Ty, C4), "",
+ // If it is unsigned, then we cannot have any nsw or nuw flags.
+ // It has been tried before, but no avail.
+ /* HasNUW */ OBO->hasNoUnsignedWrap() && IsSigned,
+ /* HasNSW */ IsSigned);
+
+ // Because both the multiplier and divisor are unsigned, we can use
+ // lshr
+ // TODO: revisit this if we let negative powers of 2
+ Instruction *Shift = BinaryOperator::CreateLShr(
+ Mul, ConstantInt::get(Ty, Q.logBase2()));
+ Shift->setIsExact(I.isExact());
+ return Shift;
+ }
+ }
+ }
}
if ((IsSigned && match(Op0, m_NSWShl(m_Value(X), m_APInt(C1))) &&
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index a44731daf81ef7..0b8a9ba8009089 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1640,8 +1640,8 @@ define i32 @sdiv_mul_sub_nsw(i32 %x, i32 %y) {
define i32 @mul_by_150_udiv_by_100 (i32 %0) {
; CHECK-LABEL: @mul_by_150_udiv_by_100(
-; CHECK-NEXT: [[TMP2:%.*]] = mul nuw i32 [[TMP0:%.*]], 150
-; CHECK-NEXT: [[TMP3:%.*]] = udiv i32 [[TMP2]], 100
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP0:%.*]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[TMP2]], 1
; CHECK-NEXT: ret i32 [[TMP3]]
;
%2 = mul nuw i32 %0, 150
>From 7017287fbfcbd9b4d99d1f106f35aff88578b7f8 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Wed, 10 Apr 2024 22:35:31 -0400
Subject: [PATCH 3/5] F
---
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | 7 +------
llvm/test/Transforms/InstCombine/div.ll | 6 +++---
2 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 4121f3c5b4b1ad..5b7454c034f872 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1158,17 +1158,13 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
// This WILL require NUW, and if it is sdiv then it also requires NSW
// TODO: Can we expand this for negative powers of 2? Is it even
// profitable or worth it?
- if (Op0->hasOneUse() && C1->isStrictlyPositive() &&
- C2->isStrictlyPositive()) {
+ if (Op0->hasOneUse()) {
APInt C3 = APIntOps::GreatestCommonDivisor(*C1, *C2);
APInt Q(C2->getBitWidth(), /*val=*/0ULL, IsSigned);
// Returns false if division by 0
if (isMultiple(*C2, C3, Q, IsSigned) && Q.isPowerOf2()) {
auto *OBO = cast<OverflowingBinaryOperator>(Op0);
- if ((!IsSigned && OBO->hasNoUnsignedWrap()) ||
- (IsSigned && OBO->hasNoSignedWrap())) {
-
APInt C4 = IsSigned ? C1->sdiv(C3) : C1->udiv(C3);
auto *Mul = Builder.CreateMul(
X, ConstantInt::get(Ty, C4), "",
@@ -1184,7 +1180,6 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
Mul, ConstantInt::get(Ty, Q.logBase2()));
Shift->setIsExact(I.isExact());
return Shift;
- }
}
}
}
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 0b8a9ba8009089..687fb67a80e8af 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1640,7 +1640,7 @@ define i32 @sdiv_mul_sub_nsw(i32 %x, i32 %y) {
define i32 @mul_by_150_udiv_by_100 (i32 %0) {
; CHECK-LABEL: @mul_by_150_udiv_by_100(
-; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP0:%.*]], 3
+; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[TMP0:%.*]], 3
; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[TMP2]], 1
; CHECK-NEXT: ret i32 [[TMP3]]
;
@@ -1653,8 +1653,8 @@ define i32 @sdiv_mul_sub_nsw(i32 %x, i32 %y) {
define i32 @mul_by_150_sdiv_by_100 (i32 %0) {
; CHECK-LABEL: @mul_by_150_sdiv_by_100(
-; CHECK-NEXT: [[TMP2:%.*]] = mul nsw i32 [[TMP0:%.*]], 150
-; CHECK-NEXT: [[TMP3:%.*]] = sdiv i32 [[TMP2]], 100
+; CHECK-NEXT: [[TMP2:%.*]] = mul nsw i32 [[TMP0:%.*]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[TMP2]], 1
; CHECK-NEXT: ret i32 [[TMP3]]
;
%2 = mul nsw i32 %0, 150
>From b3f99eba51323765e94408433a39efc3faf177ed Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Sat, 13 Apr 2024 10:14:07 -0400
Subject: [PATCH 4/5] Revert "F"
This reverts commit 7017287fbfcbd9b4d99d1f106f35aff88578b7f8.
---
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | 7 ++++++-
llvm/test/Transforms/InstCombine/div.ll | 6 +++---
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 5b7454c034f872..4121f3c5b4b1ad 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1158,13 +1158,17 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
// This WILL require NUW, and if it is sdiv then it also requires NSW
// TODO: Can we expand this for negative powers of 2? Is it even
// profitable or worth it?
- if (Op0->hasOneUse()) {
+ if (Op0->hasOneUse() && C1->isStrictlyPositive() &&
+ C2->isStrictlyPositive()) {
APInt C3 = APIntOps::GreatestCommonDivisor(*C1, *C2);
APInt Q(C2->getBitWidth(), /*val=*/0ULL, IsSigned);
// Returns false if division by 0
if (isMultiple(*C2, C3, Q, IsSigned) && Q.isPowerOf2()) {
auto *OBO = cast<OverflowingBinaryOperator>(Op0);
+ if ((!IsSigned && OBO->hasNoUnsignedWrap()) ||
+ (IsSigned && OBO->hasNoSignedWrap())) {
+
APInt C4 = IsSigned ? C1->sdiv(C3) : C1->udiv(C3);
auto *Mul = Builder.CreateMul(
X, ConstantInt::get(Ty, C4), "",
@@ -1180,6 +1184,7 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
Mul, ConstantInt::get(Ty, Q.logBase2()));
Shift->setIsExact(I.isExact());
return Shift;
+ }
}
}
}
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 687fb67a80e8af..0b8a9ba8009089 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1640,7 +1640,7 @@ define i32 @sdiv_mul_sub_nsw(i32 %x, i32 %y) {
define i32 @mul_by_150_udiv_by_100 (i32 %0) {
; CHECK-LABEL: @mul_by_150_udiv_by_100(
-; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[TMP0:%.*]], 3
+; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw i32 [[TMP0:%.*]], 3
; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[TMP2]], 1
; CHECK-NEXT: ret i32 [[TMP3]]
;
@@ -1653,8 +1653,8 @@ define i32 @sdiv_mul_sub_nsw(i32 %x, i32 %y) {
define i32 @mul_by_150_sdiv_by_100 (i32 %0) {
; CHECK-LABEL: @mul_by_150_sdiv_by_100(
-; CHECK-NEXT: [[TMP2:%.*]] = mul nsw i32 [[TMP0:%.*]], 3
-; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[TMP2]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = mul nsw i32 [[TMP0:%.*]], 150
+; CHECK-NEXT: [[TMP3:%.*]] = sdiv i32 [[TMP2]], 100
; CHECK-NEXT: ret i32 [[TMP3]]
;
%2 = mul nsw i32 %0, 150
>From cb10114b6491ec2f7f397138d07a07bb62173218 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Sat, 13 Apr 2024 13:21:43 -0400
Subject: [PATCH 5/5] e
---
.../InstCombine/InstCombineMulDivRem.cpp | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 4121f3c5b4b1ad..c73500a6883166 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1155,11 +1155,15 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
//
// (X * C1)/C2 -> X * (C1/C3) >> log2(C2/C3) where C3 divides exactly C1
// and C2 and C2/C3 is a power of 2.
- // This WILL require NUW, and if it is sdiv then it also requires NSW
- // TODO: Can we expand this for negative powers of 2? Is it even
- // profitable or worth it?
- if (Op0->hasOneUse() && C1->isStrictlyPositive() &&
- C2->isStrictlyPositive()) {
+
+ // TODO: is there a cleaner way to check for evenness?
+ if (Op0->hasOneUse() && (C1->countTrailingOnes() == 0) &&
+ (C2->countTrailingOnes() == 0) && !C2->isZero() &&
+ (C1->isNegative() == C2->isNegative())) {
+
+ if (C1->isNegative())
+ C1 = C1->
+
APInt C3 = APIntOps::GreatestCommonDivisor(*C1, *C2);
APInt Q(C2->getBitWidth(), /*val=*/0ULL, IsSigned);
More information about the llvm-commits
mailing list