Chromium Code Reviews| Index: src/arm/simulator-arm.cc |
| =================================================================== |
| --- src/arm/simulator-arm.cc (revision 6591) |
| +++ src/arm/simulator-arm.cc (working copy) |
| @@ -2539,7 +2539,7 @@ |
| (overflow_vfp_flag_ << 2) | |
| (div_zero_vfp_flag_ << 1) | |
| (inv_op_vfp_flag_ << 0) | |
| - (FPSCR_rounding_mode_ << 22); |
| + (FPSCR_rounding_mode_); |
| set_register(rt, fpscr); |
| } |
| } else if ((instr->VLValue() == 0x0) && |
| @@ -2562,7 +2562,7 @@ |
| div_zero_vfp_flag_ = (rt_value >> 1) & 1; |
| inv_op_vfp_flag_ = (rt_value >> 0) & 1; |
| FPSCR_rounding_mode_ = |
|
Søren Thygesen Gjesse
2011/02/03 09:07:17
4 char indent.
Rodolph Perfetta
2011/02/03 15:03:39
Done.
|
| - static_cast<FPSCRRoundingModes>((rt_value >> 22) & 3); |
| + static_cast<VFPRoundingMode>((rt_value) & kVFPRoundingModeMask); |
| } |
| } else { |
| UNIMPLEMENTED(); // Not used by V8. |
| @@ -2651,87 +2651,138 @@ |
| } |
| } |
| +bool get_inv_op_vfp_flag(VFPRoundingMode mode, |
| + double val, |
| + bool unsigned_) { |
| + double max_uint = static_cast<double>(0xffffffffu); |
| + double max_int = static_cast<double>(kMaxInt); |
| + double min_int = static_cast<double>(kMinInt); |
| + // This code works because 32bit integers can be exactly represented by |
| + // ieee-754 64bit floating-point values. |
| + switch (mode) { |
| + case RN: |
| + return unsigned_ ? (val >= (max_uint + 0.5)) || |
| + (val < -0.5) || |
|
Søren Thygesen Gjesse
2011/02/03 09:07:17
Please comment on what val != val checks. Maybe ha
Rodolph Perfetta
2011/02/03 15:03:39
made a separate check for NaN.
|
| + (val != val) |
| + : (val >= (max_int + 0.5)) || |
| + (val < (min_int - 0.5)) || |
| + (val != val); |
| + case RP: |
| + UNIMPLEMENTED(); |
| + return false; |
| + |
| + case RM: |
| + return unsigned_ ? (val >= (max_uint + 1.0)) || |
| + (val < 0) || |
| + (val != val) |
| + : (val >= (max_int + 1.0)) || |
| + (val < min_int) || |
| + (val != val); |
| + |
| + case RZ: |
| + return unsigned_ ? (val >= (max_uint + 1.0)) || |
| + (val <= -1) || |
| + (val != val) |
| + : (val >= (max_int + 1.0)) || |
| + (val <= (min_int - 1.0)) || |
| + (val != val); |
| + default: |
| + UNREACHABLE(); |
| + return false; |
| + } |
| +} |
| + |
| + |
| +// We call this function only if we had a vfp invalid exception. |
| +// It returns the correct saturated value. |
| +int VFPConversionSaturate(double val, bool unsigned_res) { |
| + if (val != val) { |
| + return 0; |
| + } else { |
| + if (unsigned_res) { |
| + return (val < 0) ? 0 : 0xffffffffu; |
| + } else { |
| + return (val < 0) ? kMinInt : kMaxInt; |
| + } |
| + } |
| +} |
| + |
| + |
| void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) { |
| - ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7)); |
| + ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7) && |
| + (instr->Bits(27, 23) == 0x1D)); |
| ASSERT(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) || |
| (((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1))); |
| // Conversion between floating-point and integer. |
| bool to_integer = (instr->Bit(18) == 1); |
| - VFPRegPrecision src_precision = kSinglePrecision; |
| - if (instr->SzValue() == 1) { |
| - src_precision = kDoublePrecision; |
| - } |
| + VFPRegPrecision src_precision = (instr->SzValue() == 1) ? kDoublePrecision |
| + : kSinglePrecision; |
| if (to_integer) { |
| - bool unsigned_integer = (instr->Bit(16) == 0); |
| - FPSCRRoundingModes mode; |
| - if (instr->Bit(7) != 1) { |
| - // Use FPSCR defined rounding mode. |
| - mode = FPSCR_rounding_mode_; |
| - // Only RZ and RM modes are supported. |
| - ASSERT((mode == RM) || (mode == RZ)); |
| - } else { |
| - // VFP uses round towards zero by default. |
| - mode = RZ; |
| - } |
| + // We are playing with code close to the C++ standard's limits below, |
| + // hence the very simple code and heavy checks. |
| + // |
| + // Note: |
| + // C++ defines default type casting from floating point to integer as |
| + // (close to) rounding toward zero ("fractional part discarded"). |
| int dst = instr->VFPDRegValue(kSinglePrecision); |
| int src = instr->VFPMRegValue(src_precision); |
| - int32_t kMaxInt = v8::internal::kMaxInt; |
| - int32_t kMinInt = v8::internal::kMinInt; |
| - switch (mode) { |
| - case RM: |
| - if (src_precision == kDoublePrecision) { |
| - double val = get_double_from_d_register(src); |
| - inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val); |
| + // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding |
| + // mode or the default Round to Zero mode. |
| + VFPRoundingMode mode = (instr->Bit(7) != 1) ? FPSCR_rounding_mode_ |
|
Søren Thygesen Gjesse
2011/02/03 09:07:17
Indentation.
Rodolph Perfetta
2011/02/03 15:03:39
Done.
|
| + : RZ; |
| + ASSERT((mode == RM) || (mode == RZ) || (mode == RN)); |
| - int sint = unsigned_integer ? static_cast<uint32_t>(val) : |
| - static_cast<int32_t>(val); |
| - sint = sint > val ? sint - 1 : sint; |
| + bool unsigned_integer = (instr->Bit(16) == 0); |
| + bool double_precision = (src_precision == kDoublePrecision); |
| - set_s_register_from_sinteger(dst, sint); |
| - } else { |
| - float val = get_float_from_s_register(src); |
| + double val = double_precision ? get_double_from_d_register(src) |
| + : get_float_from_s_register(src); |
| - inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val); |
| + int temp = unsigned_integer ? static_cast<uint32_t>(val) : |
|
Søren Thygesen Gjesse
2011/02/03 09:07:17
Please be consistent with where the : is placed.
Rodolph Perfetta
2011/02/03 15:03:39
Done.
|
| + static_cast<int32_t>(val); |
| - int sint = unsigned_integer ? static_cast<uint32_t>(val) : |
| - static_cast<int32_t>(val); |
| - sint = sint > val ? sint - 1 : sint; |
| + inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer); |
| - set_s_register_from_sinteger(dst, sint); |
| + if (inv_op_vfp_flag_) { |
| + temp = VFPConversionSaturate(val, unsigned_integer); |
| + } else { |
| + switch (mode) { |
| + case RN: { |
| + double abs_diff = |
| + unsigned_integer ? fabs(val - static_cast<uint32_t>(temp)) |
| + : fabs(val - temp); |
| + int val_sign = (val > 0) ? 1 : -1; |
| + if (abs_diff > 0.5) { |
| + temp += val_sign; |
| + } else if (abs_diff == 0.5) { |
| + // Round to even if exactly halfway. |
| + temp = ((temp % 2) == 0) ? temp : temp + val_sign; |
| + } |
| + break; |
| } |
| - break; |
| - case RZ: |
| - if (src_precision == kDoublePrecision) { |
| - double val = get_double_from_d_register(src); |
| - inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val); |
| + case RM: |
| + temp = temp > val ? temp - 1 : temp; |
| + break; |
| - int sint = unsigned_integer ? static_cast<uint32_t>(val) : |
| - static_cast<int32_t>(val); |
| + case RZ: |
| + // Nothing to do. |
| + break; |
| - set_s_register_from_sinteger(dst, sint); |
| - } else { |
| - float val = get_float_from_s_register(src); |
| + default: |
| + UNREACHABLE(); |
| + } |
| + } |
| - inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val); |
| + // Update the destination register. |
| + set_s_register_from_sinteger(dst, temp); |
| - int sint = unsigned_integer ? static_cast<uint32_t>(val) : |
| - static_cast<int32_t>(val); |
| - |
| - set_s_register_from_sinteger(dst, sint); |
| - } |
| - break; |
| - |
| - default: |
| - UNREACHABLE(); |
| - } |
| - |
| } else { |
| bool unsigned_integer = (instr->Bit(7) == 0); |