backend/arm64: Implement fastmem infrastructure
This commit is contained in:
parent
3eddbf8428
commit
2ea2e44f93
7 changed files with 109 additions and 5 deletions
|
@ -395,6 +395,7 @@ elseif(ARCHITECTURE STREQUAL "arm64")
|
|||
backend/arm64/emit_arm64_vector_saturation.cpp
|
||||
backend/arm64/emit_context.h
|
||||
backend/arm64/exclusive_monitor.cpp
|
||||
backend/arm64/fastmem.h
|
||||
backend/arm64/fpsr_manager.cpp
|
||||
backend/arm64/fpsr_manager.h
|
||||
backend/arm64/reg_alloc.cpp
|
||||
|
|
|
@ -19,7 +19,13 @@ namespace Dynarmic::Backend::Arm64 {
|
|||
AddressSpace::AddressSpace(size_t code_cache_size)
|
||||
: code_cache_size(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;
|
||||
|
||||
|
@ -91,7 +97,7 @@ EmittedBlockInfo AddressSpace::Emit(IR::Block block) {
|
|||
|
||||
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_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
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <tsl/robin_set.h>
|
||||
|
||||
#include "dynarmic/backend/arm64/emit_arm64.h"
|
||||
#include "dynarmic/backend/arm64/fastmem.h"
|
||||
#include "dynarmic/interface/halt_reason.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/location_descriptor.h"
|
||||
|
@ -47,6 +48,8 @@ protected:
|
|||
void Link(IR::LocationDescriptor block_descriptor, EmittedBlockInfo& block);
|
||||
void RelinkForDescriptor(IR::LocationDescriptor target_descriptor, CodePtr target_ptr);
|
||||
|
||||
FakeCall FastmemCallback(u64 host_pc);
|
||||
|
||||
const size_t code_cache_size;
|
||||
oaknut::CodeBlock mem;
|
||||
oaknut::CodeGenerator code;
|
||||
|
@ -56,6 +59,9 @@ protected:
|
|||
tsl::robin_map<u64, EmittedBlockInfo> block_infos;
|
||||
tsl::robin_map<u64, tsl::robin_set<u64>> block_references;
|
||||
|
||||
ExceptionHandler exception_handler;
|
||||
FastmemManager fastmem_manager;
|
||||
|
||||
struct PreludeInfo {
|
||||
u32* end_of_prelude;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
FpsrManager fpsr_manager{code, conf.state_fpsr_offset};
|
||||
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>();
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <mcl/stdint.hpp>
|
||||
#include <tsl/robin_map.h>
|
||||
|
||||
#include "dynarmic/backend/arm64/fastmem.h"
|
||||
#include "dynarmic/interface/A32/coprocessor.h"
|
||||
#include "dynarmic/interface/optimization_flags.h"
|
||||
#include "dynarmic/ir/location_descriptor.h"
|
||||
|
@ -99,6 +100,7 @@ struct EmittedBlockInfo {
|
|||
size_t size;
|
||||
std::vector<Relocation> relocations;
|
||||
tsl::robin_map<IR::LocationDescriptor, std::vector<BlockRelocation>> block_relocations;
|
||||
tsl::robin_map<std::ptrdiff_t, FastmemPatchInfo> fastmem_patch_info;
|
||||
};
|
||||
|
||||
struct EmitConfig {
|
||||
|
@ -149,7 +151,7 @@ struct EmitConfig {
|
|||
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>
|
||||
void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
|
||||
|
|
|
@ -23,6 +23,7 @@ class Block;
|
|||
namespace Dynarmic::Backend::Arm64 {
|
||||
|
||||
struct EmitConfig;
|
||||
class FastmemManager;
|
||||
class FpsrManager;
|
||||
|
||||
using SharedLabel = std::shared_ptr<oaknut::Label>;
|
||||
|
@ -37,6 +38,7 @@ struct EmitContext {
|
|||
const EmitConfig& conf;
|
||||
EmittedBlockInfo& ebi;
|
||||
FpsrManager& fpsr;
|
||||
FastmemManager& fastmem;
|
||||
|
||||
std::vector<std::function<void()>> deferred_emits;
|
||||
|
||||
|
|
52
src/dynarmic/backend/arm64/fastmem.h
Normal file
52
src/dynarmic/backend/arm64/fastmem.h
Normal 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
|
Loading…
Reference in a new issue