Index: src/mips/simulator-mips.cc |
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc |
index 74b81e72a0a06b728650f81ccf58863a164b4f89..938982ba2a5456f1b73aed03f0b9be9c6060f6a1 100644 |
--- a/src/mips/simulator-mips.cc |
+++ b/src/mips/simulator-mips.cc |
@@ -1159,15 +1159,30 @@ bool Simulator::test_fcsr_bit(uint32_t cc) { |
// 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) { |
- if (!isfinite(original) || |
- rounded > LONG_MAX || |
- rounded < LONG_MIN) { |
- set_fcsr_bit(6, true); // Invalid operation. |
- return true; |
- } else if (original != static_cast<double>(rounded)) { |
- set_fcsr_bit(2, true); // Inexact. |
+ bool ret = false; |
+ |
+ if (!isfinite(original) || !isfinite(rounded)) { |
+ set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
+ ret = true; |
} |
- return false; |
+ |
+ if (original != rounded) { |
+ set_fcsr_bit(kFCSRInexactFlagBit, true); |
+ } |
+ |
+ if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) { |
+ set_fcsr_bit(kFCSRUnderflowFlagBit, true); |
+ ret = true; |
+ } |
+ |
+ if (rounded > INT_MAX || rounded < INT_MIN) { |
+ set_fcsr_bit(kFCSROverflowFlagBit, true); |
+ // The reference is not really clear but it seems this is required: |
+ set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
+ ret = true; |
+ } |
+ |
+ return ret; |
} |
@@ -2054,9 +2069,10 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
break; |
case TRUNC_W_D: // Truncate double to word (round towards 0). |
{ |
- int32_t result = static_cast<int32_t>(fs); |
+ double rounded = trunc(fs); |
+ int32_t result = static_cast<int32_t>(rounded); |
set_fpu_register(fd_reg, result); |
- if (set_fcsr_round_error(fs, static_cast<double>(result))) { |
+ if (set_fcsr_round_error(fs, rounded)) { |
set_fpu_register(fd_reg, kFPUInvalidResult); |
} |
} |
@@ -2084,16 +2100,20 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { |
case CVT_S_D: // Convert double to float (single). |
set_fpu_register_float(fd_reg, static_cast<float>(fs)); |
break; |
- case CVT_L_D: // Mips32r2: Truncate double to 64-bit long-word. |
- i64 = static_cast<int64_t>(fs); |
+ case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word. |
+ double rounded = trunc(fs); |
+ i64 = static_cast<int64_t>(rounded); |
set_fpu_register(fd_reg, i64 & 0xffffffff); |
set_fpu_register(fd_reg + 1, i64 >> 32); |
break; |
- case TRUNC_L_D: // Mips32r2 instruction. |
- i64 = static_cast<int64_t>(fs); |
+ } |
+ case TRUNC_L_D: { // Mips32r2 instruction. |
+ double rounded = trunc(fs); |
+ i64 = static_cast<int64_t>(rounded); |
set_fpu_register(fd_reg, i64 & 0xffffffff); |
set_fpu_register(fd_reg + 1, i64 >> 32); |
break; |
+ } |
case ROUND_L_D: { // Mips32r2 instruction. |
double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5); |
i64 = static_cast<int64_t>(rounded); |