Index: runtime/vm/simulator_arm.cc |
=================================================================== |
--- runtime/vm/simulator_arm.cc (revision 36258) |
+++ runtime/vm/simulator_arm.cc (working copy) |
@@ -676,60 +676,9 @@ |
} |
-// Synchronization primitives support. |
-Mutex* Simulator::exclusive_access_lock_ = NULL; |
-Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags]; |
-int Simulator::next_address_tag_; |
+void Simulator::InitOnce() {} |
-void Simulator::SetExclusiveAccess(uword addr) { |
- Isolate* isolate = Isolate::Current(); |
- ASSERT(isolate != NULL); |
- int i = 0; |
- while ((i < kNumAddressTags) && |
- (exclusive_access_state_[i].isolate != isolate)) { |
- i++; |
- } |
- if (i == kNumAddressTags) { |
- i = next_address_tag_; |
- if (++next_address_tag_ == kNumAddressTags) next_address_tag_ = 0; |
- exclusive_access_state_[i].isolate = isolate; |
- } |
- exclusive_access_state_[i].addr = addr; |
-} |
- |
- |
-bool Simulator::HasExclusiveAccessAndOpen(uword addr) { |
- Isolate* isolate = Isolate::Current(); |
- ASSERT(isolate != NULL); |
- bool result = false; |
- for (int i = 0; i < kNumAddressTags; i++) { |
- if (exclusive_access_state_[i].isolate == isolate) { |
- if (exclusive_access_state_[i].addr == addr) { |
- result = true; |
- } |
- exclusive_access_state_[i].addr = static_cast<uword>(NULL); |
- continue; |
- } |
- if (exclusive_access_state_[i].addr == addr) { |
- exclusive_access_state_[i].addr = static_cast<uword>(NULL); |
- } |
- } |
- return result; |
-} |
- |
- |
-void Simulator::InitOnce() { |
- // Setup exclusive access state. |
- exclusive_access_lock_ = new Mutex(); |
- for (int i = 0; i < kNumAddressTags; i++) { |
- exclusive_access_state_[i].isolate = NULL; |
- exclusive_access_state_[i].addr = static_cast<uword>(NULL); |
- } |
- next_address_tag_ = 0; |
-} |
- |
- |
Simulator::Simulator() { |
// Setup simulator support first. Some of this information is needed to |
// setup the architecture state. |
@@ -907,30 +856,35 @@ |
// Accessors for VFP register state. |
void Simulator::set_sregister(SRegister reg, float value) { |
+ ASSERT(TargetCPUFeatures::vfp_supported()); |
ASSERT((reg >= 0) && (reg < kNumberOfSRegisters)); |
sregisters_[reg] = bit_cast<int32_t, float>(value); |
} |
float Simulator::get_sregister(SRegister reg) const { |
+ ASSERT(TargetCPUFeatures::vfp_supported()); |
ASSERT((reg >= 0) && (reg < kNumberOfSRegisters)); |
return bit_cast<float, int32_t>(sregisters_[reg]); |
} |
void Simulator::set_dregister(DRegister reg, double value) { |
+ ASSERT(TargetCPUFeatures::vfp_supported()); |
ASSERT((reg >= 0) && (reg < kNumberOfDRegisters)); |
dregisters_[reg] = bit_cast<int64_t, double>(value); |
} |
double Simulator::get_dregister(DRegister reg) const { |
+ ASSERT(TargetCPUFeatures::vfp_supported()); |
ASSERT((reg >= 0) && (reg < kNumberOfDRegisters)); |
return bit_cast<double, int64_t>(dregisters_[reg]); |
} |
void Simulator::set_qregister(QRegister reg, const simd_value_t& value) { |
+ ASSERT(TargetCPUFeatures::neon_supported()); |
ASSERT((reg >= 0) && (reg < kNumberOfQRegisters)); |
qregisters_[reg].data_[0] = value.data_[0]; |
qregisters_[reg].data_[1] = value.data_[1]; |
@@ -940,6 +894,7 @@ |
void Simulator::get_qregister(QRegister reg, simd_value_t* value) const { |
+ ASSERT(TargetCPUFeatures::neon_supported()); |
// TODO(zra): Replace this test with an assert after we support |
// 16 Q registers. |
if ((reg >= 0) && (reg < kNumberOfQRegisters)) { |
@@ -949,24 +904,28 @@ |
void Simulator::set_sregister_bits(SRegister reg, int32_t value) { |
+ ASSERT(TargetCPUFeatures::vfp_supported()); |
ASSERT((reg >= 0) && (reg < kNumberOfSRegisters)); |
sregisters_[reg] = value; |
} |
int32_t Simulator::get_sregister_bits(SRegister reg) const { |
+ ASSERT(TargetCPUFeatures::vfp_supported()); |
ASSERT((reg >= 0) && (reg < kNumberOfSRegisters)); |
return sregisters_[reg]; |
} |
void Simulator::set_dregister_bits(DRegister reg, int64_t value) { |
+ ASSERT(TargetCPUFeatures::vfp_supported()); |
ASSERT((reg >= 0) && (reg < kNumberOfDRegisters)); |
dregisters_[reg] = value; |
} |
int64_t Simulator::get_dregister_bits(DRegister reg) const { |
+ ASSERT(TargetCPUFeatures::vfp_supported()); |
ASSERT((reg >= 0) && (reg < kNumberOfDRegisters)); |
return dregisters_[reg]; |
} |
@@ -1101,53 +1060,6 @@ |
} |
-// Synchronization primitives support. |
-void Simulator::ClearExclusive() { |
- // This lock is initialized in Simulator::InitOnce(). |
- MutexLocker ml(exclusive_access_lock_); |
- // Set exclusive access to open state for this isolate. |
- HasExclusiveAccessAndOpen(static_cast<uword>(NULL)); |
-} |
- |
- |
-intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) { |
- // This lock is initialized in Simulator::InitOnce(). |
- MutexLocker ml(exclusive_access_lock_); |
- SetExclusiveAccess(addr); |
- return ReadW(addr, instr); |
-} |
- |
- |
-intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) { |
- // This lock is initialized in Simulator::InitOnce(). |
- MutexLocker ml(exclusive_access_lock_); |
- bool write_allowed = HasExclusiveAccessAndOpen(addr); |
- if (write_allowed) { |
- WriteW(addr, value, instr); |
- return 0; // Success. |
- } |
- return 1; // Failure. |
-} |
- |
- |
-uword Simulator::CompareExchange(uword* address, |
- uword compare_value, |
- uword new_value) { |
- // This lock is initialized in Simulator::InitOnce(). |
- MutexLocker ml(exclusive_access_lock_); |
- uword value = *address; |
- if (value == compare_value) { |
- *address = new_value; |
- // Same effect on exclusive access state as a successful STREX. |
- HasExclusiveAccessAndOpen(reinterpret_cast<uword>(address)); |
- } else { |
- // Same effect on exclusive access state as an LDREX. |
- SetExclusiveAccess(reinterpret_cast<uword>(address)); |
- } |
- return value; |
-} |
- |
- |
// Returns the top of the stack area to enable checking for stack pointer |
// validity. |
uword Simulator::StackTop() const { |
@@ -1597,18 +1509,20 @@ |
set_register(R3, icount_); |
set_register(IP, icount_); |
set_register(LR, icount_); |
- double zap_dvalue = static_cast<double>(icount_); |
- // Do not zap D0, as it may contain a float result. |
- for (int i = D1; i <= D7; i++) { |
- set_dregister(static_cast<DRegister>(i), zap_dvalue); |
+ if (TargetCPUFeatures::vfp_supported()) { |
+ double zap_dvalue = static_cast<double>(icount_); |
+ // Do not zap D0, as it may contain a float result. |
+ for (int i = D1; i <= D7; i++) { |
+ set_dregister(static_cast<DRegister>(i), zap_dvalue); |
+ } |
+ // The above loop also zaps overlapping registers S2-S15. |
+ // Registers D8-D15 (overlapping with S16-S31) are preserved. |
+#if defined(VFPv3_D32) |
+ for (int i = D16; i <= D31; i++) { |
+ set_dregister(static_cast<DRegister>(i), zap_dvalue); |
+ } |
+#endif |
} |
- // The above loop also zaps overlapping registers S2-S15. |
- // Registers D8-D15 (overlapping with S16-S31) are preserved. |
-#ifdef VFPv3_D32 |
- for (int i = D16; i <= D31; i++) { |
- set_dregister(static_cast<DRegister>(i), zap_dvalue); |
- } |
-#endif // VFPv3_D32 |
// Return. |
set_pc(saved_lr); |
@@ -1715,6 +1629,12 @@ |
} |
} else if (instr->IsMultiplyOrSyncPrimitive()) { |
if (instr->Bit(24) == 0) { |
+ if ((TargetCPUFeatures::arm_version() != ARMv7) && |
+ (instr->Bits(21, 3) != 0)) { |
+ // mla ... smlal only supported on armv7. |
+ UnimplementedInstruction(instr); |
+ return; |
+ } |
// multiply instructions. |
Register rn = instr->RnField(); |
Register rd = instr->RdField(); |
@@ -1820,49 +1740,25 @@ |
} |
} |
} else { |
- // synchronization primitives |
- Register rd = instr->RdField(); |
- Register rn = instr->RnField(); |
- uword addr = get_register(rn); |
- switch (instr->Bits(20, 4)) { |
- case 8: { |
- // Format(instr, "strex'cond 'rd, 'rm, ['rn]"); |
- if (IsIllegalAddress(addr)) { |
- HandleIllegalAccess(addr, instr); |
- } else { |
- Register rm = instr->RmField(); |
- set_register(rd, WriteExclusiveW(addr, get_register(rm), instr)); |
- } |
- break; |
- } |
- case 9: { |
- // Format(instr, "ldrex'cond 'rd, ['rn]"); |
- if (IsIllegalAddress(addr)) { |
- HandleIllegalAccess(addr, instr); |
- } else { |
- set_register(rd, ReadExclusiveW(addr, instr)); |
- } |
- break; |
- } |
- default: { |
- UnimplementedInstruction(instr); |
- break; |
- } |
- } |
+ UnimplementedInstruction(instr); |
} |
} else if (instr->Bit(25) == 1) { |
// 16-bit immediate loads, msr (immediate), and hints |
switch (instr->Bits(20, 5)) { |
case 16: |
case 20: { |
- uint16_t imm16 = instr->MovwField(); |
- Register rd = instr->RdField(); |
- if (instr->Bit(22) == 0) { |
- // Format(instr, "movw'cond 'rd, #'imm4_12"); |
- set_register(rd, imm16); |
+ if (TargetCPUFeatures::arm_version() == ARMv7) { |
+ uint16_t imm16 = instr->MovwField(); |
+ Register rd = instr->RdField(); |
+ if (instr->Bit(22) == 0) { |
+ // Format(instr, "movw'cond 'rd, #'imm4_12"); |
+ set_register(rd, imm16); |
+ } else { |
+ // Format(instr, "movt'cond 'rd, #'imm4_12"); |
+ set_register(rd, (get_register(rd) & 0xffff) | (imm16 << 16)); |
+ } |
} else { |
- // Format(instr, "movt'cond 'rd, #'imm4_12"); |
- set_register(rd, (get_register(rd) & 0xffff) | (imm16 << 16)); |
+ UnimplementedInstruction(instr); |
} |
break; |
} |
@@ -2304,11 +2200,15 @@ |
void Simulator::DoDivision(Instr* instr) { |
- ASSERT(TargetCPUFeatures::integer_division_supported()); |
- Register rd = instr->DivRdField(); |
- Register rn = instr->DivRnField(); |
- Register rm = instr->DivRmField(); |
+ const Register rd = instr->DivRdField(); |
+ const Register rn = instr->DivRnField(); |
+ const Register rm = instr->DivRmField(); |
+ if (!TargetCPUFeatures::integer_division_supported()) { |
+ UnimplementedInstruction(instr); |
+ return; |
+ } |
+ |
// ARMv7-a does not trap on divide-by-zero. The destination register is just |
// set to 0. |
if (get_register(rm) == 0) { |
@@ -3539,7 +3439,7 @@ |
if (instr->ConditionField() == kSpecialCondition) { |
if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) { |
// Format(instr, "clrex"); |
- ClearExclusive(); |
+ UnimplementedInstruction(instr); |
} else { |
if (instr->IsSIMDDataProcessing()) { |
DecodeSIMDDataProcessing(instr); |
@@ -3645,6 +3545,7 @@ |
// Setup parameters. |
if (fp_args) { |
+ ASSERT(TargetCPUFeatures::vfp_supported()); |
set_sregister(S0, bit_cast<float, int32_t>(parameter0)); |
set_sregister(S1, bit_cast<float, int32_t>(parameter1)); |
set_sregister(S2, bit_cast<float, int32_t>(parameter2)); |
@@ -3683,15 +3584,26 @@ |
int32_t r10_val = get_register(R10); |
int32_t r11_val = get_register(R11); |
- double d8_val = get_dregister(D8); |
- double d9_val = get_dregister(D9); |
- double d10_val = get_dregister(D10); |
- double d11_val = get_dregister(D11); |
- double d12_val = get_dregister(D12); |
- double d13_val = get_dregister(D13); |
- double d14_val = get_dregister(D14); |
- double d15_val = get_dregister(D15); |
+ double d8_val = 0.0; |
+ double d9_val = 0.0; |
+ double d10_val = 0.0; |
+ double d11_val = 0.0; |
+ double d12_val = 0.0; |
+ double d13_val = 0.0; |
+ double d14_val = 0.0; |
+ double d15_val = 0.0; |
+ if (TargetCPUFeatures::vfp_supported()) { |
+ d8_val = get_dregister(D8); |
+ d9_val = get_dregister(D9); |
+ d10_val = get_dregister(D10); |
+ d11_val = get_dregister(D11); |
+ d12_val = get_dregister(D12); |
+ d13_val = get_dregister(D13); |
+ d14_val = get_dregister(D14); |
+ d15_val = get_dregister(D15); |
+ } |
+ |
// Setup the callee-saved registers with a known value. To be able to check |
// that they are preserved properly across dart execution. |
int32_t callee_saved_value = icount_; |
@@ -3704,15 +3616,18 @@ |
set_register(R10, callee_saved_value); |
set_register(R11, callee_saved_value); |
- double callee_saved_dvalue = static_cast<double>(icount_); |
- set_dregister(D8, callee_saved_dvalue); |
- set_dregister(D9, callee_saved_dvalue); |
- set_dregister(D10, callee_saved_dvalue); |
- set_dregister(D11, callee_saved_dvalue); |
- set_dregister(D12, callee_saved_dvalue); |
- set_dregister(D13, callee_saved_dvalue); |
- set_dregister(D14, callee_saved_dvalue); |
- set_dregister(D15, callee_saved_dvalue); |
+ double callee_saved_dvalue = 0.0; |
+ if (TargetCPUFeatures::vfp_supported()) { |
+ callee_saved_dvalue = static_cast<double>(icount_); |
+ set_dregister(D8, callee_saved_dvalue); |
+ set_dregister(D9, callee_saved_dvalue); |
+ set_dregister(D10, callee_saved_dvalue); |
+ set_dregister(D11, callee_saved_dvalue); |
+ set_dregister(D12, callee_saved_dvalue); |
+ set_dregister(D13, callee_saved_dvalue); |
+ set_dregister(D14, callee_saved_dvalue); |
+ set_dregister(D15, callee_saved_dvalue); |
+ } |
// Start the simulation |
Execute(); |
@@ -3727,14 +3642,16 @@ |
ASSERT(callee_saved_value == get_register(R10)); |
ASSERT(callee_saved_value == get_register(R11)); |
- ASSERT(callee_saved_dvalue == get_dregister(D8)); |
- ASSERT(callee_saved_dvalue == get_dregister(D9)); |
- ASSERT(callee_saved_dvalue == get_dregister(D10)); |
- ASSERT(callee_saved_dvalue == get_dregister(D11)); |
- ASSERT(callee_saved_dvalue == get_dregister(D12)); |
- ASSERT(callee_saved_dvalue == get_dregister(D13)); |
- ASSERT(callee_saved_dvalue == get_dregister(D14)); |
- ASSERT(callee_saved_dvalue == get_dregister(D15)); |
+ if (TargetCPUFeatures::vfp_supported()) { |
+ ASSERT(callee_saved_dvalue == get_dregister(D8)); |
+ ASSERT(callee_saved_dvalue == get_dregister(D9)); |
+ ASSERT(callee_saved_dvalue == get_dregister(D10)); |
+ ASSERT(callee_saved_dvalue == get_dregister(D11)); |
+ ASSERT(callee_saved_dvalue == get_dregister(D12)); |
+ ASSERT(callee_saved_dvalue == get_dregister(D13)); |
+ ASSERT(callee_saved_dvalue == get_dregister(D14)); |
+ ASSERT(callee_saved_dvalue == get_dregister(D15)); |
+ } |
// Restore callee-saved registers with the original value. |
set_register(R4, r4_val); |
@@ -3746,19 +3663,22 @@ |
set_register(R10, r10_val); |
set_register(R11, r11_val); |
- set_dregister(D8, d8_val); |
- set_dregister(D9, d9_val); |
- set_dregister(D10, d10_val); |
- set_dregister(D11, d11_val); |
- set_dregister(D12, d12_val); |
- set_dregister(D13, d13_val); |
- set_dregister(D14, d14_val); |
- set_dregister(D15, d15_val); |
+ if (TargetCPUFeatures::vfp_supported()) { |
+ set_dregister(D8, d8_val); |
+ set_dregister(D9, d9_val); |
+ set_dregister(D10, d10_val); |
+ set_dregister(D11, d11_val); |
+ set_dregister(D12, d12_val); |
+ set_dregister(D13, d13_val); |
+ set_dregister(D14, d14_val); |
+ set_dregister(D15, d15_val); |
+ } |
// Restore the SP register and return R1:R0. |
set_register(SP, sp_before_call); |
int64_t return_value; |
if (fp_return) { |
+ ASSERT(TargetCPUFeatures::vfp_supported()); |
return_value = bit_cast<int64_t, double>(get_dregister(D0)); |
} else { |
return_value = Utils::LowHighTo64Bits(get_register(R0), get_register(R1)); |