[PATCH] D71010: [ConstantRange] Add `getClosestToZero()` method - what value[s] are closest to signed zero?

Roman Lebedev via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 4 06:16:04 PST 2019


lebedev.ri created this revision.
lebedev.ri added reviewers: reames, nikic, efriedma, spatel, sanjoy.
lebedev.ri added a project: LLVM.
Herald added a subscriber: hiraditya.
lebedev.ri added a child revision: D70043: [ConstantRange] Add `mulWithNoWrap()` method.
lebedev.ri added a child revision: D71011: [ConstantRange] Add `shlWithNoWrap()` method.

This method is needed in the follow-up patches adding
`ConstantRange::mulWithNoWrap()`/`ConstantRange::shlWithNoWrap()` support
to detect the all-overflow cases where we should/could return empty-set.

There's an exhaustive test so we know this is correct and optimal.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D71010

Files:
  llvm/include/llvm/IR/ConstantRange.h
  llvm/lib/IR/ConstantRange.cpp
  llvm/unittests/IR/ConstantRangeTest.cpp


Index: llvm/unittests/IR/ConstantRangeTest.cpp
===================================================================
--- llvm/unittests/IR/ConstantRangeTest.cpp
+++ llvm/unittests/IR/ConstantRangeTest.cpp
@@ -2295,4 +2295,37 @@
   });
 }
 
+TEST_F(ConstantRangeTest, getClosestToZero) {
+  unsigned Bits = 4;
+  EnumerateConstantRanges(Bits, [&](const ConstantRange &CR) {
+    const SmallVector<APInt, 2> ClosestToZero = CR.getClosestToZero();
+
+    EXPECT_EQ(ClosestToZero.empty(), CR.isEmptySet());
+    if (ClosestToZero.empty())
+      return;
+
+    EXPECT_LE(ClosestToZero.size(), 2U);
+    if (ClosestToZero.size() == 2U)
+      EXPECT_EQ(ClosestToZero.front(), -(ClosestToZero.back()));
+
+    for (const APInt &V : ClosestToZero)
+      EXPECT_TRUE(CR.contains(V));
+
+    if (llvm::any_of(ClosestToZero, [Bits](const APInt &V) {
+          return V == APInt::getSignedMinValue(Bits);
+        })) {
+      EXPECT_EQ(ClosestToZero.size(), 1U);
+      const APInt *S = CR.getSingleElement();
+      EXPECT_NE(S, nullptr);
+      EXPECT_EQ(*S, ClosestToZero.front());
+
+      return;
+    }
+
+    APInt ClosestToZeroAbs = ClosestToZero.front().abs();
+    for (APInt C = APInt(Bits, 0); C.ult(ClosestToZeroAbs); ++C)
+      EXPECT_FALSE(CR.contains(C) || CR.contains(-C));
+  });
+}
+
 }  // anonymous namespace
Index: llvm/lib/IR/ConstantRange.cpp
===================================================================
--- llvm/lib/IR/ConstantRange.cpp
+++ llvm/lib/IR/ConstantRange.cpp
@@ -385,6 +385,30 @@
   return getLower();
 }
 
+SmallVector<APInt, 2> ConstantRange::getClosestToZero() const {
+  if (isEmptySet())
+    return {};
+
+  // If the range contains zero, said zero itself is the answer.
+  APInt Zero = APInt::getNullValue(getBitWidth());
+  if (contains(Zero))
+    return {Zero};
+
+  APInt Lower = getLower();
+  APInt Upper = getUpper() - 1;
+
+  // If both limits are equidistant from zero, then we *MUST* return both!
+  // We can don't bother checking for zero, we know we don't have it by now.
+  if (Lower.isNonNegative() && Upper.isNegative() && Lower == -Upper)
+    return {Lower, Upper};
+
+  // Return the limit that has smallest absolute value. This is INT_MIN-safe.
+  auto CompareAbs = [](const APInt &A, const APInt &B) {
+    return A.abs().ult(B.abs());
+  };
+  return {std::min({Lower, Upper}, CompareAbs)};
+}
+
 bool ConstantRange::contains(const APInt &V) const {
   if (Lower == Upper)
     return isFullSet();
Index: llvm/include/llvm/IR/ConstantRange.h
===================================================================
--- llvm/include/llvm/IR/ConstantRange.h
+++ llvm/include/llvm/IR/ConstantRange.h
@@ -245,6 +245,10 @@
   /// Return the smallest signed value contained in the ConstantRange.
   APInt getSignedMin() const;
 
+  /// Return the value contained in the ConstantRange with smallest absolute
+  /// value.
+  SmallVector<APInt, 2> getClosestToZero() const;
+
   /// Return true if this range is equal to another range.
   bool operator==(const ConstantRange &CR) const {
     return Lower == CR.Lower && Upper == CR.Upper;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D71010.232105.patch
Type: text/x-patch
Size: 3091 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20191204/26a9b072/attachment.bin>


More information about the llvm-commits mailing list