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
This commit is contained in:
parent
c500e61966
commit
a692cf61a2
@ -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)
|
||||
|
@ -81,6 +81,9 @@ struct Jit::Impl {
|
||||
Atomic::Or(&jit_state.halt_reason, static_cast<u32>(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<u32, 16>& Jit::Regs() {
|
||||
return impl->jit_state.Reg;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -252,6 +252,9 @@ constexpr bool IsGPR(ARM64Reg reg) {
|
||||
constexpr ARM64Reg DecodeReg(ARM64Reg reg) {
|
||||
return static_cast<ARM64Reg>(reg & 0x1F);
|
||||
}
|
||||
constexpr ARM64Reg EncodeRegTo32(ARM64Reg reg) {
|
||||
return static_cast<ARM64Reg>(reg & 0x1F);
|
||||
}
|
||||
constexpr ARM64Reg EncodeRegTo64(ARM64Reg reg) {
|
||||
return static_cast<ARM64Reg>(reg | 0x20);
|
||||
}
|
||||
|
60
src/dynarmic/backend/A64/exclusive_monitor.cpp
Normal file
60
src/dynarmic/backend/A64/exclusive_monitor.cpp
Normal file
@ -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 <algorithm>
|
||||
|
||||
#include <mcl/assert.hpp>
|
||||
|
||||
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
|
28
src/dynarmic/backend/A64/exclusive_monitor_friend.h
Normal file
28
src/dynarmic/backend/A64/exclusive_monitor_friend.h
Normal file
@ -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
|
77
src/dynarmic/backend/A64/spin_lock_arm64.cpp
Normal file
77
src/dynarmic/backend/A64/spin_lock_arm64.cpp
Normal file
@ -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<void (*)(volatile int*)>(code.GetWritableCodePtr());
|
||||
EmitSpinLockLock(code, ABI_PARAM1, ARM64Reg::W8, ARM64Reg::W9);
|
||||
code.RET();
|
||||
|
||||
code.AlignCode16();
|
||||
unlock = reinterpret_cast<void (*)(volatile int*)>(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
|
13
src/dynarmic/backend/A64/spin_lock_arm64.h
Normal file
13
src/dynarmic/backend/A64/spin_lock_arm64.h
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user