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
@ -399,7 +399,7 @@ elseif(ARCHITECTURE STREQUAL "arm64")
|
|||||||
backend/A64/emit_a64_saturation.cpp
|
backend/A64/emit_a64_saturation.cpp
|
||||||
# backend/A64/emit_a64_sm4.cpp
|
# backend/A64/emit_a64_sm4.cpp
|
||||||
# backend/A64/emit_a64_vector.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/exception_handler.h
|
||||||
backend/A64/hostloc.cpp
|
backend/A64/hostloc.cpp
|
||||||
backend/A64/hostloc.h
|
backend/A64/hostloc.h
|
||||||
@ -409,6 +409,10 @@ elseif(ARCHITECTURE STREQUAL "arm64")
|
|||||||
backend/A64/perf_map.h
|
backend/A64/perf_map.h
|
||||||
backend/A64/reg_alloc.cpp
|
backend/A64/reg_alloc.cpp
|
||||||
backend/A64/reg_alloc.h
|
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)
|
if ("A32" IN_LIST DYNARMIC_FRONTENDS)
|
||||||
|
@ -81,6 +81,9 @@ struct Jit::Impl {
|
|||||||
Atomic::Or(&jit_state.halt_reason, static_cast<u32>(hr));
|
Atomic::Or(&jit_state.halt_reason, static_cast<u32>(hr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClearExclusiveState() {
|
||||||
|
jit_state.exclusive_state = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void PerformCacheInvalidation() {
|
void PerformCacheInvalidation() {
|
||||||
if (invalidate_entire_cache) {
|
if (invalidate_entire_cache) {
|
||||||
@ -207,6 +210,10 @@ void Jit::HaltExecution(HaltReason hr) {
|
|||||||
impl->HaltExecution(hr);
|
impl->HaltExecution(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Jit::ClearExclusiveState() {
|
||||||
|
impl->ClearExclusiveState();
|
||||||
|
}
|
||||||
|
|
||||||
std::array<u32, 16>& Jit::Regs() {
|
std::array<u32, 16>& Jit::Regs() {
|
||||||
return impl->jit_state.Reg;
|
return impl->jit_state.Reg;
|
||||||
}
|
}
|
||||||
|
@ -1532,6 +1532,7 @@ void ARM64XEmitter::STP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load/Store Exclusive
|
// 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) {
|
void ARM64XEmitter::STXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) {
|
||||||
EncodeLoadStoreExcInst(0, Rs, SP, Rt, Rn);
|
EncodeLoadStoreExcInst(0, Rs, SP, Rt, Rn);
|
||||||
}
|
}
|
||||||
@ -1569,7 +1570,7 @@ void ARM64XEmitter::LDARH(ARM64Reg Rt, ARM64Reg Rn) {
|
|||||||
EncodeLoadStoreExcInst(11, SP, SP, Rt, Rn);
|
EncodeLoadStoreExcInst(11, SP, SP, Rt, Rn);
|
||||||
}
|
}
|
||||||
void ARM64XEmitter::STXR(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg 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) {
|
void ARM64XEmitter::STLXR(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) {
|
||||||
EncodeLoadStoreExcInst(14 + Is64Bit(Rt), Rs, SP, Rt, 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);
|
EncodeLoadStoreExcInst(20 + Is64Bit(Rt), SP, SP, Rt, Rn);
|
||||||
}
|
}
|
||||||
void ARM64XEmitter::LDAXR(ARM64Reg Rt, ARM64Reg 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) {
|
void ARM64XEmitter::LDXP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn) {
|
||||||
EncodeLoadStoreExcInst(24 + Is64Bit(Rt), SP, Rt2, Rt, 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);
|
EncodeLoadStoreExcInst(26 + Is64Bit(Rt), SP, Rt2, Rt, Rn);
|
||||||
}
|
}
|
||||||
void ARM64XEmitter::STLR(ARM64Reg Rt, ARM64Reg 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) {
|
void ARM64XEmitter::LDAR(ARM64Reg Rt, ARM64Reg Rn) {
|
||||||
EncodeLoadStoreExcInst(30 + Is64Bit(Rt), SP, SP, Rt, Rn);
|
EncodeLoadStoreExcInst(30 + Is64Bit(Rt), SP, SP, Rt, Rn);
|
||||||
|
@ -252,6 +252,9 @@ constexpr bool IsGPR(ARM64Reg reg) {
|
|||||||
constexpr ARM64Reg DecodeReg(ARM64Reg reg) {
|
constexpr ARM64Reg DecodeReg(ARM64Reg reg) {
|
||||||
return static_cast<ARM64Reg>(reg & 0x1F);
|
return static_cast<ARM64Reg>(reg & 0x1F);
|
||||||
}
|
}
|
||||||
|
constexpr ARM64Reg EncodeRegTo32(ARM64Reg reg) {
|
||||||
|
return static_cast<ARM64Reg>(reg & 0x1F);
|
||||||
|
}
|
||||||
constexpr ARM64Reg EncodeRegTo64(ARM64Reg reg) {
|
constexpr ARM64Reg EncodeRegTo64(ARM64Reg reg) {
|
||||||
return static_cast<ARM64Reg>(reg | 0x20);
|
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