backend/arm64: Implement fastmem infrastructure

This commit is contained in:
Merry 2022-12-11 14:57:05 +00:00
parent 3eddbf8428
commit 2ea2e44f93
7 changed files with 109 additions and 5 deletions

View file

@ -395,6 +395,7 @@ elseif(ARCHITECTURE STREQUAL "arm64")
backend/arm64/emit_arm64_vector_saturation.cpp backend/arm64/emit_arm64_vector_saturation.cpp
backend/arm64/emit_context.h backend/arm64/emit_context.h
backend/arm64/exclusive_monitor.cpp backend/arm64/exclusive_monitor.cpp
backend/arm64/fastmem.h
backend/arm64/fpsr_manager.cpp backend/arm64/fpsr_manager.cpp
backend/arm64/fpsr_manager.h backend/arm64/fpsr_manager.h
backend/arm64/reg_alloc.cpp backend/arm64/reg_alloc.cpp

View file

@ -19,7 +19,13 @@ namespace Dynarmic::Backend::Arm64 {
AddressSpace::AddressSpace(size_t code_cache_size) AddressSpace::AddressSpace(size_t code_cache_size)
: code_cache_size(code_cache_size) : code_cache_size(code_cache_size)
, mem(code_cache_size) , mem(code_cache_size)
, code(mem.ptr()) {} , code(mem.ptr())
, fastmem_manager(exception_handler) {
exception_handler.Register(mem, code_cache_size);
exception_handler.SetFastmemCallback([this](u64 host_pc) {
return FastmemCallback(host_pc);
});
}
AddressSpace::~AddressSpace() = default; AddressSpace::~AddressSpace() = default;
@ -91,7 +97,7 @@ EmittedBlockInfo AddressSpace::Emit(IR::Block block) {
mem.unprotect(); mem.unprotect();
EmittedBlockInfo block_info = EmitArm64(code, std::move(block), GetEmitConfig()); EmittedBlockInfo block_info = EmitArm64(code, std::move(block), GetEmitConfig(), fastmem_manager);
block_infos.insert_or_assign(block.Location().Value(), block_info); block_infos.insert_or_assign(block.Location().Value(), block_info);
block_entries.insert_or_assign(block.Location().Value(), block_info.entry_point); block_entries.insert_or_assign(block.Location().Value(), block_info.entry_point);
@ -274,4 +280,39 @@ void AddressSpace::RelinkForDescriptor(IR::LocationDescriptor target_descriptor,
} }
} }
FakeCall AddressSpace::FastmemCallback(u64 host_pc) {
{
const auto host_ptr = mcl::bit_cast<CodePtr>(host_pc);
const auto location_descriptor = ReverseGet(host_ptr);
if (!location_descriptor) {
goto fail;
}
const auto block_iter = block_infos.find(location_descriptor->Value());
if (block_iter == block_infos.end()) {
goto fail;
}
const auto block_entry_point = block_iter->second.entry_point;
const auto iter = block_iter->second.fastmem_patch_info.find(host_ptr - block_entry_point);
if (iter == block_iter->second.fastmem_patch_info.end()) {
goto fail;
}
if (iter->second.recompile) {
const auto marker = iter->second.marker;
fastmem_manager.MarkDoNotFastmem(marker);
InvalidateBasicBlocks({std::get<0>(marker)});
}
return iter->second.fc;
}
fail:
fmt::print("dynarmic: Segfault happened within JITted code at host_pc = {:016x}\n", host_pc);
fmt::print("Segfault wasn't at a fastmem patch location!\n");
ASSERT_FALSE("segfault");
}
} // namespace Dynarmic::Backend::Arm64 } // namespace Dynarmic::Backend::Arm64

View file

@ -15,6 +15,7 @@
#include <tsl/robin_set.h> #include <tsl/robin_set.h>
#include "dynarmic/backend/arm64/emit_arm64.h" #include "dynarmic/backend/arm64/emit_arm64.h"
#include "dynarmic/backend/arm64/fastmem.h"
#include "dynarmic/interface/halt_reason.h" #include "dynarmic/interface/halt_reason.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/location_descriptor.h" #include "dynarmic/ir/location_descriptor.h"
@ -47,6 +48,8 @@ protected:
void Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block); void Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block);
void RelinkForDescriptor(IR::LocationDescriptor target_descriptor, CodePtr target_ptr); void RelinkForDescriptor(IR::LocationDescriptor target_descriptor, CodePtr target_ptr);
FakeCall FastmemCallback(u64 host_pc);
const size_t code_cache_size; const size_t code_cache_size;
oaknut::CodeBlock mem; oaknut::CodeBlock mem;
oaknut::CodeGenerator code; oaknut::CodeGenerator code;
@ -56,6 +59,9 @@ protected:
tsl::robin_map<u64, EmittedBlockInfo> block_infos; tsl::robin_map<u64, EmittedBlockInfo> block_infos;
tsl::robin_map<u64, tsl::robin_set<u64>> block_references; tsl::robin_map<u64, tsl::robin_set<u64>> block_references;
ExceptionHandler exception_handler;
FastmemManager fastmem_manager;
struct PreludeInfo { struct PreludeInfo {
u32* end_of_prelude; u32* end_of_prelude;

View file

@ -175,12 +175,12 @@ static void EmitAddCycles(oaknut::CodeGenerator& code, EmitContext& ctx, size_t
} }
} }
EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& conf) { EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& conf, FastmemManager& fastmem_manager) {
EmittedBlockInfo ebi; EmittedBlockInfo ebi;
FpsrManager fpsr_manager{code, conf.state_fpsr_offset}; FpsrManager fpsr_manager{code, conf.state_fpsr_offset};
RegAlloc reg_alloc{code, fpsr_manager, GPR_ORDER, FPR_ORDER}; RegAlloc reg_alloc{code, fpsr_manager, GPR_ORDER, FPR_ORDER};
EmitContext ctx{block, reg_alloc, conf, ebi, fpsr_manager, {}}; EmitContext ctx{block, reg_alloc, conf, ebi, fpsr_manager, fastmem_manager, {}};
ebi.entry_point = code.ptr<CodePtr>(); ebi.entry_point = code.ptr<CodePtr>();

View file

@ -13,6 +13,7 @@
#include <mcl/stdint.hpp> #include <mcl/stdint.hpp>
#include <tsl/robin_map.h> #include <tsl/robin_map.h>
#include "dynarmic/backend/arm64/fastmem.h"
#include "dynarmic/interface/A32/coprocessor.h" #include "dynarmic/interface/A32/coprocessor.h"
#include "dynarmic/interface/optimization_flags.h" #include "dynarmic/interface/optimization_flags.h"
#include "dynarmic/ir/location_descriptor.h" #include "dynarmic/ir/location_descriptor.h"
@ -99,6 +100,7 @@ struct EmittedBlockInfo {
size_t size; size_t size;
std::vector<Relocation> relocations; std::vector<Relocation> relocations;
tsl::robin_map<IR::LocationDescriptor, std::vector<BlockRelocation>> block_relocations; tsl::robin_map<IR::LocationDescriptor, std::vector<BlockRelocation>> block_relocations;
tsl::robin_map<std::ptrdiff_t, FastmemPatchInfo> fastmem_patch_info;
}; };
struct EmitConfig { struct EmitConfig {
@ -149,7 +151,7 @@ struct EmitConfig {
std::array<std::shared_ptr<A32::Coprocessor>, 16> coprocessors{}; std::array<std::shared_ptr<A32::Coprocessor>, 16> coprocessors{};
}; };
EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& emit_conf); EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& emit_conf, FastmemManager& fastmem_manager);
template<IR::Opcode op> template<IR::Opcode op>
void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst); void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);

View file

@ -23,6 +23,7 @@ class Block;
namespace Dynarmic::Backend::Arm64 { namespace Dynarmic::Backend::Arm64 {
struct EmitConfig; struct EmitConfig;
class FastmemManager;
class FpsrManager; class FpsrManager;
using SharedLabel = std::shared_ptr<oaknut::Label>; using SharedLabel = std::shared_ptr<oaknut::Label>;
@ -37,6 +38,7 @@ struct EmitContext {
const EmitConfig& conf; const EmitConfig& conf;
EmittedBlockInfo& ebi; EmittedBlockInfo& ebi;
FpsrManager& fpsr; FpsrManager& fpsr;
FastmemManager& fastmem;
std::vector<std::function<void()>> deferred_emits; std::vector<std::function<void()>> deferred_emits;

View file

@ -0,0 +1,52 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <cstddef>
#include <tuple>
#include <mcl/hash/xmrx.hpp>
#include <mcl/stdint.hpp>
#include <tsl/robin_set.h>
#include "dynarmic/backend/exception_handler.h"
#include "dynarmic/ir/location_descriptor.h"
namespace Dynarmic::Backend::Arm64 {
using DoNotFastmemMarker = std::tuple<IR::LocationDescriptor, std::ptrdiff_t>;
struct DoNotFastmemMarkerHash {
size_t operator()(const DoNotFastmemMarker& value) const {
return mcl::hash::xmrx(std::get<0>(value).Value() ^ static_cast<u64>(std::get<1>(value)));
}
};
struct FastmemPatchInfo {
DoNotFastmemMarker marker;
FakeCall fc;
bool recompile;
};
class FastmemManager {
public:
explicit FastmemManager(ExceptionHandler& eh)
: exception_handler(eh) {}
bool ShouldFastmem(DoNotFastmemMarker marker) const {
return exception_handler.SupportsFastmem() && do_not_fastmem.count(marker) == 0;
}
void MarkDoNotFastmem(DoNotFastmemMarker marker) {
do_not_fastmem.emplace(marker);
}
private:
ExceptionHandler& exception_handler;
tsl::robin_set<DoNotFastmemMarker, DoNotFastmemMarkerHash> do_not_fastmem;
};
} // namespace Dynarmic::Backend::Arm64