]> granicus.if.org Git - llvm/commitdiff
[ConstantRange] Make getEquivalentICmp smarter
authorSanjoy Das <sanjoy@playingwithpointers.com>
Sun, 2 Oct 2016 20:59:05 +0000 (20:59 +0000)
committerSanjoy Das <sanjoy@playingwithpointers.com>
Sun, 2 Oct 2016 20:59:05 +0000 (20:59 +0000)
This change teaches getEquivalentICmp to be smarter about generating
ICMP_NE and ICMP_EQ predicates.

An earlier version of this change was landed as rL283057 which had a
use-after-free bug.  This new version has a fix for that bug, and a (C++
unittests/) test case that would have triggered it rL283057.

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

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

index 9458fa9f5c8612d3101bd45297faaf70aa51c531..2fb176fe9eb92794aed3e3a5fc40bcef9d9fd88b 100644 (file)
@@ -166,6 +166,14 @@ public:
     return nullptr;
   }
 
+  /// If this set contains all but a single element, return it, otherwise return
+  /// null.
+  const APInt *getSingleMissingElement() const {
+    if (Lower == Upper + 1)
+      return &Upper;
+    return nullptr;
+  }
+
   /// Return true if this set contains exactly one member.
   ///
   bool isSingleElement() const { return getSingleElement() != nullptr; }
index 0f5c7128f3d09e871537a4b45ffc836f49aec1e6..b422eea369206e19d77dbe0e2a1234e9c82aa7b1 100644 (file)
@@ -147,6 +147,14 @@ bool ConstantRange::getEquivalentICmp(CmpInst::Predicate &Pred,
     Pred = isEmptySet() ? CmpInst::ICMP_ULT : CmpInst::ICMP_UGE;
     RHS = APInt(getBitWidth(), 0);
     Success = true;
+  } else if (auto *OnlyElt = getSingleElement()) {
+    Pred = CmpInst::ICMP_EQ;
+    RHS = *OnlyElt;
+    Success = true;
+  } else if (auto *OnlyMissingElt = getSingleMissingElement()) {
+    Pred = CmpInst::ICMP_NE;
+    RHS = *OnlyMissingElt;
+    Success = true;
   } else if (getLower().isMinSignedValue() || getLower().isMinValue()) {
     Pred =
         getLower().isMinSignedValue() ? CmpInst::ICMP_SLT : CmpInst::ICMP_ULT;
index f7a8a82043b9c071019d139cb8cb7ea753cc650f..b890a4a0bc436d4e47ee699a93af146e89343fc1 100644 (file)
@@ -102,10 +102,19 @@ TEST_F(ConstantRangeTest, Equality) {
 TEST_F(ConstantRangeTest, SingleElement) {
   EXPECT_EQ(Full.getSingleElement(), static_cast<APInt *>(nullptr));
   EXPECT_EQ(Empty.getSingleElement(), static_cast<APInt *>(nullptr));
+  EXPECT_EQ(Full.getSingleMissingElement(), static_cast<APInt *>(nullptr));
+  EXPECT_EQ(Empty.getSingleMissingElement(), static_cast<APInt *>(nullptr));
+
   EXPECT_EQ(*One.getSingleElement(), APInt(16, 0xa));
   EXPECT_EQ(Some.getSingleElement(), static_cast<APInt *>(nullptr));
   EXPECT_EQ(Wrap.getSingleElement(), static_cast<APInt *>(nullptr));
 
+  EXPECT_EQ(One.getSingleMissingElement(), static_cast<APInt *>(nullptr));
+  EXPECT_EQ(Some.getSingleMissingElement(), static_cast<APInt *>(nullptr));
+
+  ConstantRange OneInverse = One.inverse();
+  EXPECT_EQ(*OneInverse.getSingleMissingElement(), *One.getSingleElement());
+
   EXPECT_FALSE(Full.isSingleElement());
   EXPECT_FALSE(Empty.isSingleElement());
   EXPECT_TRUE(One.isSingleElement());
@@ -760,6 +769,42 @@ TEST(ConstantRange, GetEquivalentICmp) {
   EXPECT_FALSE(ConstantRange(APInt::getMinValue(32) - APInt(32, 100),
                              APInt::getMinValue(32) + APInt(32, 100))
                    .getEquivalentICmp(Pred, RHS));
+
+  EXPECT_TRUE(ConstantRange(APInt(32, 100)).getEquivalentICmp(Pred, RHS));
+  EXPECT_EQ(Pred, CmpInst::ICMP_EQ);
+  EXPECT_EQ(RHS, APInt(32, 100));
+
+  EXPECT_TRUE(
+      ConstantRange(APInt(32, 100)).inverse().getEquivalentICmp(Pred, RHS));
+  EXPECT_EQ(Pred, CmpInst::ICMP_NE);
+  EXPECT_EQ(RHS, APInt(32, 100));
+
+  EXPECT_TRUE(
+      ConstantRange(APInt(512, 100)).inverse().getEquivalentICmp(Pred, RHS));
+  EXPECT_EQ(Pred, CmpInst::ICMP_NE);
+  EXPECT_EQ(RHS, APInt(512, 100));
+
+  // NB!  It would be correct for the following four calls to getEquivalentICmp
+  // to return ordered predicates like CmpInst::ICMP_ULT or CmpInst::ICMP_UGT.
+  // However, that's not the case today.
+
+  EXPECT_TRUE(ConstantRange(APInt(32, 0)).getEquivalentICmp(Pred, RHS));
+  EXPECT_EQ(Pred, CmpInst::ICMP_EQ);
+  EXPECT_EQ(RHS, APInt(32, 0));
+
+  EXPECT_TRUE(
+      ConstantRange(APInt(32, 0)).inverse().getEquivalentICmp(Pred, RHS));
+  EXPECT_EQ(Pred, CmpInst::ICMP_NE);
+  EXPECT_EQ(RHS, APInt(32, 0));
+
+  EXPECT_TRUE(ConstantRange(APInt(32, -1)).getEquivalentICmp(Pred, RHS));
+  EXPECT_EQ(Pred, CmpInst::ICMP_EQ);
+  EXPECT_EQ(RHS, APInt(32, -1));
+
+  EXPECT_TRUE(
+      ConstantRange(APInt(32, -1)).inverse().getEquivalentICmp(Pred, RHS));
+  EXPECT_EQ(Pred, CmpInst::ICMP_NE);
+  EXPECT_EQ(RHS, APInt(32, -1));
 }
 
 }  // anonymous namespace