Commit cf43195d authored by jacob.bramley@arm.com's avatar jacob.bramley@arm.com

A64: Fix a few simulation inaccuracies.

  - Return the correct NaN when an invalid operation generates a NaN.
  - When one or more operands are NaN, handle them as the processor
    would, prioritising signalling NaNs and making them quiet.
  - Fix fmadd and related instructions:
     - Fnmadd is fma(-n, m, -a), not -fma(n, m, a).
     - Some common libc implementations incorrectly implement fma for
       zero results, so work around these cases.
  - Replace some unreliable tests.

This patch also adds support for Default-NaN mode, since once all the
other work was done, it only required a couple of lines of code.
Default-NaN mode was used for an optimisation in ARM, and it should now
be possible to apply the same optimisation to A64.

BUG=
R=jochen@chromium.org

Review URL: https://codereview.chromium.org/199083005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19927 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 11df4b88
......@@ -85,12 +85,18 @@ const int64_t kSRegMask = 0x00000000ffffffffL;
const int64_t kDRegMask = 0xffffffffffffffffL;
// TODO(all) check if the expression below works on all compilers or if it
// triggers an overflow error.
const int64_t kDSignMask = 0x1L << 63;
const int64_t kDSignBit = 63;
const int64_t kXSignMask = 0x1L << 63;
const int64_t kDSignMask = 0x1L << kDSignBit;
const int64_t kSSignBit = 31;
const int64_t kSSignMask = 0x1L << kSSignBit;
const int64_t kXSignBit = 63;
const int64_t kWSignMask = 0x1L << 31;
const int64_t kXSignMask = 0x1L << kXSignBit;
const int64_t kWSignBit = 31;
const int64_t kWSignMask = 0x1L << kWSignBit;
const int64_t kDQuietNanBit = 51;
const int64_t kDQuietNanMask = 0x1L << kDQuietNanBit;
const int64_t kSQuietNanBit = 22;
const int64_t kSQuietNanMask = 0x1L << kSQuietNanBit;
const int64_t kByteMask = 0xffL;
const int64_t kHalfWordMask = 0xffffL;
const int64_t kWordMask = 0xffffffffL;
......
......@@ -67,6 +67,10 @@ DEFINE_FLOAT(kFP32SignallingNaN, 0x7f800001);
DEFINE_DOUBLE(kFP64QuietNaN, 0x7ff800007fc00001);
DEFINE_FLOAT(kFP32QuietNaN, 0x7fc00001);
// The default NaN values (for FPCR.DN=1).
DEFINE_DOUBLE(kFP64DefaultNaN, 0x7ff8000000000000UL);
DEFINE_FLOAT(kFP32DefaultNaN, 0x7fc00000);
#undef DEFINE_FLOAT
#undef DEFINE_DOUBLE
......
This diff is collapsed.
......@@ -537,8 +537,9 @@ class Simulator : public DecoderVisitor {
SimSystemRegister& nzcv() { return nzcv_; }
// TODO(jbramley): Find a way to make the fpcr_ members return the proper
// types, so this accessor is not necessary.
// types, so these accessors are not necessary.
FPRounding RMode() { return static_cast<FPRounding>(fpcr_.RMode()); }
bool DN() { return fpcr_.DN() != 0; }
SimSystemRegister& fpcr() { return fpcr_; }
// Debug helpers
......@@ -707,6 +708,9 @@ class Simulator : public DecoderVisitor {
uint64_t ReverseBits(uint64_t value, unsigned num_bits);
uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode);
template <typename T>
T FPDefaultNaN() const;
void FPCompare(double val0, double val1);
double FPRoundInt(double value, FPRounding round_mode);
double FPToDouble(float value);
......@@ -721,17 +725,47 @@ class Simulator : public DecoderVisitor {
uint64_t FPToUInt64(double value, FPRounding rmode);
template <typename T>
T FPMax(T a, T b);
T FPAdd(T op1, T op2);
template <typename T>
T FPMin(T a, T b);
T FPDiv(T op1, T op2);
template <typename T>
T FPMax(T a, T b);
template <typename T>
T FPMaxNM(T a, T b);
template <typename T>
T FPMin(T a, T b);
template <typename T>
T FPMinNM(T a, T b);
template <typename T>
T FPMul(T op1, T op2);
template <typename T>
T FPMulAdd(T a, T op1, T op2);
template <typename T>
T FPSqrt(T op);
template <typename T>
T FPSub(T op1, T op2);
// Standard NaN processing.
template <typename T>
T FPProcessNaN(T op);
bool FPProcessNaNs(Instruction* instr);
template <typename T>
T FPProcessNaNs(T op1, T op2);
template <typename T>
T FPProcessNaNs3(T op1, T op2, T op3);
void CheckStackAlignment();
inline void CheckPCSComplianceAndRun();
......@@ -784,7 +818,6 @@ class Simulator : public DecoderVisitor {
// functions, or to save and restore it when entering and leaving generated
// code.
void AssertSupportedFPCR() {
ASSERT(fpcr().DN() == 0); // No default-NaN support.
ASSERT(fpcr().FZ() == 0); // No flush-to-zero support.
ASSERT(fpcr().RMode() == FPTieEven); // Ties-to-even rounding only.
......
......@@ -70,7 +70,7 @@ static inline double rawbits_to_double(uint64_t bits) {
}
// Bits counting.
// Bit counting.
int CountLeadingZeros(uint64_t value, int width);
int CountLeadingSignBits(int64_t value, int width);
int CountTrailingZeros(uint64_t value, int width);
......@@ -80,9 +80,8 @@ int MaskToBit(uint64_t mask);
// NaN tests.
inline bool IsSignallingNaN(double num) {
const uint64_t kFP64QuietNaNMask = 0x0008000000000000UL;
uint64_t raw = double_to_rawbits(num);
if (std::isnan(num) && ((raw & kFP64QuietNaNMask) == 0)) {
if (std::isnan(num) && ((raw & kDQuietNanMask) == 0)) {
return true;
}
return false;
......@@ -90,9 +89,8 @@ inline bool IsSignallingNaN(double num) {
inline bool IsSignallingNaN(float num) {
const uint64_t kFP32QuietNaNMask = 0x00400000UL;
uint32_t raw = float_to_rawbits(num);
if (std::isnan(num) && ((raw & kFP32QuietNaNMask) == 0)) {
if (std::isnan(num) && ((raw & kSQuietNanMask) == 0)) {
return true;
}
return false;
......@@ -104,6 +102,30 @@ inline bool IsQuietNaN(T num) {
return std::isnan(num) && !IsSignallingNaN(num);
}
// Convert the NaN in 'num' to a quiet NaN.
inline double ToQuietNaN(double num) {
ASSERT(isnan(num));
return rawbits_to_double(double_to_rawbits(num) | kDQuietNanMask);
}
inline float ToQuietNaN(float num) {
ASSERT(isnan(num));
return rawbits_to_float(float_to_rawbits(num) | kSQuietNanMask);
}
// Fused multiply-add.
inline double FusedMultiplyAdd(double op1, double op2, double a) {
return fma(op1, op2, a);
}
inline float FusedMultiplyAdd(float op1, float op2, float a) {
return fmaf(op1, op2, a);
}
} } // namespace v8::internal
#endif // V8_A64_UTILS_A64_H_
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment