[llvm] r371610 - [InstCombine] fold sign-bit compares of srem

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 11 05:04:26 PDT 2019


Author: spatel
Date: Wed Sep 11 05:04:26 2019
New Revision: 371610

URL: http://llvm.org/viewvc/llvm-project?rev=371610&view=rev
Log:
[InstCombine] fold sign-bit compares of srem

(srem X, pow2C) sgt/slt 0 can be reduced using bit hacks by masking
off the sign bit and the module (low) bits:
https://rise4fun.com/Alive/jSO
A '2' divisor allows slightly more folding:
https://rise4fun.com/Alive/tDBM

Any chance to remove an 'srem' use is probably worthwhile, but this is limited
to the one-use improvement case because doing more may expose other missing
folds. That means it does nothing for PR21929 yet:
https://bugs.llvm.org/show_bug.cgi?id=21929

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

Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/trunk/lib/Transforms/InstCombine/InstCombineInternal.h
    llvm/trunk/test/Transforms/InstCombine/icmp-div-constant.ll

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp?rev=371610&r1=371609&r2=371610&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp Wed Sep 11 05:04:26 2019
@@ -2249,6 +2249,44 @@ Instruction *InstCombiner::foldICmpShrCo
   return nullptr;
 }
 
+Instruction *InstCombiner::foldICmpSRemConstant(ICmpInst &Cmp,
+                                                BinaryOperator *SRem,
+                                                const APInt &C) {
+  // Match an 'is positive' or 'is negative' comparison of remainder by a
+  // constant power-of-2 value:
+  // (X % pow2C) sgt/slt 0
+  const ICmpInst::Predicate Pred = Cmp.getPredicate();
+  if (Pred != ICmpInst::ICMP_SGT && Pred != ICmpInst::ICMP_SLT)
+    return nullptr;
+
+  // TODO: The one-use check is standard because we do not typically want to
+  //       create longer instruction sequences, but this might be a special-case
+  //       because srem is not good for analysis or codegen.
+  if (!SRem->hasOneUse())
+    return nullptr;
+
+  const APInt *DivisorC;
+  if (!C.isNullValue() || !match(SRem->getOperand(1), m_Power2(DivisorC)))
+    return nullptr;
+
+  // Mask off the sign bit and the modulo bits (low-bits).
+  Type *Ty = SRem->getType();
+  APInt SignMask = APInt::getSignMask(Ty->getScalarSizeInBits());
+  Constant *MaskC = ConstantInt::get(Ty, SignMask | (*DivisorC - 1));
+  Value *And = Builder.CreateAnd(SRem->getOperand(0), MaskC);
+
+  // For 'is positive?' check that the sign-bit is clear and at least 1 masked
+  // bit is set. Example:
+  // (i8 X % 32) s> 0 --> (X & 159) s> 0
+  if (Pred == ICmpInst::ICMP_SGT)
+    return new ICmpInst(ICmpInst::ICMP_SGT, And, ConstantInt::getNullValue(Ty));
+
+  // For 'is negative?' check that the sign-bit is set and at least 1 masked
+  // bit is set. Example:
+  // (i16 X % 4) s< 0 --> (X & 32771) u> 32768
+  return new ICmpInst(ICmpInst::ICMP_UGT, And, ConstantInt::get(Ty, SignMask));
+}
+
 /// Fold icmp (udiv X, Y), C.
 Instruction *InstCombiner::foldICmpUDivConstant(ICmpInst &Cmp,
                                                 BinaryOperator *UDiv,
@@ -2806,6 +2844,10 @@ Instruction *InstCombiner::foldICmpInstW
       if (Instruction *I = foldICmpShrConstant(Cmp, BO, *C))
         return I;
       break;
+    case Instruction::SRem:
+      if (Instruction *I = foldICmpSRemConstant(Cmp, BO, *C))
+        return I;
+      break;
     case Instruction::UDiv:
       if (Instruction *I = foldICmpUDivConstant(Cmp, BO, *C))
         return I;

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineInternal.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineInternal.h?rev=371610&r1=371609&r2=371610&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineInternal.h (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineInternal.h Wed Sep 11 05:04:26 2019
@@ -891,6 +891,8 @@ private:
                                    const APInt &C);
   Instruction *foldICmpShrConstant(ICmpInst &Cmp, BinaryOperator *Shr,
                                    const APInt &C);
+  Instruction *foldICmpSRemConstant(ICmpInst &Cmp, BinaryOperator *UDiv,
+                                    const APInt &C);
   Instruction *foldICmpUDivConstant(ICmpInst &Cmp, BinaryOperator *UDiv,
                                     const APInt &C);
   Instruction *foldICmpDivConstant(ICmpInst &Cmp, BinaryOperator *Div,

Modified: llvm/trunk/test/Transforms/InstCombine/icmp-div-constant.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-div-constant.ll?rev=371610&r1=371609&r2=371610&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-div-constant.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-div-constant.ll Wed Sep 11 05:04:26 2019
@@ -3,8 +3,8 @@
 
 define i1 @is_rem2_neg_i8(i8 %x) {
 ; CHECK-LABEL: @is_rem2_neg_i8(
-; CHECK-NEXT:    [[S:%.*]] = srem i8 [[X:%.*]], 2
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[S]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X:%.*]], -127
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[TMP1]], -127
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = srem i8 %x, 2
@@ -14,8 +14,8 @@ define i1 @is_rem2_neg_i8(i8 %x) {
 
 define <2 x i1> @is_rem2_pos_v2i8(<2 x i8> %x) {
 ; CHECK-LABEL: @is_rem2_pos_v2i8(
-; CHECK-NEXT:    [[S:%.*]] = srem <2 x i8> [[X:%.*]], <i8 2, i8 2>
-; CHECK-NEXT:    [[R:%.*]] = icmp sgt <2 x i8> [[S]], zeroinitializer
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -127, i8 -127>
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[TMP1]], <i8 1, i8 1>
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %s = srem <2 x i8> %x, <i8 2, i8 2>
@@ -23,10 +23,12 @@ define <2 x i1> @is_rem2_pos_v2i8(<2 x i
   ret <2 x i1> %r
 }
 
+; i8 -97 == 159 == 0b10011111
+
 define i1 @is_rem32_pos_i8(i8 %x) {
 ; CHECK-LABEL: @is_rem32_pos_i8(
-; CHECK-NEXT:    [[S:%.*]] = srem i8 [[X:%.*]], 32
-; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[S]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X:%.*]], -97
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[TMP1]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = srem i8 %x, 32
@@ -34,10 +36,12 @@ define i1 @is_rem32_pos_i8(i8 %x) {
   ret i1 %r
 }
 
+; i16 -32765 == 32771 == 0b1000000000000011
+
 define i1 @is_rem4_neg_i16(i16 %x) {
 ; CHECK-LABEL: @is_rem4_neg_i16(
-; CHECK-NEXT:    [[S:%.*]] = srem i16 [[X:%.*]], 4
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i16 [[S]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = and i16 [[X:%.*]], -32765
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i16 [[TMP1]], -32768
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = srem i16 %x, 4
@@ -47,6 +51,8 @@ define i1 @is_rem4_neg_i16(i16 %x) {
 
 declare void @use(i32)
 
+; TODO: This is still worth folding because srem is difficult?
+
 define i1 @is_rem32_neg_i32_extra_use(i32 %x) {
 ; CHECK-LABEL: @is_rem32_neg_i32_extra_use(
 ; CHECK-NEXT:    [[S:%.*]] = srem i32 [[X:%.*]], 32
@@ -60,6 +66,8 @@ define i1 @is_rem32_neg_i32_extra_use(i3
   ret i1 %r
 }
 
+; Negative test - wrong compare constant
+
 define i1 @is_rem8_nonneg_i16(i16 %x) {
 ; CHECK-LABEL: @is_rem8_nonneg_i16(
 ; CHECK-NEXT:    [[S:%.*]] = srem i16 [[X:%.*]], 8
@@ -71,6 +79,8 @@ define i1 @is_rem8_nonneg_i16(i16 %x) {
   ret i1 %r
 }
 
+; Negative test - wrong remainder constant
+
 define i1 @is_rem3_neg_i8(i8 %x) {
 ; CHECK-LABEL: @is_rem3_neg_i8(
 ; CHECK-NEXT:    [[S:%.*]] = srem i8 [[X:%.*]], 3
@@ -82,6 +92,8 @@ define i1 @is_rem3_neg_i8(i8 %x) {
   ret i1 %r
 }
 
+; Negative test - wrong compare constant
+
 define i1 @is_rem16_something_i8(i8 %x) {
 ; CHECK-LABEL: @is_rem16_something_i8(
 ; CHECK-NEXT:    [[S:%.*]] = srem i8 [[X:%.*]], 16




More information about the llvm-commits mailing list