[llvm] ffe1396 - [InstCombine] Fold (A & 2^C1) + A => A & (2^C1 - 1) iff bit C1 in A is a sign bit (PR21929)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 22 08:59:10 PDT 2022


Author: Simon Pilgrim
Date: 2022-04-22T16:59:02+01:00
New Revision: ffe13960b5795b08b574b31720b517c59f26ca2f

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

LOG: [InstCombine] Fold (A & 2^C1) + A => A & (2^C1 - 1) iff bit C1 in A is a sign bit (PR21929)

Alive2: https://alive2.llvm.org/ce/z/Ygq26C

This is the final missing fold to handle the modulo2 simplification: https://github.com/llvm/llvm-project/issues/22303

Fixes #22303

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

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
    llvm/test/Transforms/InstCombine/add-mask.ll
    llvm/test/Transforms/InstCombine/modulo.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 1ef454906e7f5..9e2215d43ea00 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1369,6 +1369,13 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
     }
   }
 
+  // (A & 2^C1) + A => A & (2^C1 - 1) iff bit C1 in A is a sign bit
+  if (match(&I, m_c_Add(m_And(m_Value(A), m_APInt(C1)), m_Deferred(A))) &&
+      C1->isPowerOf2() && (ComputeNumSignBits(A) > C1->countLeadingZeros())) {
+    Constant *NewMask = ConstantInt::get(RHS->getType(), *C1 - 1);
+    return BinaryOperator::CreateAnd(A, NewMask);
+  }
+
   // 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-mask.ll b/llvm/test/Transforms/InstCombine/add-mask.ll
index b84c05995270b..00c14e351642e 100644
--- a/llvm/test/Transforms/InstCombine/add-mask.ll
+++ b/llvm/test/Transforms/InstCombine/add-mask.ll
@@ -7,9 +7,8 @@
 
 define i32 @add_mask_sign_i32(i32 %x) {
 ; CHECK-LABEL: @add_mask_sign_i32(
-; CHECK-NEXT:    [[A:%.*]] = ashr i32 [[X:%.*]], 31
-; CHECK-NEXT:    [[M:%.*]] = and i32 [[A]], 8
-; CHECK-NEXT:    [[R:%.*]] = add nsw i32 [[M]], [[A]]
+; CHECK-NEXT:    [[ISNEG:%.*]] = icmp slt i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[ISNEG]], i32 7, i32 0
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %a = ashr i32 %x, 31
@@ -20,9 +19,8 @@ define i32 @add_mask_sign_i32(i32 %x) {
 
 define i32 @add_mask_sign_commute_i32(i32 %x) {
 ; CHECK-LABEL: @add_mask_sign_commute_i32(
-; CHECK-NEXT:    [[A:%.*]] = ashr i32 [[X:%.*]], 31
-; CHECK-NEXT:    [[M:%.*]] = and i32 [[A]], 8
-; CHECK-NEXT:    [[R:%.*]] = add nsw i32 [[A]], [[M]]
+; CHECK-NEXT:    [[ISNEG:%.*]] = icmp slt i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[ISNEG]], i32 7, i32 0
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %a = ashr i32 %x, 31
@@ -33,9 +31,8 @@ define i32 @add_mask_sign_commute_i32(i32 %x) {
 
 define <2 x i32> @add_mask_sign_v2i32(<2 x i32> %x) {
 ; CHECK-LABEL: @add_mask_sign_v2i32(
-; CHECK-NEXT:    [[A:%.*]] = ashr <2 x i32> [[X:%.*]], <i32 31, i32 31>
-; CHECK-NEXT:    [[M:%.*]] = and <2 x i32> [[A]], <i32 8, i32 8>
-; CHECK-NEXT:    [[R:%.*]] = add nsw <2 x i32> [[M]], [[A]]
+; CHECK-NEXT:    [[ISNEG:%.*]] = icmp slt <2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[ISNEG]], <2 x i32> <i32 7, i32 7>, <2 x i32> zeroinitializer
 ; CHECK-NEXT:    ret <2 x i32> [[R]]
 ;
   %a = ashr <2 x i32> %x, <i32 31, i32 31>
@@ -59,9 +56,8 @@ define <2 x i32> @add_mask_sign_v2i32_nonuniform(<2 x i32> %x) {
 
 define i32 @add_mask_ashr28_i32(i32 %x) {
 ; CHECK-LABEL: @add_mask_ashr28_i32(
-; CHECK-NEXT:    [[A:%.*]] = ashr i32 [[X:%.*]], 28
-; CHECK-NEXT:    [[M:%.*]] = and i32 [[A]], 8
-; CHECK-NEXT:    [[R:%.*]] = add nsw i32 [[M]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr i32 [[X:%.*]], 28
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[TMP1]], 7
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %a = ashr i32 %x, 28

diff  --git a/llvm/test/Transforms/InstCombine/modulo.ll b/llvm/test/Transforms/InstCombine/modulo.ll
index 7bbe3501d8137..2988c524faedc 100644
--- a/llvm/test/Transforms/InstCombine/modulo.ll
+++ b/llvm/test/Transforms/InstCombine/modulo.ll
@@ -4,9 +4,7 @@
 ; PR21929
 define i32 @modulo2(i32 %x) {
 ; CHECK-LABEL: @modulo2(
-; CHECK-NEXT:    [[REM_I:%.*]] = srem i32 [[X:%.*]], 2
-; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[REM_I]], 2
-; CHECK-NEXT:    [[RET_I:%.*]] = add nsw i32 [[TMP1]], [[REM_I]]
+; CHECK-NEXT:    [[RET_I:%.*]] = and i32 [[X:%.*]], 1
 ; CHECK-NEXT:    ret i32 [[RET_I]]
 ;
   %rem.i = srem i32 %x, 2
@@ -18,9 +16,7 @@ define i32 @modulo2(i32 %x) {
 
 define <2 x i32> @modulo2_vec(<2 x i32> %x) {
 ; CHECK-LABEL: @modulo2_vec(
-; CHECK-NEXT:    [[REM_I:%.*]] = srem <2 x i32> [[X:%.*]], <i32 2, i32 2>
-; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[REM_I]], <i32 2, i32 2>
-; CHECK-NEXT:    [[RET_I:%.*]] = add nsw <2 x i32> [[TMP1]], [[REM_I]]
+; CHECK-NEXT:    [[RET_I:%.*]] = and <2 x i32> [[X:%.*]], <i32 1, i32 1>
 ; CHECK-NEXT:    ret <2 x i32> [[RET_I]]
 ;
   %rem.i = srem <2 x i32> %x, <i32 2, i32 2>
@@ -62,9 +58,7 @@ define <2 x i32> @modulo3_vec(<2 x i32> %x) {
 
 define i32 @modulo4(i32 %x) {
 ; CHECK-LABEL: @modulo4(
-; CHECK-NEXT:    [[REM_I:%.*]] = srem i32 [[X:%.*]], 4
-; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[REM_I]], 4
-; CHECK-NEXT:    [[RET_I:%.*]] = add nsw i32 [[TMP1]], [[REM_I]]
+; CHECK-NEXT:    [[RET_I:%.*]] = and i32 [[X:%.*]], 3
 ; CHECK-NEXT:    ret i32 [[RET_I]]
 ;
   %rem.i = srem i32 %x, 4
@@ -76,9 +70,7 @@ define i32 @modulo4(i32 %x) {
 
 define <2 x i32> @modulo4_vec(<2 x i32> %x) {
 ; CHECK-LABEL: @modulo4_vec(
-; CHECK-NEXT:    [[REM_I:%.*]] = srem <2 x i32> [[X:%.*]], <i32 4, i32 4>
-; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[REM_I]], <i32 4, i32 4>
-; CHECK-NEXT:    [[RET_I:%.*]] = add nsw <2 x i32> [[TMP1]], [[REM_I]]
+; CHECK-NEXT:    [[RET_I:%.*]] = and <2 x i32> [[X:%.*]], <i32 3, i32 3>
 ; CHECK-NEXT:    ret <2 x i32> [[RET_I]]
 ;
   %rem.i = srem <2 x i32> %x, <i32 4, i32 4>
@@ -120,9 +112,7 @@ define <2 x i32> @modulo7_vec(<2 x i32> %x) {
 
 define i32 @modulo32(i32 %x) {
 ; CHECK-LABEL: @modulo32(
-; CHECK-NEXT:    [[REM_I:%.*]] = srem i32 [[X:%.*]], 32
-; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[REM_I]], 32
-; CHECK-NEXT:    [[RET_I:%.*]] = add nsw i32 [[TMP1]], [[REM_I]]
+; CHECK-NEXT:    [[RET_I:%.*]] = and i32 [[X:%.*]], 31
 ; CHECK-NEXT:    ret i32 [[RET_I]]
 ;
   %rem.i = srem i32 %x, 32
@@ -134,9 +124,7 @@ define i32 @modulo32(i32 %x) {
 
 define <2 x i32> @modulo32_vec(<2 x i32> %x) {
 ; CHECK-LABEL: @modulo32_vec(
-; CHECK-NEXT:    [[REM_I:%.*]] = srem <2 x i32> [[X:%.*]], <i32 32, i32 32>
-; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[REM_I]], <i32 32, i32 32>
-; CHECK-NEXT:    [[RET_I:%.*]] = add nsw <2 x i32> [[TMP1]], [[REM_I]]
+; CHECK-NEXT:    [[RET_I:%.*]] = and <2 x i32> [[X:%.*]], <i32 31, i32 31>
 ; CHECK-NEXT:    ret <2 x i32> [[RET_I]]
 ;
   %rem.i = srem <2 x i32> %x, <i32 32, i32 32>


        


More information about the llvm-commits mailing list