[llvm] 012909d - [InstCombine] "X - (X / C) * C == 0" to "X & C-1 == 0"

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 00:20:34 PDT 2020


Author: EgorBo
Date: 2020-06-12T10:20:06+03:00
New Revision: 012909dcaf852d4260decd04a76dfe45e7d329c0

URL: https://github.com/llvm/llvm-project/commit/012909dcaf852d4260decd04a76dfe45e7d329c0
DIFF: https://github.com/llvm/llvm-project/commit/012909dcaf852d4260decd04a76dfe45e7d329c0.diff

LOG: [InstCombine] "X - (X / C) * C == 0" to "X & C-1 == 0"

Summary:
"X % C == 0" is optimized to "X & C-1 == 0" (where C is a power-of-two)
However, "X % Y" can also be represented as "X - (X / Y) * Y" so if I rewrite the initial expression:
"X - (X / C) * C == 0" it's not currently optimized to "X & C-1 == 0", see godbolt: https://godbolt.org/z/KzuXUj

This is my first contribution to LLVM so I hope I didn't mess things up

Reviewers: lebedev.ri, spatel

Reviewed By: lebedev.ri

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D79369

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
    llvm/test/Transforms/InstCombine/add-shl-sdiv-to-srem.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 288d0d148689..68367b7f7a41 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1314,6 +1314,17 @@ Instruction *InstCombiner::visitAdd(BinaryOperator &I) {
   // X % C0 + (( X / C0 ) % C1) * C0 => X % (C0 * C1)
   if (Value *V = SimplifyAddWithRemainder(I)) return replaceInstUsesWith(I, V);
 
+  // ((X s/ C1) << C2) + X => X s% -C1 where -C1 is 1 << C2
+  const APInt *C1, *C2;
+  if (match(LHS, m_Shl(m_SDiv(m_Specific(RHS), m_APInt(C1)), m_APInt(C2)))) {
+    APInt one(C2->getBitWidth(), 1);
+    APInt minusC1 = -(*C1);
+    if (minusC1 == (one << *C2)) {
+      Constant *NewRHS = ConstantInt::get(RHS->getType(), minusC1);
+      return BinaryOperator::CreateSRem(RHS, NewRHS);
+    }
+  }
+
   // A+B --> A|B iff A and B have no bits set in common.
   if (haveNoCommonBitsSet(LHS, RHS, DL, &AC, &I, &DT))
     return BinaryOperator::CreateOr(LHS, RHS);

diff  --git a/llvm/test/Transforms/InstCombine/add-shl-sdiv-to-srem.ll b/llvm/test/Transforms/InstCombine/add-shl-sdiv-to-srem.ll
index d7118b591159..57a10c165f15 100644
--- a/llvm/test/Transforms/InstCombine/add-shl-sdiv-to-srem.ll
+++ b/llvm/test/Transforms/InstCombine/add-shl-sdiv-to-srem.ll
@@ -3,9 +3,7 @@
 
 define i8 @add-shl-sdiv-scalar0(i8 %x) {
 ; CHECK-LABEL: @add-shl-sdiv-scalar0(
-; CHECK-NEXT:    [[SD:%.*]] = sdiv i8 [[X:%.*]], -4
-; CHECK-NEXT:    [[SL:%.*]] = shl i8 [[SD]], 2
-; CHECK-NEXT:    [[RZ:%.*]] = add i8 [[SL]], [[X]]
+; CHECK-NEXT:    [[RZ:%.*]] = srem i8 [[X:%.*]], 4
 ; CHECK-NEXT:    ret i8 [[RZ]]
 ;
   %sd = sdiv i8 %x, -4
@@ -16,9 +14,7 @@ define i8 @add-shl-sdiv-scalar0(i8 %x) {
 
 define i8 @add-shl-sdiv-scalar1(i8 %x) {
 ; CHECK-LABEL: @add-shl-sdiv-scalar1(
-; CHECK-NEXT:    [[SD:%.*]] = sdiv i8 [[X:%.*]], -64
-; CHECK-NEXT:    [[SL:%.*]] = shl i8 [[SD]], 6
-; CHECK-NEXT:    [[RZ:%.*]] = add i8 [[SL]], [[X]]
+; CHECK-NEXT:    [[RZ:%.*]] = srem i8 [[X:%.*]], 64
 ; CHECK-NEXT:    ret i8 [[RZ]]
 ;
   %sd = sdiv i8 %x, -64
@@ -29,9 +25,7 @@ define i8 @add-shl-sdiv-scalar1(i8 %x) {
 
 define i32 @add-shl-sdiv-scalar2(i32 %x) {
 ; CHECK-LABEL: @add-shl-sdiv-scalar2(
-; CHECK-NEXT:    [[SD:%.*]] = sdiv i32 [[X:%.*]], -1073741824
-; CHECK-NEXT:    [[SL:%.*]] = shl i32 [[SD]], 30
-; CHECK-NEXT:    [[RZ:%.*]] = add i32 [[SL]], [[X]]
+; CHECK-NEXT:    [[RZ:%.*]] = srem i32 [[X:%.*]], 1073741824
 ; CHECK-NEXT:    ret i32 [[RZ]]
 ;
   %sd = sdiv i32 %x, -1073741824
@@ -44,9 +38,7 @@ define i32 @add-shl-sdiv-scalar2(i32 %x) {
 
 define <3 x i8> @add-shl-sdiv-splat0(<3 x i8> %x) {
 ; CHECK-LABEL: @add-shl-sdiv-splat0(
-; CHECK-NEXT:    [[SD:%.*]] = sdiv <3 x i8> [[X:%.*]], <i8 -4, i8 -4, i8 -4>
-; CHECK-NEXT:    [[SL:%.*]] = shl <3 x i8> [[SD]], <i8 2, i8 2, i8 2>
-; CHECK-NEXT:    [[RZ:%.*]] = add <3 x i8> [[SL]], [[X]]
+; CHECK-NEXT:    [[RZ:%.*]] = srem <3 x i8> [[X:%.*]], <i8 4, i8 4, i8 4>
 ; CHECK-NEXT:    ret <3 x i8> [[RZ]]
 ;
   %sd = sdiv <3 x i8> %x, <i8 -4, i8 -4, i8 -4>
@@ -57,9 +49,7 @@ define <3 x i8> @add-shl-sdiv-splat0(<3 x i8> %x) {
 
 define <4 x i32> @add-shl-sdiv-splat1(<4 x i32> %x) {
 ; CHECK-LABEL: @add-shl-sdiv-splat1(
-; CHECK-NEXT:    [[SD:%.*]] = sdiv <4 x i32> [[X:%.*]], <i32 -1073741824, i32 -1073741824, i32 -1073741824, i32 -1073741824>
-; CHECK-NEXT:    [[SL:%.*]] = shl <4 x i32> [[SD]], <i32 30, i32 30, i32 30, i32 30>
-; CHECK-NEXT:    [[RZ:%.*]] = add <4 x i32> [[SL]], [[X]]
+; CHECK-NEXT:    [[RZ:%.*]] = srem <4 x i32> [[X:%.*]], <i32 1073741824, i32 1073741824, i32 1073741824, i32 1073741824>
 ; CHECK-NEXT:    ret <4 x i32> [[RZ]]
 ;
   %sd = sdiv <4 x i32> %x, <i32 -1073741824, i32 -1073741824, i32 -1073741824, i32 -1073741824>
@@ -70,9 +60,7 @@ define <4 x i32> @add-shl-sdiv-splat1(<4 x i32> %x) {
 
 define <2 x i64> @add-shl-sdiv-splat2(<2 x i64> %x) {
 ; CHECK-LABEL: @add-shl-sdiv-splat2(
-; CHECK-NEXT:    [[SD:%.*]] = sdiv <2 x i64> [[X:%.*]], <i64 -32, i64 -32>
-; CHECK-NEXT:    [[SL:%.*]] = shl <2 x i64> [[SD]], <i64 5, i64 5>
-; CHECK-NEXT:    [[RZ:%.*]] = add <2 x i64> [[SL]], [[X]]
+; CHECK-NEXT:    [[RZ:%.*]] = srem <2 x i64> [[X:%.*]], <i64 32, i64 32>
 ; CHECK-NEXT:    ret <2 x i64> [[RZ]]
 ;
   %sd = sdiv <2 x i64> %x, <i64 -32, i64 -32>
@@ -87,9 +75,7 @@ declare void @use32(i32)
 define i32 @add-shl-sdiv-i32-4-use0(i32 %x) {
 ; CHECK-LABEL: @add-shl-sdiv-i32-4-use0(
 ; CHECK-NEXT:    call void @use32(i32 [[X:%.*]])
-; CHECK-NEXT:    [[SD:%.*]] = sdiv i32 [[X]], -16
-; CHECK-NEXT:    [[SL:%.*]] = shl i32 [[SD]], 4
-; CHECK-NEXT:    [[RZ:%.*]] = add i32 [[SL]], [[X]]
+; CHECK-NEXT:    [[RZ:%.*]] = srem i32 [[X]], 16
 ; CHECK-NEXT:    ret i32 [[RZ]]
 ;
   call void @use32(i32 %x)
@@ -103,8 +89,7 @@ define i32 @add-shl-sdiv-i32-use1(i32 %x) {
 ; CHECK-LABEL: @add-shl-sdiv-i32-use1(
 ; CHECK-NEXT:    [[SD:%.*]] = sdiv i32 [[X:%.*]], -16
 ; CHECK-NEXT:    call void @use32(i32 [[SD]])
-; CHECK-NEXT:    [[SL:%.*]] = shl i32 [[SD]], 4
-; CHECK-NEXT:    [[RZ:%.*]] = add i32 [[SL]], [[X]]
+; CHECK-NEXT:    [[RZ:%.*]] = srem i32 [[X]], 16
 ; CHECK-NEXT:    ret i32 [[RZ]]
 ;
   %sd = sdiv i32 %x, -16
@@ -119,7 +104,7 @@ define i32 @add-shl-sdiv-i32-use2(i32 %x) {
 ; CHECK-NEXT:    [[SD:%.*]] = sdiv i32 [[X:%.*]], -16
 ; CHECK-NEXT:    [[SL:%.*]] = shl i32 [[SD]], 4
 ; CHECK-NEXT:    call void @use32(i32 [[SL]])
-; CHECK-NEXT:    [[RZ:%.*]] = add i32 [[SL]], [[X]]
+; CHECK-NEXT:    [[RZ:%.*]] = srem i32 [[X]], 16
 ; CHECK-NEXT:    ret i32 [[RZ]]
 ;
   %sd = sdiv i32 %x, -16
@@ -135,7 +120,7 @@ define i32 @add-shl-sdiv-i32-use3(i32 %x) {
 ; CHECK-NEXT:    call void @use32(i32 [[SD]])
 ; CHECK-NEXT:    [[SL:%.*]] = shl i32 [[SD]], 4
 ; CHECK-NEXT:    call void @use32(i32 [[SL]])
-; CHECK-NEXT:    [[RZ:%.*]] = add i32 [[SL]], [[X]]
+; CHECK-NEXT:    [[RZ:%.*]] = srem i32 [[X]], 16
 ; CHECK-NEXT:    ret i32 [[RZ]]
 ;
   %sd = sdiv i32 %x, -16
@@ -151,8 +136,7 @@ define <3 x i8> @add-shl-sdiv-use4(<3 x i8> %x) {
 ; CHECK-LABEL: @add-shl-sdiv-use4(
 ; CHECK-NEXT:    [[SD:%.*]] = sdiv <3 x i8> [[X:%.*]], <i8 -4, i8 -4, i8 -4>
 ; CHECK-NEXT:    call void @use3xi8(<3 x i8> [[SD]])
-; CHECK-NEXT:    [[SL:%.*]] = shl <3 x i8> [[SD]], <i8 2, i8 2, i8 2>
-; CHECK-NEXT:    [[RZ:%.*]] = add <3 x i8> [[SL]], [[X]]
+; CHECK-NEXT:    [[RZ:%.*]] = srem <3 x i8> [[X]], <i8 4, i8 4, i8 4>
 ; CHECK-NEXT:    ret <3 x i8> [[RZ]]
 ;
   %sd = sdiv <3 x i8> %x, <i8 -4, i8 -4, i8 -4>


        


More information about the llvm-commits mailing list