address_space: Deduplicate {A32,A64}AddressSpace
This commit is contained in:
parent
0707aa3a04
commit
8f9d1dbf4e
7 changed files with 327 additions and 496 deletions
|
@ -373,6 +373,8 @@ elseif(ARCHITECTURE STREQUAL "arm64")
|
|||
backend/arm64/a32_jitstate.h
|
||||
backend/arm64/abi.cpp
|
||||
backend/arm64/abi.h
|
||||
backend/arm64/address_space.cpp
|
||||
backend/arm64/address_space.h
|
||||
backend/arm64/devirtualize.h
|
||||
backend/arm64/emit_arm64.cpp
|
||||
backend/arm64/emit_arm64.h
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "dynarmic/common/fp/fpcr.h"
|
||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
#include "dynarmic/interface/exclusive_monitor.h"
|
||||
#include "dynarmic/ir/opt/passes.h"
|
||||
|
||||
|
@ -97,9 +98,8 @@ static void* EmitExclusiveWriteCallTrampoline(oaknut::CodeGenerator& code, const
|
|||
}
|
||||
|
||||
A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf)
|
||||
: conf(conf)
|
||||
, mem(conf.code_cache_size)
|
||||
, code(mem.ptr()) {
|
||||
: AddressSpace(conf.code_cache_size)
|
||||
, conf(conf) {
|
||||
EmitPrelude();
|
||||
}
|
||||
|
||||
|
@ -121,33 +121,6 @@ IR::Block A32AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const {
|
|||
return ir_block;
|
||||
}
|
||||
|
||||
CodePtr A32AddressSpace::Get(IR::LocationDescriptor descriptor) {
|
||||
if (const auto iter = block_entries.find(descriptor.Value()); iter != block_entries.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CodePtr A32AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) {
|
||||
if (CodePtr block_entry = Get(descriptor)) {
|
||||
return block_entry;
|
||||
}
|
||||
|
||||
IR::Block ir_block = GenerateIR(descriptor);
|
||||
const EmittedBlockInfo block_info = Emit(std::move(ir_block));
|
||||
|
||||
block_infos.insert_or_assign(descriptor.Value(), block_info);
|
||||
block_entries.insert_or_assign(descriptor.Value(), block_info.entry_point);
|
||||
return block_info.entry_point;
|
||||
}
|
||||
|
||||
void A32AddressSpace::ClearCache() {
|
||||
block_entries.clear();
|
||||
block_infos.clear();
|
||||
block_references.clear();
|
||||
code.set_ptr(prelude_info.end_of_prelude);
|
||||
}
|
||||
|
||||
void A32AddressSpace::EmitPrelude() {
|
||||
using namespace oaknut::util;
|
||||
|
||||
|
@ -291,18 +264,8 @@ void A32AddressSpace::EmitPrelude() {
|
|||
mem.protect();
|
||||
}
|
||||
|
||||
size_t A32AddressSpace::GetRemainingSize() {
|
||||
return conf.code_cache_size - (code.ptr<CodePtr>() - reinterpret_cast<CodePtr>(mem.ptr()));
|
||||
}
|
||||
|
||||
EmittedBlockInfo A32AddressSpace::Emit(IR::Block block) {
|
||||
if (GetRemainingSize() < 1024 * 1024) {
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
mem.unprotect();
|
||||
|
||||
const EmitConfig emit_conf{
|
||||
EmitConfig A32AddressSpace::GetEmitConfig() {
|
||||
return EmitConfig{
|
||||
.optimizations = conf.unsafe_optimizations ? conf.optimizations : conf.optimizations & all_safe_optimizations,
|
||||
|
||||
.hook_isb = conf.hook_isb,
|
||||
|
@ -328,132 +291,6 @@ EmittedBlockInfo A32AddressSpace::Emit(IR::Block block) {
|
|||
|
||||
.coprocessors = conf.coprocessors,
|
||||
};
|
||||
EmittedBlockInfo block_info = EmitArm64(code, std::move(block), emit_conf);
|
||||
|
||||
Link(block.Location(), block_info);
|
||||
|
||||
mem.invalidate(reinterpret_cast<u32*>(block_info.entry_point), block_info.size);
|
||||
|
||||
RelinkForDescriptor(block.Location());
|
||||
|
||||
mem.protect();
|
||||
|
||||
return block_info;
|
||||
}
|
||||
|
||||
static void LinkBlockLinks(const CodePtr entry_point, const CodePtr target_ptr, const std::vector<BlockRelocation>& block_relocations_list) {
|
||||
using namespace oaknut;
|
||||
using namespace oaknut::util;
|
||||
|
||||
for (auto [ptr_offset] : block_relocations_list) {
|
||||
CodeGenerator c{reinterpret_cast<u32*>(entry_point + ptr_offset)};
|
||||
|
||||
if (target_ptr) {
|
||||
c.B((void*)target_ptr);
|
||||
} else {
|
||||
c.NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void A32AddressSpace::Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block_info) {
|
||||
using namespace oaknut;
|
||||
using namespace oaknut::util;
|
||||
|
||||
for (auto [ptr_offset, target] : block_info.relocations) {
|
||||
CodeGenerator c{reinterpret_cast<u32*>(block_info.entry_point + ptr_offset)};
|
||||
|
||||
switch (target) {
|
||||
case LinkTarget::ReturnToDispatcher:
|
||||
c.B(prelude_info.return_to_dispatcher);
|
||||
break;
|
||||
case LinkTarget::ReturnFromRunCode:
|
||||
c.B(prelude_info.return_from_run_code);
|
||||
break;
|
||||
case LinkTarget::ReadMemory8:
|
||||
c.BL(prelude_info.read_memory_8);
|
||||
break;
|
||||
case LinkTarget::ReadMemory16:
|
||||
c.BL(prelude_info.read_memory_16);
|
||||
break;
|
||||
case LinkTarget::ReadMemory32:
|
||||
c.BL(prelude_info.read_memory_32);
|
||||
break;
|
||||
case LinkTarget::ReadMemory64:
|
||||
c.BL(prelude_info.read_memory_64);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory8:
|
||||
c.BL(prelude_info.exclusive_read_memory_8);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory16:
|
||||
c.BL(prelude_info.exclusive_read_memory_16);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory32:
|
||||
c.BL(prelude_info.exclusive_read_memory_32);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory64:
|
||||
c.BL(prelude_info.exclusive_read_memory_64);
|
||||
break;
|
||||
case LinkTarget::WriteMemory8:
|
||||
c.BL(prelude_info.write_memory_8);
|
||||
break;
|
||||
case LinkTarget::WriteMemory16:
|
||||
c.BL(prelude_info.write_memory_16);
|
||||
break;
|
||||
case LinkTarget::WriteMemory32:
|
||||
c.BL(prelude_info.write_memory_32);
|
||||
break;
|
||||
case LinkTarget::WriteMemory64:
|
||||
c.BL(prelude_info.write_memory_64);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory8:
|
||||
c.BL(prelude_info.exclusive_write_memory_8);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory16:
|
||||
c.BL(prelude_info.exclusive_write_memory_16);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory32:
|
||||
c.BL(prelude_info.exclusive_write_memory_32);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory64:
|
||||
c.BL(prelude_info.exclusive_write_memory_64);
|
||||
break;
|
||||
case LinkTarget::CallSVC:
|
||||
c.BL(prelude_info.call_svc);
|
||||
break;
|
||||
case LinkTarget::ExceptionRaised:
|
||||
c.BL(prelude_info.exception_raised);
|
||||
break;
|
||||
case LinkTarget::InstructionSynchronizationBarrierRaised:
|
||||
c.BL(prelude_info.isb_raised);
|
||||
break;
|
||||
case LinkTarget::AddTicks:
|
||||
c.BL(prelude_info.add_ticks);
|
||||
break;
|
||||
case LinkTarget::GetTicksRemaining:
|
||||
c.BL(prelude_info.get_ticks_remaining);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid relocation target");
|
||||
}
|
||||
}
|
||||
|
||||
for (auto [target_descriptor, list] : block_info.block_relocations) {
|
||||
block_references[target_descriptor.Value()].emplace(block_descriptor.Value());
|
||||
LinkBlockLinks(block_info.entry_point, Get(target_descriptor), list);
|
||||
}
|
||||
}
|
||||
|
||||
void A32AddressSpace::RelinkForDescriptor(IR::LocationDescriptor target_descriptor) {
|
||||
for (auto block_descriptor : block_references[target_descriptor.Value()]) {
|
||||
if (auto iter = block_infos.find(block_descriptor); iter != block_infos.end()) {
|
||||
const EmittedBlockInfo& block_info = iter->second;
|
||||
|
||||
LinkBlockLinks(block_info.entry_point, Get(target_descriptor), block_infos[block_descriptor].block_relocations[target_descriptor]);
|
||||
|
||||
mem.invalidate(reinterpret_cast<u32*>(block_info.entry_point), block_info.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::Backend::Arm64
|
||||
|
|
|
@ -5,84 +5,24 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <mcl/stdint.hpp>
|
||||
#include <oaknut/code_block.hpp>
|
||||
#include <oaknut/oaknut.hpp>
|
||||
#include <tsl/robin_map.h>
|
||||
#include <tsl/robin_set.h>
|
||||
|
||||
#include "dynarmic/backend/arm64/emit_arm64.h"
|
||||
#include "dynarmic/backend/arm64/address_space.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
#include "dynarmic/interface/halt_reason.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/location_descriptor.h"
|
||||
|
||||
namespace Dynarmic::Backend::Arm64 {
|
||||
|
||||
struct A32JitState;
|
||||
|
||||
class A32AddressSpace final {
|
||||
class A32AddressSpace final : public AddressSpace {
|
||||
public:
|
||||
explicit A32AddressSpace(const A32::UserConfig& conf);
|
||||
|
||||
IR::Block GenerateIR(IR::LocationDescriptor) const;
|
||||
IR::Block GenerateIR(IR::LocationDescriptor) const override;
|
||||
|
||||
CodePtr Get(IR::LocationDescriptor descriptor);
|
||||
|
||||
CodePtr GetOrEmit(IR::LocationDescriptor descriptor);
|
||||
|
||||
void ClearCache();
|
||||
|
||||
private:
|
||||
protected:
|
||||
friend class A32Core;
|
||||
|
||||
void EmitPrelude();
|
||||
|
||||
size_t GetRemainingSize();
|
||||
EmittedBlockInfo Emit(IR::Block ir_block);
|
||||
void Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block);
|
||||
void RelinkForDescriptor(IR::LocationDescriptor target_descriptor);
|
||||
EmitConfig GetEmitConfig() override;
|
||||
|
||||
const A32::UserConfig conf;
|
||||
|
||||
oaknut::CodeBlock mem;
|
||||
oaknut::CodeGenerator code;
|
||||
|
||||
tsl::robin_map<u64, CodePtr> block_entries;
|
||||
tsl::robin_map<u64, EmittedBlockInfo> block_infos;
|
||||
tsl::robin_map<u64, tsl::robin_set<u64>> block_references;
|
||||
|
||||
struct PreludeInfo {
|
||||
u32* end_of_prelude;
|
||||
|
||||
using RunCodeFuncType = HaltReason (*)(CodePtr entry_point, A32JitState* context, volatile u32* halt_reason);
|
||||
RunCodeFuncType run_code;
|
||||
RunCodeFuncType step_code;
|
||||
void* return_to_dispatcher;
|
||||
void* return_from_run_code;
|
||||
|
||||
void* read_memory_8;
|
||||
void* read_memory_16;
|
||||
void* read_memory_32;
|
||||
void* read_memory_64;
|
||||
void* exclusive_read_memory_8;
|
||||
void* exclusive_read_memory_16;
|
||||
void* exclusive_read_memory_32;
|
||||
void* exclusive_read_memory_64;
|
||||
void* write_memory_8;
|
||||
void* write_memory_16;
|
||||
void* write_memory_32;
|
||||
void* write_memory_64;
|
||||
void* exclusive_write_memory_8;
|
||||
void* exclusive_write_memory_16;
|
||||
void* exclusive_write_memory_32;
|
||||
void* exclusive_write_memory_64;
|
||||
void* call_svc;
|
||||
void* exception_raised;
|
||||
void* isb_raised;
|
||||
void* add_ticks;
|
||||
void* get_ticks_remaining;
|
||||
} prelude_info;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::Backend::Arm64
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "dynarmic/common/fp/fpcr.h"
|
||||
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
|
||||
#include "dynarmic/frontend/A64/translate/a64_translate.h"
|
||||
#include "dynarmic/interface/A64/config.h"
|
||||
#include "dynarmic/interface/exclusive_monitor.h"
|
||||
#include "dynarmic/ir/opt/passes.h"
|
||||
|
||||
|
@ -96,8 +97,6 @@ static void* EmitExclusiveWriteCallTrampoline(oaknut::CodeGenerator& code, const
|
|||
return target;
|
||||
}
|
||||
|
||||
/* =========================== 128-bit versions =========================== */
|
||||
|
||||
static void* EmitRead128CallTrampoline(oaknut::CodeGenerator& code, A64::UserCallbacks* this_) {
|
||||
using namespace oaknut::util;
|
||||
|
||||
|
@ -214,9 +213,8 @@ static void* EmitExclusiveWrite128CallTrampoline(oaknut::CodeGenerator& code, co
|
|||
}
|
||||
|
||||
A64AddressSpace::A64AddressSpace(const A64::UserConfig& conf)
|
||||
: conf(conf)
|
||||
, mem(conf.code_cache_size)
|
||||
, code(mem.ptr()) {
|
||||
: AddressSpace(conf.code_cache_size)
|
||||
, conf(conf) {
|
||||
EmitPrelude();
|
||||
}
|
||||
|
||||
|
@ -242,33 +240,6 @@ IR::Block A64AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const {
|
|||
return ir_block;
|
||||
}
|
||||
|
||||
CodePtr A64AddressSpace::Get(IR::LocationDescriptor descriptor) {
|
||||
if (const auto iter = block_entries.find(descriptor.Value()); iter != block_entries.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CodePtr A64AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) {
|
||||
if (CodePtr block_entry = Get(descriptor)) {
|
||||
return block_entry;
|
||||
}
|
||||
|
||||
IR::Block ir_block = GenerateIR(descriptor);
|
||||
const EmittedBlockInfo block_info = Emit(std::move(ir_block));
|
||||
|
||||
block_infos.insert_or_assign(descriptor.Value(), block_info);
|
||||
block_entries.insert_or_assign(descriptor.Value(), block_info.entry_point);
|
||||
return block_info.entry_point;
|
||||
}
|
||||
|
||||
void A64AddressSpace::ClearCache() {
|
||||
block_entries.clear();
|
||||
block_infos.clear();
|
||||
block_references.clear();
|
||||
code.set_ptr(prelude_info.end_of_prelude);
|
||||
}
|
||||
|
||||
void A64AddressSpace::EmitPrelude() {
|
||||
using namespace oaknut::util;
|
||||
|
||||
|
@ -421,18 +392,8 @@ void A64AddressSpace::EmitPrelude() {
|
|||
mem.protect();
|
||||
}
|
||||
|
||||
size_t A64AddressSpace::GetRemainingSize() {
|
||||
return conf.code_cache_size - (code.ptr<CodePtr>() - reinterpret_cast<CodePtr>(mem.ptr()));
|
||||
}
|
||||
|
||||
EmittedBlockInfo A64AddressSpace::Emit(IR::Block block) {
|
||||
if (GetRemainingSize() < 1024 * 1024) {
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
mem.unprotect();
|
||||
|
||||
const EmitConfig emit_conf{
|
||||
EmitConfig A64AddressSpace::GetEmitConfig() {
|
||||
return EmitConfig{
|
||||
.optimizations = conf.unsafe_optimizations ? conf.optimizations : conf.optimizations & all_safe_optimizations,
|
||||
|
||||
.hook_isb = conf.hook_isb,
|
||||
|
@ -458,153 +419,6 @@ EmittedBlockInfo A64AddressSpace::Emit(IR::Block block) {
|
|||
|
||||
.coprocessors{},
|
||||
};
|
||||
EmittedBlockInfo block_info = EmitArm64(code, std::move(block), emit_conf);
|
||||
|
||||
Link(block.Location(), block_info);
|
||||
|
||||
mem.invalidate(reinterpret_cast<u32*>(block_info.entry_point), block_info.size);
|
||||
|
||||
RelinkForDescriptor(block.Location());
|
||||
|
||||
mem.protect();
|
||||
|
||||
return block_info;
|
||||
}
|
||||
|
||||
static void LinkBlockLinks(const CodePtr entry_point, const CodePtr target_ptr, const std::vector<BlockRelocation>& block_relocations_list) {
|
||||
using namespace oaknut;
|
||||
using namespace oaknut::util;
|
||||
|
||||
for (auto [ptr_offset] : block_relocations_list) {
|
||||
CodeGenerator c{reinterpret_cast<u32*>(entry_point + ptr_offset)};
|
||||
|
||||
if (target_ptr) {
|
||||
c.B((void*)target_ptr);
|
||||
} else {
|
||||
c.NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void A64AddressSpace::Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block_info) {
|
||||
using namespace oaknut;
|
||||
using namespace oaknut::util;
|
||||
|
||||
for (auto [ptr_offset, target] : block_info.relocations) {
|
||||
CodeGenerator c{reinterpret_cast<u32*>(block_info.entry_point + ptr_offset)};
|
||||
|
||||
switch (target) {
|
||||
case LinkTarget::ReturnToDispatcher:
|
||||
c.B(prelude_info.return_to_dispatcher);
|
||||
break;
|
||||
case LinkTarget::ReturnFromRunCode:
|
||||
c.B(prelude_info.return_from_run_code);
|
||||
break;
|
||||
case LinkTarget::ReadMemory8:
|
||||
c.BL(prelude_info.read_memory_8);
|
||||
break;
|
||||
case LinkTarget::ReadMemory16:
|
||||
c.BL(prelude_info.read_memory_16);
|
||||
break;
|
||||
case LinkTarget::ReadMemory32:
|
||||
c.BL(prelude_info.read_memory_32);
|
||||
break;
|
||||
case LinkTarget::ReadMemory64:
|
||||
c.BL(prelude_info.read_memory_64);
|
||||
break;
|
||||
case LinkTarget::ReadMemory128:
|
||||
c.BL(prelude_info.read_memory_128);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory8:
|
||||
c.BL(prelude_info.exclusive_read_memory_8);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory16:
|
||||
c.BL(prelude_info.exclusive_read_memory_16);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory32:
|
||||
c.BL(prelude_info.exclusive_read_memory_32);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory64:
|
||||
c.BL(prelude_info.exclusive_read_memory_64);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory128:
|
||||
c.BL(prelude_info.exclusive_read_memory_128);
|
||||
break;
|
||||
case LinkTarget::WriteMemory8:
|
||||
c.BL(prelude_info.write_memory_8);
|
||||
break;
|
||||
case LinkTarget::WriteMemory16:
|
||||
c.BL(prelude_info.write_memory_16);
|
||||
break;
|
||||
case LinkTarget::WriteMemory32:
|
||||
c.BL(prelude_info.write_memory_32);
|
||||
break;
|
||||
case LinkTarget::WriteMemory64:
|
||||
c.BL(prelude_info.write_memory_64);
|
||||
break;
|
||||
case LinkTarget::WriteMemory128:
|
||||
c.BL(prelude_info.write_memory_128);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory8:
|
||||
c.BL(prelude_info.exclusive_write_memory_8);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory16:
|
||||
c.BL(prelude_info.exclusive_write_memory_16);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory32:
|
||||
c.BL(prelude_info.exclusive_write_memory_32);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory64:
|
||||
c.BL(prelude_info.exclusive_write_memory_64);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory128:
|
||||
c.BL(prelude_info.exclusive_write_memory_128);
|
||||
break;
|
||||
case LinkTarget::CallSVC:
|
||||
c.BL(prelude_info.call_svc);
|
||||
break;
|
||||
case LinkTarget::ExceptionRaised:
|
||||
c.BL(prelude_info.exception_raised);
|
||||
break;
|
||||
case LinkTarget::InstructionSynchronizationBarrierRaised:
|
||||
c.BL(prelude_info.isb_raised);
|
||||
break;
|
||||
case LinkTarget::InstructionCacheOperationRaised:
|
||||
c.BL(prelude_info.ic_raised);
|
||||
break;
|
||||
case LinkTarget::DataCacheOperationRaised:
|
||||
c.BL(prelude_info.dc_raised);
|
||||
break;
|
||||
case LinkTarget::GetCNTPCT:
|
||||
c.BL(prelude_info.get_cntpct);
|
||||
break;
|
||||
case LinkTarget::AddTicks:
|
||||
c.BL(prelude_info.add_ticks);
|
||||
break;
|
||||
case LinkTarget::GetTicksRemaining:
|
||||
c.BL(prelude_info.get_ticks_remaining);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid relocation target");
|
||||
}
|
||||
}
|
||||
|
||||
for (auto [target_descriptor, list] : block_info.block_relocations) {
|
||||
block_references[target_descriptor.Value()].emplace(block_descriptor.Value());
|
||||
LinkBlockLinks(block_info.entry_point, Get(target_descriptor), list);
|
||||
}
|
||||
}
|
||||
|
||||
void A64AddressSpace::RelinkForDescriptor(IR::LocationDescriptor target_descriptor) {
|
||||
for (auto block_descriptor : block_references[target_descriptor.Value()]) {
|
||||
if (auto iter = block_infos.find(block_descriptor); iter != block_infos.end()) {
|
||||
const EmittedBlockInfo& block_info = iter->second;
|
||||
|
||||
LinkBlockLinks(block_info.entry_point, Get(target_descriptor), block_infos[block_descriptor].block_relocations[target_descriptor]);
|
||||
|
||||
mem.invalidate(reinterpret_cast<u32*>(block_info.entry_point), block_info.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::Backend::Arm64
|
||||
|
|
|
@ -5,91 +5,24 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <mcl/stdint.hpp>
|
||||
#include <oaknut/code_block.hpp>
|
||||
#include <oaknut/oaknut.hpp>
|
||||
#include <tsl/robin_map.h>
|
||||
#include <tsl/robin_set.h>
|
||||
|
||||
#include "dynarmic/backend/arm64/emit_arm64.h"
|
||||
#include "dynarmic/backend/arm64/address_space.h"
|
||||
#include "dynarmic/interface/A64/config.h"
|
||||
#include "dynarmic/interface/halt_reason.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/location_descriptor.h"
|
||||
|
||||
namespace Dynarmic::Backend::Arm64 {
|
||||
|
||||
struct A64JitState;
|
||||
|
||||
class A64AddressSpace final {
|
||||
class A64AddressSpace final : public AddressSpace {
|
||||
public:
|
||||
explicit A64AddressSpace(const A64::UserConfig& conf);
|
||||
|
||||
IR::Block GenerateIR(IR::LocationDescriptor) const;
|
||||
IR::Block GenerateIR(IR::LocationDescriptor) const override;
|
||||
|
||||
CodePtr Get(IR::LocationDescriptor descriptor);
|
||||
|
||||
CodePtr GetOrEmit(IR::LocationDescriptor descriptor);
|
||||
|
||||
void ClearCache();
|
||||
|
||||
private:
|
||||
protected:
|
||||
friend class A64Core;
|
||||
|
||||
void EmitPrelude();
|
||||
|
||||
size_t GetRemainingSize();
|
||||
EmittedBlockInfo Emit(IR::Block ir_block);
|
||||
void Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block);
|
||||
void RelinkForDescriptor(IR::LocationDescriptor target_descriptor);
|
||||
EmitConfig GetEmitConfig() override;
|
||||
|
||||
const A64::UserConfig conf;
|
||||
|
||||
oaknut::CodeBlock mem;
|
||||
oaknut::CodeGenerator code;
|
||||
|
||||
tsl::robin_map<u64, CodePtr> block_entries;
|
||||
tsl::robin_map<u64, EmittedBlockInfo> block_infos;
|
||||
tsl::robin_map<u64, tsl::robin_set<u64>> block_references;
|
||||
|
||||
struct PreludeInfo {
|
||||
u32* end_of_prelude;
|
||||
|
||||
using RunCodeFuncType = HaltReason (*)(CodePtr entry_point, A64JitState* context, volatile u32* halt_reason);
|
||||
RunCodeFuncType run_code;
|
||||
RunCodeFuncType step_code;
|
||||
void* return_to_dispatcher;
|
||||
void* return_from_run_code;
|
||||
|
||||
void* read_memory_8;
|
||||
void* read_memory_16;
|
||||
void* read_memory_32;
|
||||
void* read_memory_64;
|
||||
void* read_memory_128;
|
||||
void* exclusive_read_memory_8;
|
||||
void* exclusive_read_memory_16;
|
||||
void* exclusive_read_memory_32;
|
||||
void* exclusive_read_memory_64;
|
||||
void* exclusive_read_memory_128;
|
||||
void* write_memory_8;
|
||||
void* write_memory_16;
|
||||
void* write_memory_32;
|
||||
void* write_memory_64;
|
||||
void* write_memory_128;
|
||||
void* exclusive_write_memory_8;
|
||||
void* exclusive_write_memory_16;
|
||||
void* exclusive_write_memory_32;
|
||||
void* exclusive_write_memory_64;
|
||||
void* exclusive_write_memory_128;
|
||||
void* call_svc;
|
||||
void* exception_raised;
|
||||
void* dc_raised;
|
||||
void* ic_raised;
|
||||
void* isb_raised;
|
||||
void* get_cntpct;
|
||||
void* add_ticks;
|
||||
void* get_ticks_remaining;
|
||||
} prelude_info;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::Backend::Arm64
|
||||
|
|
213
src/dynarmic/backend/arm64/address_space.cpp
Normal file
213
src/dynarmic/backend/arm64/address_space.cpp
Normal file
|
@ -0,0 +1,213 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2022 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include "dynarmic/backend/arm64/a64_address_space.h"
|
||||
#include "dynarmic/backend/arm64/a64_jitstate.h"
|
||||
#include "dynarmic/backend/arm64/abi.h"
|
||||
#include "dynarmic/backend/arm64/devirtualize.h"
|
||||
#include "dynarmic/backend/arm64/emit_arm64.h"
|
||||
#include "dynarmic/backend/arm64/stack_layout.h"
|
||||
#include "dynarmic/common/cast_util.h"
|
||||
#include "dynarmic/common/fp/fpcr.h"
|
||||
#include "dynarmic/interface/exclusive_monitor.h"
|
||||
#include "dynarmic/ir/opt/passes.h"
|
||||
|
||||
namespace Dynarmic::Backend::Arm64 {
|
||||
|
||||
AddressSpace::AddressSpace(size_t code_cache_size)
|
||||
: code_cache_size(code_cache_size)
|
||||
, mem(code_cache_size)
|
||||
, code(mem.ptr()) {}
|
||||
|
||||
AddressSpace::~AddressSpace() = default;
|
||||
|
||||
CodePtr AddressSpace::Get(IR::LocationDescriptor descriptor) {
|
||||
if (const auto iter = block_entries.find(descriptor.Value()); iter != block_entries.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CodePtr AddressSpace::GetOrEmit(IR::LocationDescriptor descriptor) {
|
||||
if (CodePtr block_entry = Get(descriptor)) {
|
||||
return block_entry;
|
||||
}
|
||||
|
||||
IR::Block ir_block = GenerateIR(descriptor);
|
||||
const EmittedBlockInfo block_info = Emit(std::move(ir_block));
|
||||
|
||||
block_infos.insert_or_assign(descriptor.Value(), block_info);
|
||||
block_entries.insert_or_assign(descriptor.Value(), block_info.entry_point);
|
||||
return block_info.entry_point;
|
||||
}
|
||||
|
||||
void AddressSpace::ClearCache() {
|
||||
block_entries.clear();
|
||||
block_infos.clear();
|
||||
block_references.clear();
|
||||
code.set_ptr(prelude_info.end_of_prelude);
|
||||
}
|
||||
|
||||
size_t AddressSpace::GetRemainingSize() {
|
||||
return code_cache_size - (code.ptr<CodePtr>() - reinterpret_cast<CodePtr>(mem.ptr()));
|
||||
}
|
||||
|
||||
EmittedBlockInfo AddressSpace::Emit(IR::Block block) {
|
||||
if (GetRemainingSize() < 1024 * 1024) {
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
mem.unprotect();
|
||||
|
||||
EmittedBlockInfo block_info = EmitArm64(code, std::move(block), GetEmitConfig());
|
||||
|
||||
Link(block.Location(), block_info);
|
||||
|
||||
mem.invalidate(reinterpret_cast<u32*>(block_info.entry_point), block_info.size);
|
||||
|
||||
RelinkForDescriptor(block.Location());
|
||||
|
||||
mem.protect();
|
||||
|
||||
return block_info;
|
||||
}
|
||||
|
||||
static void LinkBlockLinks(const CodePtr entry_point, const CodePtr target_ptr, const std::vector<BlockRelocation>& block_relocations_list) {
|
||||
using namespace oaknut;
|
||||
using namespace oaknut::util;
|
||||
|
||||
for (auto [ptr_offset] : block_relocations_list) {
|
||||
CodeGenerator c{reinterpret_cast<u32*>(entry_point + ptr_offset)};
|
||||
|
||||
if (target_ptr) {
|
||||
c.B((void*)target_ptr);
|
||||
} else {
|
||||
c.NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddressSpace::Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block_info) {
|
||||
using namespace oaknut;
|
||||
using namespace oaknut::util;
|
||||
|
||||
for (auto [ptr_offset, target] : block_info.relocations) {
|
||||
CodeGenerator c{reinterpret_cast<u32*>(block_info.entry_point + ptr_offset)};
|
||||
|
||||
switch (target) {
|
||||
case LinkTarget::ReturnToDispatcher:
|
||||
c.B(prelude_info.return_to_dispatcher);
|
||||
break;
|
||||
case LinkTarget::ReturnFromRunCode:
|
||||
c.B(prelude_info.return_from_run_code);
|
||||
break;
|
||||
case LinkTarget::ReadMemory8:
|
||||
c.BL(prelude_info.read_memory_8);
|
||||
break;
|
||||
case LinkTarget::ReadMemory16:
|
||||
c.BL(prelude_info.read_memory_16);
|
||||
break;
|
||||
case LinkTarget::ReadMemory32:
|
||||
c.BL(prelude_info.read_memory_32);
|
||||
break;
|
||||
case LinkTarget::ReadMemory64:
|
||||
c.BL(prelude_info.read_memory_64);
|
||||
break;
|
||||
case LinkTarget::ReadMemory128:
|
||||
c.BL(prelude_info.read_memory_128);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory8:
|
||||
c.BL(prelude_info.exclusive_read_memory_8);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory16:
|
||||
c.BL(prelude_info.exclusive_read_memory_16);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory32:
|
||||
c.BL(prelude_info.exclusive_read_memory_32);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory64:
|
||||
c.BL(prelude_info.exclusive_read_memory_64);
|
||||
break;
|
||||
case LinkTarget::ExclusiveReadMemory128:
|
||||
c.BL(prelude_info.exclusive_read_memory_128);
|
||||
break;
|
||||
case LinkTarget::WriteMemory8:
|
||||
c.BL(prelude_info.write_memory_8);
|
||||
break;
|
||||
case LinkTarget::WriteMemory16:
|
||||
c.BL(prelude_info.write_memory_16);
|
||||
break;
|
||||
case LinkTarget::WriteMemory32:
|
||||
c.BL(prelude_info.write_memory_32);
|
||||
break;
|
||||
case LinkTarget::WriteMemory64:
|
||||
c.BL(prelude_info.write_memory_64);
|
||||
break;
|
||||
case LinkTarget::WriteMemory128:
|
||||
c.BL(prelude_info.write_memory_128);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory8:
|
||||
c.BL(prelude_info.exclusive_write_memory_8);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory16:
|
||||
c.BL(prelude_info.exclusive_write_memory_16);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory32:
|
||||
c.BL(prelude_info.exclusive_write_memory_32);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory64:
|
||||
c.BL(prelude_info.exclusive_write_memory_64);
|
||||
break;
|
||||
case LinkTarget::ExclusiveWriteMemory128:
|
||||
c.BL(prelude_info.exclusive_write_memory_128);
|
||||
break;
|
||||
case LinkTarget::CallSVC:
|
||||
c.BL(prelude_info.call_svc);
|
||||
break;
|
||||
case LinkTarget::ExceptionRaised:
|
||||
c.BL(prelude_info.exception_raised);
|
||||
break;
|
||||
case LinkTarget::InstructionSynchronizationBarrierRaised:
|
||||
c.BL(prelude_info.isb_raised);
|
||||
break;
|
||||
case LinkTarget::InstructionCacheOperationRaised:
|
||||
c.BL(prelude_info.ic_raised);
|
||||
break;
|
||||
case LinkTarget::DataCacheOperationRaised:
|
||||
c.BL(prelude_info.dc_raised);
|
||||
break;
|
||||
case LinkTarget::GetCNTPCT:
|
||||
c.BL(prelude_info.get_cntpct);
|
||||
break;
|
||||
case LinkTarget::AddTicks:
|
||||
c.BL(prelude_info.add_ticks);
|
||||
break;
|
||||
case LinkTarget::GetTicksRemaining:
|
||||
c.BL(prelude_info.get_ticks_remaining);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid relocation target");
|
||||
}
|
||||
}
|
||||
|
||||
for (auto [target_descriptor, list] : block_info.block_relocations) {
|
||||
block_references[target_descriptor.Value()].emplace(block_descriptor.Value());
|
||||
LinkBlockLinks(block_info.entry_point, Get(target_descriptor), list);
|
||||
}
|
||||
}
|
||||
|
||||
void AddressSpace::RelinkForDescriptor(IR::LocationDescriptor target_descriptor) {
|
||||
for (auto block_descriptor : block_references[target_descriptor.Value()]) {
|
||||
if (auto iter = block_infos.find(block_descriptor); iter != block_infos.end()) {
|
||||
const EmittedBlockInfo& block_info = iter->second;
|
||||
|
||||
LinkBlockLinks(block_info.entry_point, Get(target_descriptor), block_infos[block_descriptor].block_relocations[target_descriptor]);
|
||||
|
||||
mem.invalidate(reinterpret_cast<u32*>(block_info.entry_point), block_info.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::Backend::Arm64
|
92
src/dynarmic/backend/arm64/address_space.h
Normal file
92
src/dynarmic/backend/arm64/address_space.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2022 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mcl/stdint.hpp>
|
||||
#include <oaknut/code_block.hpp>
|
||||
#include <oaknut/oaknut.hpp>
|
||||
#include <tsl/robin_map.h>
|
||||
#include <tsl/robin_set.h>
|
||||
|
||||
#include "dynarmic/backend/arm64/emit_arm64.h"
|
||||
#include "dynarmic/interface/halt_reason.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/location_descriptor.h"
|
||||
|
||||
namespace Dynarmic::Backend::Arm64 {
|
||||
|
||||
class AddressSpace {
|
||||
public:
|
||||
explicit AddressSpace(size_t code_cache_size);
|
||||
virtual ~AddressSpace();
|
||||
|
||||
virtual IR::Block GenerateIR(IR::LocationDescriptor) const = 0;
|
||||
|
||||
CodePtr Get(IR::LocationDescriptor descriptor);
|
||||
|
||||
CodePtr GetOrEmit(IR::LocationDescriptor descriptor);
|
||||
|
||||
void ClearCache();
|
||||
|
||||
protected:
|
||||
virtual EmitConfig GetEmitConfig() = 0;
|
||||
|
||||
size_t GetRemainingSize();
|
||||
EmittedBlockInfo Emit(IR::Block ir_block);
|
||||
void Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block);
|
||||
void RelinkForDescriptor(IR::LocationDescriptor target_descriptor);
|
||||
|
||||
const size_t code_cache_size;
|
||||
oaknut::CodeBlock mem;
|
||||
oaknut::CodeGenerator code;
|
||||
|
||||
tsl::robin_map<u64, CodePtr> block_entries;
|
||||
tsl::robin_map<u64, EmittedBlockInfo> block_infos;
|
||||
tsl::robin_map<u64, tsl::robin_set<u64>> block_references;
|
||||
|
||||
struct PreludeInfo {
|
||||
u32* end_of_prelude;
|
||||
|
||||
using RunCodeFuncType = HaltReason (*)(CodePtr entry_point, void* jit_state, volatile u32* halt_reason);
|
||||
RunCodeFuncType run_code;
|
||||
RunCodeFuncType step_code;
|
||||
void* return_to_dispatcher;
|
||||
void* return_from_run_code;
|
||||
|
||||
void* read_memory_8;
|
||||
void* read_memory_16;
|
||||
void* read_memory_32;
|
||||
void* read_memory_64;
|
||||
void* read_memory_128;
|
||||
void* exclusive_read_memory_8;
|
||||
void* exclusive_read_memory_16;
|
||||
void* exclusive_read_memory_32;
|
||||
void* exclusive_read_memory_64;
|
||||
void* exclusive_read_memory_128;
|
||||
void* write_memory_8;
|
||||
void* write_memory_16;
|
||||
void* write_memory_32;
|
||||
void* write_memory_64;
|
||||
void* write_memory_128;
|
||||
void* exclusive_write_memory_8;
|
||||
void* exclusive_write_memory_16;
|
||||
void* exclusive_write_memory_32;
|
||||
void* exclusive_write_memory_64;
|
||||
void* exclusive_write_memory_128;
|
||||
|
||||
void* call_svc;
|
||||
void* exception_raised;
|
||||
void* dc_raised;
|
||||
void* ic_raised;
|
||||
void* isb_raised;
|
||||
|
||||
void* get_cntpct;
|
||||
void* add_ticks;
|
||||
void* get_ticks_remaining;
|
||||
} prelude_info;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::Backend::Arm64
|
Loading…
Reference in a new issue