Skip to content

[ConstantFPRange] Address review comments. NFC. #110793

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions llvm/include/llvm/IR/ConstantFPRange.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ class [[nodiscard]] ConstantFPRange {

void makeEmpty();
void makeFull();
bool isNaNOnly() const;

/// Initialize a full or empty set for the specified semantics.
explicit ConstantFPRange(const fltSemantics &Sem, bool IsFullSet);
Expand Down Expand Up @@ -78,6 +77,9 @@ class [[nodiscard]] ConstantFPRange {
/// Helper for (-inf, inf) to represent all finite values.
static ConstantFPRange getFinite(const fltSemantics &Sem);

/// Helper for [-inf, inf] to represent all non-NaN values.
static ConstantFPRange getNonNaN(const fltSemantics &Sem);

/// Create a range which doesn't contain NaNs.
static ConstantFPRange getNonNaN(APFloat LowerVal, APFloat UpperVal) {
return ConstantFPRange(std::move(LowerVal), std::move(UpperVal),
Expand Down Expand Up @@ -118,13 +120,13 @@ class [[nodiscard]] ConstantFPRange {

/// Produce the exact range such that all values in the returned range satisfy
/// the given predicate with any value contained within Other. Formally, this
/// returns the exact answer when the superset of 'union over all y in Other
/// is exactly same as the subset of intersection over all y in Other.
/// { x : fcmp op x y is true}'.
/// returns { x : fcmp op x Other is true }.
///
/// Example: Pred = olt and Other = float 3 returns [-inf, 3)
static ConstantFPRange makeExactFCmpRegion(FCmpInst::Predicate Pred,
const APFloat &Other);
/// If the exact answer is not representable as a ConstantFPRange, returns
/// std::nullopt.
static std::optional<ConstantFPRange>
makeExactFCmpRegion(FCmpInst::Predicate Pred, const APFloat &Other);

/// Does the predicate \p Pred hold between ranges this and \p Other?
/// NOTE: false does not mean that inverse predicate holds!
Expand All @@ -139,6 +141,7 @@ class [[nodiscard]] ConstantFPRange {
bool containsNaN() const { return MayBeQNaN || MayBeSNaN; }
bool containsQNaN() const { return MayBeQNaN; }
bool containsSNaN() const { return MayBeSNaN; }
bool isNaNOnly() const;

/// Get the semantics of this ConstantFPRange.
const fltSemantics &getSemantics() const { return Lower.getSemantics(); }
Expand All @@ -157,10 +160,15 @@ class [[nodiscard]] ConstantFPRange {
bool contains(const ConstantFPRange &CR) const;

/// If this set contains a single element, return it, otherwise return null.
const APFloat *getSingleElement() const;
/// If \p ExcludesNaN is true, return the non-NaN single element.
const APFloat *getSingleElement(bool ExcludesNaN = false) const;

/// Return true if this set contains exactly one member.
bool isSingleElement() const { return getSingleElement() != nullptr; }
/// If \p ExcludesNaN is true, return true if this set contains exactly one
/// non-NaN member.
bool isSingleElement(bool ExcludesNaN = false) const {
return getSingleElement(ExcludesNaN) != nullptr;
}

/// Return true if the sign bit of all values in this range is 1.
/// Return false if the sign bit of all values in this range is 0.
Expand All @@ -185,7 +193,7 @@ class [[nodiscard]] ConstantFPRange {
/// another range.
ConstantFPRange intersectWith(const ConstantFPRange &CR) const;

/// Return the range that results from the union of this range
/// Return the smallest range that results from the union of this range
/// with another range. The resultant range is guaranteed to include the
/// elements of both sets, but may contain more.
ConstantFPRange unionWith(const ConstantFPRange &CR) const;
Expand Down
28 changes: 17 additions & 11 deletions llvm/lib/IR/ConstantFPRange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,12 @@ static void canonicalizeRange(APFloat &Lower, APFloat &Upper) {
}

ConstantFPRange::ConstantFPRange(APFloat LowerVal, APFloat UpperVal,
bool MayBeQNaN, bool MayBeSNaN)
: Lower(std::move(LowerVal)), Upper(std::move(UpperVal)) {
bool MayBeQNaNVal, bool MayBeSNaNVal)
: Lower(std::move(LowerVal)), Upper(std::move(UpperVal)),
MayBeQNaN(MayBeQNaNVal), MayBeSNaN(MayBeSNaNVal) {
assert(&Lower.getSemantics() == &Upper.getSemantics() &&
"Should only use the same semantics");
assert(!isNonCanonicalEmptySet(Lower, Upper) && "Non-canonical form");
this->MayBeQNaN = MayBeQNaN;
this->MayBeSNaN = MayBeSNaN;
}

ConstantFPRange ConstantFPRange::getFinite(const fltSemantics &Sem) {
Expand All @@ -103,6 +102,12 @@ ConstantFPRange ConstantFPRange::getNaNOnly(const fltSemantics &Sem,
MayBeSNaN);
}

ConstantFPRange ConstantFPRange::getNonNaN(const fltSemantics &Sem) {
return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/true),
APFloat::getInf(Sem, /*Negative=*/false),
/*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
}

ConstantFPRange
ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred,
const ConstantFPRange &Other) {
Expand All @@ -117,9 +122,10 @@ ConstantFPRange::makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred,
return getEmpty(Other.getSemantics());
}

ConstantFPRange ConstantFPRange::makeExactFCmpRegion(FCmpInst::Predicate Pred,
const APFloat &Other) {
return makeAllowedFCmpRegion(Pred, ConstantFPRange(Other));
std::optional<ConstantFPRange>
ConstantFPRange::makeExactFCmpRegion(FCmpInst::Predicate Pred,
const APFloat &Other) {
return std::nullopt;
}

bool ConstantFPRange::fcmp(FCmpInst::Predicate Pred,
Expand Down Expand Up @@ -161,8 +167,8 @@ bool ConstantFPRange::contains(const ConstantFPRange &CR) const {
strictCompare(CR.Upper, Upper) != APFloat::cmpGreaterThan;
}

const APFloat *ConstantFPRange::getSingleElement() const {
if (MayBeSNaN || MayBeQNaN)
const APFloat *ConstantFPRange::getSingleElement(bool ExcludesNaN) const {
if (!ExcludesNaN && (MayBeSNaN || MayBeQNaN))
return nullptr;
return Lower.bitwiseIsEqual(Upper) ? &Lower : nullptr;
}
Expand All @@ -189,8 +195,8 @@ FPClassTest ConstantFPRange::classify() const {
FPClassTest LowerMask = Lower.classify();
FPClassTest UpperMask = Upper.classify();
assert(LowerMask <= UpperMask && "Range is nan-only.");
for (uint32_t I = LowerMask; I <= UpperMask; I <<= 1)
Mask |= I;
// Set all bits from log2(LowerMask) to log2(UpperMask).
Mask |= (UpperMask << 1) - LowerMask;
}
return static_cast<FPClassTest>(Mask);
}
Expand Down
4 changes: 4 additions & 0 deletions llvm/unittests/IR/ConstantFPRangeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,16 @@ TEST_F(ConstantFPRangeTest, SingleElement) {
EXPECT_EQ(*One.getSingleElement(), APFloat(1.0));
EXPECT_EQ(*PosZero.getSingleElement(), APFloat::getZero(Sem));
EXPECT_EQ(*PosInf.getSingleElement(), APFloat::getInf(Sem));
ConstantFPRange PosZeroOrNaN = PosZero.unionWith(NaN);
EXPECT_EQ(*PosZeroOrNaN.getSingleElement(/*ExcludesNaN=*/true),
APFloat::getZero(Sem));

EXPECT_FALSE(Full.isSingleElement());
EXPECT_FALSE(Empty.isSingleElement());
EXPECT_TRUE(One.isSingleElement());
EXPECT_FALSE(Some.isSingleElement());
EXPECT_FALSE(Zero.isSingleElement());
EXPECT_TRUE(PosZeroOrNaN.isSingleElement(/*ExcludesNaN=*/true));
}

TEST_F(ConstantFPRangeTest, ExhaustivelyEnumerate) {
Expand Down
Loading