[llvm] goldsteinn/mul of exact div (PR #96915)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 27 07:51:34 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: None (goldsteinn)
<details>
<summary>Changes</summary>
- **[InstCombine] Add tests for folding `(mul (div exact X, C0), C1)`; NFC**
- **[InstCombine] Fold `(mul (div exact X, C0), C1)` -> `(div exact X, C0/C1)`**
---
Full diff: https://github.com/llvm/llvm-project/pull/96915.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp (+22)
- (modified) llvm/test/Transforms/InstCombine/exact.ll (+65-11)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index c3f1c12d2f564..aadf836669794 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -365,6 +365,28 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
return BinaryOperator::CreateMul(NegOp0, X);
}
+ if (Op0->hasOneUse()) {
+ // (mul (div exact X, C0), C1)
+ // -> (div exact C0 / C1)
+ // iff C0 % C1 == 0 and C0 / C1 doesn't create UB.
+ const APInt *C1;
+ auto UDivCheck = [&C1](const APInt &C) { return C.urem(*C1).isZero(); };
+ auto SDivCheck = [&C1](const APInt &C) {
+ APInt Quot, Rem;
+ APInt::sdivrem(C, *C1, Quot, Rem);
+ return Rem.isZero() && !Quot.isMinSignedValue();
+ };
+ if (match(Op1, m_APInt(C1)) &&
+ (match(Op0, m_Exact(m_UDiv(m_Value(X), m_CheckedInt(UDivCheck)))) ||
+ match(Op0, m_Exact(m_SDiv(m_Value(X), m_CheckedInt(SDivCheck)))))) {
+ auto BOpc = cast<BinaryOperator>(Op0)->getOpcode();
+ return BinaryOperator::CreateExact(
+ BOpc, X,
+ Builder.CreateBinOp(BOpc, cast<BinaryOperator>(Op0)->getOperand(1),
+ Op1));
+ }
+ }
+
// (X / Y) * Y = X - (X % Y)
// (X / Y) * -Y = (X % Y) - X
{
diff --git a/llvm/test/Transforms/InstCombine/exact.ll b/llvm/test/Transforms/InstCombine/exact.ll
index 10d46e7b2dfb3..4d2ea7dcd0fa8 100644
--- a/llvm/test/Transforms/InstCombine/exact.ll
+++ b/llvm/test/Transforms/InstCombine/exact.ll
@@ -63,7 +63,7 @@ define i32 @sdiv5(i32 %x) {
define i32 @sdiv6(i32 %x) {
; CHECK-LABEL: @sdiv6(
-; CHECK-NEXT: [[Z:%.*]] = sub i32 0, [[X:%.*]]
+; CHECK-NEXT: [[Z:%.*]] = sub nsw i32 0, [[X:%.*]]
; CHECK-NEXT: ret i32 [[Z]]
;
%y = sdiv exact i32 %x, 3
@@ -120,7 +120,7 @@ define i1 @ashr_icmp1(i64 %X) {
; CHECK-NEXT: [[B:%.*]] = icmp eq i64 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[B]]
;
- %A = ashr exact i64 %X, 2 ; X/4
+ %A = ashr exact i64 %X, 2 ; X/4
%B = icmp eq i64 %A, 0
ret i1 %B
}
@@ -131,7 +131,7 @@ define i1 @ashr_icmp2(i64 %X) {
; CHECK-NEXT: ret i1 [[Z]]
;
%Y = ashr exact i64 %X, 2 ; x / 4
- %Z = icmp slt i64 %Y, 4 ; x < 16
+ %Z = icmp slt i64 %Y, 4 ; x < 16
ret i1 %Z
}
@@ -181,7 +181,7 @@ define i1 @udiv_icmp1(i64 %X) {
; CHECK-NEXT: [[B:%.*]] = icmp ne i64 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[B]]
;
- %A = udiv exact i64 %X, 5 ; X/5
+ %A = udiv exact i64 %X, 5 ; X/5
%B = icmp ne i64 %A, 0
ret i1 %B
}
@@ -201,7 +201,7 @@ define i1 @udiv_icmp2(i64 %X) {
; CHECK-NEXT: [[B:%.*]] = icmp eq i64 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[B]]
;
- %A = udiv exact i64 %X, 5 ; X/5 == 0 --> x == 0
+ %A = udiv exact i64 %X, 5 ; X/5 == 0 --> x == 0
%B = icmp eq i64 %A, 0
ret i1 %B
}
@@ -221,7 +221,7 @@ define i1 @sdiv_icmp1(i64 %X) {
; CHECK-NEXT: [[B:%.*]] = icmp eq i64 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[B]]
;
- %A = sdiv exact i64 %X, 5 ; X/5 == 0 --> x == 0
+ %A = sdiv exact i64 %X, 5 ; X/5 == 0 --> x == 0
%B = icmp eq i64 %A, 0
ret i1 %B
}
@@ -241,7 +241,7 @@ define i1 @sdiv_icmp2(i64 %X) {
; CHECK-NEXT: [[B:%.*]] = icmp eq i64 [[X:%.*]], 5
; CHECK-NEXT: ret i1 [[B]]
;
- %A = sdiv exact i64 %X, 5 ; X/5 == 1 --> x == 5
+ %A = sdiv exact i64 %X, 5 ; X/5 == 1 --> x == 5
%B = icmp eq i64 %A, 1
ret i1 %B
}
@@ -261,7 +261,7 @@ define i1 @sdiv_icmp3(i64 %X) {
; CHECK-NEXT: [[B:%.*]] = icmp eq i64 [[X:%.*]], -5
; CHECK-NEXT: ret i1 [[B]]
;
- %A = sdiv exact i64 %X, 5 ; X/5 == -1 --> x == -5
+ %A = sdiv exact i64 %X, 5 ; X/5 == -1 --> x == -5
%B = icmp eq i64 %A, -1
ret i1 %B
}
@@ -281,7 +281,7 @@ define i1 @sdiv_icmp4(i64 %X) {
; CHECK-NEXT: [[B:%.*]] = icmp eq i64 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[B]]
;
- %A = sdiv exact i64 %X, -5 ; X/-5 == 0 --> x == 0
+ %A = sdiv exact i64 %X, -5 ; X/-5 == 0 --> x == 0
%B = icmp eq i64 %A, 0
ret i1 %B
}
@@ -301,7 +301,7 @@ define i1 @sdiv_icmp5(i64 %X) {
; CHECK-NEXT: [[B:%.*]] = icmp eq i64 [[X:%.*]], -5
; CHECK-NEXT: ret i1 [[B]]
;
- %A = sdiv exact i64 %X, -5 ; X/-5 == 1 --> x == -5
+ %A = sdiv exact i64 %X, -5 ; X/-5 == 1 --> x == -5
%B = icmp eq i64 %A, 1
ret i1 %B
}
@@ -321,7 +321,7 @@ define i1 @sdiv_icmp6(i64 %X) {
; CHECK-NEXT: [[B:%.*]] = icmp eq i64 [[X:%.*]], 5
; CHECK-NEXT: ret i1 [[B]]
;
- %A = sdiv exact i64 %X, -5 ; X/-5 == -1 --> x == 5
+ %A = sdiv exact i64 %X, -5 ; X/-5 == -1 --> x == 5
%B = icmp eq i64 %A, -1
ret i1 %B
}
@@ -336,3 +336,57 @@ define <2 x i1> @sdiv_icmp6_vec(<2 x i64> %X) {
ret <2 x i1> %B
}
+define i8 @mul_of_udiv(i8 %x) {
+; CHECK-LABEL: @mul_of_udiv(
+; CHECK-NEXT: [[MUL1:%.*]] = lshr exact i8 [[X:%.*]], 1
+; CHECK-NEXT: ret i8 [[MUL1]]
+;
+ %div = udiv exact i8 %x, 12
+ %mul = mul i8 %div, 6
+ ret i8 %mul
+}
+
+define i8 @mul_of_sdiv(i8 %x) {
+; CHECK-LABEL: @mul_of_sdiv(
+; CHECK-NEXT: [[MUL_NEG:%.*]] = ashr exact i8 [[X:%.*]], 1
+; CHECK-NEXT: [[MUL:%.*]] = sub nsw i8 0, [[MUL_NEG]]
+; CHECK-NEXT: ret i8 [[MUL]]
+;
+ %div = sdiv exact i8 %x, 12
+ %mul = mul i8 %div, -6
+ ret i8 %mul
+}
+
+define i8 @mul_of_sdiv_fail_missing_exact(i8 %x) {
+; CHECK-LABEL: @mul_of_sdiv_fail_missing_exact(
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[X:%.*]], 12
+; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[DIV]], -6
+; CHECK-NEXT: ret i8 [[MUL]]
+;
+ %div = sdiv i8 %x, 12
+ %mul = mul i8 %div, -6
+ ret i8 %mul
+}
+
+define i8 @mul_of_udiv_fail_bad_remainder(i8 %x) {
+; CHECK-LABEL: @mul_of_udiv_fail_bad_remainder(
+; CHECK-NEXT: [[DIV:%.*]] = udiv exact i8 [[X:%.*]], 11
+; CHECK-NEXT: [[MUL:%.*]] = mul nuw i8 [[DIV]], 6
+; CHECK-NEXT: ret i8 [[MUL]]
+;
+ %div = udiv exact i8 %x, 11
+ %mul = mul i8 %div, 6
+ ret i8 %mul
+}
+
+define i8 @mul_of_sdiv_fail_ub(i8 %x) {
+; CHECK-LABEL: @mul_of_sdiv_fail_ub(
+; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[X_FR]], 6
+; CHECK-NEXT: [[MUL:%.*]] = sub i8 [[TMP1]], [[X_FR]]
+; CHECK-NEXT: ret i8 [[MUL]]
+;
+ %div = sdiv i8 %x, 6
+ %mul = mul i8 %div, -6
+ ret i8 %mul
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/96915
More information about the llvm-commits
mailing list