/// @}
- /// Used to insert APFloat objects, or objects that contain APFloat objects,
- /// into FoldingSets.
- void Profile(FoldingSetNodeID &NID) const;
-
/// \name Arithmetic
/// @{
/// 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;
- }
/// @}
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);
/// 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.
///
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;
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
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
/// \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() &&
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,
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; }
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(); }
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);
/// 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.
/// 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) {
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;
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);
}
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,
IEEEFloat MagicConstant(*semantics);
fs = MagicConstant.convertFromAPInt(IntegerConstant, false,
rmNearestTiesToEven);
- MagicConstant.copySign(*this);
+ MagicConstant.sign = sign;
if (fs != opOK)
return fs;
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. */
}
APInt IEEEFloat::convertPPCDoubleDoubleAPFloatToAPInt() const {
- assert(semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleImpl);
+ assert(semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleLegacy);
assert(partCount()==2);
uint64_t words[2];
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 &&
// 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;
return initFromF80LongDoubleAPInt(api);
if (Sem == &semIEEEquad)
return initFromQuadrupleAPInt(api);
- if (Sem == &semPPCDoubleDoubleImpl)
+ if (Sem == &semPPCDoubleDoubleLegacy)
return initFromPPCDoubleDoubleAPInt(api);
llvm_unreachable(nullptr);
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;
reciprocal.significandLSB() == reciprocal.semantics->precision - 1);
if (inv)
- *inv = reciprocal;
+ *inv = APFloat(reciprocal, *semantics);
return true;
}
}
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);
}
: 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);
}
}
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,
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();
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) {
}
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) {
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()) &&
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
; 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
}
#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"
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,
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,
<< 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();
<< 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();
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,
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,
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,
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]);
+}
}