aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/arm/simulator-arm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/arm/simulator-arm.cc')
-rw-r--r--deps/v8/src/arm/simulator-arm.cc258
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);
}
}