Commit 60d77c8a authored by ivica.bogosavljevic's avatar ivica.bogosavljevic Committed by Commit bot

MIPS: Correct handling of Nan values on MIPS R6

MIPS R6 introduced new behavior for handling of NaN values
for TRUNC, FLOOR, CEIL and CVT instructions. Adding support for
the new behavior in MIPS and MIPS64 simulators. Fixing tests
for MIPS and MIPS64 to align them with the new behavior.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#32499}
parent aa0ddf7d
......@@ -143,8 +143,11 @@ const int kInvalidFPURegister = -1;
const int kFCSRRegister = 31;
const int kInvalidFPUControlRegister = -1;
const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1 << 31) - 1;
const int32_t kFPUInvalidResultNegative = static_cast<int32_t>(1 << 31);
const uint64_t kFPU64InvalidResult =
static_cast<uint64_t>(static_cast<uint64_t>(1) << 63) - 1;
const int64_t kFPU64InvalidResultNegative =
static_cast<int64_t>(static_cast<uint64_t>(1) << 63);
// FCSR constants.
const uint32_t kFCSRInexactFlagBit = 2;
......@@ -152,12 +155,14 @@ const uint32_t kFCSRUnderflowFlagBit = 3;
const uint32_t kFCSROverflowFlagBit = 4;
const uint32_t kFCSRDivideByZeroFlagBit = 5;
const uint32_t kFCSRInvalidOpFlagBit = 6;
const uint32_t kFCSRNaN2008FlagBit = 18;
const uint32_t kFCSRInexactFlagMask = 1 << kFCSRInexactFlagBit;
const uint32_t kFCSRUnderflowFlagMask = 1 << kFCSRUnderflowFlagBit;
const uint32_t kFCSROverflowFlagMask = 1 << kFCSROverflowFlagBit;
const uint32_t kFCSRDivideByZeroFlagMask = 1 << kFCSRDivideByZeroFlagBit;
const uint32_t kFCSRInvalidOpFlagMask = 1 << kFCSRInvalidOpFlagBit;
const uint32_t kFCSRNaN2008FlagMask = 1 << kFCSRNaN2008FlagBit;
const uint32_t kFCSRFlagMask =
kFCSRInexactFlagMask |
......
......@@ -968,7 +968,12 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
for (int i = 0; i < kNumFPURegisters; i++) {
FPUregisters_[i] = 0;
}
FCSR_ = 0;
if (IsMipsArchVariant(kMips32r6)) {
FCSR_ = kFCSRNaN2008FlagMask;
} else {
DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
FCSR_ = 0;
}
// The sp is initialized to point to the bottom (high address) of the
// allocated stack area. To be safe in potential stack underflows we leave
......@@ -1296,6 +1301,125 @@ unsigned int Simulator::get_fcsr_rounding_mode() {
}
void Simulator::set_fpu_register_word_invalid_result(float original,
float rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min();
if (std::isnan(original)) {
set_fpu_register_word(fd_reg(), 0);
} else if (rounded > max_int32) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
} else if (rounded < min_int32) {
set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
}
}
void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min();
if (std::isnan(original)) {
set_fpu_register(fd_reg(), 0);
} else if (rounded > max_int32) {
set_fpu_register(fd_reg(), kFPUInvalidResult);
} else if (rounded < min_int32) {
set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register(fd_reg(), kFPUInvalidResult);
}
}
void Simulator::set_fpu_register_invalid_result64(float original,
float rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int64 = std::numeric_limits<int64_t>::max();
double min_int64 = std::numeric_limits<int64_t>::min();
if (std::isnan(original)) {
set_fpu_register(fd_reg(), 0);
} else if (rounded > max_int64) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
} else if (rounded < min_int64) {
set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
}
}
void Simulator::set_fpu_register_word_invalid_result(double original,
double rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min();
if (std::isnan(original)) {
set_fpu_register_word(fd_reg(), 0);
} else if (rounded > max_int32) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
} else if (rounded < min_int32) {
set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
}
}
void Simulator::set_fpu_register_invalid_result(double original,
double rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min();
if (std::isnan(original)) {
set_fpu_register(fd_reg(), 0);
} else if (rounded > max_int32) {
set_fpu_register(fd_reg(), kFPUInvalidResult);
} else if (rounded < min_int32) {
set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register(fd_reg(), kFPUInvalidResult);
}
}
void Simulator::set_fpu_register_invalid_result64(double original,
double rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int64 = std::numeric_limits<int64_t>::max();
double min_int64 = std::numeric_limits<int64_t>::min();
if (std::isnan(original)) {
set_fpu_register(fd_reg(), 0);
} else if (rounded > max_int64) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
} else if (rounded < min_int64) {
set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
}
}
// Sets the rounding error codes in FCSR based on the result of the rounding.
// Returns true if the operation was invalid.
bool Simulator::set_fcsr_round_error(double original, double rounded) {
......@@ -2415,7 +2539,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
round_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case ROUND_W_D: // Round double to word (round half to even).
......@@ -2429,7 +2553,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
}
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case TRUNC_W_D: // Truncate double to word (round towards 0).
......@@ -2438,7 +2562,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case FLOOR_W_D: // Round double to word towards negative infinity.
......@@ -2447,7 +2571,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case CEIL_W_D: // Round double to word towards positive infinity.
......@@ -2456,7 +2580,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case CVT_S_D: // Convert double to float (single).
......@@ -2469,7 +2593,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
round64_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
} else {
UNSUPPORTED();
......@@ -2484,7 +2608,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
if (IsFp64Mode()) {
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
} else {
UNSUPPORTED();
......@@ -2504,7 +2628,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
if (IsFp64Mode()) {
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
} else {
UNSUPPORTED();
......@@ -2518,7 +2642,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
if (IsFp64Mode()) {
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
} else {
UNSUPPORTED();
......@@ -2532,7 +2656,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
if (IsFp64Mode()) {
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
} else {
UNSUPPORTED();
......@@ -2935,7 +3059,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case TRUNC_L_S: { // Mips32r2 instruction.
......@@ -2945,7 +3069,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
if (IsFp64Mode()) {
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
} else {
UNSUPPORTED();
......@@ -2958,7 +3082,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case FLOOR_L_S: { // Mips32r2 instruction.
......@@ -2968,7 +3092,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
if (IsFp64Mode()) {
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
} else {
UNSUPPORTED();
......@@ -2985,7 +3109,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
}
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
break;
}
......@@ -3002,7 +3126,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
if (IsFp64Mode()) {
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
} else {
UNSUPPORTED();
......@@ -3015,7 +3139,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case CEIL_L_S: { // Mips32r2 instruction.
......@@ -3025,7 +3149,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
if (IsFp64Mode()) {
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
} else {
UNSUPPORTED();
......@@ -3107,7 +3231,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
round64_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
} else {
UNSUPPORTED();
......@@ -3120,7 +3244,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
round_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
break;
}
......@@ -3249,11 +3373,18 @@ void Simulator::DecodeTypeRegisterCOP1() {
case MFHC1:
set_register(rt_reg(), get_fpu_register_hi_word(fs_reg()));
break;
case CTC1:
case CTC1: {
// At the moment only FCSR is supported.
DCHECK(fs_reg() == kFCSRRegister);
FCSR_ = registers_[rt_reg()];
int32_t reg = registers_[rt_reg()];
if (IsMipsArchVariant(kMips32r6)) {
FCSR_ = reg | kFCSRNaN2008FlagMask;
} else {
DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
FCSR_ = reg & ~kFCSRNaN2008FlagMask;
}
break;
}
case MTC1:
// Hardware writes upper 32-bits to zero on mtc1.
set_fpu_register_hi_word(fs_reg(), 0);
......
......@@ -171,6 +171,12 @@ class Simulator {
void set_fpu_register_hi_word(int fpureg, int32_t value);
void set_fpu_register_float(int fpureg, float value);
void set_fpu_register_double(int fpureg, double value);
void set_fpu_register_invalid_result64(float original, float rounded);
void set_fpu_register_invalid_result(float original, float rounded);
void set_fpu_register_word_invalid_result(float original, float rounded);
void set_fpu_register_invalid_result64(double original, double rounded);
void set_fpu_register_invalid_result(double original, double rounded);
void set_fpu_register_word_invalid_result(double original, double rounded);
int64_t get_fpu_register(int fpureg) const;
int32_t get_fpu_register_word(int fpureg) const;
int32_t get_fpu_register_signed_word(int fpureg) const;
......
......@@ -119,8 +119,11 @@ const int kInvalidFPURegister = -1;
const int kFCSRRegister = 31;
const int kInvalidFPUControlRegister = -1;
const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1 << 31) - 1;
const int32_t kFPUInvalidResultNegative = static_cast<int32_t>(1 << 31);
const uint64_t kFPU64InvalidResult =
static_cast<uint64_t>(static_cast<uint64_t>(1) << 63) - 1;
const int64_t kFPU64InvalidResultNegative =
static_cast<int64_t>(static_cast<uint64_t>(1) << 63);
// FCSR constants.
const uint32_t kFCSRInexactFlagBit = 2;
......@@ -128,12 +131,14 @@ const uint32_t kFCSRUnderflowFlagBit = 3;
const uint32_t kFCSROverflowFlagBit = 4;
const uint32_t kFCSRDivideByZeroFlagBit = 5;
const uint32_t kFCSRInvalidOpFlagBit = 6;
const uint32_t kFCSRNaN2008FlagBit = 18;
const uint32_t kFCSRInexactFlagMask = 1 << kFCSRInexactFlagBit;
const uint32_t kFCSRUnderflowFlagMask = 1 << kFCSRUnderflowFlagBit;
const uint32_t kFCSROverflowFlagMask = 1 << kFCSROverflowFlagBit;
const uint32_t kFCSRDivideByZeroFlagMask = 1 << kFCSRDivideByZeroFlagBit;
const uint32_t kFCSRInvalidOpFlagMask = 1 << kFCSRInvalidOpFlagBit;
const uint32_t kFCSRNaN2008FlagMask = 1 << kFCSRNaN2008FlagBit;
const uint32_t kFCSRFlagMask =
kFCSRInexactFlagMask |
......
......@@ -898,7 +898,12 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
for (int i = 0; i < kNumFPURegisters; i++) {
FPUregisters_[i] = 0;
}
FCSR_ = 0;
if (kArchVariant == kMips64r6) {
FCSR_ = kFCSRNaN2008FlagMask;
} else {
FCSR_ = 0;
}
// The sp is initialized to point to the bottom (high address) of the
// allocated stack area. To be safe in potential stack underflows we leave
......@@ -1315,6 +1320,124 @@ bool Simulator::set_fcsr_round_error(float original, float rounded) {
return ret;
}
void Simulator::set_fpu_register_word_invalid_result(float original,
float rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min();
if (std::isnan(original)) {
set_fpu_register_word(fd_reg(), 0);
} else if (rounded > max_int32) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
} else if (rounded < min_int32) {
set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
}
}
void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min();
if (std::isnan(original)) {
set_fpu_register(fd_reg(), 0);
} else if (rounded > max_int32) {
set_fpu_register(fd_reg(), kFPUInvalidResult);
} else if (rounded < min_int32) {
set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register(fd_reg(), kFPUInvalidResult);
}
}
void Simulator::set_fpu_register_invalid_result64(float original,
float rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int64 = std::numeric_limits<int64_t>::max();
double min_int64 = std::numeric_limits<int64_t>::min();
if (std::isnan(original)) {
set_fpu_register(fd_reg(), 0);
} else if (rounded > max_int64) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
} else if (rounded < min_int64) {
set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
}
}
void Simulator::set_fpu_register_word_invalid_result(double original,
double rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min();
if (std::isnan(original)) {
set_fpu_register_word(fd_reg(), 0);
} else if (rounded > max_int32) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
} else if (rounded < min_int32) {
set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
}
}
void Simulator::set_fpu_register_invalid_result(double original,
double rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min();
if (std::isnan(original)) {
set_fpu_register(fd_reg(), 0);
} else if (rounded > max_int32) {
set_fpu_register(fd_reg(), kFPUInvalidResult);
} else if (rounded < min_int32) {
set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register(fd_reg(), kFPUInvalidResult);
}
}
void Simulator::set_fpu_register_invalid_result64(double original,
double rounded) {
if (FCSR_ & kFCSRNaN2008FlagMask) {
double max_int64 = std::numeric_limits<int64_t>::max();
double min_int64 = std::numeric_limits<int64_t>::min();
if (std::isnan(original)) {
set_fpu_register(fd_reg(), 0);
} else if (rounded > max_int64) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
} else if (rounded < min_int64) {
set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
} else {
UNREACHABLE();
}
} else {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
}
}
// Sets the rounding error codes in FCSR based on the result of the rounding.
// Returns true if the operation was invalid.
......@@ -2371,7 +2494,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
round64_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
......@@ -2381,7 +2504,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
round_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
break;
}
......@@ -2390,7 +2513,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case TRUNC_L_S: { // Mips64r2 instruction.
......@@ -2398,7 +2521,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
......@@ -2412,7 +2535,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
}
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
break;
}
......@@ -2427,7 +2550,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int64_t i64 = static_cast<int64_t>(result);
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
......@@ -2436,7 +2559,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
......@@ -2446,7 +2569,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
} break;
case CEIL_W_S: // Round double to word towards positive infinity.
......@@ -2455,7 +2578,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPUInvalidResult);
set_fpu_register_invalid_result(fs, rounded);
}
} break;
case CEIL_L_S: { // Mips64r2 instruction.
......@@ -2463,7 +2586,7 @@ void Simulator::DecodeTypeRegisterSRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
......@@ -2807,7 +2930,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
round_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register_word(fd_reg(), kFPUInvalidResult);
set_fpu_register_word_invalid_result(fs, rounded);
}
break;
}
......@@ -2822,7 +2945,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
}
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPUInvalidResult);
set_fpu_register_invalid_result(fs, rounded);
}
} break;
case TRUNC_W_D: // Truncate double to word (round towards 0).
......@@ -2831,7 +2954,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPUInvalidResult);
set_fpu_register_invalid_result(fs, rounded);
}
} break;
case FLOOR_W_D: // Round double to word towards negative infinity.
......@@ -2840,7 +2963,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPUInvalidResult);
set_fpu_register_invalid_result(fs, rounded);
}
} break;
case CEIL_W_D: // Round double to word towards positive infinity.
......@@ -2849,7 +2972,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int32_t result = static_cast<int32_t>(rounded);
set_fpu_register_word(fd_reg(), result);
if (set_fcsr_round_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPUInvalidResult);
set_fpu_register_invalid_result(fs, rounded);
}
} break;
case CVT_S_D: // Convert double to float (single).
......@@ -2861,7 +2984,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
round64_according_to_fcsr(fs, rounded, result, fs);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
......@@ -2876,7 +2999,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int64_t i64 = static_cast<int64_t>(result);
set_fpu_register(fd_reg(), i64);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
......@@ -2885,7 +3008,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
......@@ -2894,7 +3017,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
......@@ -2903,7 +3026,7 @@ void Simulator::DecodeTypeRegisterDRsType() {
int64_t result = static_cast<int64_t>(rounded);
set_fpu_register(fd_reg(), result);
if (set_fcsr_round64_error(fs, rounded)) {
set_fpu_register(fd_reg(), kFPU64InvalidResult);
set_fpu_register_invalid_result64(fs, rounded);
}
break;
}
......@@ -3188,11 +3311,18 @@ void Simulator::DecodeTypeRegisterCOP1() {
case MFHC1:
set_register(rt_reg(), get_fpu_register_hi_word(fs_reg()));
break;
case CTC1:
case CTC1: {
// At the moment only FCSR is supported.
DCHECK(fs_reg() == kFCSRRegister);
FCSR_ = static_cast<uint32_t>(rt());
uint32_t reg = static_cast<uint32_t>(rt());
if (kArchVariant == kMips64r6) {
FCSR_ = reg | kFCSRNaN2008FlagMask;
} else {
DCHECK(kArchVariant == kMips64r2);
FCSR_ = reg & ~kFCSRNaN2008FlagMask;
}
break;
}
case MTC1:
// Hardware writes upper 32-bits to zero on mtc1.
set_fpu_register_hi_word(fs_reg(), 0);
......
......@@ -202,6 +202,12 @@ class Simulator {
void set_fpu_register_hi_word(int fpureg, int32_t value);
void set_fpu_register_float(int fpureg, float value);
void set_fpu_register_double(int fpureg, double value);
void set_fpu_register_invalid_result64(float original, float rounded);
void set_fpu_register_invalid_result(float original, float rounded);
void set_fpu_register_word_invalid_result(float original, float rounded);
void set_fpu_register_invalid_result64(double original, double rounded);
void set_fpu_register_invalid_result(double original, double rounded);
void set_fpu_register_word_invalid_result(double original, double rounded);
int64_t get_fpu_register(int fpureg) const;
int32_t get_fpu_register_word(int fpureg) const;
int32_t get_fpu_register_signed_word(int fpureg) const;
......
......@@ -1204,6 +1204,7 @@ TEST(MIPS14) {
HandleScope scope(isolate);
#define ROUND_STRUCT_ELEMENT(x) \
uint32_t x##_isNaN2008; \
int32_t x##_up_out; \
int32_t x##_down_out; \
int32_t neg_##x##_up_out; \
......@@ -1241,6 +1242,8 @@ TEST(MIPS14) {
// Disable FPU exceptions.
__ ctc1(zero_reg, FCSR);
#define RUN_ROUND_TEST(x) \
__ cfc1(t0, FCSR);\
__ sw(t0, MemOperand(a0, offsetof(T, x##_isNaN2008))); \
__ ldc1(f0, MemOperand(a0, offsetof(T, round_up_in))); \
__ x##_w_d(f0, f0); \
__ swc1(f0, MemOperand(a0, offsetof(T, x##_up_out))); \
......@@ -1313,12 +1316,18 @@ TEST(MIPS14) {
USE(dummy);
#define GET_FPU_ERR(x) (static_cast<int>(x & kFCSRFlagMask))
#define CHECK_NAN2008(x) (x & kFCSRNaN2008FlagMask)
#define CHECK_ROUND_RESULT(type) \
CHECK(GET_FPU_ERR(t.type##_err1_out) & kFCSRInexactFlagMask); \
CHECK_EQ(0, GET_FPU_ERR(t.type##_err2_out)); \
CHECK(GET_FPU_ERR(t.type##_err3_out) & kFCSRInvalidOpFlagMask); \
CHECK(GET_FPU_ERR(t.type##_err4_out) & kFCSRInvalidOpFlagMask); \
CHECK_EQ(kFPUInvalidResult, static_cast<uint>(t.type##_invalid_result));
if (CHECK_NAN2008(t.type##_isNaN2008) && kArchVariant == kMips32r6) {\
CHECK_EQ(static_cast<int32_t>(0), t.type##_invalid_result);\
} else {\
CHECK_EQ(static_cast<int32_t>(kFPUInvalidResult), t.type##_invalid_result);\
}
CHECK_ROUND_RESULT(round);
CHECK_ROUND_RESULT(floor);
......@@ -1967,6 +1976,7 @@ TEST(trunc_l) {
v8::internal::CodeObjectRequired::kYes);
const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int64_t c; // a trunc result
......@@ -1992,7 +2002,15 @@ TEST(trunc_l) {
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
2147483648.0, dFPU64InvalidResult,
dFPU64InvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 2.0, 2.0, 3.0, 3.0, 3.0,
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
2147483648.0,
0,
dFPU64InvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ trunc_l_d(f8, f4);
......@@ -2011,7 +2029,12 @@ TEST(trunc_l) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) &&
kArchVariant == kMips32r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2288,6 +2311,7 @@ TEST(trunc_w) {
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int32_t c; // a trunc result
......@@ -2313,7 +2337,15 @@ TEST(trunc_w) {
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
kFPUInvalidResult, kFPUInvalidResult,
kFPUInvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 2.0, 2.0, 3.0, 3.0, 3.0,
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
kFPUInvalidResult,
0,
kFPUInvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ trunc_w_d(f8, f4);
......@@ -2332,7 +2364,11 @@ TEST(trunc_w) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) && kArchVariant == kMips32r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2345,6 +2381,7 @@ TEST(round_w) {
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int32_t c; // a trunc result
......@@ -2370,7 +2407,14 @@ TEST(round_w) {
-2.0, -3.0, -2.0, -3.0, -4.0, -4.0,
kFPUInvalidResult, kFPUInvalidResult,
kFPUInvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 3.0, 2.0, 3.0, 4.0, 4.0,
-2.0, -3.0, -2.0, -3.0, -4.0, -4.0,
kFPUInvalidResult, 0,
kFPUInvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ round_w_d(f8, f4);
......@@ -2389,7 +2433,11 @@ TEST(round_w) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) && kArchVariant == kMips32r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2404,6 +2452,7 @@ TEST(round_l) {
v8::internal::CodeObjectRequired::kYes);
const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int64_t c;
......@@ -2429,7 +2478,15 @@ TEST(round_l) {
-2.0, -3.0, -2.0, -3.0, -4.0, -4.0,
2147483648.0, dFPU64InvalidResult,
dFPU64InvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 3.0, 2.0, 3.0, 4.0, 4.0,
-2.0, -3.0, -2.0, -3.0, -4.0, -4.0,
2147483648.0,
0,
dFPU64InvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ round_l_d(f8, f4);
......@@ -2448,7 +2505,12 @@ TEST(round_l) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) &&
kArchVariant == kMips32r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2802,6 +2864,7 @@ TEST(floor_w) {
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int32_t c; // a floor result
......@@ -2827,7 +2890,15 @@ TEST(floor_w) {
-3.0, -3.0, -3.0, -4.0, -4.0, -4.0,
kFPUInvalidResult, kFPUInvalidResult,
kFPUInvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 2.0, 2.0, 3.0, 3.0, 3.0,
-3.0, -3.0, -3.0, -4.0, -4.0, -4.0,
kFPUInvalidResult,
0,
kFPUInvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ floor_w_d(f8, f4);
......@@ -2846,7 +2917,11 @@ TEST(floor_w) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) && kArchVariant == kMips32r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2861,6 +2936,7 @@ TEST(floor_l) {
v8::internal::CodeObjectRequired::kYes);
const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int64_t c;
......@@ -2886,7 +2962,15 @@ TEST(floor_l) {
-3.0, -3.0, -3.0, -4.0, -4.0, -4.0,
2147483648.0, dFPU64InvalidResult,
dFPU64InvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 2.0, 2.0, 3.0, 3.0, 3.0,
-3.0, -3.0, -3.0, -4.0, -4.0, -4.0,
2147483648.0,
0,
dFPU64InvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ floor_l_d(f8, f4);
......@@ -2905,7 +2989,12 @@ TEST(floor_l) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) &&
kArchVariant == kMips32r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2919,6 +3008,7 @@ TEST(ceil_w) {
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int32_t c; // a floor result
......@@ -2944,7 +3034,15 @@ TEST(ceil_w) {
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
kFPUInvalidResult, kFPUInvalidResult,
kFPUInvalidResult};
double outputsNaN2008[kTableLength] = {
3.0, 3.0, 3.0, 4.0, 4.0, 4.0,
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
kFPUInvalidResult,
0,
kFPUInvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ ceil_w_d(f8, f4);
......@@ -2963,7 +3061,11 @@ TEST(ceil_w) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) && kArchVariant == kMips32r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2978,6 +3080,7 @@ TEST(ceil_l) {
v8::internal::CodeObjectRequired::kYes);
const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int64_t c;
......@@ -3003,7 +3106,15 @@ TEST(ceil_l) {
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
2147483648.0, dFPU64InvalidResult,
dFPU64InvalidResult};
double outputsNaN2008[kTableLength] = {
3.0, 3.0, 3.0, 4.0, 4.0, 4.0,
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
2147483648.0,
0,
dFPU64InvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ ceil_l_d(f8, f4);
......@@ -3022,7 +3133,12 @@ TEST(ceil_l) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) &&
kArchVariant == kMips32r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......
......@@ -1234,6 +1234,7 @@ TEST(MIPS14) {
HandleScope scope(isolate);
#define ROUND_STRUCT_ELEMENT(x) \
uint32_t x##_isNaN2008; \
int32_t x##_up_out; \
int32_t x##_down_out; \
int32_t neg_##x##_up_out; \
......@@ -1271,6 +1272,8 @@ TEST(MIPS14) {
// Disable FPU exceptions.
__ ctc1(zero_reg, FCSR);
#define RUN_ROUND_TEST(x) \
__ cfc1(t0, FCSR);\
__ sw(t0, MemOperand(a0, offsetof(T, x##_isNaN2008))); \
__ ldc1(f0, MemOperand(a0, offsetof(T, round_up_in))); \
__ x##_w_d(f0, f0); \
__ swc1(f0, MemOperand(a0, offsetof(T, x##_up_out))); \
......@@ -1343,12 +1346,17 @@ TEST(MIPS14) {
USE(dummy);
#define GET_FPU_ERR(x) (static_cast<int>(x & kFCSRFlagMask))
#define CHECK_NAN2008(x) (x & kFCSRNaN2008FlagMask)
#define CHECK_ROUND_RESULT(type) \
CHECK(GET_FPU_ERR(t.type##_err1_out) & kFCSRInexactFlagMask); \
CHECK_EQ(0, GET_FPU_ERR(t.type##_err2_out)); \
CHECK(GET_FPU_ERR(t.type##_err3_out) & kFCSRInvalidOpFlagMask); \
CHECK(GET_FPU_ERR(t.type##_err4_out) & kFCSRInvalidOpFlagMask); \
CHECK_EQ(static_cast<int32_t>(kFPUInvalidResult), t.type##_invalid_result);
if (CHECK_NAN2008(t.type##_isNaN2008) && kArchVariant == kMips64r6) { \
CHECK_EQ(static_cast<int32_t>(0), t.type##_invalid_result);\
} else { \
CHECK_EQ(static_cast<int32_t>(kFPUInvalidResult), t.type##_invalid_result);\
}
CHECK_ROUND_RESULT(round);
CHECK_ROUND_RESULT(floor);
......@@ -2051,6 +2059,7 @@ TEST(trunc_l) {
v8::internal::CodeObjectRequired::kYes);
const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int64_t c; // a trunc result
......@@ -2076,7 +2085,14 @@ TEST(trunc_l) {
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
2147483648.0, dFPU64InvalidResult,
dFPU64InvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 2.0, 2.0, 3.0, 3.0, 3.0,
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
2147483648.0, dFPU64InvalidResult,
dFPU64InvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ trunc_l_d(f8, f4);
......@@ -2095,7 +2111,12 @@ TEST(trunc_l) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) &&
kArchVariant == kMips64r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2372,6 +2393,7 @@ TEST(trunc_w) {
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int32_t c; // a trunc result
......@@ -2397,7 +2419,15 @@ TEST(trunc_w) {
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
kFPUInvalidResult, kFPUInvalidResult,
kFPUInvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 2.0, 2.0, 3.0, 3.0, 3.0,
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
kFPUInvalidResult,
0,
kFPUInvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ trunc_w_d(f8, f4);
......@@ -2416,7 +2446,11 @@ TEST(trunc_w) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) && kArchVariant == kMips64r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2429,6 +2463,7 @@ TEST(round_w) {
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int32_t c; // a trunc result
......@@ -2454,7 +2489,14 @@ TEST(round_w) {
-2.0, -3.0, -2.0, -3.0, -4.0, -4.0,
kFPUInvalidResult, kFPUInvalidResult,
kFPUInvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 3.0, 2.0, 3.0, 4.0, 4.0,
-2.0, -3.0, -2.0, -3.0, -4.0, -4.0,
kFPUInvalidResult, 0,
kFPUInvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ round_w_d(f8, f4);
......@@ -2473,7 +2515,11 @@ TEST(round_w) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) && kArchVariant == kMips64r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2487,6 +2533,7 @@ TEST(round_l) {
v8::internal::CodeObjectRequired::kYes);
const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int64_t c;
......@@ -2512,7 +2559,15 @@ TEST(round_l) {
-2.0, -3.0, -2.0, -3.0, -4.0, -4.0,
2147483648.0, dFPU64InvalidResult,
dFPU64InvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 3.0, 2.0, 3.0, 4.0, 4.0,
-2.0, -3.0, -2.0, -3.0, -4.0, -4.0,
2147483648.0,
0,
dFPU64InvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ round_l_d(f8, f4);
......@@ -2530,9 +2585,13 @@ TEST(round_l) {
for (int i = 0; i < kTableLength; i++) {
test.a = inputs_D[i];
test.b = inputs_S[i];
std::cout<< i<< "\n";
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) &&
kArchVariant == kMips64r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2877,6 +2936,7 @@ TEST(floor_w) {
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int32_t c; // a floor result
......@@ -2902,7 +2962,15 @@ TEST(floor_w) {
-3.0, -3.0, -3.0, -4.0, -4.0, -4.0,
kFPUInvalidResult, kFPUInvalidResult,
kFPUInvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 2.0, 2.0, 3.0, 3.0, 3.0,
-3.0, -3.0, -3.0, -4.0, -4.0, -4.0,
kFPUInvalidResult,
0,
kFPUInvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ floor_w_d(f8, f4);
......@@ -2921,7 +2989,11 @@ TEST(floor_w) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) && kArchVariant == kMips64r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2935,6 +3007,7 @@ TEST(floor_l) {
v8::internal::CodeObjectRequired::kYes);
const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int64_t c;
......@@ -2960,7 +3033,15 @@ TEST(floor_l) {
-3.0, -3.0, -3.0, -4.0, -4.0, -4.0,
2147483648.0, dFPU64InvalidResult,
dFPU64InvalidResult};
double outputsNaN2008[kTableLength] = {
2.0, 2.0, 2.0, 3.0, 3.0, 3.0,
-3.0, -3.0, -3.0, -4.0, -4.0, -4.0,
2147483648.0,
0,
dFPU64InvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ floor_l_d(f8, f4);
......@@ -2979,7 +3060,12 @@ TEST(floor_l) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) &&
kArchVariant == kMips64r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -2992,6 +3078,7 @@ TEST(ceil_w) {
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int32_t c; // a floor result
......@@ -3017,7 +3104,15 @@ TEST(ceil_w) {
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
kFPUInvalidResult, kFPUInvalidResult,
kFPUInvalidResult};
double outputsNaN2008[kTableLength] = {
3.0, 3.0, 3.0, 4.0, 4.0, 4.0,
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
kFPUInvalidResult,
0,
kFPUInvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ ceil_w_d(f8, f4);
......@@ -3036,7 +3131,11 @@ TEST(ceil_w) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) && kArchVariant == kMips64r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......@@ -3050,6 +3149,7 @@ TEST(ceil_l) {
v8::internal::CodeObjectRequired::kYes);
const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult);
typedef struct test_float {
uint32_t isNaN2008;
double a;
float b;
int64_t c;
......@@ -3075,7 +3175,15 @@ TEST(ceil_l) {
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
2147483648.0, dFPU64InvalidResult,
dFPU64InvalidResult};
double outputsNaN2008[kTableLength] = {
3.0, 3.0, 3.0, 4.0, 4.0, 4.0,
-2.0, -2.0, -2.0, -3.0, -3.0, -3.0,
2147483648.0,
0,
dFPU64InvalidResult};
__ cfc1(t1, FCSR);
__ sw(t1, MemOperand(a0, offsetof(Test, isNaN2008)));
__ ldc1(f4, MemOperand(a0, offsetof(Test, a)) );
__ lwc1(f6, MemOperand(a0, offsetof(Test, b)) );
__ ceil_l_d(f8, f4);
......@@ -3094,7 +3202,12 @@ TEST(ceil_l) {
test.a = inputs_D[i];
test.b = inputs_S[i];
(CALL_GENERATED_CODE(isolate, f, &test, 0, 0, 0, 0));
CHECK_EQ(test.c, outputs[i]);
if ((test.isNaN2008 & kFCSRNaN2008FlagMask) &&
kArchVariant == kMips64r6) {
CHECK_EQ(test.c, outputsNaN2008[i]);
} else {
CHECK_EQ(test.c, outputs[i]);
}
CHECK_EQ(test.d, test.c);
}
}
......
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