зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1455019 : [MIPS64] Add error detection for int64 <-> fp conversion in simulator; r=bbouvier
--HG-- extra : rebase_source : 2ee6f92b3ff3ce803d746f8cd9747c1ee41a2e06
This commit is contained in:
Родитель
d7aa10c574
Коммит
e5d8449944
|
@ -36,6 +36,7 @@
|
|||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include <float.h>
|
||||
#include <limits>
|
||||
|
||||
#include "jit/AtomicOperations.h"
|
||||
#include "jit/mips64/Assembler-mips64.h"
|
||||
|
@ -1557,6 +1558,7 @@ Simulator::testFCSRBit(uint32_t cc)
|
|||
|
||||
// Sets the rounding error codes in FCSR based on the result of the rounding.
|
||||
// Returns true if the operation was invalid.
|
||||
template <typename T>
|
||||
bool
|
||||
Simulator::setFCSRRoundError(double original, double rounded)
|
||||
{
|
||||
|
@ -1584,7 +1586,9 @@ Simulator::setFCSRRoundError(double original, double rounded)
|
|||
ret = true;
|
||||
}
|
||||
|
||||
if (rounded > INT_MAX || rounded < INT_MIN) {
|
||||
if ((long double)rounded > (long double)std::numeric_limits<T>::max() ||
|
||||
(long double)rounded < (long double)std::numeric_limits<T>::min())
|
||||
{
|
||||
setFCSRBit(kFCSROverflowFlagBit, true);
|
||||
setFCSRBit(kFCSROverflowCauseBit, true);
|
||||
// The reference is not really clear but it seems this is required:
|
||||
|
@ -2730,7 +2734,7 @@ Simulator::configureTypeRegister(SimInstruction* instr,
|
|||
alu_out = ~(rs | rt);
|
||||
break;
|
||||
case ff_slt:
|
||||
alu_out = I32_CHECK(rs) < I32_CHECK(rt) ? 1 : 0;
|
||||
alu_out = I64(rs) < I64(rt) ? 1 : 0;
|
||||
break;
|
||||
case ff_sltu:
|
||||
alu_out = U64(rs) < U64(rt) ? 1 : 0;
|
||||
|
@ -2774,7 +2778,7 @@ Simulator::configureTypeRegister(SimInstruction* instr,
|
|||
}
|
||||
break;
|
||||
case ff_ddiv:
|
||||
if (I32_CHECK(rs) == INT_MIN && I32_CHECK(rt) == -1) {
|
||||
if (I64(rs) == INT64_MIN && I64(rt) == -1) {
|
||||
i128hilo = U64(INT64_MIN);
|
||||
} else {
|
||||
uint64_t div = rs / rt;
|
||||
|
@ -3086,65 +3090,72 @@ Simulator::decodeTypeRegister(SimInstruction* instr)
|
|||
result--;
|
||||
}
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(fs_value, rounded)) {
|
||||
if (setFCSRRoundError<int32_t>(fs_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ff_trunc_w_fmt: { // Truncate float to word (round towards 0).
|
||||
float rounded = truncf(fs_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(fs_value, rounded)) {
|
||||
if (setFCSRRoundError<int32_t>(fs_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ff_floor_w_fmt: { // Round float to word towards negative infinity.
|
||||
float rounded = std::floor(fs_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(fs_value, rounded)) {
|
||||
if (setFCSRRoundError<int32_t>(fs_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ff_ceil_w_fmt: { // Round double to word towards positive infinity.
|
||||
float rounded = std::ceil(fs_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(fs_value, rounded)) {
|
||||
if (setFCSRRoundError<int32_t>(fs_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ff_cvt_l_fmt: { // Mips64r2: Truncate float to 64-bit long-word.
|
||||
float rounded = truncf(fs_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
break;
|
||||
}
|
||||
case ff_cvt_l_fmt: // Mips64r2: Truncate float to 64-bit long-word.
|
||||
// Rounding modes are not yet supported.
|
||||
MOZ_ASSERT((FCSR_ & 3) == 0);
|
||||
// In rounding mode 0 it should behave like ROUND.
|
||||
MOZ_FALLTHROUGH;
|
||||
case ff_round_l_fmt: { // Mips64r2 instruction.
|
||||
float rounded =
|
||||
fs_value > 0 ? std::floor(fs_value + 0.5) : std::ceil(fs_value - 0.5);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(fs_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_trunc_l_fmt: { // Mips64r2 instruction.
|
||||
float rounded = truncf(fs_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(fs_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_floor_l_fmt: // Mips64r2 instruction.
|
||||
i64 = I64(std::floor(fs_value));
|
||||
case ff_floor_l_fmt: { // Mips64r2 instruction.
|
||||
float rounded = std::floor(fs_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(fs_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
case ff_ceil_l_fmt: // Mips64r2 instruction.
|
||||
i64 = I64(std::ceil(fs_value));
|
||||
}
|
||||
case ff_ceil_l_fmt: { // Mips64r2 instruction.
|
||||
float rounded = std::ceil(fs_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(fs_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_cvt_ps_s:
|
||||
case ff_c_f_fmt:
|
||||
MOZ_CRASH();
|
||||
|
@ -3237,7 +3248,7 @@ Simulator::decodeTypeRegister(SimInstruction* instr)
|
|||
result--;
|
||||
}
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(ds_value, rounded))
|
||||
if (setFCSRRoundError<int32_t>(ds_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
break;
|
||||
}
|
||||
|
@ -3245,7 +3256,7 @@ Simulator::decodeTypeRegister(SimInstruction* instr)
|
|||
double rounded = trunc(ds_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(ds_value, rounded))
|
||||
if (setFCSRRoundError<int32_t>(ds_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
break;
|
||||
}
|
||||
|
@ -3253,7 +3264,7 @@ Simulator::decodeTypeRegister(SimInstruction* instr)
|
|||
double rounded = std::floor(ds_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(ds_value, rounded))
|
||||
if (setFCSRRoundError<int32_t>(ds_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
break;
|
||||
}
|
||||
|
@ -3261,40 +3272,51 @@ Simulator::decodeTypeRegister(SimInstruction* instr)
|
|||
double rounded = std::ceil(ds_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(ds_value, rounded))
|
||||
if (setFCSRRoundError<int32_t>(ds_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
break;
|
||||
}
|
||||
case ff_cvt_s_fmt: // Convert double to float (single).
|
||||
setFpuRegisterFloat(fd_reg, static_cast<float>(ds_value));
|
||||
break;
|
||||
case ff_cvt_l_fmt: { // Mips64r2: Truncate double to 64-bit long-word.
|
||||
double rounded = trunc(ds_value);
|
||||
case ff_cvt_l_fmt: // Mips64r2: Truncate double to 64-bit long-word.
|
||||
// Rounding modes are not yet supported.
|
||||
MOZ_ASSERT((FCSR_ & 3) == 0);
|
||||
// In rounding mode 0 it should behave like ROUND.
|
||||
MOZ_FALLTHROUGH;
|
||||
case ff_round_l_fmt: { // Mips64r2 instruction.
|
||||
double rounded =
|
||||
ds_value > 0 ? std::floor(ds_value + 0.5) : std::ceil(ds_value - 0.5);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(ds_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_trunc_l_fmt: { // Mips64r2 instruction.
|
||||
double rounded = trunc(ds_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(ds_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_round_l_fmt: { // Mips64r2 instruction.
|
||||
double rounded =
|
||||
ds_value > 0 ? std::floor(ds_value + 0.5) : std::ceil(ds_value - 0.5);
|
||||
case ff_floor_l_fmt: { // Mips64r2 instruction.
|
||||
double rounded = std::floor(ds_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(ds_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_floor_l_fmt: // Mips64r2 instruction.
|
||||
i64 = I64(std::floor(ds_value));
|
||||
setFpuRegister(fd_reg, i64);
|
||||
break;
|
||||
case ff_ceil_l_fmt: // Mips64r2 instruction.
|
||||
i64 = I64(std::ceil(ds_value));
|
||||
case ff_ceil_l_fmt: { // Mips64r2 instruction.
|
||||
double rounded = std::ceil(ds_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(ds_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_c_f_fmt:
|
||||
MOZ_CRASH();
|
||||
break;
|
||||
|
|
|
@ -75,6 +75,7 @@ const int kNumFPURegisters = 32;
|
|||
const int kFCSRRegister = 31;
|
||||
const int kInvalidFPUControlRegister = -1;
|
||||
const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1 << 31) - 1;
|
||||
const uint64_t kFPUInvalidResult64 = static_cast<uint64_t>(1ULL << 63) - 1;
|
||||
|
||||
// FCSR constants.
|
||||
const uint32_t kFCSRInexactFlagBit = 2;
|
||||
|
@ -197,6 +198,7 @@ class Simulator {
|
|||
double getFpuRegisterDouble(int fpureg) const;
|
||||
void setFCSRBit(uint32_t cc, bool value);
|
||||
bool testFCSRBit(uint32_t cc);
|
||||
template <typename T>
|
||||
bool setFCSRRoundError(double original, double rounded);
|
||||
|
||||
// Special case of set_register and get_register to access the raw PC value.
|
||||
|
|
Загрузка…
Ссылка в новой задаче