Skip to content

Commit

Permalink
APFloat: Add getExactLog2
Browse files Browse the repository at this point in the history
  • Loading branch information
arsenm committed Aug 7, 2023
1 parent 4b1702e commit 0b57c3a
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 0 deletions.
13 changes: 13 additions & 0 deletions llvm/include/llvm/ADT/APFloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,11 @@ class IEEEFloat final : public APFloatBase {
/// return true.
bool getExactInverse(APFloat *inv) const;

// If this is an exact power of two, return the exponent. If it's not an exact
// power of 2, return INT_MIN
LLVM_READONLY
int getExactLog2() const;

/// Returns the exponent of the internal representation of the APFloat.
///
/// Because the radix of APFloat is 2, this is equivalent to floor(log2(x)).
Expand Down Expand Up @@ -747,6 +752,9 @@ class DoubleAPFloat final : public APFloatBase {

bool getExactInverse(APFloat *inv) const;

LLVM_READONLY
int getExactLog2() const;

friend DoubleAPFloat scalbn(const DoubleAPFloat &X, int Exp, roundingMode);
friend DoubleAPFloat frexp(const DoubleAPFloat &X, int &Exp, roundingMode);
friend hash_code hash_value(const DoubleAPFloat &Arg);
Expand Down Expand Up @@ -1316,6 +1324,11 @@ class APFloat : public APFloatBase {
APFLOAT_DISPATCH_ON_SEMANTICS(getExactInverse(inv));
}

LLVM_READONLY
int getExactLog2() const {
APFLOAT_DISPATCH_ON_SEMANTICS(getExactLog2());
}

friend hash_code hash_value(const APFloat &Arg);
friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); }
friend APFloat scalbn(APFloat X, int Exp, roundingMode RM);
Expand Down
34 changes: 34 additions & 0 deletions llvm/lib/Support/APFloat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4292,6 +4292,35 @@ bool IEEEFloat::getExactInverse(APFloat *inv) const {
return true;
}

int IEEEFloat::getExactLog2() const {
if (!isFinite() || isZero() || isNegative())
return INT_MIN;

const integerPart *Parts = significandParts();
const int PartCount = partCountForBits(semantics->precision);

int PopCount = 0;
for (int i = 0; i < PartCount; ++i) {
PopCount += llvm::popcount(Parts[i]);
if (PopCount > 1)
return INT_MIN;
}

if (exponent != semantics->minExponent)
return exponent;

int CountrParts = 0;
for (int i = 0; i < PartCount;
++i, CountrParts += APInt::APINT_BITS_PER_WORD) {
if (Parts[i] != 0) {
return exponent - semantics->precision + CountrParts +
llvm::countr_zero(Parts[i]) + 1;
}
}

llvm_unreachable("didn't find the set bit");
}

bool IEEEFloat::isSignaling() const {
if (!isNaN())
return false;
Expand Down Expand Up @@ -5087,6 +5116,11 @@ bool DoubleAPFloat::getExactInverse(APFloat *inv) const {
return Ret;
}

int DoubleAPFloat::getExactLog2() const {
// TODO: Implement me
return INT_MIN;
}

DoubleAPFloat scalbn(const DoubleAPFloat &Arg, int Exp,
APFloat::roundingMode RM) {
assert(Arg.Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
Expand Down
49 changes: 49 additions & 0 deletions llvm/unittests/ADT/APFloatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6587,4 +6587,53 @@ TEST(APFloatTest, FloatTF32ToFloat) {
EXPECT_TRUE(std::isnan(QNaN.convertToFloat()));
}

TEST(APFloatTest, getExactLog2) {
for (unsigned I = 0; I != APFloat::S_MaxSemantics + 1; ++I) {
auto SemEnum = static_cast<APFloat::Semantics>(I);
const fltSemantics &Semantics = APFloat::EnumToSemantics(SemEnum);

APFloat One(Semantics, "1.0");

if (I == APFloat::S_PPCDoubleDouble) {
// Not implemented
EXPECT_EQ(INT_MIN, One.getExactLog2());
continue;
}

int MinExp = APFloat::semanticsMinExponent(Semantics);
int MaxExp = APFloat::semanticsMaxExponent(Semantics);
int Precision = APFloat::semanticsPrecision(Semantics);

EXPECT_EQ(0, One.getExactLog2());
EXPECT_EQ(INT_MIN, APFloat(Semantics, "3.0").getExactLog2());
EXPECT_EQ(INT_MIN, APFloat(Semantics, "-3.0").getExactLog2());
EXPECT_EQ(3, APFloat(Semantics, "8.0").getExactLog2());
EXPECT_EQ(INT_MIN, APFloat(Semantics, "-8.0").getExactLog2());
EXPECT_EQ(INT_MIN, APFloat(Semantics, "-0.25").getExactLog2());
EXPECT_EQ(-2, APFloat(Semantics, "0.25").getExactLog2());

EXPECT_EQ(INT_MIN, APFloat::getZero(Semantics, false).getExactLog2());
EXPECT_EQ(INT_MIN, APFloat::getZero(Semantics, true).getExactLog2());
EXPECT_EQ(INT_MIN, APFloat::getInf(Semantics).getExactLog2());
EXPECT_EQ(INT_MIN, APFloat::getInf(Semantics, true).getExactLog2());
EXPECT_EQ(INT_MIN, APFloat::getNaN(Semantics, false).getExactLog2());
EXPECT_EQ(INT_MIN, APFloat::getNaN(Semantics, true).getExactLog2());

EXPECT_EQ(INT_MIN,
scalbn(One, MinExp - Precision - 1, APFloat::rmNearestTiesToEven)
.getExactLog2());
EXPECT_EQ(INT_MIN,
scalbn(One, MinExp - Precision, APFloat::rmNearestTiesToEven)
.getExactLog2());

EXPECT_EQ(
INT_MIN,
scalbn(One, MaxExp + 1, APFloat::rmNearestTiesToEven).getExactLog2());

for (int i = MinExp - Precision + 1; i <= MaxExp; ++i) {
EXPECT_EQ(i, scalbn(One, i, APFloat::rmNearestTiesToEven).getExactLog2());
}
}
}

} // namespace

0 comments on commit 0b57c3a

Please sign in to comment.