[PATCH] D125603: [ConstantRange] Improve the implementation of binaryAnd

Alexander Shaposhnikov via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Sat May 14 03:52:09 PDT 2022


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

This diff adds support for the cases [Lower, Upper] & Mask and Mask & [Lower, Upper] where Upper < 2^{index of the first nonzero bit}.

Test plan:
1/ ninja check-llvm
2/ ninja check-llvm-unit


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D125603

Files:
  llvm/lib/IR/ConstantRange.cpp
  llvm/test/Transforms/SCCP/range-and.ll
  llvm/unittests/IR/ConstantRangeTest.cpp


Index: llvm/unittests/IR/ConstantRangeTest.cpp
===================================================================
--- llvm/unittests/IR/ConstantRangeTest.cpp
+++ llvm/unittests/IR/ConstantRangeTest.cpp
@@ -2510,6 +2510,26 @@
   EXPECT_TRUE(IntToPtr.isFullSet());
 }
 
+TEST_F(ConstantRangeTest, binaryAnd) {
+  // Single element ranges.
+  ConstantRange R16(APInt(8, 16));
+  ConstantRange R20(APInt(8, 20));
+  EXPECT_EQ(*R16.binaryAnd(R16).getSingleElement(), APInt(8, 16));
+  EXPECT_EQ(*R16.binaryAnd(R20).getSingleElement(), APInt(8, 16 & 20));
+
+  // 'And' with a high bits mask.
+  ConstantRange R16_31(APInt(8, 16), APInt(8, 31));
+  ConstantRange R32(APInt(8, 32));
+  EXPECT_TRUE(R16_31.binaryAnd(R32).getSingleElement()->isZero());
+  EXPECT_TRUE(R32.binaryAnd(R16_31).getSingleElement()->isZero());
+
+  // Ranges with more than one element. Handled conservatively for now.
+  ConstantRange R0_99(APInt(8, 0), APInt(8, 99));
+  ConstantRange R0_31(APInt(8, 0), APInt(8, 31));
+  EXPECT_EQ(R16_31.binaryAnd(R0_99), R0_31);
+  EXPECT_EQ(R0_99.binaryAnd(R16_31), R0_31);
+}
+
 TEST_F(ConstantRangeTest, binaryXor) {
   // Single element ranges.
   ConstantRange R16(APInt(8, 16));
Index: llvm/test/Transforms/SCCP/range-and.ll
===================================================================
--- llvm/test/Transforms/SCCP/range-and.ll
+++ llvm/test/Transforms/SCCP/range-and.ll
@@ -140,7 +140,7 @@
 ; CHECK-NEXT:    br label [[BB3]]
 ; CHECK:       bb3:
 ; CHECK-NEXT:    [[P:%.*]] = phi i64 [ [[R_1]], [[BB1]] ], [ [[R_2]], [[BB2]] ]
-; CHECK-NEXT:    [[P_AND:%.*]] = and i64 [[P]], 512
+; CHECK-NEXT:    [[P_AND:%.*]] = and i64 [[P]], 255
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    ret i64 [[P_AND]]
 ;
@@ -157,7 +157,7 @@
 
 bb3:
   %p = phi i64 [ %r.1, %bb1 ], [ %r.2, %bb2 ]
-  %p.and = and i64 %p, 512
+  %p.and = and i64 %p, 255
   %c = icmp ult i64 %p.and, 256
   call void @use(i1 %c)
   ret i64 %p.and
Index: llvm/lib/IR/ConstantRange.cpp
===================================================================
--- llvm/lib/IR/ConstantRange.cpp
+++ llvm/lib/IR/ConstantRange.cpp
@@ -1368,6 +1368,11 @@
   return ConstantRange(APInt::getAllOnes(getBitWidth())).sub(*this);
 }
 
+static APInt getMaxPowOf2Factor(const APInt &X) {
+  assert(!X.isZero() && "value is assumed to be nonzero");
+  return APInt::getOneBitSet(X.getBitWidth(), X.countTrailingZeros());
+}
+
 ConstantRange
 ConstantRange::binaryAnd(const ConstantRange &Other) const {
   if (isEmptySet() || Other.isEmptySet())
@@ -1377,8 +1382,16 @@
   if (isSingleElement() && Other.isSingleElement())
     return {*getSingleElement() & *Other.getSingleElement()};
 
-  // TODO: replace this with something less conservative
+  // 'and' with a mask to extract high bits.
+  if (isSingleElement() && !getSingleElement()->isZero()
+      && getMaxPowOf2Factor(*getSingleElement()).ugt(Other.getUnsignedMax()))
+      return { APInt::getZero(getBitWidth()) };
+  // 'and' with a mask to extract high bits.
+  if (Other.isSingleElement() && !Other.getSingleElement()->isZero()
+      && getMaxPowOf2Factor(*Other.getSingleElement()).ugt(getUnsignedMax()))
+    return { APInt::getZero(getBitWidth()) };
 
+  // TODO: replace this with something less conservative
   APInt umin = APIntOps::umin(Other.getUnsignedMax(), getUnsignedMax());
   return getNonEmpty(APInt::getZero(getBitWidth()), std::move(umin) + 1);
 }


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D125603.429435.patch
Type: text/x-patch
Size: 3407 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20220514/7fbc740c/attachment.bin>


More information about the llvm-commits mailing list