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:
SachinVin 2022-06-18 19:00:50 +05:30
parent c500e61966
commit a692cf61a2
8 changed files with 197 additions and 4 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View 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

View 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

View 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

View 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