From 6d25995375440a4bcaa82d3fbb74b16d46b9ee85 Mon Sep 17 00:00:00 2001 From: SachinVin Date: Tue, 16 Jul 2019 17:00:08 +0530 Subject: [PATCH] backend/a64: Redesign Const Pool --- src/backend/A64/a32_emit_a64.cpp | 1 + src/backend/A64/block_of_code.cpp | 14 +++++++-- src/backend/A64/block_of_code.h | 6 +++- src/backend/A64/constant_pool.cpp | 50 +++++++++++++++++++++++++++++-- src/backend/A64/constant_pool.h | 18 ++++++++++- src/backend/A64/reg_alloc.cpp | 2 +- 6 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/backend/A64/a32_emit_a64.cpp b/src/backend/A64/a32_emit_a64.cpp index 9adda38e..c22bcabd 100644 --- a/src/backend/A64/a32_emit_a64.cpp +++ b/src/backend/A64/a32_emit_a64.cpp @@ -134,6 +134,7 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) { EmitAddCycles(block.CycleCount()); EmitA64::EmitTerminal(block.GetTerminal(), block.Location()); code.BRK(0); + code.PatchConstPool(); code.FlushIcacheSection(entrypoint, code.GetCodePtr()); const size_t size = static_cast(code.GetCodePtr() - entrypoint); diff --git a/src/backend/A64/block_of_code.cpp b/src/backend/A64/block_of_code.cpp index 8f32046c..61a7084f 100644 --- a/src/backend/A64/block_of_code.cpp +++ b/src/backend/A64/block_of_code.cpp @@ -45,7 +45,7 @@ namespace { constexpr size_t TOTAL_CODE_SIZE = 128 * 1024 * 1024; constexpr size_t FAR_CODE_OFFSET = 100 * 1024 * 1024; -constexpr size_t CONSTANT_POOL_SIZE = 2 * 1024 * 1024; +constexpr size_t CONSTANT_POOL_SIZE = 512 * 1024; #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT void ProtectMemory(const void* base, size_t size, bool is_executable) { @@ -103,6 +103,7 @@ void BlockOfCode::ClearCache() { near_code_ptr = near_code_begin; far_code_ptr = far_code_begin; SetCodePtr(near_code_begin); + constant_pool.Clear(); } size_t BlockOfCode::SpaceRemaining() const { @@ -259,10 +260,19 @@ void BlockOfCode::LookupBlock() { cb.LookupBlock->EmitCall(*this); } -void* BlockOfCode::MConst(u64 lower, u64 upper) { +u64 BlockOfCode::MConst(u64 lower, u64 upper) { return constant_pool.GetConstant(lower, upper); } +void BlockOfCode::EmitPatchLDR(Arm64Gen::ARM64Reg Rt, u64 lower, u64 upper) { + ASSERT_MSG(!in_far_code, "Can't patch when in far code"); + constant_pool.EmitPatchLDR(Rt, lower, upper); +} + +void BlockOfCode::PatchConstPool() { + constant_pool.PatchPool(); +} + void BlockOfCode::SwitchToFarCode() { ASSERT(prelude_complete); ASSERT(!in_far_code); diff --git a/src/backend/A64/block_of_code.h b/src/backend/A64/block_of_code.h index 7c48af7b..76941628 100644 --- a/src/backend/A64/block_of_code.h +++ b/src/backend/A64/block_of_code.h @@ -62,7 +62,11 @@ public: /// @note this clobbers ABI caller-save registers void LookupBlock(); - void* MConst(u64 lower, u64 upper = 0); + u64 MConst(u64 lower, u64 upper = 0); + + void EmitPatchLDR(Arm64Gen::ARM64Reg Rt, u64 lower, u64 upper = 0); + + void PatchConstPool(); /// Far code sits far away from the near code. Execution remains primarily in near code. /// "Cold" / Rarely executed instructions sit in far code, so the CPU doesn't fetch them unless necessary. diff --git a/src/backend/A64/constant_pool.cpp b/src/backend/A64/constant_pool.cpp index c2303b4f..784124fc 100644 --- a/src/backend/A64/constant_pool.cpp +++ b/src/backend/A64/constant_pool.cpp @@ -22,7 +22,7 @@ void ConstantPool::AllocatePool() { ASSERT(code.GetCodePtr() - pool_begin == static_cast(pool_size)); } -void* ConstantPool::GetConstant(u64 lower, u64 upper) { +u64 ConstantPool::GetConstant(u64 lower, u64 upper) { const auto constant = std::make_tuple(lower, upper); auto iter = constant_info.find(constant); if (iter == constant_info.end()) { @@ -32,7 +32,53 @@ void* ConstantPool::GetConstant(u64 lower, u64 upper) { iter = constant_info.emplace(constant, current_pool_ptr).first; current_pool_ptr += align_size; } - return iter->second; + return reinterpret_cast(iter->second) - reinterpret_cast(code.GetCodePtr()); +} + +void ConstantPool::EmitPatchLDR(Arm64Gen::ARM64Reg Rt, u64 lower, u64 upper) { + const auto constant = std::make_tuple(lower, upper); + auto iter = constant_info.find(constant); + if (iter == constant_info.end()) { + struct PatchInfo p = { code.GetCodePtr(), Rt, constant }; + patch_info.emplace_back(p); + code.BRK(0); + return; + } + + const s32 offset = reinterpret_cast(iter->second) - reinterpret_cast(code.GetCodePtr()); + + if (!(offset >= -0x40000 && offset <= 0x3FFFF)) { + constant_info.erase(constant); + struct PatchInfo p = { code.GetCodePtr(), Rt, constant }; + patch_info.emplace_back(p); + code.BRK(0x42); + return; + } + + code.LDR(Rt, offset); +} + +void ConstantPool::PatchPool() { + + u8* pool_ptr = const_cast(code.GetCodePtr()); + for (PatchInfo patch : patch_info) { + std::memcpy(pool_ptr, &std::get<0>(patch.constant), sizeof(u64)); + std::memcpy(pool_ptr + sizeof(u64), &std::get<1>(patch.constant), sizeof(u64)); + constant_info.emplace(patch.constant, pool_ptr); + + code.SetCodePtr(patch.ptr); + size_t offset = reinterpret_cast(pool_ptr) - reinterpret_cast(code.GetCodePtr()); + code.LDR(patch.Rt, offset); + + pool_ptr += align_size; + } + patch_info.clear(); + code.SetCodePtr(pool_ptr); +} + +void ConstantPool::Clear() { + constant_info.clear(); + patch_info.clear(); } } // namespace Dynarmic::BackendX64 diff --git a/src/backend/A64/constant_pool.h b/src/backend/A64/constant_pool.h index f6f65459..43756055 100644 --- a/src/backend/A64/constant_pool.h +++ b/src/backend/A64/constant_pool.h @@ -24,7 +24,15 @@ public: void AllocatePool(); - void* GetConstant(u64 lower, u64 upper = 0); + u64 GetConstant(u64 lower, u64 upper = 0); + + void EmitPatchLDR(Arm64Gen::ARM64Reg Rt, u64 lower, u64 upper = 0); + + void PatchPool(); + + void Clear(); + + private: static constexpr size_t align_size = 16; // bytes @@ -35,6 +43,14 @@ private: size_t pool_size; u8* pool_begin; u8* current_pool_ptr; + + struct PatchInfo { + const void* ptr; + Arm64Gen::ARM64Reg Rt; + std::tuple constant; + }; + + std::vector patch_info; }; } // namespace Dynarmic::BackendA64 diff --git a/src/backend/A64/reg_alloc.cpp b/src/backend/A64/reg_alloc.cpp index 9a96e272..e6f606f9 100644 --- a/src/backend/A64/reg_alloc.cpp +++ b/src/backend/A64/reg_alloc.cpp @@ -498,7 +498,7 @@ HostLoc RegAlloc::LoadImmediate(IR::Value imm, HostLoc host_loc) { if (imm_value == 0) code.fp_emitter.FMOV(reg, 0); else { - code.LDR(reg, code.MConst(imm_value)); + code.EmitPatchLDR(reg, imm_value); } return host_loc; }