From b38d897e802664034c7e6e4654328256ed370a61 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Tue, 22 Sep 2020 11:50:25 +0300 Subject: [PATCH] [ConstantRange] binaryXor(): special-case binary complement case - the result is precise Use the fact that `~X` is equivalent to `-1 - X`, which gives us fully-precise answer, and we only need to special-handle the wrapped case. This fires ~16k times for vanilla llvm test-suite + RawSpeed. --- llvm/include/llvm/IR/ConstantRange.h | 5 +++++ llvm/lib/IR/ConstantRange.cpp | 16 ++++++++++++++++ llvm/unittests/IR/ConstantRangeTest.cpp | 18 ++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h index 318532b24e83..494a14a10cdb 100644 --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -409,6 +409,11 @@ public: /// value in \p Other. ConstantRange srem(const ConstantRange &Other) const; + /// Return a new range representing the possible values resulting from + /// a binary-xor of a value in this range by an all-one value, + /// aka bitwise complement operation. + ConstantRange binaryNot() const; + /// Return a new range representing the possible values resulting /// from a binary-and of a value in this range by a value in \p Other. ConstantRange binaryAnd(const ConstantRange &Other) const; diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index 396c39b5b3a8..7b8dd66b993c 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -1240,6 +1240,16 @@ ConstantRange ConstantRange::srem(const ConstantRange &RHS) const { return ConstantRange(std::move(Lower), std::move(Upper)); } +ConstantRange ConstantRange::binaryNot() const { + if (isEmptySet()) + return getEmpty(); + + if (isWrappedSet()) + return getFull(); + + return ConstantRange(APInt::getAllOnesValue(getBitWidth())).sub(*this); +} + ConstantRange ConstantRange::binaryAnd(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) @@ -1278,6 +1288,12 @@ ConstantRange ConstantRange::binaryXor(const ConstantRange &Other) const { if (isSingleElement() && Other.isSingleElement()) return {*getSingleElement() ^ *Other.getSingleElement()}; + // Special-case binary complement, since we can give a precise answer. + if (Other.isSingleElement() && Other.getSingleElement()->isAllOnesValue()) + return binaryNot(); + if (isSingleElement() && getSingleElement()->isAllOnesValue()) + return Other.binaryNot(); + // TODO: replace this with something less conservative return getFull(); } diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp index 8bcc6efdc265..474a94af3932 100644 --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -2349,4 +2349,22 @@ TEST_F(ConstantRangeTest, binaryXor) { EXPECT_TRUE(R0_99.binaryXor(R16_35).isFullSet()); } +TEST_F(ConstantRangeTest, binaryNot) { + TestUnsignedUnaryOpExhaustive( + [](const ConstantRange &CR) { return CR.binaryNot(); }, + [](const APInt &N) { return ~N; }); + TestUnsignedUnaryOpExhaustive( + [](const ConstantRange &CR) { + return CR.binaryXor( + ConstantRange(APInt::getAllOnesValue(CR.getBitWidth()))); + }, + [](const APInt &N) { return ~N; }); + TestUnsignedUnaryOpExhaustive( + [](const ConstantRange &CR) { + return ConstantRange(APInt::getAllOnesValue(CR.getBitWidth())) + .binaryXor(CR); + }, + [](const APInt &N) { return ~N; }); +} + } // anonymous namespace