diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index da561d6c..86c1e863 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -154,6 +154,7 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS) frontend/A32/translate/translate_thumb.cpp ir_opt/a32_constant_memory_reads_pass.cpp ir_opt/a32_get_set_elimination_pass.cpp + ir_opt/a32_merge_interpret_blocks.cpp ) endif() diff --git a/src/ir_opt/a32_merge_interpret_blocks.cpp b/src/ir_opt/a32_merge_interpret_blocks.cpp new file mode 100644 index 00000000..4977b7b5 --- /dev/null +++ b/src/ir_opt/a32_merge_interpret_blocks.cpp @@ -0,0 +1,56 @@ +/* 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 + +#include + +#include "common/assert.h" +#include "common/common_types.h" +#include "dynarmic/A32/config.h" +#include "frontend/A32/location_descriptor.h" +#include "frontend/A32/translate/translate.h" +#include "frontend/ir/basic_block.h" +#include "ir_opt/passes.h" + +namespace Dynarmic::Optimization { + +void A32MergeInterpretBlocksPass(IR::Block& block, A32::UserCallbacks* cb) { + const auto is_interpret_instruction = [cb](A32::LocationDescriptor location) { + const u32 instruction = cb->MemoryReadCode(location.PC()); + + IR::Block new_block{location}; + A32::TranslateSingleInstruction(new_block, location, instruction); + + if (!new_block.Instructions().empty()) + return false; + + const IR::Terminal terminal = new_block.GetTerminal(); + if (auto term = boost::get(&terminal)) { + return term->next == location; + } + + return false; + }; + + IR::Terminal terminal = block.GetTerminal(); + auto term = boost::get(&terminal); + if (!term) + return; + + A32::LocationDescriptor location{term->next}; + size_t num_instructions = 1; + + while (is_interpret_instruction(location.AdvancePC(static_cast(num_instructions * 4)))) { + num_instructions++; + } + + term->num_instructions = num_instructions; + block.ReplaceTerminal(terminal); + block.CycleCount() += num_instructions - 1; +} + +} // namespace Dynarmic::Optimization diff --git a/src/ir_opt/passes.h b/src/ir_opt/passes.h index 3b8fd698..19acfba3 100644 --- a/src/ir_opt/passes.h +++ b/src/ir_opt/passes.h @@ -22,6 +22,7 @@ namespace Dynarmic::Optimization { void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb); void A32GetSetElimination(IR::Block& block); +void A32MergeInterpretBlocksPass(IR::Block& block, A32::UserCallbacks* cb); void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf); void A64GetSetElimination(IR::Block& block); void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb);