A64: Optimization: Merge interpret blocks
This commit is contained in:
parent
99b7516c8c
commit
c6a091d874
9 changed files with 76 additions and 2 deletions
|
@ -90,6 +90,7 @@ add_library(dynarmic
|
|||
frontend/ir/value.h
|
||||
ir_opt/a32_constant_memory_reads_pass.cpp
|
||||
ir_opt/a32_get_set_elimination_pass.cpp
|
||||
ir_opt/a64_merge_interpret_blocks.cpp
|
||||
ir_opt/constant_propagation_pass.cpp
|
||||
ir_opt/dead_code_elimination_pass.cpp
|
||||
ir_opt/passes.h
|
||||
|
|
|
@ -1075,6 +1075,7 @@ void A32EmitX64::EmitA32CoprocStoreWords(A32EmitContext& ctx, IR::Inst* inst) {
|
|||
void A32EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) {
|
||||
ASSERT_MSG(A32::LocationDescriptor{terminal.next}.TFlag() == A32::LocationDescriptor{initial_location}.TFlag(), "Unimplemented");
|
||||
ASSERT_MSG(A32::LocationDescriptor{terminal.next}.EFlag() == A32::LocationDescriptor{initial_location}.EFlag(), "Unimplemented");
|
||||
ASSERT_MSG(terminal.num_instructions == 1, "Unimplemented");
|
||||
|
||||
code->mov(code->ABI_PARAM1.cvt32(), A32::LocationDescriptor{terminal.next}.PC());
|
||||
code->mov(code->ABI_PARAM2, reinterpret_cast<u64>(jit_interface));
|
||||
|
|
|
@ -310,7 +310,7 @@ void A64EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDesc
|
|||
DEVIRT(conf.callbacks, &A64::UserCallbacks::InterpreterFallback).EmitCall(code, [&](Xbyak::Reg64 param1, Xbyak::Reg64 param2) {
|
||||
code->mov(param1, A64::LocationDescriptor{terminal.next}.PC());
|
||||
code->mov(qword[r15 + offsetof(A64JitState, pc)], param1);
|
||||
code->mov(param2.cvt32(), 1);
|
||||
code->mov(param2.cvt32(), terminal.num_instructions);
|
||||
});
|
||||
code->ReturnFromRunCode(true); // TODO: Check cycles
|
||||
}
|
||||
|
|
|
@ -176,6 +176,7 @@ private:
|
|||
// JIT Compile
|
||||
IR::Block ir_block = A64::Translate(A64::LocationDescriptor{current_location}, [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); });
|
||||
Optimization::DeadCodeElimination(ir_block);
|
||||
Optimization::A64MergeInterpretBlocksPass(ir_block, conf.callbacks);
|
||||
// printf("%s\n", IR::DumpBlock(ir_block).c_str());
|
||||
Optimization::VerificationPass(ir_block);
|
||||
return emitter.Emit(ir_block).entrypoint;
|
||||
|
|
|
@ -90,6 +90,11 @@ void Block::SetTerminal(Terminal term) {
|
|||
terminal = term;
|
||||
}
|
||||
|
||||
void Block::ReplaceTerminal(Terminal term) {
|
||||
ASSERT_MSG(HasTerminal(), "Terminal has not been set.");
|
||||
terminal = term;
|
||||
}
|
||||
|
||||
bool Block::HasTerminal() const {
|
||||
return terminal.which() != 0;
|
||||
}
|
||||
|
|
|
@ -111,6 +111,8 @@ public:
|
|||
Terminal GetTerminal() const;
|
||||
/// Sets the terminal instruction for this basic block.
|
||||
void SetTerminal(Terminal term);
|
||||
/// Replaces the terminal instruction for this basic block.
|
||||
void ReplaceTerminal(Terminal term);
|
||||
/// Determines whether or not this basic block has a terminal instruction.
|
||||
bool HasTerminal() const;
|
||||
|
||||
|
|
|
@ -20,11 +20,12 @@ struct Invalid {};
|
|||
|
||||
/**
|
||||
* This terminal instruction calls the interpreter, starting at `next`.
|
||||
* The interpreter must interpret exactly one instruction.
|
||||
* The interpreter must interpret exactly `num_instructions` instructions.
|
||||
*/
|
||||
struct Interpret {
|
||||
explicit Interpret(const LocationDescriptor& next_) : next(next_) {}
|
||||
LocationDescriptor next; ///< Location at which interpretation starts.
|
||||
size_t num_instructions = 1;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
61
src/ir_opt/a64_merge_interpret_blocks.cpp
Normal file
61
src/ir_opt/a64_merge_interpret_blocks.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2018 MerryMage
|
||||
* This software may be used and distributed according to the terms of the GNU
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <boost/variant/get.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "dynarmic/A64/config.h"
|
||||
#include "frontend/A64/location_descriptor.h"
|
||||
#include "frontend/A64/translate/translate.h"
|
||||
#include "frontend/ir/basic_block.h"
|
||||
#include "ir_opt/passes.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Optimization {
|
||||
|
||||
void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb) {
|
||||
const auto is_interpret_instruction = [cb](A64::LocationDescriptor location) {
|
||||
const u32 instruction = cb->MemoryReadCode(location.PC());
|
||||
|
||||
IR::Block new_block{location};
|
||||
A64::TranslateSingleInstruction(new_block, location, instruction);
|
||||
|
||||
if (!new_block.Instructions().empty())
|
||||
return false;
|
||||
|
||||
const IR::Terminal terminal = new_block.GetTerminal();
|
||||
if (auto term = boost::get<IR::Term::Interpret>(&terminal)) {
|
||||
printf("INTERPET %08x \\x%02x\\x%02x\\x%02x\\x%02x \n", instruction, u8(instruction >> 0), u8(instruction >> 8), u8(instruction >> 16), u8(instruction >> 24));
|
||||
return term->next == location;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
IR::Terminal terminal = block.GetTerminal();
|
||||
auto term = boost::get<IR::Term::Interpret>(&terminal);
|
||||
if (!term)
|
||||
return;
|
||||
|
||||
A64::LocationDescriptor location{term->next};
|
||||
size_t num_instructions = 1;
|
||||
|
||||
while (is_interpret_instruction(location.AdvancePC(static_cast<int>(num_instructions * 4)))) {
|
||||
num_instructions++;
|
||||
}
|
||||
|
||||
printf("%zu\n", num_instructions);
|
||||
|
||||
term->num_instructions = num_instructions;
|
||||
block.ReplaceTerminal(terminal);
|
||||
block.CycleCount() += num_instructions - 1;
|
||||
}
|
||||
|
||||
} // namespace Optimization
|
||||
} // namespace Dynarmic
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <dynarmic/A32/callbacks.h>
|
||||
#include <dynarmic/A64/config.h>
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace IR {
|
||||
|
@ -19,6 +20,7 @@ namespace Optimization {
|
|||
|
||||
void A32GetSetElimination(IR::Block& block);
|
||||
void A32ConstantMemoryReads(IR::Block& block, const A32::UserCallbacks::Memory& memory_callbacks);
|
||||
void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb);
|
||||
void ConstantPropagation(IR::Block& block);
|
||||
void DeadCodeElimination(IR::Block& block);
|
||||
void VerificationPass(const IR::Block& block);
|
||||
|
|
Loading…
Reference in a new issue