[llvm] a852234 - [ConstantRange] Handle wrapping ranges in min/max (PR48643)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 20 13:52:35 PST 2021


Author: Nikita Popov
Date: 2021-02-20T22:52:09+01:00
New Revision: a852234f70e344b238824b9d71e8df9c46de62f2

URL: https://github.com/llvm/llvm-project/commit/a852234f70e344b238824b9d71e8df9c46de62f2
DIFF: https://github.com/llvm/llvm-project/commit/a852234f70e344b238824b9d71e8df9c46de62f2.diff

LOG: [ConstantRange] Handle wrapping ranges in min/max (PR48643)

When one of the inputs is a wrapping range, intersect with the
union of the two inputs. The union of the two inputs corresponds
to the result we would get if we treated the min/max as a simple
select.

This fixes PR48643.

Added: 
    

Modified: 
    llvm/lib/IR/ConstantRange.cpp
    llvm/unittests/IR/ConstantRangeTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 275996dd02d8..4dbe1a1b902d 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -1058,7 +1058,10 @@ ConstantRange::smax(const ConstantRange &Other) const {
     return getEmpty();
   APInt NewL = APIntOps::smax(getSignedMin(), Other.getSignedMin());
   APInt NewU = APIntOps::smax(getSignedMax(), Other.getSignedMax()) + 1;
-  return getNonEmpty(std::move(NewL), std::move(NewU));
+  ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU));
+  if (isSignWrappedSet() || Other.isSignWrappedSet())
+    return Res.intersectWith(unionWith(Other, Signed), Signed);
+  return Res;
 }
 
 ConstantRange
@@ -1069,7 +1072,10 @@ ConstantRange::umax(const ConstantRange &Other) const {
     return getEmpty();
   APInt NewL = APIntOps::umax(getUnsignedMin(), Other.getUnsignedMin());
   APInt NewU = APIntOps::umax(getUnsignedMax(), Other.getUnsignedMax()) + 1;
-  return getNonEmpty(std::move(NewL), std::move(NewU));
+  ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU));
+  if (isWrappedSet() || Other.isWrappedSet())
+    return Res.intersectWith(unionWith(Other, Unsigned), Unsigned);
+  return Res;
 }
 
 ConstantRange
@@ -1080,7 +1086,10 @@ ConstantRange::smin(const ConstantRange &Other) const {
     return getEmpty();
   APInt NewL = APIntOps::smin(getSignedMin(), Other.getSignedMin());
   APInt NewU = APIntOps::smin(getSignedMax(), Other.getSignedMax()) + 1;
-  return getNonEmpty(std::move(NewL), std::move(NewU));
+  ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU));
+  if (isSignWrappedSet() || Other.isSignWrappedSet())
+    return Res.intersectWith(unionWith(Other, Signed), Signed);
+  return Res;
 }
 
 ConstantRange
@@ -1091,7 +1100,10 @@ ConstantRange::umin(const ConstantRange &Other) const {
     return getEmpty();
   APInt NewL = APIntOps::umin(getUnsignedMin(), Other.getUnsignedMin());
   APInt NewU = APIntOps::umin(getUnsignedMax(), Other.getUnsignedMax()) + 1;
-  return getNonEmpty(std::move(NewL), std::move(NewU));
+  ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU));
+  if (isWrappedSet() || Other.isWrappedSet())
+    return Res.intersectWith(unionWith(Other, Unsigned), Unsigned);
+  return Res;
 }
 
 ConstantRange

diff  --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index 2b9c56b4134f..12362b9460f9 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -1080,10 +1080,18 @@ TEST_F(ConstantRangeTest, UMax) {
   EXPECT_EQ(Some.umax(Some), Some);
   EXPECT_EQ(Some.umax(Wrap), ConstantRange(APInt(16, 0xa), APInt(16, 0)));
   EXPECT_EQ(Some.umax(One), Some);
-  // TODO: ConstantRange is currently over-conservative here.
-  EXPECT_EQ(Wrap.umax(Wrap), Full);
+  EXPECT_EQ(Wrap.umax(Wrap), Wrap);
   EXPECT_EQ(Wrap.umax(One), ConstantRange(APInt(16, 0xa), APInt(16, 0)));
   EXPECT_EQ(One.umax(One), One);
+
+  TestBinaryOpExhaustive(
+      [](const ConstantRange &CR1, const ConstantRange &CR2) {
+        return CR1.umax(CR2);
+      },
+      [](const APInt &N1, const APInt &N2) {
+        return APIntOps::umax(N1, N2);
+      },
+      PreferSmallestNonFullUnsigned);
 }
 
 TEST_F(ConstantRangeTest, SMax) {
@@ -1105,6 +1113,15 @@ TEST_F(ConstantRangeTest, SMax) {
   EXPECT_EQ(Wrap.smax(One), ConstantRange(APInt(16, 0xa),
                                           APInt(16, (uint64_t)INT16_MIN)));
   EXPECT_EQ(One.smax(One), One);
+
+  TestBinaryOpExhaustive(
+      [](const ConstantRange &CR1, const ConstantRange &CR2) {
+        return CR1.smax(CR2);
+      },
+      [](const APInt &N1, const APInt &N2) {
+        return APIntOps::smax(N1, N2);
+      },
+      PreferSmallestNonFullSigned);
 }
 
 TEST_F(ConstantRangeTest, UMin) {
@@ -1119,10 +1136,18 @@ TEST_F(ConstantRangeTest, UMin) {
   EXPECT_EQ(Some.umin(Some), Some);
   EXPECT_EQ(Some.umin(Wrap), ConstantRange(APInt(16, 0), APInt(16, 0xaaa)));
   EXPECT_EQ(Some.umin(One), One);
-  // TODO: ConstantRange is currently over-conservative here.
-  EXPECT_EQ(Wrap.umin(Wrap), Full);
+  EXPECT_EQ(Wrap.umin(Wrap), Wrap);
   EXPECT_EQ(Wrap.umin(One), ConstantRange(APInt(16, 0), APInt(16, 0xb)));
   EXPECT_EQ(One.umin(One), One);
+
+  TestBinaryOpExhaustive(
+      [](const ConstantRange &CR1, const ConstantRange &CR2) {
+        return CR1.umin(CR2);
+      },
+      [](const APInt &N1, const APInt &N2) {
+        return APIntOps::umin(N1, N2);
+      },
+      PreferSmallestNonFullUnsigned);
 }
 
 TEST_F(ConstantRangeTest, SMin) {
@@ -1139,11 +1164,19 @@ TEST_F(ConstantRangeTest, SMin) {
   EXPECT_EQ(Some.smin(Wrap), ConstantRange(APInt(16, (uint64_t)INT16_MIN),
                                            APInt(16, 0xaaa)));
   EXPECT_EQ(Some.smin(One), One);
-  // TODO: ConstantRange is currently over-conservative here.
-  EXPECT_EQ(Wrap.smin(Wrap), Full);
+  EXPECT_EQ(Wrap.smin(Wrap), Wrap);
   EXPECT_EQ(Wrap.smin(One), ConstantRange(APInt(16, (uint64_t)INT16_MIN),
                                           APInt(16, 0xb)));
   EXPECT_EQ(One.smin(One), One);
+
+  TestBinaryOpExhaustive(
+      [](const ConstantRange &CR1, const ConstantRange &CR2) {
+        return CR1.smin(CR2);
+      },
+      [](const APInt &N1, const APInt &N2) {
+        return APIntOps::smin(N1, N2);
+      },
+      PreferSmallestNonFullSigned);
 }
 
 TEST_F(ConstantRangeTest, UDiv) {


        


More information about the llvm-commits mailing list