| Index: src/mips/simulator-mips.cc
|
| diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
|
| index ca9a601b9c5bb207f79c887b7bb2f99db96e5ce8..68fbdae96ee015d27ff33ae1ddaf0eed651b03a9 100644
|
| --- a/src/mips/simulator-mips.cc
|
| +++ b/src/mips/simulator-mips.cc
|
| @@ -1282,69 +1282,9 @@ unsigned int Simulator::get_fcsr_rounding_mode() {
|
| }
|
|
|
|
|
| -bool Simulator::set_fcsr_round_error(double original, double 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 < DBL_MIN && rounded > -DBL_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(double original, double 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 < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
|
| - set_fcsr_bit(kFCSRUnderflowFlagBit, true);
|
| - 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 Simulator::set_fcsr_round_error(double original, double rounded) {
|
| bool ret = false;
|
| double max_int32 = std::numeric_limits<int32_t>::max();
|
| double min_int32 = std::numeric_limits<int32_t>::min();
|
| @@ -1358,44 +1298,12 @@ bool Simulator::set_fcsr_round_error(float original, float 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) {
|
| + if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
|
| set_fcsr_bit(kFCSRUnderflowFlagBit, true);
|
| ret = true;
|
| }
|
|
|
| - if (rounded >= max_int64 || rounded <= min_int64) {
|
| + 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);
|
| @@ -2283,10 +2191,7 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
| uint32_t cc, fcsr_cc;
|
| int64_t i64;
|
| fs = get_fpu_register_double(fs_reg);
|
| - if (instr->FunctionFieldRaw() != MOVF) {
|
| - ft = get_fpu_register_double(ft_reg);
|
| - }
|
| - fd = get_fpu_register_double(fd_reg);
|
| + ft = get_fpu_register_double(ft_reg);
|
| int64_t ft_int = bit_cast<int64_t>(ft);
|
| int64_t fd_int = bit_cast<int64_t>(fd);
|
| cc = instr->FCccValue();
|
| @@ -2341,37 +2246,6 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
| DCHECK(IsMipsArchVariant(kMips32r6));
|
| set_fpu_register_double(fd_reg, (ft_int & 0x1) != 0 ? fs : 0.0);
|
| break;
|
| - case MOVZ_C: {
|
| - DCHECK(IsMipsArchVariant(kMips32r2));
|
| - int32_t rt_reg = instr->RtValue();
|
| - int32_t rt = get_register(rt_reg);
|
| - if (rt == 0) {
|
| - set_fpu_register_double(fd_reg, fs);
|
| - }
|
| - break;
|
| - }
|
| - case MOVN_C: {
|
| - DCHECK(IsMipsArchVariant(kMips32r2));
|
| - int32_t rt_reg = instr->RtValue();
|
| - int32_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 MIN:
|
| DCHECK(IsMipsArchVariant(kMips32r6));
|
| fs = get_fpu_register_double(fs_reg);
|
| @@ -2385,48 +2259,6 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
| set_fpu_register_double(fd_reg, (fs >= ft) ? ft : fs);
|
| }
|
| break;
|
| - case MINA:
|
| - DCHECK(IsMipsArchVariant(kMips32r6));
|
| - 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(IsMipsArchVariant(kMips32r6));
|
| - 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 MAX:
|
| DCHECK(IsMipsArchVariant(kMips32r6));
|
| fs = get_fpu_register_double(fs_reg);
|
| @@ -2465,16 +2297,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;
|
| @@ -2555,72 +2377,51 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
| if (IsFp64Mode()) {
|
| set_fpu_register(fd_reg, i64);
|
| } else {
|
| - UNSUPPORTED();
|
| + set_fpu_register_word(fd_reg, i64 & 0xffffffff);
|
| + set_fpu_register_word(fd_reg + 1, i64 >> 32);
|
| }
|
| break;
|
| }
|
| case TRUNC_L_D: { // Mips32r2 instruction.
|
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
|
| double rounded = trunc(fs);
|
| i64 = static_cast<int64_t>(rounded);
|
| if (IsFp64Mode()) {
|
| set_fpu_register(fd_reg, i64);
|
| - if (set_fcsr_round64_error(fs, rounded)) {
|
| - set_fpu_register(fd_reg, kFPU64InvalidResult);
|
| - }
|
| } else {
|
| - UNSUPPORTED();
|
| + set_fpu_register_word(fd_reg, i64 & 0xffffffff);
|
| + set_fpu_register_word(fd_reg + 1, i64 >> 32);
|
| }
|
| break;
|
| }
|
| case ROUND_L_D: { // Mips32r2 instruction.
|
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
|
| - double 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);
|
| + double rounded = fs > 0 ? std::floor(fs + 0.5) : std::ceil(fs - 0.5);
|
| + i64 = static_cast<int64_t>(rounded);
|
| if (IsFp64Mode()) {
|
| set_fpu_register(fd_reg, i64);
|
| - if (set_fcsr_round64_error(fs, rounded)) {
|
| - set_fpu_register(fd_reg, kFPU64InvalidResult);
|
| - }
|
| } else {
|
| - UNSUPPORTED();
|
| + set_fpu_register_word(fd_reg, i64 & 0xffffffff);
|
| + set_fpu_register_word(fd_reg + 1, i64 >> 32);
|
| }
|
| break;
|
| }
|
| - case FLOOR_L_D: { // Mips32r2 instruction.
|
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
|
| - double rounded = std::floor(fs);
|
| - int64_t i64 = static_cast<int64_t>(rounded);
|
| + case FLOOR_L_D: // Mips32r2 instruction.
|
| + i64 = static_cast<int64_t>(std::floor(fs));
|
| if (IsFp64Mode()) {
|
| set_fpu_register(fd_reg, i64);
|
| - if (set_fcsr_round64_error(fs, rounded)) {
|
| - set_fpu_register(fd_reg, kFPU64InvalidResult);
|
| - }
|
| } else {
|
| - UNSUPPORTED();
|
| + set_fpu_register_word(fd_reg, i64 & 0xffffffff);
|
| + set_fpu_register_word(fd_reg + 1, i64 >> 32);
|
| }
|
| break;
|
| - }
|
| - case CEIL_L_D: { // Mips32r2 instruction.
|
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
|
| - double rounded = std::ceil(fs);
|
| - int64_t i64 = static_cast<int64_t>(rounded);
|
| + case CEIL_L_D: // Mips32r2 instruction.
|
| + i64 = static_cast<int64_t>(std::ceil(fs));
|
| if (IsFp64Mode()) {
|
| set_fpu_register(fd_reg, i64);
|
| - if (set_fcsr_round64_error(fs, rounded)) {
|
| - set_fpu_register(fd_reg, kFPU64InvalidResult);
|
| - }
|
| } else {
|
| - UNSUPPORTED();
|
| + set_fpu_register_word(fd_reg, i64 & 0xffffffff);
|
| + set_fpu_register_word(fd_reg + 1, i64 >> 32);
|
| }
|
| break;
|
| - }
|
| case C_F_D:
|
| UNIMPLEMENTED_MIPS();
|
| break;
|
| @@ -2652,88 +2453,38 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
|
| const int32_t& ft_reg,
|
| const int32_t& fs_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);
|
| + int64_t ft_int = static_cast<int64_t>(get_fpu_register_double(ft_reg));
|
| uint32_t cc, fcsr_cc;
|
| cc = instr->FCccValue();
|
| fcsr_cc = get_fcsr_condition_bit(cc);
|
| switch (instr->FunctionFieldRaw()) {
|
| - case RINT: {
|
| - DCHECK(IsMipsArchVariant(kMips32r6));
|
| - 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;
|
| @@ -2758,224 +2509,18 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
|
| case CVT_D_S:
|
| set_fpu_register_double(fd_reg, static_cast<double>(fs));
|
| break;
|
| - case SEL:
|
| - DCHECK(IsMipsArchVariant(kMips32r6));
|
| - set_fpu_register_float(fd_reg, (fd_int & 0x1) == 0 ? fs : ft);
|
| - break;
|
| case SELEQZ_C:
|
| DCHECK(IsMipsArchVariant(kMips32r6));
|
| - set_fpu_register_float(
|
| - fd_reg, (ft_int & 0x1) == 0 ? get_fpu_register_float(fs_reg) : 0.0);
|
| + set_fpu_register_double(
|
| + fd_reg, (ft_int & 0x1) == 0 ? get_fpu_register_double(fs_reg) : 0.0);
|
| break;
|
| case SELNEZ_C:
|
| DCHECK(IsMipsArchVariant(kMips32r6));
|
| - set_fpu_register_float(
|
| - fd_reg, (ft_int & 0x1) != 0 ? get_fpu_register_float(fs_reg) : 0.0);
|
| - break;
|
| - case MOVZ_C: {
|
| - DCHECK(IsMipsArchVariant(kMips32r2));
|
| - int32_t rt_reg = instr->RtValue();
|
| - int32_t rt = get_register(rt_reg);
|
| - if (rt == 0) {
|
| - set_fpu_register_float(fd_reg, fs);
|
| - }
|
| - break;
|
| - }
|
| - case MOVN_C: {
|
| - DCHECK(IsMipsArchVariant(kMips32r2));
|
| - int32_t rt_reg = instr->RtValue();
|
| - int32_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;
|
| - }
|
| - 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: { // Mips32r2 instruction.
|
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
|
| - float rounded = trunc(fs);
|
| - int64_t i64 = static_cast<int64_t>(rounded);
|
| - if (IsFp64Mode()) {
|
| - set_fpu_register(fd_reg, i64);
|
| - if (set_fcsr_round64_error(fs, rounded)) {
|
| - set_fpu_register(fd_reg, kFPU64InvalidResult);
|
| - }
|
| - } else {
|
| - UNSUPPORTED();
|
| - }
|
| - 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 FLOOR_L_S: { // Mips32r2 instruction.
|
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
|
| - float rounded = std::floor(fs);
|
| - int64_t i64 = static_cast<int64_t>(rounded);
|
| - if (IsFp64Mode()) {
|
| - set_fpu_register(fd_reg, i64);
|
| - if (set_fcsr_round64_error(fs, rounded)) {
|
| - set_fpu_register(fd_reg, kFPU64InvalidResult);
|
| - }
|
| - } else {
|
| - UNSUPPORTED();
|
| - }
|
| - 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: { // Mips32r2 instruction.
|
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
|
| - 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);
|
| - if (IsFp64Mode()) {
|
| - set_fpu_register(fd_reg, i64);
|
| - if (set_fcsr_round64_error(fs, rounded)) {
|
| - set_fpu_register(fd_reg, kFPU64InvalidResult);
|
| - }
|
| - } else {
|
| - UNSUPPORTED();
|
| - }
|
| - 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_word(fd_reg, kFPUInvalidResult);
|
| - }
|
| - } break;
|
| - case CEIL_L_S: { // Mips32r2 instruction.
|
| - DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
|
| - float rounded = std::ceil(fs);
|
| - int64_t i64 = static_cast<int64_t>(rounded);
|
| - if (IsFp64Mode()) {
|
| - set_fpu_register(fd_reg, i64);
|
| - if (set_fcsr_round64_error(fs, rounded)) {
|
| - set_fpu_register(fd_reg, kFPU64InvalidResult);
|
| - }
|
| - } else {
|
| - UNSUPPORTED();
|
| - }
|
| - break;
|
| - }
|
| - case MIN:
|
| - DCHECK(IsMipsArchVariant(kMips32r6));
|
| - 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(IsMipsArchVariant(kMips32r6));
|
| - 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 MINA:
|
| - DCHECK(IsMipsArchVariant(kMips32r6));
|
| - 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(IsMipsArchVariant(kMips32r6));
|
| - 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);
|
| - }
|
| + set_fpu_register_double(
|
| + fd_reg, (ft_int & 0x1) != 0 ? get_fpu_register_double(fs_reg) : 0.0);
|
| break;
|
| default:
|
| - // CVT_W_S CVT_L_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
|
| + // 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.
|
| UNREACHABLE();
|
| }
|
|
|