[llvm] r319806 - [ConstantRange] Support subtraction in makeGuaranteedNoWrapRegion.

Joel Galenson via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 5 10:14:23 PST 2017


Author: jgalenson
Date: Tue Dec  5 10:14:23 2017
New Revision: 319806

URL: http://llvm.org/viewvc/llvm-project?rev=319806&view=rev
Log:
[ConstantRange] Support subtraction in makeGuaranteedNoWrapRegion.

Previously ConstantRange::makeGuaranteedNoWrapRegion only handled addition.  This adds support for subtraction.

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

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

Modified: llvm/trunk/include/llvm/IR/ConstantRange.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/ConstantRange.h?rev=319806&r1=319805&r2=319806&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/ConstantRange.h (original)
+++ llvm/trunk/include/llvm/IR/ConstantRange.h Tue Dec  5 10:14:23 2017
@@ -96,9 +96,9 @@ public:
   ///
   /// NB! The returned set does *not* contain **all** possible values of X for
   /// which "X BinOpC Y" does not wrap -- some viable values of X may be
-  /// missing, so you cannot use this to constrain X's range.  E.g. in the last
-  /// example, "(-2) + 1" is both nsw and nuw (so the "X" could be -2), but (-2)
-  /// is not in the set returned.
+  /// missing, so you cannot use this to constrain X's range.  E.g. in the
+  /// fourth example, "(-2) + 1" is both nsw and nuw (so the "X" could be -2),
+  /// but (-2) is not in the set returned.
   ///
   /// Examples:
   ///  typedef OverflowingBinaryOperator OBO;
@@ -109,6 +109,10 @@ public:
   ///  MGNR(Add, [i8 1, 2), OBO::NoUnsignedWrap | OBO::NoSignedWrap)
   ///    == [0,INT_MAX)
   ///  MGNR(Add, [i8 -1, 6), OBO::NoSignedWrap) == [INT_MIN+1, INT_MAX-4)
+  ///  MGNR(Sub, [i8 1, 2), OBO::NoSignedWrap) == [-127, 128)
+  ///  MGNR(Sub, [i8 1, 2), OBO::NoUnsignedWrap) == [1, 0)
+  ///  MGNR(Sub, [i8 1, 2), OBO::NoUnsignedWrap | OBO::NoSignedWrap)
+  ///    == [1,INT_MAX)
   static ConstantRange makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp,
                                                   const ConstantRange &Other,
                                                   unsigned NoWrapKind);

Modified: llvm/trunk/lib/IR/ConstantRange.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/ConstantRange.cpp?rev=319806&r1=319805&r2=319806&view=diff
==============================================================================
--- llvm/trunk/lib/IR/ConstantRange.cpp (original)
+++ llvm/trunk/lib/IR/ConstantRange.cpp Tue Dec  5 10:14:23 2017
@@ -199,39 +199,63 @@ ConstantRange::makeGuaranteedNoWrapRegio
          "NoWrapKind invalid!");
 
   unsigned BitWidth = Other.getBitWidth();
-  if (BinOp != Instruction::Add)
-    // Conservative answer: empty set
-    return ConstantRange(BitWidth, false);
-
-  if (auto *C = Other.getSingleElement())
-    if (C->isNullValue())
-      // Full set: nothing signed / unsigned wraps when added to 0.
-      return ConstantRange(BitWidth);
-
   ConstantRange Result(BitWidth);
 
-  if (NoWrapKind & OBO::NoUnsignedWrap)
-    Result =
-        SubsetIntersect(Result, ConstantRange(APInt::getNullValue(BitWidth),
-                                              -Other.getUnsignedMax()));
-
-  if (NoWrapKind & OBO::NoSignedWrap) {
-    const APInt &SignedMin = Other.getSignedMin();
-    const APInt &SignedMax = Other.getSignedMax();
-
-    if (SignedMax.isStrictlyPositive())
-      Result = SubsetIntersect(
-          Result,
-          ConstantRange(APInt::getSignedMinValue(BitWidth),
-                        APInt::getSignedMinValue(BitWidth) - SignedMax));
+  switch (BinOp) {
+  default:
+    // Conservative answer: empty set
+    return ConstantRange(BitWidth, false);
 
-    if (SignedMin.isNegative())
-      Result = SubsetIntersect(
-          Result, ConstantRange(APInt::getSignedMinValue(BitWidth) - SignedMin,
-                                APInt::getSignedMinValue(BitWidth)));
+  case Instruction::Add:
+    if (auto *C = Other.getSingleElement())
+      if (C->isNullValue())
+        // Full set: nothing signed / unsigned wraps when added to 0.
+        return ConstantRange(BitWidth);
+    if (NoWrapKind & OBO::NoUnsignedWrap)
+      Result =
+          SubsetIntersect(Result, ConstantRange(APInt::getNullValue(BitWidth),
+                                                -Other.getUnsignedMax()));
+    if (NoWrapKind & OBO::NoSignedWrap) {
+      const APInt &SignedMin = Other.getSignedMin();
+      const APInt &SignedMax = Other.getSignedMax();
+      if (SignedMax.isStrictlyPositive())
+        Result = SubsetIntersect(
+            Result,
+            ConstantRange(APInt::getSignedMinValue(BitWidth),
+                          APInt::getSignedMinValue(BitWidth) - SignedMax));
+      if (SignedMin.isNegative())
+        Result = SubsetIntersect(
+            Result,
+            ConstantRange(APInt::getSignedMinValue(BitWidth) - SignedMin,
+                          APInt::getSignedMinValue(BitWidth)));
+    }
+    return Result;
+
+  case Instruction::Sub:
+    if (auto *C = Other.getSingleElement())
+      if (C->isNullValue())
+        // Full set: nothing signed / unsigned wraps when subtracting 0.
+        return ConstantRange(BitWidth);
+    if (NoWrapKind & OBO::NoUnsignedWrap)
+      Result =
+          SubsetIntersect(Result, ConstantRange(Other.getUnsignedMax(),
+                                                APInt::getMinValue(BitWidth)));
+    if (NoWrapKind & OBO::NoSignedWrap) {
+      const APInt &SignedMin = Other.getSignedMin();
+      const APInt &SignedMax = Other.getSignedMax();
+      if (SignedMax.isStrictlyPositive())
+        Result = SubsetIntersect(
+            Result,
+            ConstantRange(APInt::getSignedMinValue(BitWidth) + SignedMax,
+                          APInt::getSignedMinValue(BitWidth)));
+      if (SignedMin.isNegative())
+        Result = SubsetIntersect(
+            Result,
+            ConstantRange(APInt::getSignedMinValue(BitWidth),
+                          APInt::getSignedMinValue(BitWidth) + SignedMin));
+    }
+    return Result;
   }
-
-  return Result;
 }
 
 bool ConstantRange::isFullSet() const {

Modified: llvm/trunk/unittests/IR/ConstantRangeTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/ConstantRangeTest.cpp?rev=319806&r1=319805&r2=319806&view=diff
==============================================================================
--- llvm/trunk/unittests/IR/ConstantRangeTest.cpp (original)
+++ llvm/trunk/unittests/IR/ConstantRangeTest.cpp Tue Dec  5 10:14:23 2017
@@ -715,24 +715,102 @@ TEST(ConstantRange, MakeGuaranteedNoWrap
     }
   }
 
+  for (int Const : {0, -1, -2, 1, 2, IntMin4Bits, IntMax4Bits}) {
+    APInt C(4, Const, true /* = isSigned */);
+
+    auto NUWRegion = ConstantRange::makeGuaranteedNoWrapRegion(
+        Instruction::Sub, C, OBO::NoUnsignedWrap);
+
+    EXPECT_FALSE(NUWRegion.isEmptySet());
+
+    auto NSWRegion = ConstantRange::makeGuaranteedNoWrapRegion(
+        Instruction::Sub, C, OBO::NoSignedWrap);
+
+    EXPECT_FALSE(NSWRegion.isEmptySet());
+
+    auto NoWrapRegion = ConstantRange::makeGuaranteedNoWrapRegion(
+        Instruction::Sub, C, OBO::NoSignedWrap | OBO::NoUnsignedWrap);
+
+    EXPECT_FALSE(NoWrapRegion.isEmptySet());
+    EXPECT_TRUE(NUWRegion.intersectWith(NSWRegion).contains(NoWrapRegion));
+
+    for (APInt I = NUWRegion.getLower(), E = NUWRegion.getUpper(); I != E;
+         ++I) {
+      bool Overflow = false;
+      (void)I.usub_ov(C, Overflow);
+      EXPECT_FALSE(Overflow);
+    }
+
+    for (APInt I = NSWRegion.getLower(), E = NSWRegion.getUpper(); I != E;
+         ++I) {
+      bool Overflow = false;
+      (void)I.ssub_ov(C, Overflow);
+      EXPECT_FALSE(Overflow);
+    }
+
+    for (APInt I = NoWrapRegion.getLower(), E = NoWrapRegion.getUpper(); I != E;
+         ++I) {
+      bool Overflow = false;
+
+      (void)I.ssub_ov(C, Overflow);
+      EXPECT_FALSE(Overflow);
+
+      (void)I.usub_ov(C, Overflow);
+      EXPECT_FALSE(Overflow);
+    }
+  }
+
   auto NSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
       Instruction::Add, ConstantRange(32, /* isFullSet = */ true),
       OBO::NoSignedWrap);
   EXPECT_TRUE(NSWForAllValues.isSingleElement() &&
               NSWForAllValues.getSingleElement()->isMinValue());
 
+  NSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
+      Instruction::Sub, ConstantRange(32, /* isFullSet = */ true),
+      OBO::NoSignedWrap);
+  EXPECT_TRUE(NSWForAllValues.isSingleElement() &&
+              NSWForAllValues.getSingleElement()->isMaxValue());
+
   auto NUWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
       Instruction::Add, ConstantRange(32, /* isFullSet = */ true),
       OBO::NoUnsignedWrap);
   EXPECT_TRUE(NUWForAllValues.isSingleElement() &&
               NUWForAllValues.getSingleElement()->isMinValue());
 
+  NUWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
+      Instruction::Sub, ConstantRange(32, /* isFullSet = */ true),
+      OBO::NoUnsignedWrap);
+  EXPECT_TRUE(NUWForAllValues.isSingleElement() &&
+              NUWForAllValues.getSingleElement()->isMaxValue());
+
   auto NUWAndNSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
       Instruction::Add, ConstantRange(32, /* isFullSet = */ true),
       OBO::NoUnsignedWrap | OBO::NoSignedWrap);
   EXPECT_TRUE(NUWAndNSWForAllValues.isSingleElement() &&
               NUWAndNSWForAllValues.getSingleElement()->isMinValue());
 
+  NUWAndNSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
+      Instruction::Sub, ConstantRange(32, /* isFullSet = */ true),
+      OBO::NoUnsignedWrap | OBO::NoSignedWrap);
+  EXPECT_TRUE(NUWAndNSWForAllValues.isSingleElement() &&
+              NUWAndNSWForAllValues.getSingleElement()->isMaxValue());
+
+  EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
+      Instruction::Add, APInt(32, 0), OBO::NoUnsignedWrap).isFullSet());
+  EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
+      Instruction::Add, APInt(32, 0), OBO::NoSignedWrap).isFullSet());
+  EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
+      Instruction::Add, APInt(32, 0),
+      OBO::NoUnsignedWrap | OBO::NoSignedWrap).isFullSet());
+  EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
+      Instruction::Sub, APInt(32, 0), OBO::NoUnsignedWrap).isFullSet());
+  EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
+      Instruction::Sub, APInt(32, 0), OBO::NoSignedWrap).isFullSet());
+  EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
+      Instruction::Sub, APInt(32, 0),
+      OBO::NoUnsignedWrap | OBO::NoSignedWrap).isFullSet());
+
   ConstantRange OneToFive(APInt(32, 1), APInt(32, 6));
   EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
                 Instruction::Add, OneToFive, OBO::NoSignedWrap),
@@ -745,6 +823,17 @@ TEST(ConstantRange, MakeGuaranteedNoWrap
       ConstantRange::makeGuaranteedNoWrapRegion(
           Instruction::Add, OneToFive, OBO::NoUnsignedWrap | OBO::NoSignedWrap),
       ConstantRange(APInt::getMinValue(32), APInt::getSignedMaxValue(32) - 4));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Sub, OneToFive, OBO::NoSignedWrap),
+            ConstantRange(APInt::getSignedMinValue(32) + 5,
+                          APInt::getSignedMinValue(32)));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Sub, OneToFive, OBO::NoUnsignedWrap),
+            ConstantRange(APInt::getMinValue(32) + 5, APInt::getMinValue(32)));
+  EXPECT_EQ(
+      ConstantRange::makeGuaranteedNoWrapRegion(
+          Instruction::Sub, OneToFive, OBO::NoUnsignedWrap | OBO::NoSignedWrap),
+      ConstantRange(APInt::getMinValue(32) + 5, APInt::getSignedMinValue(32)));
 
   ConstantRange MinusFiveToMinusTwo(APInt(32, -5), APInt(32, -1));
   EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
@@ -758,6 +847,19 @@ TEST(ConstantRange, MakeGuaranteedNoWrap
                 Instruction::Add, MinusFiveToMinusTwo,
                 OBO::NoUnsignedWrap | OBO::NoSignedWrap),
             ConstantRange(APInt(32, 0), APInt(32, 2)));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Sub, MinusFiveToMinusTwo, OBO::NoSignedWrap),
+            ConstantRange(APInt::getSignedMinValue(32),
+                          APInt::getSignedMaxValue(32) - 4));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Sub, MinusFiveToMinusTwo, OBO::NoUnsignedWrap),
+            ConstantRange(APInt::getMaxValue(32) - 1,
+                          APInt::getMinValue(32)));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Sub, MinusFiveToMinusTwo,
+                OBO::NoUnsignedWrap | OBO::NoSignedWrap),
+            ConstantRange(APInt::getMaxValue(32) - 1,
+                          APInt::getMinValue(32)));
 
   ConstantRange MinusOneToOne(APInt(32, -1), APInt(32, 2));
   EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
@@ -771,6 +873,43 @@ TEST(ConstantRange, MakeGuaranteedNoWrap
                 Instruction::Add, MinusOneToOne,
                 OBO::NoUnsignedWrap | OBO::NoSignedWrap),
             ConstantRange(APInt(32, 0), APInt(32, 1)));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Sub, MinusOneToOne, OBO::NoSignedWrap),
+            ConstantRange(APInt::getSignedMinValue(32) + 1,
+                          APInt::getSignedMinValue(32) - 1));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Sub, MinusOneToOne, OBO::NoUnsignedWrap),
+            ConstantRange(APInt::getMaxValue(32),
+                          APInt::getMinValue(32)));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Sub, MinusOneToOne,
+                OBO::NoUnsignedWrap | OBO::NoSignedWrap),
+            ConstantRange(APInt::getMaxValue(32),
+                          APInt::getMinValue(32)));
+
+  ConstantRange One(APInt(32, 1), APInt(32, 2));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Add, One, OBO::NoSignedWrap),
+            ConstantRange(APInt::getSignedMinValue(32),
+                          APInt::getSignedMaxValue(32)));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Add, One, OBO::NoUnsignedWrap),
+            ConstantRange(APInt::getMinValue(32), APInt::getMaxValue(32)));
+  EXPECT_EQ(
+      ConstantRange::makeGuaranteedNoWrapRegion(
+          Instruction::Add, One, OBO::NoUnsignedWrap | OBO::NoSignedWrap),
+      ConstantRange(APInt(32, 0), APInt::getSignedMaxValue(32)));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Sub, One, OBO::NoSignedWrap),
+            ConstantRange(APInt::getSignedMinValue(32) + 1,
+                          APInt::getSignedMinValue(32)));
+  EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
+                Instruction::Sub, One, OBO::NoUnsignedWrap),
+            ConstantRange(APInt::getMinValue(32) + 1, APInt::getMinValue(32)));
+  EXPECT_EQ(
+      ConstantRange::makeGuaranteedNoWrapRegion(
+          Instruction::Sub, One, OBO::NoUnsignedWrap | OBO::NoSignedWrap),
+      ConstantRange(APInt::getMinValue(32) + 1, APInt::getSignedMinValue(32)));
 }
 
 TEST(ConstantRange, GetEquivalentICmp) {




More information about the llvm-commits mailing list