Chromium Code Reviews| Index: src/mips/simulator-mips.cc |
| diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc |
| index cd16f6aa07de596282d7c6df7c90ab9062e0e269..58c06eb6f2bfdb17d62c3119a4a56d0b008523f1 100644 |
| --- a/src/mips/simulator-mips.cc |
| +++ b/src/mips/simulator-mips.cc |
| @@ -2366,6 +2366,63 @@ static T FPUMaxA(T a, T b) { |
| return result; |
| } |
| +enum class KeepSign : bool { no = false, yes }; |
| + |
| +template <typename T> |
| +T FPUCanonalizeNaNArg(T result, T arg, KeepSign keepSign = KeepSign::no); |
| + |
| +template <> |
| +double FPUCanonalizeNaNArg(double result, double arg, KeepSign keepSign) { |
| + DCHECK(std::isnan(arg)); |
| + double qNaN = std::numeric_limits<double>::quiet_NaN(); |
| + if (keepSign == KeepSign::yes) { |
| + uint64_t resBits = bit_cast<uint64_t>(result); |
| + return resBits & Double::kSignMask ? -qNaN : qNaN; |
|
ivica.bogosavljevic
2016/09/19 08:41:18
There is a more portable way of doing this:
use s
balazs.kilvady
2016/09/20 08:28:39
Thanks for pointing it out. Done.
|
| + } |
| + return qNaN; |
| +} |
| + |
| +template <> |
| +float FPUCanonalizeNaNArg(float result, float arg, KeepSign keepSign) { |
| + DCHECK(std::isnan(arg)); |
| + float qNaN = std::numeric_limits<float>::quiet_NaN(); |
| + if (keepSign == KeepSign::yes) { |
| + uint32_t resBits = bit_cast<uint32_t>(result); |
| + return resBits & kBinary32SignMask ? -qNaN : qNaN; |
| + } |
| + return qNaN; |
| +} |
| + |
| +template <typename T> |
| +T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first) { |
| + if (std::isnan(first)) { |
| + return FPUCanonalizeNaNArg(result, first, keepSign); |
| + } |
| + return result; |
| +} |
| + |
| +template <typename T, typename... Args> |
| +T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first, Args... args) { |
| + if (std::isnan(first)) { |
| + return FPUCanonalizeNaNArg(result, first, keepSign); |
| + } |
| + return FPUCanonalizeNaNArgs(result, keepSign, args...); |
| +} |
| + |
| +template <typename Func, typename T, typename... Args> |
| +T FPUCanonalizeOperation(Func f, T first, Args... args) { |
| + return FPUCanonalizeOperation(f, KeepSign::no, first, args...); |
| +} |
| + |
| +template <typename Func, typename T, typename... Args> |
| +T FPUCanonalizeOperation(Func f, KeepSign keepSign, T first, Args... args) { |
| + T result = f(first, args...); |
| + if (std::isnan(result)) { |
| + result = FPUCanonalizeNaNArgs(result, keepSign, first, args...); |
| + } |
| + return result; |
| +} |
| + |
| // Handle execution based on instruction types. |
| void Simulator::DecodeTypeRegisterDRsType() { |
| @@ -2477,10 +2534,16 @@ void Simulator::DecodeTypeRegisterDRsType() { |
| set_fpu_register_double(fd_reg(), FPUMaxA(ft, fs)); |
| break; |
| case ADD_D: |
| - set_fpu_register_double(fd_reg(), fs + ft); |
| + set_fpu_register_double( |
| + fd_reg(), |
| + FPUCanonalizeOperation( |
| + [](double lhs, double rhs) { return lhs + rhs; }, fs, ft)); |
| break; |
| case SUB_D: |
| - set_fpu_register_double(fd_reg(), fs - ft); |
| + set_fpu_register_double( |
| + fd_reg(), |
| + FPUCanonalizeOperation( |
| + [](double lhs, double rhs) { return lhs - rhs; }, fs, ft)); |
| break; |
| case MADDF_D: |
| DCHECK(IsMipsArchVariant(kMips32r6)); |
| @@ -2491,37 +2554,45 @@ void Simulator::DecodeTypeRegisterDRsType() { |
| set_fpu_register_double(fd_reg(), fd - (fs * ft)); |
| break; |
| case MUL_D: |
| - set_fpu_register_double(fd_reg(), fs * ft); |
| + set_fpu_register_double( |
| + fd_reg(), |
| + FPUCanonalizeOperation( |
| + [](double lhs, double rhs) { return lhs * rhs; }, fs, ft)); |
| break; |
| case DIV_D: |
| - set_fpu_register_double(fd_reg(), fs / ft); |
| + set_fpu_register_double( |
| + fd_reg(), |
| + FPUCanonalizeOperation( |
| + [](double lhs, double rhs) { return lhs / rhs; }, fs, ft)); |
| break; |
| case ABS_D: |
| - set_fpu_register_double(fd_reg(), fabs(fs)); |
| + set_fpu_register_double( |
| + fd_reg(), |
| + FPUCanonalizeOperation([](double fs) { return FPAbs(fs); }, fs)); |
| break; |
| case MOV_D: |
| set_fpu_register_double(fd_reg(), fs); |
| break; |
| case NEG_D: |
| - set_fpu_register_double(fd_reg(), -fs); |
| + set_fpu_register_double( |
| + fd_reg(), FPUCanonalizeOperation([](double src) { return -src; }, |
| + KeepSign::yes, fs)); |
| break; |
| case SQRT_D: |
| - lazily_initialize_fast_sqrt(isolate_); |
| - set_fpu_register_double(fd_reg(), fast_sqrt(fs, isolate_)); |
| + set_fpu_register_double( |
| + fd_reg(), |
| + FPUCanonalizeOperation([](double fs) { return std::sqrt(fs); }, fs)); |
| break; |
| - case RSQRT_D: { |
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); |
| - lazily_initialize_fast_sqrt(isolate_); |
| - double result = 1.0 / fast_sqrt(fs, isolate_); |
| - set_fpu_register_double(fd_reg(), result); |
| + case RSQRT_D: |
| + set_fpu_register_double( |
| + fd_reg(), FPUCanonalizeOperation( |
| + [](double fs) { return 1.0 / std::sqrt(fs); }, fs)); |
| break; |
| - } |
| - case RECIP_D: { |
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); |
| - double result = 1.0 / fs; |
| - set_fpu_register_double(fd_reg(), result); |
| + case RECIP_D: |
| + set_fpu_register_double( |
| + fd_reg(), |
| + FPUCanonalizeOperation([](double fs) { return 1.0 / fs; }, fs)); |
| break; |
| - } |
| case C_UN_D: |
| set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft)); |
| break; |
| @@ -2890,10 +2961,16 @@ void Simulator::DecodeTypeRegisterSRsType() { |
| break; |
| } |
| case ADD_S: |
| - set_fpu_register_float(fd_reg(), fs + ft); |
| + set_fpu_register_float( |
| + fd_reg(), |
| + FPUCanonalizeOperation([](float lhs, float rhs) { return lhs + rhs; }, |
| + fs, ft)); |
| break; |
| case SUB_S: |
| - set_fpu_register_float(fd_reg(), fs - ft); |
| + set_fpu_register_float( |
| + fd_reg(), |
| + FPUCanonalizeOperation([](float lhs, float rhs) { return lhs - rhs; }, |
| + fs, ft)); |
| break; |
| case MADDF_S: |
| DCHECK(IsMipsArchVariant(kMips32r6)); |
| @@ -2904,37 +2981,45 @@ void Simulator::DecodeTypeRegisterSRsType() { |
| set_fpu_register_float(fd_reg(), fd - (fs * ft)); |
| break; |
| case MUL_S: |
| - set_fpu_register_float(fd_reg(), fs * ft); |
| + set_fpu_register_float( |
| + fd_reg(), |
| + FPUCanonalizeOperation([](float lhs, float rhs) { return lhs * rhs; }, |
| + fs, ft)); |
| break; |
| case DIV_S: |
| - set_fpu_register_float(fd_reg(), fs / ft); |
| + set_fpu_register_float( |
| + fd_reg(), |
| + FPUCanonalizeOperation([](float lhs, float rhs) { return lhs / rhs; }, |
| + fs, ft)); |
| break; |
| case ABS_S: |
| - set_fpu_register_float(fd_reg(), fabs(fs)); |
| + set_fpu_register_float( |
| + fd_reg(), |
| + FPUCanonalizeOperation([](float fs) { return FPAbs(fs); }, fs)); |
| break; |
| case MOV_S: |
| set_fpu_register_float(fd_reg(), fs); |
| break; |
| case NEG_S: |
| - set_fpu_register_float(fd_reg(), -fs); |
| + set_fpu_register_float( |
| + fd_reg(), FPUCanonalizeOperation([](float src) { return -src; }, |
| + KeepSign::yes, fs)); |
| break; |
| case SQRT_S: |
| - lazily_initialize_fast_sqrt(isolate_); |
| - set_fpu_register_float(fd_reg(), fast_sqrt(fs, isolate_)); |
| + set_fpu_register_float( |
| + fd_reg(), |
| + FPUCanonalizeOperation([](float src) { return std::sqrt(src); }, fs)); |
| break; |
| - case RSQRT_S: { |
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); |
| - lazily_initialize_fast_sqrt(isolate_); |
| - float result = 1.0 / fast_sqrt(fs, isolate_); |
| - set_fpu_register_float(fd_reg(), result); |
| + case RSQRT_S: |
| + set_fpu_register_float( |
| + fd_reg(), FPUCanonalizeOperation( |
| + [](float src) { return 1.0 / std::sqrt(src); }, fs)); |
| break; |
| - } |
| - case RECIP_S: { |
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)); |
| - float result = 1.0 / fs; |
| - set_fpu_register_float(fd_reg(), result); |
| + case RECIP_S: |
| + set_fpu_register_float( |
| + fd_reg(), |
| + FPUCanonalizeOperation([](float src) { return 1.0 / src; }, fs)); |
| break; |
| - } |
| case C_F_D: |
| set_fcsr_bit(fcsr_cc, false); |
| break; |