| Index: src/arm/simulator-arm.cc
|
| diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
|
| index 1ef4a9ce4a162120d5d5d508a3e388e26e149826..2b20fe420a3a8db649c8dd6ee81805d86e6321f2 100644
|
| --- a/src/arm/simulator-arm.cc
|
| +++ b/src/arm/simulator-arm.cc
|
| @@ -1921,6 +1921,80 @@ double Simulator::canonicalizeNaN(double value) {
|
| }
|
|
|
|
|
| +double Simulator::FPRoundInt(double value, VCVTRoundingMode rounding_mode) {
|
| + Double double_value(value);
|
| + if ((value == 0.0) || double_value.IsInfinite()) {
|
| + return value;
|
| + } else if (std::isnan(value)) {
|
| + return canonicalizeNaN(value);
|
| + }
|
| +
|
| + double int_result = floor(value);
|
| + double error = value - int_result;
|
| + switch (rounding_mode) {
|
| + case kVcvtTiesToAway: {
|
| + // Take care of correctly handling the range ]-0.5, -0.0], which must
|
| + // yield -0.0.
|
| + if ((-0.5 < value) && (value < 0.0)) {
|
| + int_result = -0.0;
|
| +
|
| + } else if ((error > 0.5) || ((error == 0.5) && (int_result >= 0.0))) {
|
| + // If the error is greater than 0.5, or is equal to 0.5 and the integer
|
| + // result is positive, round up.
|
| + int_result++;
|
| + }
|
| + break;
|
| + }
|
| + case kVcvtTiesToEven: {
|
| + // Take care of correctly handling the range [-0.5, -0.0], which must
|
| + // yield -0.0.
|
| + if ((-0.5 <= value) && (value < 0.0)) {
|
| + int_result = -0.0;
|
| +
|
| + // If the error is greater than 0.5, or is equal to 0.5 and the integer
|
| + // result is odd, round up.
|
| + } else if ((error > 0.5) ||
|
| + ((error == 0.5) && (fmod(int_result, 2) != 0))) {
|
| + int_result++;
|
| + }
|
| + break;
|
| + }
|
| + case kVcvtTowardPlusInfinity: {
|
| + int_result = -floor(-value);
|
| + break;
|
| + }
|
| + case kVcvtTowardMinusInfinity: {
|
| + // We always use floor(value).
|
| + break;
|
| + }
|
| + default: UNREACHABLE();
|
| + }
|
| + return int_result;
|
| +}
|
| +
|
| +
|
| +int32_t Simulator::FPToInt32(double value, VCVTRoundingMode rounding_mode) {
|
| + value = FPRoundInt(value, rounding_mode);
|
| + if (value >= kMaxInt) {
|
| + return kMaxInt;
|
| + } else if (value < kMinInt) {
|
| + return kMinInt;
|
| + }
|
| + return std::isnan(value) ? 0 : static_cast<int32_t>(value);
|
| +}
|
| +
|
| +
|
| +uint32_t Simulator::FPToUInt32(double value, VCVTRoundingMode rounding_mode) {
|
| + value = FPRoundInt(value, rounding_mode);
|
| + if (value >= kMaxUInt32) {
|
| + return kMaxUInt32;
|
| + } else if (value < 0.0) {
|
| + return 0;
|
| + }
|
| + return std::isnan(value) ? 0 : static_cast<uint32_t>(value);
|
| +}
|
| +
|
| +
|
| // Stop helper functions.
|
| bool Simulator::isStopInstruction(Instruction* instr) {
|
| return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
|
| @@ -3586,6 +3660,33 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
|
| UNIMPLEMENTED();
|
| }
|
| break;
|
| + case 0x1D:
|
| + if ((instr->Bits(21, 18) == 0xF) && (instr->Bits(11, 9) == 5) &&
|
| + (instr->Bit(6) == 1) && (instr->Bit(4) == 0)) {
|
| + // AArch32 vcvt instructions.
|
| + int size = instr->Bit(8);
|
| + int Vd = instr->VFPDRegValue(kSinglePrecision);
|
| + int Vm = instr->VFPMRegValue(static_cast<VFPRegPrecision>(size));
|
| + VCVTRoundingMode rounding_mode =
|
| + static_cast<VCVTRoundingMode>(instr->Bits(17, 16));
|
| + int data_type = instr->Bit(7);
|
| + double value;
|
| + if (size == 0) {
|
| + value = get_float_from_s_register(Vm);
|
| + } else {
|
| + value = get_double_from_d_register(Vm);
|
| + }
|
| + if (data_type == 0) {
|
| + uint32_t result = FPToUInt32(value, rounding_mode);
|
| + set_s_register_from_sinteger(Vd, result);
|
| + } else {
|
| + int32_t result = FPToInt32(value, rounding_mode);
|
| + set_s_register_from_sinteger(Vd, result);
|
| + }
|
| + } else {
|
| + UNIMPLEMENTED();
|
| + }
|
| + break;
|
| default:
|
| UNIMPLEMENTED();
|
| break;
|
|
|