]> granicus.if.org Git - llvm/commitdiff
[ConstantRange] Add signed/unsigned unionWith()
authorNikita Popov <nikita.ppv@gmail.com>
Sun, 7 Apr 2019 20:20:24 +0000 (20:20 +0000)
committerNikita Popov <nikita.ppv@gmail.com>
Sun, 7 Apr 2019 20:20:24 +0000 (20:20 +0000)
This extends D59959 to unionWith(), allowing to specify that a
non-wrapping unsigned/signed range is preferred. This is somewhat
less useful than the intersect case, because union operations are
rarer. An example use would the the phi union computed in SCEV.

The implementation is mostly a straightforward use of getPreferredRange(),
but I also had to adjust some <=/< checks to make sure that no ranges with
lower==upper get constructed before they're passed to getPreferredRange(),
as these have additional constraints.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@357876 91177308-0d34-0410-b5e6-96231b3b80d8

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

index a2e0a6b7b85335e806a513aef842773396ab4949..a8d51b379571a74eb8d8c466563732a4ea396108 100644 (file)
@@ -277,7 +277,8 @@ public:
   /// elements of both sets, but may contain more.  For example, [3, 9) union
   /// [12,15) is [3, 15), which includes 9, 10, and 11, which were not included
   /// in either set before.
-  ConstantRange unionWith(const ConstantRange &CR) const;
+  ConstantRange unionWith(const ConstantRange &CR,
+                          PreferredRangeType Type = Smallest) const;
 
   /// Return a new range representing the possible values resulting
   /// from an application of the specified cast operator to this range. \p
index 80981788eb903b34091917da030c943978ab2feb..f48fe9f737d31d35326297aa47e058d16d7036f8 100644 (file)
@@ -593,23 +593,26 @@ ConstantRange ConstantRange::intersectWith(const ConstantRange &CR,
   return getPreferredRange(*this, CR, Type);
 }
 
-ConstantRange ConstantRange::unionWith(const ConstantRange &CR) const {
+ConstantRange ConstantRange::unionWith(const ConstantRange &CR,
+                                       PreferredRangeType Type) const {
   assert(getBitWidth() == CR.getBitWidth() &&
          "ConstantRange types don't agree!");
 
   if (   isFullSet() || CR.isEmptySet()) return *this;
   if (CR.isFullSet() ||    isEmptySet()) return CR;
 
-  if (!isUpperWrapped() && CR.isUpperWrapped()) return CR.unionWith(*this);
+  if (!isUpperWrapped() && CR.isUpperWrapped())
+    return CR.unionWith(*this, Type);
 
   if (!isUpperWrapped() && !CR.isUpperWrapped()) {
-    if (CR.Upper.ult(Lower) || Upper.ult(CR.Lower)) {
-      // If the two ranges are disjoint, find the smaller gap and bridge it.
-      APInt d1 = CR.Lower - Upper, d2 = Lower - CR.Upper;
-      if (d1.ult(d2))
-        return ConstantRange(Lower, CR.Upper);
-      return ConstantRange(CR.Lower, Upper);
-    }
+    //        L---U  and  L---U        : this
+    //  L---U                   L---U  : CR
+    // result in one of
+    //  L---------U
+    // -----U L-----
+    if (CR.Upper.ult(Lower) || Upper.ult(CR.Lower))
+      return getPreferredRange(
+          ConstantRange(Lower, CR.Upper), ConstantRange(CR.Lower, Upper), Type);
 
     APInt L = CR.Lower.ult(Lower) ? CR.Lower : Lower;
     APInt U = (CR.Upper - 1).ugt(Upper - 1) ? CR.Upper : Upper;
@@ -633,22 +636,21 @@ ConstantRange ConstantRange::unionWith(const ConstantRange &CR) const {
 
     // ----U       L---- : this
     //       L---U       : CR
-    //    <d1>  <d2>
-    if (Upper.ule(CR.Lower) && CR.Upper.ule(Lower)) {
-      APInt d1 = CR.Lower - Upper, d2 = Lower - CR.Upper;
-      if (d1.ult(d2))
-        return ConstantRange(Lower, CR.Upper);
-      return ConstantRange(CR.Lower, Upper);
-    }
+    // results in one of
+    // ----------U L----
+    // ----U L----------
+    if (Upper.ult(CR.Lower) && CR.Upper.ult(Lower))
+      return getPreferredRange(
+          ConstantRange(Lower, CR.Upper), ConstantRange(CR.Lower, Upper), Type);
 
     // ----U     L----- : this
     //        L----U    : CR
-    if (Upper.ult(CR.Lower) && Lower.ult(CR.Upper))
+    if (Upper.ult(CR.Lower) && Lower.ule(CR.Upper))
       return ConstantRange(CR.Lower, Upper);
 
     // ------U    L---- : this
     //    L-----U       : CR
-    assert(CR.Lower.ult(Upper) && CR.Upper.ult(Lower) &&
+    assert(CR.Lower.ule(Upper) && CR.Upper.ult(Lower) &&
            "ConstantRange::unionWith missed a case with one range wrapped");
     return ConstantRange(Lower, CR.Upper);
   }
index 84411076ea30bdd257008f225ca9e1c058381036..d0e6cb6d60d35e5467c4ac3067de41e18dd0f33e 100644 (file)
@@ -501,6 +501,17 @@ TEST_F(ConstantRangeTest, IntersectWithExhaustive) {
       });
 }
 
+TEST_F(ConstantRangeTest, UnionWithExhaustive) {
+  testBinarySetOperationExhaustive(
+      [](const ConstantRange &CR1, const ConstantRange &CR2,
+         ConstantRange::PreferredRangeType Type) {
+        return CR1.unionWith(CR2, Type);
+      },
+      [](const ConstantRange &CR1, const ConstantRange &CR2, const APInt &N) {
+        return CR1.contains(N) || CR2.contains(N);
+      });
+}
+
 TEST_F(ConstantRangeTest, UnionWith) {
   EXPECT_EQ(Wrap.unionWith(One),
             ConstantRange(APInt(16, 0xaaa), APInt(16, 0xb)));