A32: Introduce PreCodeTranslationHook

This commit is contained in:
MerryMage 2021-05-22 12:13:16 +01:00
parent 714216fd0e
commit 51b155df92
8 changed files with 59 additions and 21 deletions

View file

@ -161,7 +161,7 @@ private:
PerformCacheInvalidation(); PerformCacheInvalidation();
} }
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, [this](u32 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); }, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) { if (conf.HasOptimization(OptimizationFlag::GetSetElimination)) {
Optimization::A32GetSetElimination(ir_block); Optimization::A32GetSetElimination(ir_block);
Optimization::DeadCodeElimination(ir_block); Optimization::DeadCodeElimination(ir_block);

View file

@ -3,17 +3,18 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/frontend/A32/location_descriptor.h"
#include "dynarmic/frontend/A32/translate/translate.h" #include "dynarmic/frontend/A32/translate/translate.h"
#include "dynarmic/frontend/A32/location_descriptor.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options); IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options); IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options) { IR::Block Translate(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_code, options); return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, tcb, options);
} }
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction); bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);

View file

@ -14,6 +14,7 @@ class Block;
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
class LocationDescriptor; class LocationDescriptor;
struct TranslateCallbacks;
using MemoryReadCodeFuncType = std::function<u32(u32 vaddr)>; using MemoryReadCodeFuncType = std::function<u32(u32 vaddr)>;
@ -34,11 +35,11 @@ struct TranslationOptions {
/** /**
* This function translates instructions in memory into our intermediate representation. * This function translates instructions in memory into our intermediate representation.
* @param descriptor The starting location of the basic block. Includes information like PC, Thumb state, &c. * @param descriptor The starting location of the basic block. Includes information like PC, Thumb state, &c.
* @param memory_read_code The function we should use to read emulated memory. * @param tcb The callbacks we should use to read emulated memory.
* @param options Configures how certain instructions are translated. * @param options Configures how certain instructions are translated.
* @return A translated basic block in the intermediate representation. * @return A translated basic block in the intermediate representation.
*/ */
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options); IR::Block Translate(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
/** /**
* This function translates a single provided instruction into our intermediate representation. * This function translates a single provided instruction into our intermediate representation.

View file

@ -11,13 +11,14 @@
#include "dynarmic/frontend/A32/translate/conditional_state.h" #include "dynarmic/frontend/A32/translate/conditional_state.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/translate.h"
#include "dynarmic/frontend/A32/translate/translate.h" #include "dynarmic/frontend/A32/translate/translate.h"
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
#include "dynarmic/frontend/A32/types.h" #include "dynarmic/frontend/A32/types.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options) { IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
const bool single_step = descriptor.SingleStepping(); const bool single_step = descriptor.SingleStepping();
IR::Block block{descriptor}; IR::Block block{descriptor};
@ -26,9 +27,11 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType mem
bool should_continue = true; bool should_continue = true;
do { do {
const u32 arm_pc = visitor.ir.current_location.PC(); const u32 arm_pc = visitor.ir.current_location.PC();
const u32 arm_instruction = memory_read_code(arm_pc); const u32 arm_instruction = tcb->MemoryReadCode(arm_pc);
visitor.current_instruction_size = 4; visitor.current_instruction_size = 4;
tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir);
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor>(arm_instruction)) { if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor>(arm_instruction)) {
should_continue = vfp_decoder->get().call(visitor, arm_instruction); should_continue = vfp_decoder->get().call(visitor, arm_instruction);
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor>(arm_instruction)) { } else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor>(arm_instruction)) {

View file

@ -0,0 +1,25 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2021 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include "dynarmic/common/common_types.h"
namespace Dynarmic::A32 {
using VAddr = u32;
class IREmitter;
struct TranslateCallbacks {
// All reads through this callback are 4-byte aligned.
// Memory must be interpreted as little endian.
virtual std::uint32_t MemoryReadCode(VAddr vaddr) = 0;
// Thus function is called before the instruction at pc is interpreted.
// IR code can be emitted by the callee prior to translation of the instruction.
virtual void PreCodeTranslationHook(bool is_thumb, VAddr pc, A32::IREmitter& ir) = 0;
};
} // namespace Dynarmic::A32

View file

@ -16,6 +16,7 @@
#include "dynarmic/frontend/A32/translate/conditional_state.h" #include "dynarmic/frontend/A32/translate/conditional_state.h"
#include "dynarmic/frontend/A32/translate/impl/translate.h" #include "dynarmic/frontend/A32/translate/impl/translate.h"
#include "dynarmic/frontend/A32/translate/translate.h" #include "dynarmic/frontend/A32/translate/translate.h"
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
#include "dynarmic/frontend/imm.h" #include "dynarmic/frontend/imm.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"
@ -40,8 +41,8 @@ bool IsUnconditionalInstruction(bool is_thumb_16, u32 instruction) {
return false; return false;
} }
std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFuncType memory_read_code) { std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, TranslateCallbacks* tcb) {
u32 first_part = memory_read_code(arm_pc & 0xFFFFFFFC); u32 first_part = tcb->MemoryReadCode(arm_pc & 0xFFFFFFFC);
if ((arm_pc & 0x2) != 0) { if ((arm_pc & 0x2) != 0) {
first_part >>= 16; first_part >>= 16;
} }
@ -55,7 +56,7 @@ std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFu
// 32-bit thumb instruction // 32-bit thumb instruction
// These always start with 0b11101, 0b11110 or 0b11111. // These always start with 0b11101, 0b11110 or 0b11111.
u32 second_part = memory_read_code((arm_pc + 2) & 0xFFFFFFFC); u32 second_part = tcb->MemoryReadCode((arm_pc + 2) & 0xFFFFFFFC);
if (((arm_pc + 2) & 0x2) != 0) { if (((arm_pc + 2) & 0x2) != 0) {
second_part >>= 16; second_part >>= 16;
} }
@ -84,7 +85,7 @@ bool MaybeVFPOrASIMDInstruction(u32 thumb_instruction) {
} // local namespace } // local namespace
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, const TranslationOptions& options) { IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
const bool single_step = descriptor.SingleStepping(); const bool single_step = descriptor.SingleStepping();
IR::Block block{descriptor}; IR::Block block{descriptor};
@ -93,10 +94,12 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType m
bool should_continue = true; bool should_continue = true;
do { do {
const u32 arm_pc = visitor.ir.current_location.PC(); const u32 arm_pc = visitor.ir.current_location.PC();
const auto [thumb_instruction, inst_size] = ReadThumbInstruction(arm_pc, memory_read_code); const auto [thumb_instruction, inst_size] = ReadThumbInstruction(arm_pc, tcb);
const bool is_thumb_16 = inst_size == ThumbInstSize::Thumb16; const bool is_thumb_16 = inst_size == ThumbInstSize::Thumb16;
visitor.current_instruction_size = is_thumb_16 ? 2 : 4; visitor.current_instruction_size = is_thumb_16 ? 2 : 4;
tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir);
if (IsUnconditionalInstruction(is_thumb_16, thumb_instruction) || visitor.ThumbConditionPassed()) { if (IsUnconditionalInstruction(is_thumb_16, thumb_instruction) || visitor.ThumbConditionPassed()) {
if (is_thumb_16) { if (is_thumb_16) {
if (const auto decoder = DecodeThumb16<TranslatorVisitor>(static_cast<u16>(thumb_instruction))) { if (const auto decoder = DecodeThumb16<TranslatorVisitor>(static_cast<u16>(thumb_instruction))) {

View file

@ -10,6 +10,7 @@
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
#include "dynarmic/interface/A32/arch_version.h" #include "dynarmic/interface/A32/arch_version.h"
#include "dynarmic/interface/optimization_flags.h" #include "dynarmic/interface/optimization_flags.h"
@ -53,12 +54,16 @@ enum class Exception {
}; };
/// These function pointers may be inserted into compiled code. /// These function pointers may be inserted into compiled code.
struct UserCallbacks { struct UserCallbacks : public TranslateCallbacks {
virtual ~UserCallbacks() = default; virtual ~UserCallbacks() = default;
// All reads through this callback are 4-byte aligned. // All reads through this callback are 4-byte aligned.
// Memory must be interpreted as little endian. // Memory must be interpreted as little endian.
virtual std::uint32_t MemoryReadCode(VAddr vaddr) { return MemoryRead32(vaddr); } std::uint32_t MemoryReadCode(VAddr vaddr) override { return MemoryRead32(vaddr); }
// Thus function is called before the instruction at pc is interpreted.
// IR code can be emitted by the callee prior to translation of the instruction.
void PreCodeTranslationHook(bool /*is_thumb*/, VAddr /*pc*/, A32::IREmitter& /*ir*/) override {}
// Reads through these callbacks may not be aligned. // Reads through these callbacks may not be aligned.
// Memory must be interpreted as if ENDIANSTATE == 0, endianness will be corrected by the JIT. // Memory must be interpreted as if ENDIANSTATE == 0, endianness will be corrected by the JIT.

View file

@ -19,10 +19,10 @@
#include "./testenv.h" #include "./testenv.h"
#include "dynarmic/common/bit_util.h" #include "dynarmic/common/bit_util.h"
#include "dynarmic/common/common_types.h" #include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
#include "dynarmic/frontend/A32/FPSCR.h" #include "dynarmic/frontend/A32/FPSCR.h"
#include "dynarmic/frontend/A32/location_descriptor.h"
#include "dynarmic/frontend/A32/PSR.h" #include "dynarmic/frontend/A32/PSR.h"
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
#include "dynarmic/frontend/A32/location_descriptor.h"
#include "dynarmic/frontend/A32/translate/translate.h" #include "dynarmic/frontend/A32/translate/translate.h"
#include "dynarmic/interface/A32/a32.h" #include "dynarmic/interface/A32/a32.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
@ -177,7 +177,7 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn<Th
size_t num_insts = 0; size_t num_insts = 0;
while (num_insts < instructions_to_execute_count) { while (num_insts < instructions_to_execute_count) {
A32::LocationDescriptor descriptor = {u32(num_insts * 4), cpsr, A32::FPSCR{}}; A32::LocationDescriptor descriptor = {u32(num_insts * 4), cpsr, A32::FPSCR{}};
IR::Block ir_block = A32::Translate(descriptor, [&test_env](u32 vaddr) { return test_env.MemoryReadCode(vaddr); }, {}); IR::Block ir_block = A32::Translate(descriptor, &test_env, {});
Optimization::A32GetSetElimination(ir_block); Optimization::A32GetSetElimination(ir_block);
Optimization::DeadCodeElimination(ir_block); Optimization::DeadCodeElimination(ir_block);
Optimization::A32ConstantMemoryReads(ir_block, &test_env); Optimization::A32ConstantMemoryReads(ir_block, &test_env);