[ConstantRange] Add toKnownBits() method

Add toKnownBits() method to mirror fromKnownBits(). We know the
top bits that are constant between min and max.

The return value for an empty range is chosen to be conservative.
This commit is contained in:
Nikita Popov 2022-05-16 16:04:11 +02:00
parent c70259405c
commit 8ab819ad90
3 changed files with 40 additions and 0 deletions

View File

@ -553,6 +553,9 @@ public:
/// Return whether unsigned mul of the two ranges always/never overflows.
OverflowResult unsignedMulMayOverflow(const ConstantRange &Other) const;
/// Return known bits for values in this range.
KnownBits toKnownBits() const;
/// Print out the bounds to a stream.
void print(raw_ostream &OS) const;

View File

@ -75,6 +75,24 @@ ConstantRange ConstantRange::fromKnownBits(const KnownBits &Known,
return ConstantRange(Lower, Upper + 1);
}
KnownBits ConstantRange::toKnownBits() const {
// TODO: We could return conflicting known bits here, but consumers are
// likely not prepared for that.
if (isEmptySet())
return KnownBits(getBitWidth());
// We can only retain the top bits that are the same between min and max.
APInt Min = getUnsignedMin();
APInt Max = getUnsignedMax();
KnownBits Known = KnownBits::makeConstant(Min);
if (Optional<unsigned> DifferentBit =
APIntOps::GetMostSignificantDifferentBit(Min, Max)) {
Known.Zero.clearLowBits(*DifferentBit + 1);
Known.One.clearLowBits(*DifferentBit + 1);
}
return Known;
}
ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred,
const ConstantRange &CR) {
if (CR.isEmptySet())

View File

@ -2366,6 +2366,25 @@ TEST_F(ConstantRangeTest, FromKnownBitsExhaustive) {
}
}
TEST_F(ConstantRangeTest, ToKnownBits) {
unsigned Bits = 4;
EnumerateConstantRanges(Bits, [&](const ConstantRange &CR) {
KnownBits Known = CR.toKnownBits();
KnownBits ExpectedKnown(Bits);
ExpectedKnown.Zero.setAllBits();
ExpectedKnown.One.setAllBits();
ForeachNumInConstantRange(CR, [&](const APInt &N) {
ExpectedKnown.One &= N;
ExpectedKnown.Zero &= ~N;
});
// For an empty CR any result would be legal.
if (!CR.isEmptySet()) {
EXPECT_EQ(ExpectedKnown.One, Known.One);
EXPECT_EQ(ExpectedKnown.Zero, Known.Zero);
}
});
}
TEST_F(ConstantRangeTest, Negative) {
// All elements in an empty set (of which there are none) are both negative
// and non-negative. Empty & full sets checked explicitly for clarity, but