diff options
Diffstat (limited to 'deps/v8/src/arm/simulator-arm.cc')
-rw-r--r-- | deps/v8/src/arm/simulator-arm.cc | 258 |
1 files changed, 184 insertions, 74 deletions
diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index 4c681ae764..ca9a0a8947 100644 --- a/deps/v8/src/arm/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -657,9 +657,8 @@ void Simulator::FlushICache(v8::internal::HashMap* i_cache, CachePage* Simulator::GetCachePage(v8::internal::HashMap* i_cache, void* page) { - v8::internal::HashMap::Entry* entry = i_cache->Lookup(page, - ICacheHash(page), - true); + v8::internal::HashMap::Entry* entry = + i_cache->LookupOrInsert(page, ICacheHash(page)); if (entry->value == NULL) { CachePage* new_page = new CachePage(); entry->value = new_page; @@ -1309,6 +1308,33 @@ bool Simulator::OverflowFrom(int32_t alu_out, // Support for VFP comparisons. +void Simulator::Compute_FPSCR_Flags(float val1, float val2) { + if (std::isnan(val1) || std::isnan(val2)) { + n_flag_FPSCR_ = false; + z_flag_FPSCR_ = false; + c_flag_FPSCR_ = true; + v_flag_FPSCR_ = true; + // All non-NaN cases. + } else if (val1 == val2) { + n_flag_FPSCR_ = false; + z_flag_FPSCR_ = true; + c_flag_FPSCR_ = true; + v_flag_FPSCR_ = false; + } else if (val1 < val2) { + n_flag_FPSCR_ = true; + z_flag_FPSCR_ = false; + c_flag_FPSCR_ = false; + v_flag_FPSCR_ = false; + } else { + // Case when (val1 > val2). + n_flag_FPSCR_ = false; + z_flag_FPSCR_ = false; + c_flag_FPSCR_ = true; + v_flag_FPSCR_ = false; + } +} + + void Simulator::Compute_FPSCR_Flags(double val1, double val2) { if (std::isnan(val1) || std::isnan(val2)) { n_flag_FPSCR_ = false; @@ -1914,6 +1940,17 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { } +float Simulator::canonicalizeNaN(float value) { + // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation + // choices" of the ARM Reference Manual. + const uint32_t kDefaultNaN = 0x7FC00000u; + if (FPSCR_default_NaN_mode_ && std::isnan(value)) { + value = bit_cast<float>(kDefaultNaN); + } + return value; +} + + double Simulator::canonicalizeNaN(double value) { // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation // choices" of the ARM Reference Manual. @@ -3009,18 +3046,30 @@ void Simulator::DecodeType7(Instruction* instr) { // vcvt: Sd = Dm // vcvt.f64.s32 Dd, Dd, #<fbits> // Dd = vabs(Dm) +// Sd = vabs(Sm) // Dd = vneg(Dm) +// Sd = vneg(Sm) // Dd = vadd(Dn, Dm) +// Sd = vadd(Sn, Sm) // Dd = vsub(Dn, Dm) +// Sd = vsub(Sn, Sm) // Dd = vmul(Dn, Dm) +// Sd = vmul(Sn, Sm) // Dd = vdiv(Dn, Dm) +// Sd = vdiv(Sn, Sm) // vcmp(Dd, Dm) -// vmrs +// vcmp(Sd, Sm) // Dd = vsqrt(Dm) +// Sd = vsqrt(Sm) +// vmrs void Simulator::DecodeTypeVFP(Instruction* instr) { DCHECK((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) ); DCHECK(instr->Bits(11, 9) == 0x5); + // Obtain single precision register codes. + int m = instr->VFPMRegValue(kSinglePrecision); + int d = instr->VFPDRegValue(kSinglePrecision); + int n = instr->VFPNRegValue(kSinglePrecision); // Obtain double precision register codes. int vm = instr->VFPMRegValue(kDoublePrecision); int vd = instr->VFPDRegValue(kDoublePrecision); @@ -3032,28 +3081,38 @@ void Simulator::DecodeTypeVFP(Instruction* instr) { if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) { // vmov register to register. if (instr->SzValue() == 0x1) { - int m = instr->VFPMRegValue(kDoublePrecision); - int d = instr->VFPDRegValue(kDoublePrecision); uint32_t data[2]; - get_d_register(m, data); - set_d_register(d, data); + get_d_register(vm, data); + set_d_register(vd, data); } else { - int m = instr->VFPMRegValue(kSinglePrecision); - int d = instr->VFPDRegValue(kSinglePrecision); - set_s_register_from_float(d, get_float_from_s_register(m)); + set_s_register(d, get_s_register(m)); } } else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) { // vabs - double dm_value = get_double_from_d_register(vm); - double dd_value = std::fabs(dm_value); - dd_value = canonicalizeNaN(dd_value); - set_d_register_from_double(vd, dd_value); + if (instr->SzValue() == 0x1) { + double dm_value = get_double_from_d_register(vm); + double dd_value = std::fabs(dm_value); + dd_value = canonicalizeNaN(dd_value); + set_d_register_from_double(vd, dd_value); + } else { + float sm_value = get_float_from_s_register(m); + float sd_value = std::fabs(sm_value); + sd_value = canonicalizeNaN(sd_value); + set_s_register_from_float(d, sd_value); + } } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) { // vneg - double dm_value = get_double_from_d_register(vm); - double dd_value = -dm_value; - dd_value = canonicalizeNaN(dd_value); - set_d_register_from_double(vd, dd_value); + if (instr->SzValue() == 0x1) { + double dm_value = get_double_from_d_register(vm); + double dd_value = -dm_value; + dd_value = canonicalizeNaN(dd_value); + set_d_register_from_double(vd, dd_value); + } else { + float sm_value = get_float_from_s_register(m); + float sd_value = -sm_value; + sd_value = canonicalizeNaN(sd_value); + set_s_register_from_float(d, sd_value); + } } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) { DecodeVCVTBetweenDoubleAndSingle(instr); } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) { @@ -3073,10 +3132,17 @@ void Simulator::DecodeTypeVFP(Instruction* instr) { DecodeVCMP(instr); } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) { // vsqrt - double dm_value = get_double_from_d_register(vm); - double dd_value = fast_sqrt(dm_value); - dd_value = canonicalizeNaN(dd_value); - set_d_register_from_double(vd, dd_value); + if (instr->SzValue() == 0x1) { + double dm_value = get_double_from_d_register(vm); + double dd_value = fast_sqrt(dm_value); + dd_value = canonicalizeNaN(dd_value); + set_d_register_from_double(vd, dd_value); + } else { + float sm_value = get_float_from_s_register(m); + float sd_value = fast_sqrt(sm_value); + sd_value = canonicalizeNaN(sd_value); + set_s_register_from_float(d, sd_value); + } } else if (instr->Opc3Value() == 0x0) { // vmov immediate. if (instr->SzValue() == 0x1) { @@ -3094,72 +3160,103 @@ void Simulator::DecodeTypeVFP(Instruction* instr) { UNREACHABLE(); // Not used by V8. } } else if (instr->Opc1Value() == 0x3) { - if (instr->SzValue() != 0x1) { - UNREACHABLE(); // Not used by V8. - } - if (instr->Opc3Value() & 0x1) { // vsub - double dn_value = get_double_from_d_register(vn); - double dm_value = get_double_from_d_register(vm); - double dd_value = dn_value - dm_value; - dd_value = canonicalizeNaN(dd_value); - set_d_register_from_double(vd, dd_value); + if (instr->SzValue() == 0x1) { + double dn_value = get_double_from_d_register(vn); + double dm_value = get_double_from_d_register(vm); + double dd_value = dn_value - dm_value; + dd_value = canonicalizeNaN(dd_value); + set_d_register_from_double(vd, dd_value); + } else { + float sn_value = get_float_from_s_register(n); + float sm_value = get_float_from_s_register(m); + float sd_value = sn_value - sm_value; + sd_value = canonicalizeNaN(sd_value); + set_s_register_from_float(d, sd_value); + } } else { // vadd + if (instr->SzValue() == 0x1) { + double dn_value = get_double_from_d_register(vn); + double dm_value = get_double_from_d_register(vm); + double dd_value = dn_value + dm_value; + dd_value = canonicalizeNaN(dd_value); + set_d_register_from_double(vd, dd_value); + } else { + float sn_value = get_float_from_s_register(n); + float sm_value = get_float_from_s_register(m); + float sd_value = sn_value + sm_value; + sd_value = canonicalizeNaN(sd_value); + set_s_register_from_float(d, sd_value); + } + } + } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) { + // vmul + if (instr->SzValue() == 0x1) { double dn_value = get_double_from_d_register(vn); double dm_value = get_double_from_d_register(vm); - double dd_value = dn_value + dm_value; + double dd_value = dn_value * dm_value; dd_value = canonicalizeNaN(dd_value); set_d_register_from_double(vd, dd_value); + } else { + float sn_value = get_float_from_s_register(n); + float sm_value = get_float_from_s_register(m); + float sd_value = sn_value * sm_value; + sd_value = canonicalizeNaN(sd_value); + set_s_register_from_float(d, sd_value); } - } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) { - // vmul - if (instr->SzValue() != 0x1) { - UNREACHABLE(); // Not used by V8. - } - - double dn_value = get_double_from_d_register(vn); - double dm_value = get_double_from_d_register(vm); - double dd_value = dn_value * dm_value; - dd_value = canonicalizeNaN(dd_value); - set_d_register_from_double(vd, dd_value); } else if ((instr->Opc1Value() == 0x0)) { // vmla, vmls const bool is_vmls = (instr->Opc3Value() & 0x1); - - if (instr->SzValue() != 0x1) { - UNREACHABLE(); // Not used by V8. - } - - const double dd_val = get_double_from_d_register(vd); - const double dn_val = get_double_from_d_register(vn); - const double dm_val = get_double_from_d_register(vm); - - // Note: we do the mul and add/sub in separate steps to avoid getting a - // result with too high precision. - set_d_register_from_double(vd, dn_val * dm_val); - if (is_vmls) { - set_d_register_from_double( - vd, - canonicalizeNaN(dd_val - get_double_from_d_register(vd))); + if (instr->SzValue() == 0x1) { + const double dd_val = get_double_from_d_register(vd); + const double dn_val = get_double_from_d_register(vn); + const double dm_val = get_double_from_d_register(vm); + + // Note: we do the mul and add/sub in separate steps to avoid getting a + // result with too high precision. + set_d_register_from_double(vd, dn_val * dm_val); + if (is_vmls) { + set_d_register_from_double( + vd, canonicalizeNaN(dd_val - get_double_from_d_register(vd))); + } else { + set_d_register_from_double( + vd, canonicalizeNaN(dd_val + get_double_from_d_register(vd))); + } } else { - set_d_register_from_double( - vd, - canonicalizeNaN(dd_val + get_double_from_d_register(vd))); + const float sd_val = get_float_from_s_register(d); + const float sn_val = get_float_from_s_register(n); + const float sm_val = get_float_from_s_register(m); + + // Note: we do the mul and add/sub in separate steps to avoid getting a + // result with too high precision. + set_s_register_from_float(d, sn_val * sm_val); + if (is_vmls) { + set_s_register_from_float( + d, canonicalizeNaN(sd_val - get_float_from_s_register(d))); + } else { + set_s_register_from_float( + d, canonicalizeNaN(sd_val + get_float_from_s_register(d))); + } } } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) { // vdiv - if (instr->SzValue() != 0x1) { - UNREACHABLE(); // Not used by V8. + if (instr->SzValue() == 0x1) { + double dn_value = get_double_from_d_register(vn); + double dm_value = get_double_from_d_register(vm); + double dd_value = dn_value / dm_value; + div_zero_vfp_flag_ = (dm_value == 0); + dd_value = canonicalizeNaN(dd_value); + set_d_register_from_double(vd, dd_value); + } else { + float sn_value = get_float_from_s_register(n); + float sm_value = get_float_from_s_register(m); + float sd_value = sn_value / sm_value; + div_zero_vfp_flag_ = (sm_value == 0); + sd_value = canonicalizeNaN(sd_value); + set_s_register_from_float(d, sd_value); } - - double dn_value = get_double_from_d_register(vn); - double dm_value = get_double_from_d_register(vm); - double dd_value = dn_value / dm_value; - div_zero_vfp_flag_ = (dm_value == 0); - dd_value = canonicalizeNaN(dd_value); - set_d_register_from_double(vd, dd_value); } else { UNIMPLEMENTED(); // Not used by V8. } @@ -3264,7 +3361,7 @@ void Simulator::DecodeVCMP(Instruction* instr) { // Comparison. VFPRegPrecision precision = kSinglePrecision; - if (instr->SzValue() == 1) { + if (instr->SzValue() == 0x1) { precision = kDoublePrecision; } @@ -3290,7 +3387,20 @@ void Simulator::DecodeVCMP(Instruction* instr) { Compute_FPSCR_Flags(dd_value, dm_value); } else { - UNIMPLEMENTED(); // Not used by V8. + float sd_value = get_float_from_s_register(d); + float sm_value = 0.0; + if (instr->Opc2Value() == 0x4) { + sm_value = get_float_from_s_register(m); + } + + // Raise exceptions for quiet NaNs if necessary. + if (instr->Bit(7) == 1) { + if (std::isnan(sd_value)) { + inv_op_vfp_flag_ = true; + } + } + + Compute_FPSCR_Flags(sd_value, sm_value); } } |