Index: llvm/include/llvm/ADT/APFloat.h =================================================================== --- llvm/include/llvm/ADT/APFloat.h +++ llvm/include/llvm/ADT/APFloat.h @@ -489,6 +489,11 @@ /// 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)). @@ -747,6 +752,9 @@ 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); @@ -1316,6 +1324,11 @@ 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); Index: llvm/lib/Support/APFloat.cpp =================================================================== --- llvm/lib/Support/APFloat.cpp +++ llvm/lib/Support/APFloat.cpp @@ -4292,6 +4292,37 @@ return true; } +int IEEEFloat::getExactLog2() const { + if (!isFinite()) + return INT_MIN; + if (isZero()) + 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; @@ -5087,6 +5118,11 @@ 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"); Index: llvm/unittests/ADT/APFloatTest.cpp =================================================================== --- llvm/unittests/ADT/APFloatTest.cpp +++ llvm/unittests/ADT/APFloatTest.cpp @@ -6587,4 +6587,47 @@ EXPECT_TRUE(std::isnan(QNaN.convertToFloat())); } +TEST(APFloatTest, getExactLog2) { + for (unsigned I = 0; I != APFloat::S_MaxSemantics + 1; ++I) { + auto SemEnum = static_cast(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::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