[PATCH] D122942: [InstCombine] Fold srem(X, PowerOf2) == C into (X & Mask) == C for positive C

Alexander Shaposhnikov via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 1 15:42:39 PDT 2022


alexander-shaposhnikov created this revision.
alexander-shaposhnikov added reviewers: spatel, craig.topper.
alexander-shaposhnikov created this object with visibility "All Users".
Herald added subscribers: StephenFan, hiraditya.
Herald added a project: All.
alexander-shaposhnikov requested review of this revision.
Herald added a project: LLVM.

This diff extends InstCombinerImpl::foldICmpSRemConstant to handle the cases
srem(X, PowerOf2) == C and
srem(X, PowerOf2) != C
for positive C.
This addresses the issue https://github.com/llvm/llvm-project/issues/54650

Test plan: ninja check-llvm


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122942

Files:
  llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
  llvm/test/Transforms/InstCombine/rem.ll


Index: llvm/test/Transforms/InstCombine/rem.ll
===================================================================
--- llvm/test/Transforms/InstCombine/rem.ll
+++ llvm/test/Transforms/InstCombine/rem.ll
@@ -740,9 +740,9 @@
   ret i1 %C
 }
 
-define i1 @positive_and_odd(i32 %A) {
-; CHECK-LABEL: @positive_and_odd(
-; CHECK-NEXT:    [[B:%.*]] = srem i32 [[A:%.*]], 2
+define i1 @positive_and_odd_eq(i32 %A) {
+; CHECK-LABEL: @positive_and_odd_eq(
+; CHECK-NEXT:    [[B:%.*]] = and i32 [[A:%.*]], -2147483647
 ; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[B]], 1
 ; CHECK-NEXT:    ret i1 [[C]]
 ;
@@ -751,8 +751,8 @@
   ret i1 %C
 }
 
-define i1 @negative_and_odd(i32 %A) {
-; CHECK-LABEL: @negative_and_odd(
+define i1 @negative_and_odd_eq(i32 %A) {
+; CHECK-LABEL: @negative_and_odd_eq(
 ; CHECK-NEXT:    [[B:%.*]] = srem i32 [[A:%.*]], 2
 ; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[B]], -1
 ; CHECK-NEXT:    ret i1 [[C]]
@@ -762,6 +762,28 @@
   ret i1 %C
 }
 
+define i1 @positive_and_odd_ne(i32 %A) {
+; CHECK-LABEL: @positive_and_odd_ne(
+; CHECK-NEXT:    [[B:%.*]] = and i32 [[A:%.*]], -2147483647
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 [[B]], 1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %B = srem i32 %A, 2
+  %C = icmp ne i32 %B, 1
+  ret i1 %C
+}
+
+define i1 @negative_and_odd_ne(i32 %A) {
+; CHECK-LABEL: @negative_and_odd_ne(
+; CHECK-NEXT:    [[B:%.*]] = srem i32 [[A:%.*]], 2
+; CHECK-NEXT:    [[C:%.*]] = icmp ne i32 [[B]], -1
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %B = srem i32 %A, 2
+  %C = icmp ne i32 %B, -1
+  ret i1 %C
+}
+
 ; FP division-by-zero is not UB.
 
 define double @PR34870(i1 %cond, double %x, double %y) {
Index: llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
===================================================================
--- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2335,7 +2335,8 @@
   // 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)
+  if (Pred != ICmpInst::ICMP_SGT && Pred != ICmpInst::ICMP_SLT &&
+      Pred != ICmpInst::ICMP_EQ && Pred != ICmpInst::ICMP_NE)
     return nullptr;
 
   // TODO: The one-use check is standard because we do not typically want to
@@ -2345,7 +2346,15 @@
     return nullptr;
 
   const APInt *DivisorC;
-  if (!C.isZero() || !match(SRem->getOperand(1), m_Power2(DivisorC)))
+  if (!match(SRem->getOperand(1), m_Power2(DivisorC)))
+    return nullptr;
+
+  // For cmp_sgt/cmp_slt only zero valued C is handled.
+  // For cmp_eq/cmp_ne only positive valued C is handled.
+  if (((Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT) &&
+       !C.isZero()) ||
+      ((Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) &&
+       !C.isStrictlyPositive()))
     return nullptr;
 
   // Mask off the sign bit and the modulo bits (low-bits).
@@ -2354,6 +2363,9 @@
   Constant *MaskC = ConstantInt::get(Ty, SignMask | (*DivisorC - 1));
   Value *And = Builder.CreateAnd(SRem->getOperand(0), MaskC);
 
+  if (Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE)
+    return new ICmpInst(Pred, And, ConstantInt::get(Ty, C));
+
   // 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


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D122942.419877.patch
Type: text/x-patch
Size: 3369 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20220401/35ed1f3e/attachment.bin>


More information about the llvm-commits mailing list