forked from OSchip/llvm-project
[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:
parent
09cca093a3
commit
fd1e5aa8df
|
@ -93,7 +93,7 @@ void bar_long_double(void) {
|
|||
// CHECK: %[[VAR22:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0
|
||||
// CHECK: %[[VAR23:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1
|
||||
// CHECK: store ppc_fp128 0xM40000000000000000000000000000000, ppc_fp128* %[[VAR22]]
|
||||
// CHECK: store ppc_fp128 0xMC0040000000000000000000000000000, ppc_fp128* %[[VAR23]]
|
||||
// CHECK: store ppc_fp128 0xMC0040000000000008000000000000000, ppc_fp128* %[[VAR23]]
|
||||
// CHECK: %[[VAR24:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0
|
||||
// CHECK: %[[VAR25:[A-Za-z0-9.]+]] = load ppc_fp128, ppc_fp128* %[[VAR24]], align 16
|
||||
// CHECK: %[[VAR26:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue