From: Sanjoy Das Date: Sun, 2 Oct 2016 20:59:05 +0000 (+0000) Subject: [ConstantRange] Make getEquivalentICmp smarter X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=53936b83aa244e42f4bfb270a910d5f783831920;p=llvm [ConstantRange] Make getEquivalentICmp smarter 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 --- diff --git a/include/llvm/IR/ConstantRange.h b/include/llvm/IR/ConstantRange.h index 9458fa9f5c8..2fb176fe9eb 100644 --- a/include/llvm/IR/ConstantRange.h +++ b/include/llvm/IR/ConstantRange.h @@ -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; } diff --git a/lib/IR/ConstantRange.cpp b/lib/IR/ConstantRange.cpp index 0f5c7128f3d..b422eea3692 100644 --- a/lib/IR/ConstantRange.cpp +++ b/lib/IR/ConstantRange.cpp @@ -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; diff --git a/unittests/IR/ConstantRangeTest.cpp b/unittests/IR/ConstantRangeTest.cpp index f7a8a82043b..b890a4a0bc4 100644 --- a/unittests/IR/ConstantRangeTest.cpp +++ b/unittests/IR/ConstantRangeTest.cpp @@ -102,10 +102,19 @@ TEST_F(ConstantRangeTest, Equality) { TEST_F(ConstantRangeTest, SingleElement) { EXPECT_EQ(Full.getSingleElement(), static_cast(nullptr)); EXPECT_EQ(Empty.getSingleElement(), static_cast(nullptr)); + EXPECT_EQ(Full.getSingleMissingElement(), static_cast(nullptr)); + EXPECT_EQ(Empty.getSingleMissingElement(), static_cast(nullptr)); + EXPECT_EQ(*One.getSingleElement(), APInt(16, 0xa)); EXPECT_EQ(Some.getSingleElement(), static_cast(nullptr)); EXPECT_EQ(Wrap.getSingleElement(), static_cast(nullptr)); + EXPECT_EQ(One.getSingleMissingElement(), static_cast(nullptr)); + EXPECT_EQ(Some.getSingleMissingElement(), static_cast(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