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