From a692cf61a2784e79455ac47f76ba2f3fcce93037 Mon Sep 17 00:00:00 2001 From: SachinVin Date: Sat, 18 Jun 2022 19:00:50 +0530 Subject: [PATCH] Backend/A64: Partial global exclusive monitor fix spinlocks on arm64 backend A64: no xbyak spin_lock_arm64 fixes simplify spin_lock_arm64 a64_emitter.cpp: fix some exclusive load/store codegen spin lcok clang format --- src/dynarmic/CMakeLists.txt | 6 +- src/dynarmic/backend/A64/a32_interface.cpp | 7 ++ .../backend/A64/emitter/a64_emitter.cpp | 7 +- .../backend/A64/emitter/a64_emitter.h | 3 + .../backend/A64/exclusive_monitor.cpp | 60 +++++++++++++++ .../backend/A64/exclusive_monitor_friend.h | 28 +++++++ src/dynarmic/backend/A64/spin_lock_arm64.cpp | 77 +++++++++++++++++++ src/dynarmic/backend/A64/spin_lock_arm64.h | 13 ++++ 8 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 src/dynarmic/backend/A64/exclusive_monitor.cpp create mode 100644 src/dynarmic/backend/A64/exclusive_monitor_friend.h create mode 100644 src/dynarmic/backend/A64/spin_lock_arm64.cpp create mode 100644 src/dynarmic/backend/A64/spin_lock_arm64.h diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index 6dd194cf..e9a6539b 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -399,7 +399,7 @@ elseif(ARCHITECTURE STREQUAL "arm64") backend/A64/emit_a64_saturation.cpp # backend/A64/emit_a64_sm4.cpp # backend/A64/emit_a64_vector.cpp - # backend/A64/emit_a64_vector_floating_point.cpp + # backend/A64/emit_a64_vector_floating_point.cpp backend/A64/exception_handler.h backend/A64/hostloc.cpp backend/A64/hostloc.h @@ -409,6 +409,10 @@ elseif(ARCHITECTURE STREQUAL "arm64") backend/A64/perf_map.h backend/A64/reg_alloc.cpp backend/A64/reg_alloc.h + backend/A64/exclusive_monitor.cpp + backend/A64/exclusive_monitor_friend.h + backend/A64/spin_lock_arm64.h + backend/A64/spin_lock_arm64.cpp ) if ("A32" IN_LIST DYNARMIC_FRONTENDS) diff --git a/src/dynarmic/backend/A64/a32_interface.cpp b/src/dynarmic/backend/A64/a32_interface.cpp index eb10200a..740f4106 100644 --- a/src/dynarmic/backend/A64/a32_interface.cpp +++ b/src/dynarmic/backend/A64/a32_interface.cpp @@ -81,6 +81,9 @@ struct Jit::Impl { Atomic::Or(&jit_state.halt_reason, static_cast(hr)); } + void ClearExclusiveState() { + jit_state.exclusive_state = 0; + } void PerformCacheInvalidation() { if (invalidate_entire_cache) { @@ -207,6 +210,10 @@ void Jit::HaltExecution(HaltReason hr) { impl->HaltExecution(hr); } +void Jit::ClearExclusiveState() { + impl->ClearExclusiveState(); +} + std::array& Jit::Regs() { return impl->jit_state.Reg; } diff --git a/src/dynarmic/backend/A64/emitter/a64_emitter.cpp b/src/dynarmic/backend/A64/emitter/a64_emitter.cpp index 7a68e653..98f62401 100644 --- a/src/dynarmic/backend/A64/emitter/a64_emitter.cpp +++ b/src/dynarmic/backend/A64/emitter/a64_emitter.cpp @@ -1532,6 +1532,7 @@ void ARM64XEmitter::STP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, } // Load/Store Exclusive +// FIXME: most of these have swapped Rt and Rn which produces incorrect code gen void ARM64XEmitter::STXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) { EncodeLoadStoreExcInst(0, Rs, SP, Rt, Rn); } @@ -1569,7 +1570,7 @@ void ARM64XEmitter::LDARH(ARM64Reg Rt, ARM64Reg Rn) { EncodeLoadStoreExcInst(11, SP, SP, Rt, Rn); } void ARM64XEmitter::STXR(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(12 + Is64Bit(Rt), Rs, SP, Rt, Rn); + EncodeLoadStoreExcInst(12 + Is64Bit(Rt), Rs, SP, Rn, Rt); } void ARM64XEmitter::STLXR(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) { EncodeLoadStoreExcInst(14 + Is64Bit(Rt), Rs, SP, Rt, Rn); @@ -1584,7 +1585,7 @@ void ARM64XEmitter::LDXR(ARM64Reg Rt, ARM64Reg Rn) { EncodeLoadStoreExcInst(20 + Is64Bit(Rt), SP, SP, Rt, Rn); } void ARM64XEmitter::LDAXR(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(22 + Is64Bit(Rt), SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(22 + Is64Bit(Rt), SP, SP, Rn, Rt); } void ARM64XEmitter::LDXP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn) { EncodeLoadStoreExcInst(24 + Is64Bit(Rt), SP, Rt2, Rt, Rn); @@ -1593,7 +1594,7 @@ void ARM64XEmitter::LDAXP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn) { EncodeLoadStoreExcInst(26 + Is64Bit(Rt), SP, Rt2, Rt, Rn); } void ARM64XEmitter::STLR(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(28 + Is64Bit(Rt), SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(28 + Is64Bit(Rt), SP, SP, Rn, Rt); } void ARM64XEmitter::LDAR(ARM64Reg Rt, ARM64Reg Rn) { EncodeLoadStoreExcInst(30 + Is64Bit(Rt), SP, SP, Rt, Rn); diff --git a/src/dynarmic/backend/A64/emitter/a64_emitter.h b/src/dynarmic/backend/A64/emitter/a64_emitter.h index 53347c4a..97e0a506 100644 --- a/src/dynarmic/backend/A64/emitter/a64_emitter.h +++ b/src/dynarmic/backend/A64/emitter/a64_emitter.h @@ -252,6 +252,9 @@ constexpr bool IsGPR(ARM64Reg reg) { constexpr ARM64Reg DecodeReg(ARM64Reg reg) { return static_cast(reg & 0x1F); } +constexpr ARM64Reg EncodeRegTo32(ARM64Reg reg) { + return static_cast(reg & 0x1F); +} constexpr ARM64Reg EncodeRegTo64(ARM64Reg reg) { return static_cast(reg | 0x20); } diff --git a/src/dynarmic/backend/A64/exclusive_monitor.cpp b/src/dynarmic/backend/A64/exclusive_monitor.cpp new file mode 100644 index 00000000..68ce912c --- /dev/null +++ b/src/dynarmic/backend/A64/exclusive_monitor.cpp @@ -0,0 +1,60 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#include "dynarmic/interface/exclusive_monitor.h" + +#include + +#include + +namespace Dynarmic { + +ExclusiveMonitor::ExclusiveMonitor(size_t processor_count) + : exclusive_addresses(processor_count, INVALID_EXCLUSIVE_ADDRESS), exclusive_values(processor_count) { + Unlock(); +} + +size_t ExclusiveMonitor::GetProcessorCount() const { + return exclusive_addresses.size(); +} + +void ExclusiveMonitor::Lock() { + lock.Lock(); +} + +void ExclusiveMonitor::Unlock() { + lock.Unlock(); +} + +bool ExclusiveMonitor::CheckAndClear(size_t processor_id, VAddr address) { + const VAddr masked_address = address & RESERVATION_GRANULE_MASK; + + Lock(); + if (exclusive_addresses[processor_id] != masked_address) { + Unlock(); + return false; + } + + for (VAddr& other_address : exclusive_addresses) { + if (other_address == masked_address) { + other_address = INVALID_EXCLUSIVE_ADDRESS; + } + } + return true; +} + +void ExclusiveMonitor::Clear() { + Lock(); + std::fill(exclusive_addresses.begin(), exclusive_addresses.end(), INVALID_EXCLUSIVE_ADDRESS); + Unlock(); +} + +void ExclusiveMonitor::ClearProcessor(size_t processor_id) { + Lock(); + exclusive_addresses[processor_id] = INVALID_EXCLUSIVE_ADDRESS; + Unlock(); +} + +} // namespace Dynarmic diff --git a/src/dynarmic/backend/A64/exclusive_monitor_friend.h b/src/dynarmic/backend/A64/exclusive_monitor_friend.h new file mode 100644 index 00000000..7f7fa242 --- /dev/null +++ b/src/dynarmic/backend/A64/exclusive_monitor_friend.h @@ -0,0 +1,28 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2022 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#pragma once + +#include "dynarmic/interface/exclusive_monitor.h" + +namespace Dynarmic { + +inline volatile int* GetExclusiveMonitorLockPointer(ExclusiveMonitor* monitor) { + return &monitor->lock.storage; +} + +inline size_t GetExclusiveMonitorProcessorCount(ExclusiveMonitor* monitor) { + return monitor->exclusive_addresses.size(); +} + +inline VAddr* GetExclusiveMonitorAddressPointer(ExclusiveMonitor* monitor, size_t index) { + return monitor->exclusive_addresses.data() + index; +} + +inline Vector* GetExclusiveMonitorValuePointer(ExclusiveMonitor* monitor, size_t index) { + return monitor->exclusive_values.data() + index; +} + +} // namespace Dynarmic diff --git a/src/dynarmic/backend/A64/spin_lock_arm64.cpp b/src/dynarmic/backend/A64/spin_lock_arm64.cpp new file mode 100644 index 00000000..e0e9e73d --- /dev/null +++ b/src/dynarmic/backend/A64/spin_lock_arm64.cpp @@ -0,0 +1,77 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2022 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#include "dynarmic/backend/A64/abi.h" +#include "dynarmic/backend/A64/emitter/a64_emitter.h" +#include "dynarmic/backend/A64/hostloc.h" +#include "dynarmic/common/spin_lock.h" + +namespace Dynarmic { + +using BackendA64::Arm64Gen::ARM64CodeBlock; +using BackendA64::Arm64Gen::ARM64Reg; + +void EmitSpinLockLock(ARM64CodeBlock& code, ARM64Reg ptr, ARM64Reg tmp1, ARM64Reg tmp2) { + BackendA64::Arm64Gen::FixupBranch start; + const u8* loop; + + ARM64Reg tmp1_32 = BackendA64::Arm64Gen::EncodeRegTo32(tmp1); + ARM64Reg tmp2_32 = BackendA64::Arm64Gen::EncodeRegTo32(tmp2); + + // Adapted from arm reference manual impl + code.MOVI2R(tmp1_32, 1); + code.HINT(BackendA64::Arm64Gen::HINT_SEVL); + start0 = code.B(); + loop = code.GetCodePtr(); + code.HINT(BackendA64::Arm64Gen::HINT_WFE); + code.SetJumpTarget(start); + code.LDAXR(tmp2_32, ptr); + code.CBNZ(tmp2_32, loop); + code.STXR(tmp2_32, tmp1_32, ptr); + code.CBNZ(tmp2_32, loop); +} + +void EmitSpinLockUnlock(ARM64CodeBlock& code, ARM64Reg ptr, ARM64Reg tmp) { + code.STLR(ARM64Reg::WZR, ptr); +} + +namespace { + +struct SpinLockImpl { + SpinLockImpl(); + + ARM64CodeBlock code; + void (*lock)(volatile int*); + void (*unlock)(volatile int*); +}; + +SpinLockImpl impl; + +SpinLockImpl::SpinLockImpl() { + code.AllocCodeSpace(64); + const ARM64Reg ABI_PARAM1 = BackendA64::HostLocToReg64(BackendA64::ABI_PARAM1); + code.AlignCode16(); + lock = reinterpret_cast(code.GetWritableCodePtr()); + EmitSpinLockLock(code, ABI_PARAM1, ARM64Reg::W8, ARM64Reg::W9); + code.RET(); + + code.AlignCode16(); + unlock = reinterpret_cast(code.GetWritableCodePtr()); + EmitSpinLockUnlock(code, ABI_PARAM1, ARM64Reg::W8); + code.RET(); + code.FlushIcache(); +} + +} // namespace + +void SpinLock::Lock() { + impl.lock(&storage); +} + +void SpinLock::Unlock() { + impl.unlock(&storage); +} + +} // namespace Dynarmic diff --git a/src/dynarmic/backend/A64/spin_lock_arm64.h b/src/dynarmic/backend/A64/spin_lock_arm64.h new file mode 100644 index 00000000..f08bc18b --- /dev/null +++ b/src/dynarmic/backend/A64/spin_lock_arm64.h @@ -0,0 +1,13 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2022 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#pragma once + +namespace Dynarmic { + +void EmitSpinLockLock(BackendA64::Arm64Gen::ARM64CodeBlock& code, BackendA64::Arm64Gen::ARM64Reg ptr, BackendA64::Arm64Gen::ARM64Reg tmp1, BackendA64::Arm64Gen::ARM64Reg tmp2); +void EmitSpinLockUnlock(BackendA64::Arm64Gen::ARM64CodeBlock& code, BackendA64::Arm64Gen::ARM64Reg ptr, BackendA64::Arm64Gen::ARM64Reg tmp); + +} // namespace Dynarmic