1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00

[APFloat] Switch from (PPCDoubleDoubleImpl, IEEEdouble) layout to (IEEEdouble, IEEEdouble)

Summary:
This patch changes the layout of DoubleAPFloat, and adjust all
operations to do either:
1) (IEEEdouble, IEEEdouble) -> (uint64_t, uint64_t) -> PPCDoubleDoubleImpl,
   then run the old algorithm.
2) Do the right thing directly.

1) includes multiply, divide, remainder, mod, fusedMultiplyAdd, roundToIntegral,
   convertFromString, next, convertToInteger, convertFromAPInt,
   convertFromSignExtendedInteger, convertFromZeroExtendedInteger,
   convertToHexString, toString, getExactInverse.
2) includes makeZero, makeLargest, makeSmallest, makeSmallestNormalized,
   compare, bitwiseIsEqual, bitcastToAPInt, isDenormal, isSmallest,
   isLargest, isInteger, ilogb, scalbn, frexp, hash_value, Profile.

I could split this into two patches, e.g. use
1) for all operatoins first, then incrementally change some of them to
2). I didn't do that, because 1) involves code that converts data between
PPCDoubleDoubleImpl and (IEEEdouble, IEEEdouble) back and forth, and may
pessimize the compiler. Instead, I find easy functions and use
approach 2) for them directly.

Next step is to implement move multiply and divide from 1) to 2). I don't
have plans for other functions in 1).

Differential Revision: https://reviews.llvm.org/D27872

llvm-svn: 292839
This commit is contained in:
Tim Shen 2017-01-23 22:39:35 +00:00
parent bd33194651
commit 4f93c19c2e
4 changed files with 744 additions and 199 deletions

View File

@ -235,10 +235,6 @@ public:
/// @}
/// Used to insert APFloat objects, or objects that contain APFloat objects,
/// into FoldingSets.
void Profile(FoldingSetNodeID &NID) const;
/// \name Arithmetic
/// @{
@ -255,53 +251,12 @@ public:
/// IEEE-754R 5.3.1: nextUp/nextDown.
opStatus next(bool nextDown);
/// \brief Operator+ overload which provides the default
/// \c nmNearestTiesToEven rounding mode and *no* error checking.
IEEEFloat operator+(const IEEEFloat &RHS) const {
IEEEFloat Result = *this;
Result.add(RHS, rmNearestTiesToEven);
return Result;
}
/// \brief Operator- overload which provides the default
/// \c nmNearestTiesToEven rounding mode and *no* error checking.
IEEEFloat operator-(const IEEEFloat &RHS) const {
IEEEFloat Result = *this;
Result.subtract(RHS, rmNearestTiesToEven);
return Result;
}
/// \brief Operator* overload which provides the default
/// \c nmNearestTiesToEven rounding mode and *no* error checking.
IEEEFloat operator*(const IEEEFloat &RHS) const {
IEEEFloat Result = *this;
Result.multiply(RHS, rmNearestTiesToEven);
return Result;
}
/// \brief Operator/ overload which provides the default
/// \c nmNearestTiesToEven rounding mode and *no* error checking.
IEEEFloat operator/(const IEEEFloat &RHS) const {
IEEEFloat Result = *this;
Result.divide(RHS, rmNearestTiesToEven);
return Result;
}
/// @}
/// \name Sign operations.
/// @{
void changeSign();
void clearSign();
void copySign(const IEEEFloat &);
/// \brief A static helper to produce a copy of an APFloat value with its sign
/// copied from some other APFloat.
static IEEEFloat copySign(IEEEFloat Value, const IEEEFloat &Sign) {
Value.copySign(Sign);
return Value;
}
/// @}
@ -311,7 +266,6 @@ public:
opStatus convert(const fltSemantics &, roundingMode, bool *);
opStatus convertToInteger(integerPart *, unsigned int, bool, roundingMode,
bool *) const;
opStatus convertToInteger(APSInt &, roundingMode, bool *) const;
opStatus convertFromAPInt(const APInt &, bool, roundingMode);
opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int,
bool, roundingMode);
@ -443,7 +397,7 @@ public:
/// If this value has an exact multiplicative inverse, store it in inv and
/// return true.
bool getExactInverse(IEEEFloat *inv) const;
bool getExactInverse(APFloat *inv) const;
/// \brief Returns the exponent of the internal representation of the APFloat.
///
@ -636,6 +590,13 @@ public:
opStatus add(const DoubleAPFloat &RHS, roundingMode RM);
opStatus subtract(const DoubleAPFloat &RHS, roundingMode RM);
opStatus multiply(const DoubleAPFloat &RHS, roundingMode RM);
opStatus divide(const DoubleAPFloat &RHS, roundingMode RM);
opStatus remainder(const DoubleAPFloat &RHS);
opStatus mod(const DoubleAPFloat &RHS);
opStatus fusedMultiplyAdd(const DoubleAPFloat &Multiplicand,
const DoubleAPFloat &Addend, roundingMode RM);
opStatus roundToIntegral(roundingMode RM);
void changeSign();
cmpResult compareAbsoluteValue(const DoubleAPFloat &RHS) const;
@ -643,9 +604,49 @@ public:
bool isNegative() const;
void makeInf(bool Neg);
void makeZero(bool Neg);
void makeLargest(bool Neg);
void makeSmallest(bool Neg);
void makeSmallestNormalized(bool Neg);
void makeNaN(bool SNaN, bool Neg, const APInt *fill);
cmpResult compare(const DoubleAPFloat &RHS) const;
bool bitwiseIsEqual(const DoubleAPFloat &RHS) const;
APInt bitcastToAPInt() const;
opStatus convertFromString(StringRef, roundingMode);
opStatus next(bool nextDown);
opStatus convertToInteger(integerPart *Input, unsigned int Width,
bool IsSigned, roundingMode RM,
bool *IsExact) const;
opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM);
opStatus convertFromSignExtendedInteger(const integerPart *Input,
unsigned int InputSize, bool IsSigned,
roundingMode RM);
opStatus convertFromZeroExtendedInteger(const integerPart *Input,
unsigned int InputSize, bool IsSigned,
roundingMode RM);
unsigned int convertToHexString(char *DST, unsigned int HexDigits,
bool UpperCase, roundingMode RM) const;
bool isDenormal() const;
bool isSmallest() const;
bool isLargest() const;
bool isInteger() const;
void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
unsigned FormatMaxPadding) const;
bool getExactInverse(APFloat *inv) const;
friend int ilogb(const DoubleAPFloat &Arg);
friend DoubleAPFloat scalbn(DoubleAPFloat X, int Exp, roundingMode);
friend DoubleAPFloat frexp(const DoubleAPFloat &X, int &Exp, roundingMode);
friend hash_code hash_value(const DoubleAPFloat &Arg);
};
hash_code hash_value(const DoubleAPFloat &Arg);
} // End detail namespace
// This is a interface class that is currently forwarding functionalities from
@ -770,26 +771,76 @@ class APFloat : public APFloatBase {
llvm_unreachable("Unexpected semantics");
}
void makeZero(bool Neg) { getIEEE().makeZero(Neg); }
void makeZero(bool Neg) {
if (usesLayout<IEEEFloat>(getSemantics())) {
U.IEEE.makeZero(Neg);
return;
}
if (usesLayout<DoubleAPFloat>(getSemantics())) {
U.Double.makeZero(Neg);
return;
}
llvm_unreachable("Unexpected semantics");
}
void makeInf(bool Neg) {
if (usesLayout<IEEEFloat>(*U.semantics))
return U.IEEE.makeInf(Neg);
if (usesLayout<DoubleAPFloat>(*U.semantics))
return U.Double.makeInf(Neg);
if (usesLayout<IEEEFloat>(*U.semantics)) {
U.IEEE.makeInf(Neg);
return;
}
if (usesLayout<DoubleAPFloat>(*U.semantics)) {
U.Double.makeInf(Neg);
return;
}
llvm_unreachable("Unexpected semantics");
}
void makeNaN(bool SNaN, bool Neg, const APInt *fill) {
getIEEE().makeNaN(SNaN, Neg, fill);
if (usesLayout<IEEEFloat>(getSemantics())) {
U.IEEE.makeNaN(SNaN, Neg, fill);
return;
}
if (usesLayout<DoubleAPFloat>(getSemantics())) {
return U.Double.makeNaN(SNaN, Neg, fill);
return;
}
llvm_unreachable("Unexpected semantics");
}
void makeLargest(bool Neg) { getIEEE().makeLargest(Neg); }
void makeLargest(bool Neg) {
if (usesLayout<IEEEFloat>(getSemantics())) {
U.IEEE.makeLargest(Neg);
return;
}
if (usesLayout<DoubleAPFloat>(getSemantics())) {
U.Double.makeLargest(Neg);
return;
}
llvm_unreachable("Unexpected semantics");
}
void makeSmallest(bool Neg) { getIEEE().makeSmallest(Neg); }
void makeSmallest(bool Neg) {
if (usesLayout<IEEEFloat>(getSemantics())) {
U.IEEE.makeSmallest(Neg);
return;
}
if (usesLayout<DoubleAPFloat>(getSemantics())) {
U.Double.makeSmallest(Neg);
return;
}
llvm_unreachable("Unexpected semantics");
}
void makeSmallestNormalized(bool Neg) {
getIEEE().makeSmallestNormalized(Neg);
if (usesLayout<IEEEFloat>(getSemantics())) {
U.IEEE.makeSmallestNormalized(Neg);
return;
}
if (usesLayout<DoubleAPFloat>(getSemantics())) {
U.Double.makeSmallestNormalized(Neg);
return;
}
llvm_unreachable("Unexpected semantics");
}
// FIXME: This is due to clang 3.3 (or older version) always checks for the
@ -921,7 +972,9 @@ public:
/// \param isIEEE - If 128 bit number, select between PPC and IEEE
static APFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false);
void Profile(FoldingSetNodeID &NID) const { getIEEE().Profile(NID); }
/// Used to insert APFloat objects, or objects that contain APFloat objects,
/// into FoldingSets.
void Profile(FoldingSetNodeID &NID) const;
opStatus add(const APFloat &RHS, roundingMode RM) {
assert(&getSemantics() == &RHS.getSemantics() &&
@ -942,48 +995,127 @@ public:
llvm_unreachable("Unexpected semantics");
}
opStatus multiply(const APFloat &RHS, roundingMode RM) {
return getIEEE().multiply(RHS.getIEEE(), RM);
assert(&getSemantics() == &RHS.getSemantics() &&
"Should only call on two APFloats with the same semantics");
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.multiply(RHS.U.IEEE, RM);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.multiply(RHS.U.Double, RM);
llvm_unreachable("Unexpected semantics");
}
opStatus divide(const APFloat &RHS, roundingMode RM) {
return getIEEE().divide(RHS.getIEEE(), RM);
assert(&getSemantics() == &RHS.getSemantics() &&
"Should only call on two APFloats with the same semantics");
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.divide(RHS.U.IEEE, RM);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.divide(RHS.U.Double, RM);
llvm_unreachable("Unexpected semantics");
}
opStatus remainder(const APFloat &RHS) {
return getIEEE().remainder(RHS.getIEEE());
assert(&getSemantics() == &RHS.getSemantics() &&
"Should only call on two APFloats with the same semantics");
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.remainder(RHS.U.IEEE);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.remainder(RHS.U.Double);
llvm_unreachable("Unexpected semantics");
}
opStatus mod(const APFloat &RHS) {
assert(&getSemantics() == &RHS.getSemantics() &&
"Should only call on two APFloats with the same semantics");
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.mod(RHS.U.IEEE);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.mod(RHS.U.Double);
llvm_unreachable("Unexpected semantics");
}
opStatus mod(const APFloat &RHS) { return getIEEE().mod(RHS.getIEEE()); }
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend,
roundingMode RM) {
return getIEEE().fusedMultiplyAdd(Multiplicand.getIEEE(), Addend.getIEEE(),
RM);
assert(&getSemantics() == &Multiplicand.getSemantics() &&
"Should only call on APFloats with the same semantics");
assert(&getSemantics() == &Addend.getSemantics() &&
"Should only call on APFloats with the same semantics");
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.fusedMultiplyAdd(Multiplicand.U.IEEE, Addend.U.IEEE, RM);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.fusedMultiplyAdd(Multiplicand.U.Double, Addend.U.Double,
RM);
llvm_unreachable("Unexpected semantics");
}
opStatus roundToIntegral(roundingMode RM) {
return getIEEE().roundToIntegral(RM);
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.roundToIntegral(RM);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.roundToIntegral(RM);
llvm_unreachable("Unexpected semantics");
}
opStatus next(bool nextDown) { return getIEEE().next(nextDown); }
opStatus next(bool nextDown) {
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.next(nextDown);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.next(nextDown);
llvm_unreachable("Unexpected semantics");
}
/// \brief Operator+ overload which provides the default
/// \c rmNearestTiesToEven rounding mode and *no* error checking.
APFloat operator+(const APFloat &RHS) const {
return APFloat(getIEEE() + RHS.getIEEE(), getSemantics());
APFloat Result(*this);
(void)Result.add(RHS, rmNearestTiesToEven);
return Result;
}
/// \brief Operator- overload which provides the default
/// \c rmNearestTiesToEven rounding mode and *no* error checking.
APFloat operator-(const APFloat &RHS) const {
return APFloat(getIEEE() - RHS.getIEEE(), getSemantics());
APFloat Result(*this);
(void)Result.subtract(RHS, rmNearestTiesToEven);
return Result;
}
/// \brief Operator* overload which provides the default
/// \c rmNearestTiesToEven rounding mode and *no* error checking.
APFloat operator*(const APFloat &RHS) const {
return APFloat(getIEEE() * RHS.getIEEE(), getSemantics());
APFloat Result(*this);
(void)Result.multiply(RHS, rmNearestTiesToEven);
return Result;
}
/// \brief Operator/ overload which provides the default
/// \c rmNearestTiesToEven rounding mode and *no* error checking.
APFloat operator/(const APFloat &RHS) const {
return APFloat(getIEEE() / RHS.getIEEE(), getSemantics());
APFloat Result(*this);
(void)Result.divide(RHS, rmNearestTiesToEven);
return Result;
}
void changeSign() { getIEEE().changeSign(); }
void clearSign() { getIEEE().clearSign(); }
void copySign(const APFloat &RHS) { getIEEE().copySign(RHS.getIEEE()); }
void changeSign() {
if (usesLayout<IEEEFloat>(getSemantics())) {
U.IEEE.changeSign();
return;
}
if (usesLayout<DoubleAPFloat>(getSemantics())) {
U.Double.changeSign();
return;
}
llvm_unreachable("Unexpected semantics");
}
void clearSign() {
if (isNegative())
changeSign();
}
void copySign(const APFloat &RHS) {
if (isNegative() != RHS.isNegative())
changeSign();
}
/// \brief A static helper to produce a copy of an APFloat value with its sign
/// copied from some other APFloat.
static APFloat copySign(APFloat Value, const APFloat &Sign) {
return APFloat(IEEEFloat::copySign(Value.getIEEE(), Sign.getIEEE()),
Value.getSemantics());
Value.copySign(Sign);
return Value;
}
opStatus convert(const fltSemantics &ToSemantics, roundingMode RM,
@ -991,46 +1123,84 @@ public:
opStatus convertToInteger(integerPart *Input, unsigned int Width,
bool IsSigned, roundingMode RM,
bool *IsExact) const {
return getIEEE().convertToInteger(Input, Width, IsSigned, RM, IsExact);
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.convertToInteger(Input, Width, IsSigned, RM, IsExact);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.convertToInteger(Input, Width, IsSigned, RM, IsExact);
llvm_unreachable("Unexpected semantics");
}
opStatus convertToInteger(APSInt &Result, roundingMode RM,
bool *IsExact) const {
return getIEEE().convertToInteger(Result, RM, IsExact);
}
bool *IsExact) const;
opStatus convertFromAPInt(const APInt &Input, bool IsSigned,
roundingMode RM) {
return getIEEE().convertFromAPInt(Input, IsSigned, RM);
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.convertFromAPInt(Input, IsSigned, RM);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.convertFromAPInt(Input, IsSigned, RM);
llvm_unreachable("Unexpected semantics");
}
opStatus convertFromSignExtendedInteger(const integerPart *Input,
unsigned int InputSize, bool IsSigned,
roundingMode RM) {
return getIEEE().convertFromSignExtendedInteger(Input, InputSize, IsSigned,
RM);
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.convertFromSignExtendedInteger(Input, InputSize, IsSigned,
RM);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.convertFromSignExtendedInteger(Input, InputSize, IsSigned,
RM);
llvm_unreachable("Unexpected semantics");
}
opStatus convertFromZeroExtendedInteger(const integerPart *Input,
unsigned int InputSize, bool IsSigned,
roundingMode RM) {
return getIEEE().convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
RM);
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
RM);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
RM);
llvm_unreachable("Unexpected semantics");
}
opStatus convertFromString(StringRef, roundingMode);
APInt bitcastToAPInt() const { return getIEEE().bitcastToAPInt(); }
APInt bitcastToAPInt() const {
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.bitcastToAPInt();
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.bitcastToAPInt();
llvm_unreachable("Unexpected semantics");
}
double convertToDouble() const { return getIEEE().convertToDouble(); }
float convertToFloat() const { return getIEEE().convertToFloat(); }
bool operator==(const APFloat &) const = delete;
cmpResult compare(const APFloat &RHS) const {
return getIEEE().compare(RHS.getIEEE());
assert(&getSemantics() == &RHS.getSemantics() &&
"Should only compare APFloats with the same semantics");
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.compare(RHS.U.IEEE);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.compare(RHS.U.Double);
llvm_unreachable("Unexpected semantics");
}
bool bitwiseIsEqual(const APFloat &RHS) const {
return getIEEE().bitwiseIsEqual(RHS.getIEEE());
if (&getSemantics() != &RHS.getSemantics())
return false;
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.bitwiseIsEqual(RHS.U.IEEE);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.bitwiseIsEqual(RHS.U.Double);
llvm_unreachable("Unexpected semantics");
}
unsigned int convertToHexString(char *DST, unsigned int HexDigits,
bool UpperCase, roundingMode RM) const {
return getIEEE().convertToHexString(DST, HexDigits, UpperCase, RM);
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.convertToHexString(DST, HexDigits, UpperCase, RM);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.convertToHexString(DST, HexDigits, UpperCase, RM);
llvm_unreachable("Unexpected semantics");
}
bool isZero() const { return getCategory() == fcZero; }
@ -1038,7 +1208,13 @@ public:
bool isNaN() const { return getCategory() == fcNaN; }
bool isNegative() const { return getIEEE().isNegative(); }
bool isDenormal() const { return getIEEE().isDenormal(); }
bool isDenormal() const {
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.isDenormal();
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.isDenormal();
llvm_unreachable("Unexpected semantics");
}
bool isSignaling() const { return getIEEE().isSignaling(); }
bool isNormal() const { return !isDenormal() && isFiniteNonZero(); }
@ -1050,30 +1226,53 @@ public:
bool isFiniteNonZero() const { return isFinite() && !isZero(); }
bool isPosZero() const { return isZero() && !isNegative(); }
bool isNegZero() const { return isZero() && isNegative(); }
bool isSmallest() const { return getIEEE().isSmallest(); }
bool isLargest() const { return getIEEE().isLargest(); }
bool isInteger() const { return getIEEE().isInteger(); }
bool isSmallest() const {
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.isSmallest();
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.isSmallest();
llvm_unreachable("Unexpected semantics");
}
bool isLargest() const {
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.isLargest();
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.isLargest();
llvm_unreachable("Unexpected semantics");
}
bool isInteger() const {
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.isInteger();
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.isInteger();
llvm_unreachable("Unexpected semantics");
}
APFloat &operator=(const APFloat &RHS) = default;
APFloat &operator=(APFloat &&RHS) = default;
void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision = 0,
unsigned FormatMaxPadding = 3) const {
return getIEEE().toString(Str, FormatPrecision, FormatMaxPadding);
if (usesLayout<IEEEFloat>(getSemantics())) {
U.IEEE.toString(Str, FormatPrecision, FormatMaxPadding);
return;
}
if (usesLayout<DoubleAPFloat>(getSemantics())) {
U.Double.toString(Str, FormatPrecision, FormatMaxPadding);
return;
}
llvm_unreachable("Unexpected semantics");
}
void print(raw_ostream &) const;
void dump() const;
bool getExactInverse(APFloat *inv) const {
return getIEEE().getExactInverse(inv ? &inv->getIEEE() : nullptr);
}
// This is for internal test only.
// TODO: Remove it after the PPCDoubleDouble transition.
const APFloat &getSecondFloat() const {
assert(&getSemantics() == &PPCDoubleDouble());
return U.Double.getSecond();
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.getExactInverse(inv);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.getExactInverse(inv);
llvm_unreachable("Unexpected semantics");
}
friend hash_code hash_value(const APFloat &Arg);
@ -1090,7 +1289,11 @@ public:
/// xlC compiler.
hash_code hash_value(const APFloat &Arg);
inline APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode RM) {
return APFloat(scalbn(X.getIEEE(), Exp, RM), X.getSemantics());
if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics()))
return APFloat(scalbn(X.U.IEEE, Exp, RM), X.getSemantics());
if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics()))
return APFloat(scalbn(X.U.Double, Exp, RM), X.getSemantics());
llvm_unreachable("Unexpected semantics");
}
/// \brief Equivalent of C standard library function.
@ -1098,7 +1301,11 @@ inline APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode RM) {
/// While the C standard says Exp is an unspecified value for infinity and nan,
/// this returns INT_MAX for infinities, and INT_MIN for NaNs.
inline APFloat frexp(const APFloat &X, int &Exp, APFloat::roundingMode RM) {
return APFloat(frexp(X.getIEEE(), Exp, RM), X.getSemantics());
if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics()))
return APFloat(frexp(X.U.IEEE, Exp, RM), X.getSemantics());
if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics()))
return APFloat(frexp(X.U.Double, Exp, RM), X.getSemantics());
llvm_unreachable("Unexpected semantics");
}
/// \brief Returns the absolute value of the argument.
inline APFloat abs(APFloat X) {

View File

@ -83,16 +83,26 @@ namespace llvm {
and we heavily rely on them having distinct addresses. */
static const fltSemantics semPPCDoubleDouble = {-1, 0, 0, 0};
/* There are temporary semantics for the real PPCDoubleDouble implementation.
Currently, APFloat of PPCDoubleDouble holds one PPCDoubleDoubleImpl as the
high part of double double, and one IEEEdouble as the low part, so that
the old operations operate on PPCDoubleDoubleImpl, while the newly added
operations also populate the IEEEdouble.
/* These are legacy semantics for the fallback, inaccrurate implementation of
IBM double-double, if the accurate semPPCDoubleDouble doesn't handle the
case. It's equivalent to have an IEEE number with consecutive 106 bits of
mantissa, and 11 bits of exponent. It's not accurate, becuase the two
53-bit mantissa parts don't actually have to be consecutive,
e.g. 1 + epsilon.
TODO: Once all functions support DoubleAPFloat mode, we'll change all
PPCDoubleDoubleImpl to IEEEdouble and remove PPCDoubleDoubleImpl. */
static const fltSemantics semPPCDoubleDoubleImpl = {1023, -1022 + 53, 53 + 53,
128};
Currently, these semantics are used in the following way:
(IEEEdouble, IEEEdouble) -> (64-bit APInt, 64-bit APInt) ->
(128-bit APInt) -> semPPCDoubleDoubleLegacy -> IEEE operations
We use bitcastToAPInt() to get the bit representation (in APInt) of the
underlying IEEEdouble, then use the APInt constructor to construct the
legacy IEEE float.
TODO: Implement all operations in semPPCDoubleDouble, and delete these
semantics. */
static const fltSemantics semPPCDoubleDoubleLegacy = {1023, -1022 + 53,
53 + 53, 128};
const fltSemantics &APFloatBase::IEEEhalf() {
return semIEEEhalf;
@ -862,11 +872,6 @@ IEEEFloat::IEEEFloat(IEEEFloat &&rhs) : semantics(&semBogus) {
IEEEFloat::~IEEEFloat() { freeSignificand(); }
// Profile - This method 'profiles' an APFloat for use with FoldingSet.
void IEEEFloat::Profile(FoldingSetNodeID &ID) const {
ID.Add(bitcastToAPInt());
}
unsigned int IEEEFloat::partCount() const {
return partCountForBits(semantics->precision + 1);
}
@ -1611,16 +1616,6 @@ void IEEEFloat::changeSign() {
sign = !sign;
}
void IEEEFloat::clearSign() {
/* So is this one. */
sign = 0;
}
void IEEEFloat::copySign(const IEEEFloat &rhs) {
/* And this one. */
sign = rhs.sign;
}
/* Normalized addition or subtraction. */
IEEEFloat::opStatus IEEEFloat::addOrSubtract(const IEEEFloat &rhs,
roundingMode rounding_mode,
@ -1840,7 +1835,7 @@ IEEEFloat::opStatus IEEEFloat::roundToIntegral(roundingMode rounding_mode) {
IEEEFloat MagicConstant(*semantics);
fs = MagicConstant.convertFromAPInt(IntegerConstant, false,
rmNearestTiesToEven);
MagicConstant.copySign(*this);
MagicConstant.sign = sign;
if (fs != opOK)
return fs;
@ -2185,22 +2180,6 @@ IEEEFloat::opStatus IEEEFloat::convertToInteger(integerPart *parts,
return fs;
}
/* Same as convertToInteger(integerPart*, ...), except the result is returned in
an APSInt, whose initial bit-width and signed-ness are used to determine the
precision of the conversion.
*/
IEEEFloat::opStatus IEEEFloat::convertToInteger(APSInt &result,
roundingMode rounding_mode,
bool *isExact) const {
unsigned bitWidth = result.getBitWidth();
SmallVector<uint64_t, 4> parts(result.getNumWords());
opStatus status = convertToInteger(
parts.data(), bitWidth, result.isSigned(), rounding_mode, isExact);
// Keeps the original signed-ness.
result = APInt(bitWidth, parts);
return status;
}
/* Convert an unsigned integer SRC to a floating point number,
rounding according to ROUNDING_MODE. The sign of the floating
point number is not modified. */
@ -2852,7 +2831,7 @@ APInt IEEEFloat::convertF80LongDoubleAPFloatToAPInt() const {
}
APInt IEEEFloat::convertPPCDoubleDoubleAPFloatToAPInt() const {
assert(semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleImpl);
assert(semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleLegacy);
assert(partCount()==2);
uint64_t words[2];
@ -3033,7 +3012,7 @@ APInt IEEEFloat::bitcastToAPInt() const {
if (semantics == (const llvm::fltSemantics*)&semIEEEquad)
return convertQuadrupleAPFloatToAPInt();
if (semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleImpl)
if (semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleLegacy)
return convertPPCDoubleDoubleAPFloatToAPInt();
assert(semantics == (const llvm::fltSemantics*)&semX87DoubleExtended &&
@ -3103,14 +3082,14 @@ void IEEEFloat::initFromPPCDoubleDoubleAPInt(const APInt &api) {
// Get the first double and convert to our format.
initFromDoubleAPInt(APInt(64, i1));
fs = convert(semPPCDoubleDoubleImpl, rmNearestTiesToEven, &losesInfo);
fs = convert(semPPCDoubleDoubleLegacy, rmNearestTiesToEven, &losesInfo);
assert(fs == opOK && !losesInfo);
(void)fs;
// Unless we have a special case, add in second double.
if (isFiniteNonZero()) {
IEEEFloat v(semIEEEdouble, APInt(64, i2));
fs = v.convert(semPPCDoubleDoubleImpl, rmNearestTiesToEven, &losesInfo);
fs = v.convert(semPPCDoubleDoubleLegacy, rmNearestTiesToEven, &losesInfo);
assert(fs == opOK && !losesInfo);
(void)fs;
@ -3264,7 +3243,7 @@ void IEEEFloat::initFromAPInt(const fltSemantics *Sem, const APInt &api) {
return initFromF80LongDoubleAPInt(api);
if (Sem == &semIEEEquad)
return initFromQuadrupleAPInt(api);
if (Sem == &semPPCDoubleDoubleImpl)
if (Sem == &semPPCDoubleDoubleLegacy)
return initFromPPCDoubleDoubleAPInt(api);
llvm_unreachable(nullptr);
@ -3620,7 +3599,7 @@ void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
Str.push_back(buffer[NDigits-I-1]);
}
bool IEEEFloat::getExactInverse(IEEEFloat *inv) const {
bool IEEEFloat::getExactInverse(APFloat *inv) const {
// Special floats and denormals have no exact inverse.
if (!isFiniteNonZero())
return false;
@ -3644,7 +3623,7 @@ bool IEEEFloat::getExactInverse(IEEEFloat *inv) const {
reciprocal.significandLSB() == reciprocal.semantics->precision - 1);
if (inv)
*inv = reciprocal;
*inv = APFloat(reciprocal, *semantics);
return true;
}
@ -3856,28 +3835,29 @@ IEEEFloat frexp(const IEEEFloat &Val, int &Exp, IEEEFloat::roundingMode RM) {
}
DoubleAPFloat::DoubleAPFloat(const fltSemantics &S)
: Semantics(&S), Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl),
APFloat(semIEEEdouble)}) {
: Semantics(&S),
Floats(new APFloat[2]{APFloat(semIEEEdouble), APFloat(semIEEEdouble)}) {
assert(Semantics == &semPPCDoubleDouble);
}
DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, uninitializedTag)
: Semantics(&S),
Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl, uninitialized),
Floats(new APFloat[2]{APFloat(semIEEEdouble, uninitialized),
APFloat(semIEEEdouble, uninitialized)}) {
assert(Semantics == &semPPCDoubleDouble);
}
DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, integerPart I)
: Semantics(&S), Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl, I),
: Semantics(&S), Floats(new APFloat[2]{APFloat(semIEEEdouble, I),
APFloat(semIEEEdouble)}) {
assert(Semantics == &semPPCDoubleDouble);
}
DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, const APInt &I)
: Semantics(&S), Floats(new APFloat[2]{
APFloat(semPPCDoubleDoubleImpl, I),
APFloat(semIEEEdouble, APInt(64, I.getRawData()[1]))}) {
: Semantics(&S),
Floats(new APFloat[2]{
APFloat(semIEEEdouble, APInt(64, I.getRawData()[0])),
APFloat(semIEEEdouble, APInt(64, I.getRawData()[1]))}) {
assert(Semantics == &semPPCDoubleDouble);
}
@ -3886,9 +3866,7 @@ DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, APFloat &&First,
: Semantics(&S),
Floats(new APFloat[2]{std::move(First), std::move(Second)}) {
assert(Semantics == &semPPCDoubleDouble);
// TODO Check for First == &IEEEdouble once the transition is done.
assert(&Floats[0].getSemantics() == &semPPCDoubleDoubleImpl ||
&Floats[0].getSemantics() == &semIEEEdouble);
assert(&Floats[0].getSemantics() == &semIEEEdouble);
assert(&Floats[1].getSemantics() == &semIEEEdouble);
}
@ -4033,25 +4011,15 @@ APFloat::opStatus DoubleAPFloat::addWithSpecial(const DoubleAPFloat &LHS,
}
assert(LHS.getCategory() == fcNormal && RHS.getCategory() == fcNormal);
// These conversions will go away once PPCDoubleDoubleImpl goes away.
// (PPCDoubleDoubleImpl, IEEEDouble) -> (IEEEDouble, IEEEDouble)
APFloat A(semIEEEdouble,
APInt(64, LHS.Floats[0].bitcastToAPInt().getRawData()[0])),
AA(LHS.Floats[1]),
C(semIEEEdouble, APInt(64, RHS.Floats[0].bitcastToAPInt().getRawData()[0])),
APFloat A(LHS.Floats[0]), AA(LHS.Floats[1]), C(RHS.Floats[0]),
CC(RHS.Floats[1]);
assert(&A.getSemantics() == &semIEEEdouble);
assert(&AA.getSemantics() == &semIEEEdouble);
assert(&C.getSemantics() == &semIEEEdouble);
assert(&CC.getSemantics() == &semIEEEdouble);
Out.Floats[0] = APFloat(semIEEEdouble);
assert(&Out.Floats[0].getSemantics() == &semIEEEdouble);
assert(&Out.Floats[1].getSemantics() == &semIEEEdouble);
auto Ret = Out.addImpl(A, AA, C, CC, RM);
// (IEEEDouble, IEEEDouble) -> (PPCDoubleDoubleImpl, IEEEDouble)
uint64_t Buffer[] = {Out.Floats[0].bitcastToAPInt().getRawData()[0],
Out.Floats[1].bitcastToAPInt().getRawData()[0]};
Out.Floats[0] = APFloat(semPPCDoubleDoubleImpl, APInt(128, 2, Buffer));
return Ret;
return Out.addImpl(A, AA, C, CC, RM);
}
APFloat::opStatus DoubleAPFloat::add(const DoubleAPFloat &RHS,
@ -4067,6 +4035,64 @@ APFloat::opStatus DoubleAPFloat::subtract(const DoubleAPFloat &RHS,
return Ret;
}
APFloat::opStatus DoubleAPFloat::multiply(const DoubleAPFloat &RHS,
APFloat::roundingMode RM) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
auto Ret =
Tmp.multiply(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()), RM);
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
return Ret;
}
APFloat::opStatus DoubleAPFloat::divide(const DoubleAPFloat &RHS,
APFloat::roundingMode RM) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
auto Ret =
Tmp.divide(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()), RM);
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
return Ret;
}
APFloat::opStatus DoubleAPFloat::remainder(const DoubleAPFloat &RHS) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
auto Ret =
Tmp.remainder(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()));
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
return Ret;
}
APFloat::opStatus DoubleAPFloat::mod(const DoubleAPFloat &RHS) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
auto Ret = Tmp.mod(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()));
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
return Ret;
}
APFloat::opStatus
DoubleAPFloat::fusedMultiplyAdd(const DoubleAPFloat &Multiplicand,
const DoubleAPFloat &Addend,
APFloat::roundingMode RM) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
auto Ret = Tmp.fusedMultiplyAdd(
APFloat(semPPCDoubleDoubleLegacy, Multiplicand.bitcastToAPInt()),
APFloat(semPPCDoubleDoubleLegacy, Addend.bitcastToAPInt()), RM);
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
return Ret;
}
APFloat::opStatus DoubleAPFloat::roundToIntegral(APFloat::roundingMode RM) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
auto Ret = Tmp.roundToIntegral(RM);
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
return Ret;
}
void DoubleAPFloat::changeSign() {
Floats[0].changeSign();
Floats[1].changeSign();
@ -4104,11 +4130,198 @@ void DoubleAPFloat::makeInf(bool Neg) {
Floats[1].makeZero(false);
}
void DoubleAPFloat::makeZero(bool Neg) {
Floats[0].makeZero(Neg);
Floats[1].makeZero(false);
}
void DoubleAPFloat::makeLargest(bool Neg) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x7fefffffffffffffull));
Floats[1] = APFloat(semIEEEdouble, APInt(64, 0x7c8ffffffffffffeull));
if (Neg)
changeSign();
}
void DoubleAPFloat::makeSmallest(bool Neg) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
Floats[0].makeSmallest(Neg);
Floats[1].makeZero(false);
}
void DoubleAPFloat::makeSmallestNormalized(bool Neg) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x0360000000000000ull));
if (Neg)
Floats[0].changeSign();
Floats[1].makeZero(false);
}
void DoubleAPFloat::makeNaN(bool SNaN, bool Neg, const APInt *fill) {
Floats[0].makeNaN(SNaN, Neg, fill);
Floats[1].makeZero(false);
}
APFloat::cmpResult DoubleAPFloat::compare(const DoubleAPFloat &RHS) const {
auto Result = Floats[0].compare(RHS.Floats[0]);
if (Result == APFloat::cmpEqual)
return Floats[1].compare(RHS.Floats[1]);
return Result;
}
bool DoubleAPFloat::bitwiseIsEqual(const DoubleAPFloat &RHS) const {
return Floats[0].bitwiseIsEqual(RHS.Floats[0]) &&
Floats[1].bitwiseIsEqual(RHS.Floats[1]);
}
hash_code hash_value(const DoubleAPFloat &Arg) {
if (Arg.Floats)
return hash_combine(hash_value(Arg.Floats[0]), hash_value(Arg.Floats[1]));
return hash_combine(Arg.Semantics);
}
APInt DoubleAPFloat::bitcastToAPInt() const {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
uint64_t Data[] = {
Floats[0].bitcastToAPInt().getRawData()[0],
Floats[1].bitcastToAPInt().getRawData()[0],
};
return APInt(128, 2, Data);
}
APFloat::opStatus DoubleAPFloat::convertFromString(StringRef S,
roundingMode RM) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy);
auto Ret = Tmp.convertFromString(S, RM);
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
return Ret;
}
APFloat::opStatus DoubleAPFloat::next(bool nextDown) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
auto Ret = Tmp.next(nextDown);
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
return Ret;
}
APFloat::opStatus DoubleAPFloat::convertToInteger(integerPart *Input,
unsigned int Width,
bool IsSigned,
roundingMode RM,
bool *IsExact) const {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
return APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt())
.convertToInteger(Input, Width, IsSigned, RM, IsExact);
}
APFloat::opStatus DoubleAPFloat::convertFromAPInt(const APInt &Input,
bool IsSigned,
roundingMode RM) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy);
auto Ret = Tmp.convertFromAPInt(Input, IsSigned, RM);
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
return Ret;
}
APFloat::opStatus
DoubleAPFloat::convertFromSignExtendedInteger(const integerPart *Input,
unsigned int InputSize,
bool IsSigned, roundingMode RM) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy);
auto Ret = Tmp.convertFromSignExtendedInteger(Input, InputSize, IsSigned, RM);
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
return Ret;
}
APFloat::opStatus
DoubleAPFloat::convertFromZeroExtendedInteger(const integerPart *Input,
unsigned int InputSize,
bool IsSigned, roundingMode RM) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy);
auto Ret = Tmp.convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM);
*this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
return Ret;
}
unsigned int DoubleAPFloat::convertToHexString(char *DST,
unsigned int HexDigits,
bool UpperCase,
roundingMode RM) const {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
return APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt())
.convertToHexString(DST, HexDigits, UpperCase, RM);
}
bool DoubleAPFloat::isDenormal() const {
return getCategory() == fcNormal &&
(Floats[0].isDenormal() || Floats[1].isDenormal() ||
Floats[0].compare(Floats[0] + Floats[1]) != cmpEqual);
}
bool DoubleAPFloat::isSmallest() const {
if (getCategory() != fcNormal)
return false;
DoubleAPFloat Tmp(*this);
Tmp.makeSmallest(this->isNegative());
return Tmp.compare(*this) == cmpEqual;
}
bool DoubleAPFloat::isLargest() const {
if (getCategory() != fcNormal)
return false;
DoubleAPFloat Tmp(*this);
Tmp.makeLargest(this->isNegative());
return Tmp.compare(*this) == cmpEqual;
}
bool DoubleAPFloat::isInteger() const {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy);
(void)Tmp.add(Floats[0], rmNearestTiesToEven);
(void)Tmp.add(Floats[1], rmNearestTiesToEven);
return Tmp.isInteger();
}
void DoubleAPFloat::toString(SmallVectorImpl<char> &Str,
unsigned FormatPrecision,
unsigned FormatMaxPadding) const {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt())
.toString(Str, FormatPrecision, FormatMaxPadding);
}
bool DoubleAPFloat::getExactInverse(APFloat *inv) const {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
if (!inv)
return Tmp.getExactInverse(nullptr);
APFloat Inv(semPPCDoubleDoubleLegacy);
auto Ret = Tmp.getExactInverse(&Inv);
*inv = APFloat(semPPCDoubleDouble, Inv.bitcastToAPInt());
return Ret;
}
DoubleAPFloat scalbn(DoubleAPFloat Arg, int Exp, APFloat::roundingMode RM) {
assert(Arg.Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
return DoubleAPFloat(semPPCDoubleDouble, scalbn(Arg.Floats[0], Exp, RM),
scalbn(Arg.Floats[1], Exp, RM));
}
DoubleAPFloat frexp(const DoubleAPFloat &Arg, int &Exp,
APFloat::roundingMode RM) {
assert(Arg.Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat First = frexp(Arg.Floats[0], Exp, RM);
APFloat Second = Arg.Floats[1];
if (Arg.getCategory() == APFloat::fcNormal)
Second = scalbn(Second, -Exp, RM);
return DoubleAPFloat(semPPCDoubleDouble, std::move(First), std::move(Second));
}
} // End detail namespace
APFloat::Storage::Storage(IEEEFloat F, const fltSemantics &Semantics) {
@ -4126,10 +4339,20 @@ APFloat::Storage::Storage(IEEEFloat F, const fltSemantics &Semantics) {
}
APFloat::opStatus APFloat::convertFromString(StringRef Str, roundingMode RM) {
return getIEEE().convertFromString(Str, RM);
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.convertFromString(Str, RM);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.convertFromString(Str, RM);
llvm_unreachable("Unexpected semantics");
}
hash_code hash_value(const APFloat &Arg) { return hash_value(Arg.getIEEE()); }
hash_code hash_value(const APFloat &Arg) {
if (APFloat::usesLayout<detail::IEEEFloat>(Arg.getSemantics()))
return hash_value(Arg.U.IEEE);
if (APFloat::usesLayout<detail::DoubleAPFloat>(Arg.getSemantics()))
return hash_value(Arg.U.Double);
llvm_unreachable("Unexpected semantics");
}
APFloat::APFloat(const fltSemantics &Semantics, StringRef S)
: APFloat(Semantics) {
@ -4146,10 +4369,8 @@ APFloat::opStatus APFloat::convert(const fltSemantics &ToSemantics,
if (usesLayout<IEEEFloat>(getSemantics()) &&
usesLayout<DoubleAPFloat>(ToSemantics)) {
assert(&ToSemantics == &semPPCDoubleDouble);
auto Ret = U.IEEE.convert(semPPCDoubleDoubleImpl, RM, losesInfo);
*this = APFloat(DoubleAPFloat(semPPCDoubleDouble, std::move(*this),
APFloat(semIEEEdouble)),
ToSemantics);
auto Ret = U.IEEE.convert(semPPCDoubleDoubleLegacy, RM, losesInfo);
*this = APFloat(ToSemantics, U.IEEE.bitcastToAPInt());
return Ret;
}
if (usesLayout<DoubleAPFloat>(getSemantics()) &&
@ -4191,4 +4412,24 @@ void APFloat::print(raw_ostream &OS) const {
void APFloat::dump() const { print(dbgs()); }
void APFloat::Profile(FoldingSetNodeID &NID) const {
NID.Add(bitcastToAPInt());
}
/* Same as convertToInteger(integerPart*, ...), except the result is returned in
an APSInt, whose initial bit-width and signed-ness are used to determine the
precision of the conversion.
*/
APFloat::opStatus APFloat::convertToInteger(APSInt &result,
roundingMode rounding_mode,
bool *isExact) const {
unsigned bitWidth = result.getBitWidth();
SmallVector<uint64_t, 4> parts(result.getNumWords());
opStatus status = convertToInteger(parts.data(), bitWidth, result.isSigned(),
rounding_mode, isExact);
// Keeps the original signed-ness.
result = APInt(bitWidth, parts);
return status;
}
} // End llvm namespace

View File

@ -128,7 +128,7 @@ entry:
; PPC32-DAG: oris {{[0-9]+}}, [[FLIP_BIT]], 16399
; PPC32-DAG: xoris {{[0-9]+}}, [[FLIP_BIT]], 48304
; PPC32: blr
%0 = tail call ppc_fp128 @llvm.copysign.ppcf128(ppc_fp128 0xMBCB0000000000000400F000000000000, ppc_fp128 %x)
%0 = tail call ppc_fp128 @llvm.copysign.ppcf128(ppc_fp128 0xM400F000000000000BCB0000000000000, ppc_fp128 %x)
%1 = bitcast ppc_fp128 %0 to i128
ret i128 %1
}

View File

@ -9,6 +9,7 @@
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
@ -3181,7 +3182,7 @@ TEST(APFloatTest, PPCDoubleDoubleAddSpecial) {
0x7948000000000000ull, 0ull, APFloat::fcInfinity,
APFloat::rmNearestTiesToEven),
// TODO: change the 4th 0x75effffffffffffe to 0x75efffffffffffff when
// PPCDoubleDoubleImpl is gone.
// semPPCDoubleDoubleLegacy is gone.
// LDBL_MAX + (1.011111... >> (1023 - 106) + (1.1111111...0 >> (1023 -
// 160))) = fcNormal
std::make_tuple(0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
@ -3234,14 +3235,14 @@ TEST(APFloatTest, PPCDoubleDoubleAdd) {
0x3ff0000000000000ull, 0x0000000000000001ull,
APFloat::rmNearestTiesToEven),
// TODO: change 0xf950000000000000 to 0xf940000000000000, when
// PPCDoubleDoubleImpl is gone.
// semPPCDoubleDoubleLegacy is gone.
// (DBL_MAX - 1 << (1023 - 105)) + (1 << (1023 - 53) + 0) = DBL_MAX +
// 1.11111... << (1023 - 52)
std::make_tuple(0x7fefffffffffffffull, 0xf950000000000000ull,
0x7c90000000000000ull, 0, 0x7fefffffffffffffull,
0x7c8ffffffffffffeull, APFloat::rmNearestTiesToEven),
// TODO: change 0xf950000000000000 to 0xf940000000000000, when
// PPCDoubleDoubleImpl is gone.
// semPPCDoubleDoubleLegacy is gone.
// (1 << (1023 - 53) + 0) + (DBL_MAX - 1 << (1023 - 105)) = DBL_MAX +
// 1.11111... << (1023 - 52)
std::make_tuple(0x7c90000000000000ull, 0, 0x7fefffffffffffffull,
@ -3262,7 +3263,7 @@ TEST(APFloatTest, PPCDoubleDoubleAdd) {
<< formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
Op2[1])
.str();
EXPECT_EQ(Expected[1], A1.getSecondFloat().bitcastToAPInt().getRawData()[0])
EXPECT_EQ(Expected[1], A1.bitcastToAPInt().getRawData()[1])
<< formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
Op2[1])
.str();
@ -3296,7 +3297,7 @@ TEST(APFloatTest, PPCDoubleDoubleSubtract) {
<< formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
Op2[1])
.str();
EXPECT_EQ(Expected[1], A1.getSecondFloat().bitcastToAPInt().getRawData()[0])
EXPECT_EQ(Expected[1], A1.bitcastToAPInt().getRawData()[1])
<< formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
Op2[1])
.str();
@ -3496,12 +3497,53 @@ TEST(APFloatTest, PPCDoubleDoubleCompare) {
APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
EXPECT_EQ(Expected, A1.compare(A2))
<< formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
<< formatv("compare(({0:x} + {1:x}), ({2:x} + {3:x}))", Op1[0], Op1[1],
Op2[0], Op2[1])
.str();
}
}
TEST(APFloatTest, PPCDoubleDoubleBitwiseIsEqual) {
using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, bool>;
DataType Data[] = {
// (1 + 0) = (1 + 0)
std::make_tuple(0x3ff0000000000000ull, 0, 0x3ff0000000000000ull, 0, true),
// (1 + 0) != (1.00...1 + 0)
std::make_tuple(0x3ff0000000000000ull, 0, 0x3ff0000000000001ull, 0,
false),
// NaN = NaN
std::make_tuple(0x7ff8000000000000ull, 0, 0x7ff8000000000000ull, 0, true),
// NaN != NaN with a different bit pattern
std::make_tuple(0x7ff8000000000000ull, 0, 0x7ff8000000000000ull,
0x3ff0000000000000ull, false),
// Inf = Inf
std::make_tuple(0x7ff0000000000000ull, 0, 0x7ff0000000000000ull, 0, true),
};
for (auto Tp : Data) {
uint64_t Op1[2], Op2[2];
bool Expected;
std::tie(Op1[0], Op1[1], Op2[0], Op2[1], Expected) = Tp;
APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
EXPECT_EQ(Expected, A1.bitwiseIsEqual(A2))
<< formatv("({0:x} + {1:x}) = ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
Op2[1])
.str();
}
}
TEST(APFloatTest, PPCDoubleDoubleHashValue) {
uint64_t Data1[] = {0x3ff0000000000001ull, 0x0000000000000001ull};
uint64_t Data2[] = {0x3ff0000000000001ull, 0};
// The hash values are *hopefully* different.
EXPECT_NE(
hash_value(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data1))),
hash_value(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data2))));
}
TEST(APFloatTest, PPCDoubleDoubleChangeSign) {
uint64_t Data[] = {
0x400f000000000000ull, 0xbcb0000000000000ull,
@ -3529,6 +3571,13 @@ TEST(APFloatTest, PPCDoubleDoubleFactories) {
EXPECT_EQ(APInt(128, 2, Data),
APFloat::getZero(APFloat::PPCDoubleDouble()).bitcastToAPInt());
}
{
uint64_t Data[] = {
0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
};
EXPECT_EQ(APInt(128, 2, Data),
APFloat::getLargest(APFloat::PPCDoubleDouble()).bitcastToAPInt());
}
{
uint64_t Data[] = {
0x0000000000000001ull, 0,
@ -3551,6 +3600,14 @@ TEST(APFloatTest, PPCDoubleDoubleFactories) {
APInt(128, 2, Data),
APFloat::getZero(APFloat::PPCDoubleDouble(), true).bitcastToAPInt());
}
{
uint64_t Data[] = {
0xffefffffffffffffull, 0xfc8ffffffffffffeull,
};
EXPECT_EQ(
APInt(128, 2, Data),
APFloat::getLargest(APFloat::PPCDoubleDouble(), true).bitcastToAPInt());
}
{
uint64_t Data[] = {
0x8000000000000001ull, 0x0000000000000000ull,
@ -3559,18 +3616,58 @@ TEST(APFloatTest, PPCDoubleDoubleFactories) {
APFloat::getSmallest(APFloat::PPCDoubleDouble(), true)
.bitcastToAPInt());
}
EXPECT_EQ(0x8360000000000000ull,
APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
.bitcastToAPInt()
.getRawData()[0]);
EXPECT_EQ(0x0000000000000000ull,
APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
.getSecondFloat()
.bitcastToAPInt()
.getRawData()[0]);
{
uint64_t Data[] = {
0x8360000000000000ull, 0x0000000000000000ull,
};
EXPECT_EQ(APInt(128, 2, Data),
APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
.bitcastToAPInt());
}
EXPECT_TRUE(APFloat::getSmallest(APFloat::PPCDoubleDouble()).isSmallest());
EXPECT_TRUE(APFloat::getLargest(APFloat::PPCDoubleDouble()).isLargest());
}
TEST(APFloatTest, PPCDoubleDoubleIsDenormal) {
EXPECT_TRUE(APFloat::getSmallest(APFloat::PPCDoubleDouble()).isDenormal());
EXPECT_FALSE(APFloat::getLargest(APFloat::PPCDoubleDouble()).isDenormal());
EXPECT_FALSE(
APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble()).isDenormal());
{
// (4 + 3) is not normalized
uint64_t Data[] = {
0x4010000000000000ull, 0x4008000000000000ull,
};
EXPECT_TRUE(
APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data)).isDenormal());
}
}
TEST(APFloatTest, PPCDoubleDoubleScalbn) {
// 3.0 + 3.0 << 53
uint64_t Input[] = {
0x4008000000000000ull, 0x3cb8000000000000ull,
};
APFloat Result =
scalbn(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Input)), 1,
APFloat::rmNearestTiesToEven);
// 6.0 + 6.0 << 53
EXPECT_EQ(0x4018000000000000ull, Result.bitcastToAPInt().getRawData()[0]);
EXPECT_EQ(0x3cc8000000000000ull, Result.bitcastToAPInt().getRawData()[1]);
}
TEST(APFloatTest, PPCDoubleDoubleFrexp) {
// 3.0 + 3.0 << 53
uint64_t Input[] = {
0x4008000000000000ull, 0x3cb8000000000000ull,
};
int Exp;
// 0.75 + 0.75 << 53
APFloat Result =
frexp(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Input)), Exp,
APFloat::rmNearestTiesToEven);
EXPECT_EQ(2, Exp);
EXPECT_EQ(0x3fe8000000000000ull, Result.bitcastToAPInt().getRawData()[0]);
EXPECT_EQ(0x3c98000000000000ull, Result.bitcastToAPInt().getRawData()[1]);
}
}