| Index: src/mips64/simulator-mips64.cc
|
| diff --git a/src/mips64/simulator-mips64.cc b/src/mips64/simulator-mips64.cc
|
| index ed0ef3a26c89a26d4a5491f7fdb1e6e068f0d88e..29fccd0b5974b8d5b81f2002f0d4fd6656d65866 100644
|
| --- a/src/mips64/simulator-mips64.cc
|
| +++ b/src/mips64/simulator-mips64.cc
|
| @@ -1188,16 +1188,6 @@ bool Simulator::test_fcsr_bit(uint32_t cc) {
|
| }
|
|
|
|
|
| -void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
|
| - FCSR_ |= mode & kFPURoundingModeMask;
|
| -}
|
| -
|
| -
|
| -unsigned int Simulator::get_fcsr_rounding_mode() {
|
| - return FCSR_ & kFPURoundingModeMask;
|
| -}
|
| -
|
| -
|
| // 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) {
|
| @@ -1219,7 +1209,7 @@ bool Simulator::set_fcsr_round_error(double original, double rounded) {
|
| ret = true;
|
| }
|
|
|
| - if (rounded >= max_int32 || rounded <= min_int32) {
|
| + if (rounded > max_int32 || rounded < min_int32) {
|
| set_fcsr_bit(kFCSROverflowFlagBit, true);
|
| // The reference is not really clear but it seems this is required:
|
| set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
|
| @@ -1251,69 +1241,7 @@ bool Simulator::set_fcsr_round64_error(double original, double rounded) {
|
| ret = true;
|
| }
|
|
|
| - if (rounded >= max_int64 || rounded <= min_int64) {
|
| - 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;
|
| -}
|
| -
|
| -
|
| -bool Simulator::set_fcsr_round_error(float original, float rounded) {
|
| - bool ret = false;
|
| - double max_int32 = std::numeric_limits<int32_t>::max();
|
| - double min_int32 = std::numeric_limits<int32_t>::min();
|
| -
|
| - if (!std::isfinite(original) || !std::isfinite(rounded)) {
|
| - set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
|
| - ret = true;
|
| - }
|
| -
|
| - if (original != rounded) {
|
| - set_fcsr_bit(kFCSRInexactFlagBit, true);
|
| - }
|
| -
|
| - if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
|
| - set_fcsr_bit(kFCSRUnderflowFlagBit, true);
|
| - ret = true;
|
| - }
|
| -
|
| - if (rounded >= max_int32 || rounded <= min_int32) {
|
| - 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;
|
| -}
|
| -
|
| -
|
| -// 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_round64_error(float original, float rounded) {
|
| - bool ret = false;
|
| - double max_int64 = std::numeric_limits<int64_t>::max();
|
| - double min_int64 = std::numeric_limits<int64_t>::min();
|
| -
|
| - if (!std::isfinite(original) || !std::isfinite(rounded)) {
|
| - set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
|
| - ret = true;
|
| - }
|
| -
|
| - if (original != rounded) {
|
| - set_fcsr_bit(kFCSRInexactFlagBit, true);
|
| - }
|
| -
|
| - if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
|
| - set_fcsr_bit(kFCSRUnderflowFlagBit, true);
|
| - ret = true;
|
| - }
|
| -
|
| - if (rounded >= max_int64 || rounded <= min_int64) {
|
| + if (rounded > max_int64 || rounded < min_int64) {
|
| set_fcsr_bit(kFCSROverflowFlagBit, true);
|
| // The reference is not really clear but it seems this is required:
|
| set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
|
| @@ -2428,88 +2356,37 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
|
| const int32_t& fs_reg,
|
| const int32_t& ft_reg,
|
| const int32_t& fd_reg) {
|
| - float fs, ft, fd;
|
| + float fs, ft;
|
| fs = get_fpu_register_float(fs_reg);
|
| ft = get_fpu_register_float(ft_reg);
|
| - fd = get_fpu_register_float(fd_reg);
|
| - int32_t ft_int = bit_cast<int32_t>(ft);
|
| - int32_t fd_int = bit_cast<int32_t>(fd);
|
| uint32_t cc, fcsr_cc;
|
| cc = instr->FCccValue();
|
| fcsr_cc = get_fcsr_condition_bit(cc);
|
| switch (instr->FunctionFieldRaw()) {
|
| - case RINT: {
|
| - DCHECK(kArchVariant == kMips64r6);
|
| - float result, temp_result;
|
| - double temp;
|
| - float upper = std::ceil(fs);
|
| - float lower = std::floor(fs);
|
| - switch (get_fcsr_rounding_mode()) {
|
| - case kRoundToNearest:
|
| - if (upper - fs < fs - lower) {
|
| - result = upper;
|
| - } else if (upper - fs > fs - lower) {
|
| - result = lower;
|
| - } else {
|
| - temp_result = upper / 2;
|
| - float reminder = modf(temp_result, &temp);
|
| - if (reminder == 0) {
|
| - result = upper;
|
| - } else {
|
| - result = lower;
|
| - }
|
| - }
|
| - break;
|
| - case kRoundToZero:
|
| - result = (fs > 0 ? lower : upper);
|
| - break;
|
| - case kRoundToPlusInf:
|
| - result = upper;
|
| - break;
|
| - case kRoundToMinusInf:
|
| - result = lower;
|
| - break;
|
| - }
|
| - set_fpu_register_float(fd_reg, result);
|
| - if (result != fs) {
|
| - set_fcsr_bit(kFCSRInexactFlagBit, true);
|
| - }
|
| - break;
|
| - }
|
| - case ADD_S:
|
| + case ADD_D:
|
| set_fpu_register_float(fd_reg, fs + ft);
|
| break;
|
| - case SUB_S:
|
| + case SUB_D:
|
| set_fpu_register_float(fd_reg, fs - ft);
|
| break;
|
| - case MUL_S:
|
| + case MUL_D:
|
| set_fpu_register_float(fd_reg, fs * ft);
|
| break;
|
| - case DIV_S:
|
| + case DIV_D:
|
| set_fpu_register_float(fd_reg, fs / ft);
|
| break;
|
| - case ABS_S:
|
| + case ABS_D:
|
| set_fpu_register_float(fd_reg, fabs(fs));
|
| break;
|
| - case MOV_S:
|
| + case MOV_D:
|
| set_fpu_register_float(fd_reg, fs);
|
| break;
|
| - case NEG_S:
|
| + case NEG_D:
|
| set_fpu_register_float(fd_reg, -fs);
|
| break;
|
| - case SQRT_S:
|
| + case SQRT_D:
|
| set_fpu_register_float(fd_reg, fast_sqrt(fs));
|
| break;
|
| - case RSQRT_S: {
|
| - float result = 1.0 / fast_sqrt(fs);
|
| - set_fpu_register_float(fd_reg, result);
|
| - break;
|
| - }
|
| - case RECIP_S: {
|
| - float result = 1.0 / fs;
|
| - set_fpu_register_float(fd_reg, result);
|
| - break;
|
| - }
|
| case C_UN_D:
|
| set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
|
| break;
|
| @@ -2534,202 +2411,6 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
|
| case CVT_D_S:
|
| set_fpu_register_double(fd_reg, static_cast<double>(fs));
|
| break;
|
| - case TRUNC_W_S: { // Truncate single to word (round towards 0).
|
| - float rounded = trunc(fs);
|
| - 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);
|
| - }
|
| - } break;
|
| - case TRUNC_L_S: { // Mips64r2 instruction.
|
| - float rounded = trunc(fs);
|
| - 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);
|
| - }
|
| - break;
|
| - }
|
| - case ROUND_W_S: {
|
| - float rounded = std::floor(fs + 0.5);
|
| - int32_t result = static_cast<int32_t>(rounded);
|
| - if ((result & 1) != 0 && result - fs == 0.5) {
|
| - // If the number is halfway between two integers,
|
| - // round to the even one.
|
| - result--;
|
| - }
|
| - set_fpu_register_word(fd_reg, result);
|
| - if (set_fcsr_round_error(fs, rounded)) {
|
| - set_fpu_register_word(fd_reg, kFPUInvalidResult);
|
| - }
|
| - break;
|
| - }
|
| - case ROUND_L_S: { // Mips64r2 instruction.
|
| - float rounded = std::floor(fs + 0.5);
|
| - int64_t result = static_cast<int64_t>(rounded);
|
| - if ((result & 1) != 0 && result - fs == 0.5) {
|
| - // If the number is halfway between two integers,
|
| - // round to the even one.
|
| - result--;
|
| - }
|
| - 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);
|
| - }
|
| - break;
|
| - }
|
| - case FLOOR_L_S: { // Mips64r2 instruction.
|
| - float rounded = floor(fs);
|
| - 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);
|
| - }
|
| - break;
|
| - }
|
| - case FLOOR_W_S: // Round double to word towards negative infinity.
|
| - {
|
| - float rounded = std::floor(fs);
|
| - 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);
|
| - }
|
| - } break;
|
| - case CEIL_W_S: // Round double to word towards positive infinity.
|
| - {
|
| - float rounded = std::ceil(fs);
|
| - 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);
|
| - }
|
| - } break;
|
| - case CEIL_L_S: { // Mips64r2 instruction.
|
| - float rounded = ceil(fs);
|
| - 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);
|
| - }
|
| - break;
|
| - }
|
| - case MINA:
|
| - DCHECK(kArchVariant == kMips64r6);
|
| - fs = get_fpu_register_float(fs_reg);
|
| - if (std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, fs);
|
| - } else if (std::isnan(fs) && !std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, ft);
|
| - } else if (!std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, fs);
|
| - } else {
|
| - float result;
|
| - if (fabs(fs) > fabs(ft)) {
|
| - result = ft;
|
| - } else if (fabs(fs) < fabs(ft)) {
|
| - result = fs;
|
| - } else {
|
| - result = (fs > ft ? fs : ft);
|
| - }
|
| - set_fpu_register_float(fd_reg, result);
|
| - }
|
| - break;
|
| - case MAXA:
|
| - DCHECK(kArchVariant == kMips64r6);
|
| - fs = get_fpu_register_float(fs_reg);
|
| - if (std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, fs);
|
| - } else if (std::isnan(fs) && !std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, ft);
|
| - } else if (!std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, fs);
|
| - } else {
|
| - float result;
|
| - if (fabs(fs) < fabs(ft)) {
|
| - result = ft;
|
| - } else if (fabs(fs) > fabs(ft)) {
|
| - result = fs;
|
| - } else {
|
| - result = (fs > ft ? fs : ft);
|
| - }
|
| - set_fpu_register_float(fd_reg, result);
|
| - }
|
| - break;
|
| - case MIN:
|
| - DCHECK(kArchVariant == kMips64r6);
|
| - fs = get_fpu_register_float(fs_reg);
|
| - if (std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, fs);
|
| - } else if (std::isnan(fs) && !std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, ft);
|
| - } else if (!std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, fs);
|
| - } else {
|
| - set_fpu_register_float(fd_reg, (fs >= ft) ? ft : fs);
|
| - }
|
| - break;
|
| - case MAX:
|
| - DCHECK(kArchVariant == kMips64r6);
|
| - fs = get_fpu_register_float(fs_reg);
|
| - if (std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, fs);
|
| - } else if (std::isnan(fs) && !std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, ft);
|
| - } else if (!std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_float(fd_reg, fs);
|
| - } else {
|
| - set_fpu_register_float(fd_reg, (fs <= ft) ? ft : fs);
|
| - }
|
| - break;
|
| - case SEL:
|
| - DCHECK(kArchVariant == kMips64r6);
|
| - set_fpu_register_float(fd_reg, (fd_int & 0x1) == 0 ? fs : ft);
|
| - break;
|
| - case SELEQZ_C:
|
| - DCHECK(kArchVariant == kMips64r6);
|
| - set_fpu_register_float(
|
| - fd_reg, (ft_int & 0x1) == 0 ? get_fpu_register_float(fs_reg) : 0.0);
|
| - break;
|
| - case SELNEZ_C:
|
| - DCHECK(kArchVariant == kMips64r6);
|
| - set_fpu_register_float(
|
| - fd_reg, (ft_int & 0x1) != 0 ? get_fpu_register_float(fs_reg) : 0.0);
|
| - break;
|
| - case MOVZ_C: {
|
| - DCHECK(kArchVariant == kMips64r2);
|
| - int32_t rt_reg = instr->RtValue();
|
| - int64_t rt = get_register(rt_reg);
|
| - if (rt == 0) {
|
| - set_fpu_register_float(fd_reg, fs);
|
| - }
|
| - break;
|
| - }
|
| - case MOVN_C: {
|
| - DCHECK(kArchVariant == kMips64r2);
|
| - int32_t rt_reg = instr->RtValue();
|
| - int64_t rt = get_register(rt_reg);
|
| - if (rt != 0) {
|
| - set_fpu_register_float(fd_reg, fs);
|
| - }
|
| - break;
|
| - }
|
| - case MOVF: {
|
| - // Same function field for MOVT.D and MOVF.D
|
| - uint32_t ft_cc = (ft_reg >> 2) & 0x7;
|
| - ft_cc = get_fcsr_condition_bit(ft_cc);
|
| -
|
| - if (instr->Bit(16)) { // Read Tf bit.
|
| - // MOVT.D
|
| - if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg, fs);
|
| - } else {
|
| - // MOVF.D
|
| - if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg, fs);
|
| - }
|
| - break;
|
| - }
|
| default:
|
| // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
|
| // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
|
| @@ -2745,9 +2426,7 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
| double ft, fs, fd;
|
| uint32_t cc, fcsr_cc;
|
| fs = get_fpu_register_double(fs_reg);
|
| - if (instr->FunctionFieldRaw() != MOVF) {
|
| - ft = get_fpu_register_double(ft_reg);
|
| - }
|
| + ft = get_fpu_register_double(ft_reg);
|
| fd = get_fpu_register_double(fd_reg);
|
| cc = instr->FCccValue();
|
| fcsr_cc = get_fcsr_condition_bit(cc);
|
| @@ -2759,7 +2438,7 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
| double result, temp, temp_result;
|
| double upper = std::ceil(fs);
|
| double lower = std::floor(fs);
|
| - switch (get_fcsr_rounding_mode()) {
|
| + switch (FCSR_ & 0x3) {
|
| case kRoundToNearest:
|
| if (upper - fs < fs - lower) {
|
| result = upper;
|
| @@ -2803,79 +2482,6 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
| DCHECK(kArchVariant == kMips64r6);
|
| set_fpu_register_double(fd_reg, (ft_int & 0x1) != 0 ? fs : 0.0);
|
| break;
|
| - case MOVZ_C: {
|
| - DCHECK(kArchVariant == kMips64r2);
|
| - int32_t rt_reg = instr->RtValue();
|
| - int64_t rt = get_register(rt_reg);
|
| - if (rt == 0) {
|
| - set_fpu_register_double(fd_reg, fs);
|
| - }
|
| - break;
|
| - }
|
| - case MOVN_C: {
|
| - DCHECK(kArchVariant == kMips64r2);
|
| - int32_t rt_reg = instr->RtValue();
|
| - int64_t rt = get_register(rt_reg);
|
| - if (rt != 0) {
|
| - set_fpu_register_double(fd_reg, fs);
|
| - }
|
| - break;
|
| - }
|
| - case MOVF: {
|
| - // Same function field for MOVT.D and MOVF.D
|
| - uint32_t ft_cc = (ft_reg >> 2) & 0x7;
|
| - ft_cc = get_fcsr_condition_bit(ft_cc);
|
| - if (instr->Bit(16)) { // Read Tf bit.
|
| - // MOVT.D
|
| - if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg, fs);
|
| - } else {
|
| - // MOVF.D
|
| - if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg, fs);
|
| - }
|
| - break;
|
| - }
|
| - case MINA:
|
| - DCHECK(kArchVariant == kMips64r6);
|
| - fs = get_fpu_register_double(fs_reg);
|
| - if (std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_double(fd_reg, fs);
|
| - } else if (std::isnan(fs) && !std::isnan(ft)) {
|
| - set_fpu_register_double(fd_reg, ft);
|
| - } else if (!std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_double(fd_reg, fs);
|
| - } else {
|
| - double result;
|
| - if (fabs(fs) > fabs(ft)) {
|
| - result = ft;
|
| - } else if (fabs(fs) < fabs(ft)) {
|
| - result = fs;
|
| - } else {
|
| - result = (fs > ft ? fs : ft);
|
| - }
|
| - set_fpu_register_double(fd_reg, result);
|
| - }
|
| - break;
|
| - case MAXA:
|
| - DCHECK(kArchVariant == kMips64r6);
|
| - fs = get_fpu_register_double(fs_reg);
|
| - if (std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_double(fd_reg, fs);
|
| - } else if (std::isnan(fs) && !std::isnan(ft)) {
|
| - set_fpu_register_double(fd_reg, ft);
|
| - } else if (!std::isnan(fs) && std::isnan(ft)) {
|
| - set_fpu_register_double(fd_reg, fs);
|
| - } else {
|
| - double result;
|
| - if (fabs(fs) < fabs(ft)) {
|
| - result = ft;
|
| - } else if (fabs(fs) > fabs(ft)) {
|
| - result = fs;
|
| - } else {
|
| - result = (fs > ft ? fs : ft);
|
| - }
|
| - set_fpu_register_double(fd_reg, result);
|
| - }
|
| - break;
|
| case MIN:
|
| DCHECK(kArchVariant == kMips64r6);
|
| fs = get_fpu_register_double(fs_reg);
|
| @@ -2926,16 +2532,6 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
| case SQRT_D:
|
| set_fpu_register_double(fd_reg, fast_sqrt(fs));
|
| break;
|
| - case RSQRT_D: {
|
| - double result = 1.0 / fast_sqrt(fs);
|
| - set_fpu_register_double(fd_reg, result);
|
| - break;
|
| - }
|
| - case RECIP_D: {
|
| - double result = 1.0 / fs;
|
| - set_fpu_register_double(fd_reg, result);
|
| - break;
|
| - }
|
| case C_UN_D:
|
| set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
|
| break;
|
| @@ -3022,15 +2618,10 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
| break;
|
| }
|
| case ROUND_L_D: { // Mips64r2 instruction.
|
| - double rounded = std::floor(fs + 0.5);
|
| + // check error cases
|
| + double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
|
| int64_t result = static_cast<int64_t>(rounded);
|
| - if ((result & 1) != 0 && result - fs == 0.5) {
|
| - // If the number is halfway between two integers,
|
| - // round to the even one.
|
| - result--;
|
| - }
|
| - int64_t i64 = static_cast<int64_t>(result);
|
| - set_fpu_register(fd_reg, i64);
|
| + set_fpu_register(fd_reg, result);
|
| if (set_fcsr_round64_error(fs, rounded)) {
|
| set_fpu_register(fd_reg, kFPU64InvalidResult);
|
| }
|
|
|