diff --git a/include/dynarmic/dynarmic.h b/include/dynarmic/dynarmic.h index aa73aad3..c1c73abf 100644 --- a/include/dynarmic/dynarmic.h +++ b/include/dynarmic/dynarmic.h @@ -15,8 +15,8 @@ namespace Dynarmic { -namespace Arm { -struct LocationDescriptor; +namespace IR { +class LocationDescriptor; } class Jit final { @@ -76,7 +76,7 @@ public: * @param descriptor Basic block descriptor. * @return A string containing disassembly of the host machine code produced for the basic block. */ - std::string Disassemble(const Arm::LocationDescriptor& descriptor); + std::string Disassemble(const IR::LocationDescriptor& descriptor); private: bool is_executing = false; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9fc7d62e..b5cbbfc2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,6 +64,7 @@ set(HEADERS frontend/disassembler/disassembler.h frontend/ir/basic_block.h frontend/ir/ir_emitter.h + frontend/ir/location_descriptor.h frontend/ir/microinstruction.h frontend/ir/opcodes.h frontend/ir/terminal.h diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index cd9fb324..731d341a 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -14,6 +14,7 @@ #include "backend_x64/jitstate.h" #include "frontend/arm_types.h" #include "frontend/ir/basic_block.h" +#include "frontend/ir/location_descriptor.h" #include "frontend/ir/microinstruction.h" // TODO: Have ARM flags in host flags and not have them use up GPR registers unless necessary. @@ -50,7 +51,7 @@ static void EraseInstruction(IR::Block& block, IR::Inst* inst) { } EmitX64::BlockDescriptor EmitX64::Emit(IR::Block& block) { - const Arm::LocationDescriptor descriptor = block.Location(); + const IR::LocationDescriptor descriptor = block.Location(); reg_alloc.Reset(); @@ -2156,7 +2157,7 @@ void EmitX64::EmitCondPrelude(const IR::Block& block) { code->L(pass); } -void EmitX64::EmitTerminal(IR::Terminal terminal, Arm::LocationDescriptor initial_location) { +void EmitX64::EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location) { switch (terminal.which()) { case 1: EmitTerminalInterpret(boost::get(terminal), initial_location); @@ -2185,7 +2186,7 @@ void EmitX64::EmitTerminal(IR::Terminal terminal, Arm::LocationDescriptor initia } } -void EmitX64::EmitTerminalInterpret(IR::Term::Interpret terminal, Arm::LocationDescriptor initial_location) { +void EmitX64::EmitTerminalInterpret(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) { ASSERT_MSG(terminal.next.TFlag() == initial_location.TFlag(), "Unimplemented"); ASSERT_MSG(terminal.next.EFlag() == initial_location.EFlag(), "Unimplemented"); @@ -2198,11 +2199,11 @@ void EmitX64::EmitTerminalInterpret(IR::Term::Interpret terminal, Arm::LocationD code->ReturnFromRunCode(false); // TODO: Check cycles } -void EmitX64::EmitTerminalReturnToDispatch(IR::Term::ReturnToDispatch, Arm::LocationDescriptor initial_location) { +void EmitX64::EmitTerminalReturnToDispatch(IR::Term::ReturnToDispatch, IR::LocationDescriptor initial_location) { code->ReturnFromRunCode(); } -void EmitX64::EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, Arm::LocationDescriptor initial_location) { +void EmitX64::EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) { using namespace Xbyak::util; if (terminal.next.TFlag() != initial_location.TFlag()) { @@ -2233,7 +2234,7 @@ void EmitX64::EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, Arm::LocationD code->ReturnFromRunCode(); // TODO: Check cycles, Properly do a link } -void EmitX64::EmitTerminalLinkBlockFast(IR::Term::LinkBlockFast terminal, Arm::LocationDescriptor initial_location) { +void EmitX64::EmitTerminalLinkBlockFast(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) { using namespace Xbyak::util; if (terminal.next.TFlag() != initial_location.TFlag()) { @@ -2263,7 +2264,7 @@ void EmitX64::EmitTerminalLinkBlockFast(IR::Term::LinkBlockFast terminal, Arm::L } } -void EmitX64::EmitTerminalPopRSBHint(IR::Term::PopRSBHint, Arm::LocationDescriptor initial_location) { +void EmitX64::EmitTerminalPopRSBHint(IR::Term::PopRSBHint, IR::LocationDescriptor initial_location) { using namespace Xbyak::util; // This calculation has to match up with IREmitter::PushRSB @@ -2284,14 +2285,14 @@ void EmitX64::EmitTerminalPopRSBHint(IR::Term::PopRSBHint, Arm::LocationDescript code->jmp(rax); } -void EmitX64::EmitTerminalIf(IR::Term::If terminal, Arm::LocationDescriptor initial_location) { +void EmitX64::EmitTerminalIf(IR::Term::If terminal, IR::LocationDescriptor initial_location) { Xbyak::Label pass = EmitCond(code, terminal.if_); EmitTerminal(terminal.else_, initial_location); code->L(pass); EmitTerminal(terminal.then_, initial_location); } -void EmitX64::EmitTerminalCheckHalt(IR::Term::CheckHalt terminal, Arm::LocationDescriptor initial_location) { +void EmitX64::EmitTerminalCheckHalt(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location) { using namespace Xbyak::util; code->cmp(code->byte[r15 + offsetof(JitState, halt_requested)], u8(0)); @@ -2299,7 +2300,7 @@ void EmitX64::EmitTerminalCheckHalt(IR::Term::CheckHalt terminal, Arm::LocationD EmitTerminal(terminal.else_, initial_location); } -void EmitX64::Patch(Arm::LocationDescriptor desc, CodePtr bb) { +void EmitX64::Patch(IR::LocationDescriptor desc, CodePtr bb) { using namespace Xbyak::util; const CodePtr save_code_ptr = code->getCurr(); diff --git a/src/backend_x64/emit_x64.h b/src/backend_x64/emit_x64.h index 6b6ce997..2d046020 100644 --- a/src/backend_x64/emit_x64.h +++ b/src/backend_x64/emit_x64.h @@ -14,7 +14,7 @@ #include "backend_x64/block_of_code.h" #include "backend_x64/reg_alloc.h" #include "dynarmic/callbacks.h" -#include "frontend/arm_types.h" +#include "frontend/ir/location_descriptor.h" #include "frontend/ir/terminal.h" namespace Dynarmic { @@ -45,7 +45,7 @@ public: BlockDescriptor Emit(IR::Block& ir); /// Looks up an emitted host block in the cache. - boost::optional GetBasicBlock(Arm::LocationDescriptor descriptor) { + boost::optional GetBasicBlock(IR::LocationDescriptor descriptor) { auto iter = basic_blocks.find(descriptor); if (iter == basic_blocks.end()) return boost::none; @@ -66,15 +66,15 @@ private: void EmitCondPrelude(const IR::Block& block); // Terminal instruction emitters - void EmitTerminal(IR::Terminal terminal, Arm::LocationDescriptor initial_location); - void EmitTerminalInterpret(IR::Term::Interpret terminal, Arm::LocationDescriptor initial_location); - void EmitTerminalReturnToDispatch(IR::Term::ReturnToDispatch terminal, Arm::LocationDescriptor initial_location); - void EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, Arm::LocationDescriptor initial_location); - void EmitTerminalLinkBlockFast(IR::Term::LinkBlockFast terminal, Arm::LocationDescriptor initial_location); - void EmitTerminalPopRSBHint(IR::Term::PopRSBHint terminal, Arm::LocationDescriptor initial_location); - void EmitTerminalIf(IR::Term::If terminal, Arm::LocationDescriptor initial_location); - void EmitTerminalCheckHalt(IR::Term::CheckHalt terminal, Arm::LocationDescriptor initial_location); - void Patch(Arm::LocationDescriptor desc, CodePtr bb); + void EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location); + void EmitTerminalInterpret(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location); + void EmitTerminalReturnToDispatch(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location); + void EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location); + void EmitTerminalLinkBlockFast(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location); + void EmitTerminalPopRSBHint(IR::Term::PopRSBHint terminal, IR::LocationDescriptor initial_location); + void EmitTerminalIf(IR::Term::If terminal, IR::LocationDescriptor initial_location); + void EmitTerminalCheckHalt(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location); + void Patch(IR::LocationDescriptor desc, CodePtr bb); // Per-block state RegAlloc reg_alloc; @@ -85,9 +85,9 @@ private: Jit* jit_interface; std::unordered_map unique_hash_to_code_ptr; std::unordered_map> patch_unique_hash_locations; - std::unordered_map basic_blocks; - std::unordered_map> patch_jg_locations; - std::unordered_map> patch_jmp_locations; + std::unordered_map basic_blocks; + std::unordered_map> patch_jg_locations; + std::unordered_map> patch_jmp_locations; }; } // namespace BackendX64 diff --git a/src/backend_x64/interface_x64.cpp b/src/backend_x64/interface_x64.cpp index 65058643..987d009c 100644 --- a/src/backend_x64/interface_x64.cpp +++ b/src/backend_x64/interface_x64.cpp @@ -20,8 +20,8 @@ #include "common/common_types.h" #include "common/scope_exit.h" #include "dynarmic/dynarmic.h" -#include "frontend/arm_types.h" #include "frontend/ir/basic_block.h" +#include "frontend/ir/location_descriptor.h" #include "frontend/translate/translate.h" #include "ir_opt/passes.h" @@ -47,13 +47,13 @@ struct Jit::Impl { size_t Execute(size_t cycle_count) { u32 pc = jit_state.Reg[15]; - Arm::LocationDescriptor descriptor{pc, Arm::PSR{jit_state.Cpsr}, Arm::FPSCR{jit_state.guest_FPSCR_mode}}; + IR::LocationDescriptor descriptor{pc, Arm::PSR{jit_state.Cpsr}, Arm::FPSCR{jit_state.guest_FPSCR_mode}}; CodePtr code_ptr = GetBasicBlock(descriptor).code_ptr; return block_of_code.RunCode(&jit_state, code_ptr, cycle_count); } - std::string Disassemble(const Arm::LocationDescriptor& descriptor) { + std::string Disassemble(const IR::LocationDescriptor& descriptor) { auto block = GetBasicBlock(descriptor); std::string result = fmt::format("address: {}\nsize: {} bytes\n", block.code_ptr, block.size); @@ -98,7 +98,7 @@ struct Jit::Impl { } private: - EmitX64::BlockDescriptor GetBasicBlock(Arm::LocationDescriptor descriptor) { + EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) { auto block = emitter.GetBasicBlock(descriptor); if (block) return *block; @@ -187,7 +187,7 @@ void Jit::SetFpscr(u32 value) const { return impl->jit_state.SetFpscr(value); } -std::string Jit::Disassemble(const Arm::LocationDescriptor& descriptor) { +std::string Jit::Disassemble(const IR::LocationDescriptor& descriptor) { return impl->Disassemble(descriptor); } diff --git a/src/backend_x64/jitstate.cpp b/src/backend_x64/jitstate.cpp index f0e49352..52378bdc 100644 --- a/src/backend_x64/jitstate.cpp +++ b/src/backend_x64/jitstate.cpp @@ -9,7 +9,7 @@ #include "common/assert.h" #include "common/bit_util.h" #include "common/common_types.h" -#include "frontend/arm_types.h" +#include "frontend/ir/location_descriptor.h" namespace Dynarmic { namespace BackendX64 { @@ -75,7 +75,7 @@ void JitState::ResetRSB() { */ // NZCV; QC (ASMID only), AHP; DN, FZ, RMode, Stride; SBZP; Len; trap enables; cumulative bits -constexpr u32 FPSCR_MODE_MASK = Arm::LocationDescriptor::FPSCR_MODE_MASK; +constexpr u32 FPSCR_MODE_MASK = IR::LocationDescriptor::FPSCR_MODE_MASK; constexpr u32 FPSCR_NZCV_MASK = 0xF0000000; u32 JitState::Fpscr() const { diff --git a/src/frontend/arm_types.h b/src/frontend/arm_types.h index 36434a1a..312ff9dc 100644 --- a/src/frontend/arm_types.h +++ b/src/frontend/arm_types.h @@ -6,15 +6,11 @@ #pragma once -#include #include -#include #include #include "common/assert.h" #include "common/common_types.h" -#include "frontend/arm/FPSCR.h" -#include "frontend/arm/PSR.h" namespace Dynarmic { namespace Arm { @@ -66,77 +62,6 @@ enum class SignExtendRotation { ROR_24 ///< ROR #24 }; -/** - * LocationDescriptor describes the location of a basic block. - * The location is not solely based on the PC because other flags influence the way - * instructions should be translated. The CPSR.T flag is most notable since it - * tells us if the processor is in Thumb or Arm mode. - */ -struct LocationDescriptor { - // Indicates bits that should be preserved within descriptors. - static constexpr u32 CPSR_MODE_MASK = 0x00000220; - static constexpr u32 FPSCR_MODE_MASK = 0x03F79F00; - - LocationDescriptor(u32 arm_pc, PSR cpsr, FPSCR fpscr) - : arm_pc(arm_pc), cpsr(cpsr.Value() & CPSR_MODE_MASK), fpscr(fpscr.Value() & FPSCR_MODE_MASK) {} - - u32 PC() const { return arm_pc; } - bool TFlag() const { return cpsr.T(); } - bool EFlag() const { return cpsr.E(); } - - Arm::PSR CPSR() const { return cpsr; } - Arm::FPSCR FPSCR() const { return fpscr; } - - bool operator == (const LocationDescriptor& o) const { - return std::tie(arm_pc, cpsr, fpscr) == std::tie(o.arm_pc, o.cpsr, o.fpscr); - } - - bool operator != (const LocationDescriptor& o) const { - return !operator==(o); - } - - LocationDescriptor SetPC(u32 new_arm_pc) const { - return LocationDescriptor(new_arm_pc, cpsr, fpscr); - } - - LocationDescriptor AdvancePC(int amount) const { - return LocationDescriptor(static_cast(arm_pc + amount), cpsr, fpscr); - } - - LocationDescriptor SetTFlag(bool new_tflag) const { - PSR new_cpsr = cpsr; - new_cpsr.T(new_tflag); - - return LocationDescriptor(arm_pc, new_cpsr, fpscr); - } - - LocationDescriptor SetEFlag(bool new_eflag) const { - PSR new_cpsr = cpsr; - new_cpsr.E(new_eflag); - - return LocationDescriptor(arm_pc, new_cpsr, fpscr); - } - - LocationDescriptor SetFPSCR(u32 new_fpscr) const { - return LocationDescriptor(arm_pc, cpsr, Arm::FPSCR{new_fpscr & FPSCR_MODE_MASK}); - } - - u64 UniqueHash() const { - // This value MUST BE UNIQUE. - // This calculation has to match up with EmitX64::EmitTerminalPopRSBHint - u64 pc_u64 = u64(arm_pc); - u64 fpscr_u64 = u64(fpscr.Value()) << 32; - u64 t_u64 = cpsr.T() ? (1ull << 35) : 0; - u64 e_u64 = cpsr.E() ? (1ull << 39) : 0; - return pc_u64 | fpscr_u64 | t_u64 | e_u64; - } - -private: - u32 arm_pc; ///< Current program counter value. - Arm::PSR cpsr; ///< Current program status register. - Arm::FPSCR fpscr; ///< Floating point status control register. -}; - const char* CondToString(Cond cond, bool explicit_al = false); const char* RegToString(Reg reg); const char* ExtRegToString(ExtReg reg); @@ -177,12 +102,3 @@ inline ExtReg operator+(ExtReg reg, size_t number) { } // namespace Arm } // namespace Dynarmic - -namespace std { -template <> -struct hash { - size_t operator()(const Dynarmic::Arm::LocationDescriptor& x) const { - return std::hash()(x.UniqueHash()); - } -}; -} // namespace std diff --git a/src/frontend/ir/basic_block.cpp b/src/frontend/ir/basic_block.cpp index 81e005f5..0952aa52 100644 --- a/src/frontend/ir/basic_block.cpp +++ b/src/frontend/ir/basic_block.cpp @@ -30,7 +30,7 @@ void Block::AppendNewInst(Opcode opcode, std::initializer_list args) instructions.push_back(inst); } -Arm::LocationDescriptor Block::Location() const { +LocationDescriptor Block::Location() const { return location; } @@ -42,11 +42,11 @@ void Block::SetCondition(Arm::Cond condition) { cond = condition; } -Arm::LocationDescriptor Block::ConditionFailedLocation() const { +LocationDescriptor Block::ConditionFailedLocation() const { return cond_failed.get(); } -void Block::SetConditionFailedLocation(Arm::LocationDescriptor fail_location) { +void Block::SetConditionFailedLocation(LocationDescriptor fail_location) { cond_failed = fail_location; } @@ -91,7 +91,7 @@ const size_t& Block::CycleCount() const { return cycle_count; } -static std::string LocDescToString(const Arm::LocationDescriptor& loc) { +static std::string LocDescToString(const LocationDescriptor& loc) { return fmt::format("{{{},{},{},{}}}", loc.PC(), loc.TFlag() ? "T" : "!T", diff --git a/src/frontend/ir/basic_block.h b/src/frontend/ir/basic_block.h index 18a05b0f..31310adf 100644 --- a/src/frontend/ir/basic_block.h +++ b/src/frontend/ir/basic_block.h @@ -15,7 +15,7 @@ #include "common/common_types.h" #include "common/intrusive_list.h" #include "common/memory_pool.h" -#include "frontend/arm_types.h" +#include "frontend/ir/location_descriptor.h" #include "frontend/ir/microinstruction.h" #include "frontend/ir/terminal.h" #include "frontend/ir/value.h" @@ -40,7 +40,7 @@ public: using reverse_iterator = InstructionList::reverse_iterator; using const_reverse_iterator = InstructionList::const_reverse_iterator; - explicit Block(const Arm::LocationDescriptor& location) : location(location) {} + explicit Block(const LocationDescriptor& location) : location(location) {} bool empty() const { return instructions.empty(); } size_type size() const { return instructions.size(); } @@ -77,7 +77,7 @@ public: void AppendNewInst(Opcode op, std::initializer_list args); /// Gets the starting location for this basic block. - Arm::LocationDescriptor Location() const; + LocationDescriptor Location() const; /// Gets the condition required to pass in order to execute this block. Arm::Cond GetCondition() const; @@ -85,9 +85,9 @@ public: void SetCondition(Arm::Cond condition); /// Gets the location of the block to execute if the predicated condition fails. - Arm::LocationDescriptor ConditionFailedLocation() const; + LocationDescriptor ConditionFailedLocation() const; /// Sets the location of the block to execute if the predicated condition fails. - void SetConditionFailedLocation(Arm::LocationDescriptor fail_location); + void SetConditionFailedLocation(LocationDescriptor fail_location); /// Determines whether or not a prediated condition failure block is present. bool HasConditionFailedLocation() const; @@ -115,11 +115,11 @@ public: private: /// Description of the starting location of this block - Arm::LocationDescriptor location; + LocationDescriptor location; /// Conditional to pass in order to execute this block Arm::Cond cond = Arm::Cond::AL; /// Block to execute next if `cond` did not pass. - boost::optional cond_failed = {}; + boost::optional cond_failed = {}; /// Number of cycles this block takes to execute if the conditional fails. size_t cond_failed_cycle_count = 0; diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 8c92119c..1ca4d027 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -99,7 +99,7 @@ void IREmitter::CallSupervisor(const Value& value) { Inst(Opcode::CallSupervisor, {value}); } -void IREmitter::PushRSB(const Arm::LocationDescriptor& return_location) { +void IREmitter::PushRSB(const LocationDescriptor& return_location) { Inst(Opcode::PushRSB, {Value(return_location.UniqueHash())}); } diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index 6a0b8df1..c839f883 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -9,8 +9,8 @@ #include #include "common/common_types.h" -#include "frontend/arm_types.h" #include "frontend/ir/basic_block.h" +#include "frontend/ir/location_descriptor.h" #include "frontend/ir/terminal.h" #include "frontend/ir/value.h" @@ -33,10 +33,10 @@ enum class Opcode; */ class IREmitter { public: - explicit IREmitter(Arm::LocationDescriptor descriptor) : block(descriptor), current_location(descriptor) {} + explicit IREmitter(LocationDescriptor descriptor) : block(descriptor), current_location(descriptor) {} Block block; - Arm::LocationDescriptor current_location; + LocationDescriptor current_location; struct ResultAndCarry { Value result; @@ -67,7 +67,7 @@ public: void BXWritePC(const Value& value); void LoadWritePC(const Value& value); void CallSupervisor(const Value& value); - void PushRSB(const Arm::LocationDescriptor& return_location); + void PushRSB(const LocationDescriptor& return_location); Value GetCpsr(); void SetCpsr(const Value& value); diff --git a/src/frontend/ir/location_descriptor.h b/src/frontend/ir/location_descriptor.h new file mode 100644 index 00000000..43ec0786 --- /dev/null +++ b/src/frontend/ir/location_descriptor.h @@ -0,0 +1,100 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2016 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#include +#include +#include "common/common_types.h" +#include "frontend/arm/FPSCR.h" +#include "frontend/arm/PSR.h" + +namespace Dynarmic { +namespace IR { + +/** + * LocationDescriptor describes the location of a basic block. + * The location is not solely based on the PC because other flags influence the way + * instructions should be translated. The CPSR.T flag is most notable since it + * tells us if the processor is in Thumb or Arm mode. + */ +class LocationDescriptor { +public: + // Indicates bits that should be preserved within descriptors. + static constexpr u32 CPSR_MODE_MASK = 0x00000220; + static constexpr u32 FPSCR_MODE_MASK = 0x03F79F00; + + LocationDescriptor(u32 arm_pc, Arm::PSR cpsr, Arm::FPSCR fpscr) + : arm_pc(arm_pc), cpsr(cpsr.Value() & CPSR_MODE_MASK), fpscr(fpscr.Value() & FPSCR_MODE_MASK) {} + + u32 PC() const { return arm_pc; } + bool TFlag() const { return cpsr.T(); } + bool EFlag() const { return cpsr.E(); } + + Arm::PSR CPSR() const { return cpsr; } + Arm::FPSCR FPSCR() const { return fpscr; } + + bool operator == (const LocationDescriptor& o) const { + return std::tie(arm_pc, cpsr, fpscr) == std::tie(o.arm_pc, o.cpsr, o.fpscr); + } + + bool operator != (const LocationDescriptor& o) const { + return !operator==(o); + } + + LocationDescriptor SetPC(u32 new_arm_pc) const { + return LocationDescriptor(new_arm_pc, cpsr, fpscr); + } + + LocationDescriptor AdvancePC(int amount) const { + return LocationDescriptor(static_cast(arm_pc + amount), cpsr, fpscr); + } + + LocationDescriptor SetTFlag(bool new_tflag) const { + Arm::PSR new_cpsr = cpsr; + new_cpsr.T(new_tflag); + + return LocationDescriptor(arm_pc, new_cpsr, fpscr); + } + + LocationDescriptor SetEFlag(bool new_eflag) const { + Arm::PSR new_cpsr = cpsr; + new_cpsr.E(new_eflag); + + return LocationDescriptor(arm_pc, new_cpsr, fpscr); + } + + LocationDescriptor SetFPSCR(u32 new_fpscr) const { + return LocationDescriptor(arm_pc, cpsr, Arm::FPSCR{new_fpscr & FPSCR_MODE_MASK}); + } + + u64 UniqueHash() const { + // This value MUST BE UNIQUE. + // This calculation has to match up with EmitX64::EmitTerminalPopRSBHint + u64 pc_u64 = u64(arm_pc); + u64 fpscr_u64 = u64(fpscr.Value()) << 32; + u64 t_u64 = cpsr.T() ? (1ull << 35) : 0; + u64 e_u64 = cpsr.E() ? (1ull << 39) : 0; + return pc_u64 | fpscr_u64 | t_u64 | e_u64; + } + +private: + u32 arm_pc; ///< Current program counter value. + Arm::PSR cpsr; ///< Current program status register. + Arm::FPSCR fpscr; ///< Floating point status control register. +}; + +} // namespace IR +} // namespace Dynarmic + +namespace std { +template <> +struct hash { + size_t operator()(const Dynarmic::IR::LocationDescriptor& x) const { + return std::hash()(x.UniqueHash()); + } +}; +} // namespace std diff --git a/src/frontend/ir/terminal.h b/src/frontend/ir/terminal.h index 13142751..b7fcc09f 100644 --- a/src/frontend/ir/terminal.h +++ b/src/frontend/ir/terminal.h @@ -9,7 +9,7 @@ #include #include "common/common_types.h" -#include "frontend/arm_types.h" +#include "frontend/ir/location_descriptor.h" namespace Dynarmic { namespace IR { @@ -22,8 +22,8 @@ struct Invalid {}; * The interpreter must interpret exactly one instruction. */ struct Interpret { - explicit Interpret(const Arm::LocationDescriptor& next_) : next(next_) {} - Arm::LocationDescriptor next; ///< Location at which interpretation starts. + explicit Interpret(const LocationDescriptor& next_) : next(next_) {} + LocationDescriptor next; ///< Location at which interpretation starts. }; /** @@ -38,8 +38,8 @@ struct ReturnToDispatch {}; * dispatcher, which will return control to the host. */ struct LinkBlock { - explicit LinkBlock(const Arm::LocationDescriptor& next_) : next(next_) {} - Arm::LocationDescriptor next; ///< Location descriptor for next block. + explicit LinkBlock(const LocationDescriptor& next_) : next(next_) {} + LocationDescriptor next; ///< Location descriptor for next block. }; /** @@ -51,8 +51,8 @@ struct LinkBlock { * as LinkBlock. */ struct LinkBlockFast { - explicit LinkBlockFast(const Arm::LocationDescriptor& next_) : next(next_) {} - Arm::LocationDescriptor next; ///< Location descriptor for next block. + explicit LinkBlockFast(const LocationDescriptor& next_) : next(next_) {} + LocationDescriptor next; ///< Location descriptor for next block. }; /** diff --git a/src/frontend/translate/translate.cpp b/src/frontend/translate/translate.cpp index 537aa776..af288ab8 100644 --- a/src/frontend/translate/translate.cpp +++ b/src/frontend/translate/translate.cpp @@ -4,17 +4,17 @@ * General Public License version 2 or any later version. */ -#include "frontend/arm_types.h" #include "frontend/ir/basic_block.h" +#include "frontend/ir/location_descriptor.h" #include "frontend/translate/translate.h" namespace Dynarmic { namespace Arm { -IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32); -IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32); +IR::Block TranslateArm(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32); +IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32); -IR::Block Translate(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) { +IR::Block Translate(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) { return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_32); } diff --git a/src/frontend/translate/translate.h b/src/frontend/translate/translate.h index 73af7800..05f7fadd 100644 --- a/src/frontend/translate/translate.h +++ b/src/frontend/translate/translate.h @@ -10,7 +10,8 @@ namespace Dynarmic { namespace IR { - class Block; +class Block; +class LocationDescriptor; } // namespace IR namespace Arm { @@ -25,7 +26,7 @@ using MemoryRead32FuncType = u32 (*)(u32 vaddr); * @param memory_read_32 The function we should use to read emulated memory. * @return A translated basic block in the intermediate representation. */ -IR::Block Translate(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32); +IR::Block Translate(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32); } // namespace Arm } // namespace Dynarmic diff --git a/src/frontend/translate/translate_arm.cpp b/src/frontend/translate/translate_arm.cpp index 6f406415..d6cb4d85 100644 --- a/src/frontend/translate/translate_arm.cpp +++ b/src/frontend/translate/translate_arm.cpp @@ -11,6 +11,7 @@ #include "frontend/decoder/arm.h" #include "frontend/decoder/vfp2.h" #include "frontend/ir/basic_block.h" +#include "frontend/ir/location_descriptor.h" #include "frontend/translate/translate.h" #include "frontend/translate/translate_arm/translate_arm.h" @@ -27,7 +28,7 @@ static bool CondCanContinue(ConditionalState cond_state, const IR::IREmitter& ir return std::all_of(ir.block.begin(), ir.block.end(), [](const IR::Inst& inst) { return !inst.WritesToCPSR(); }); } -IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) { +IR::Block TranslateArm(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) { ArmTranslatorVisitor visitor{descriptor}; bool should_continue = true; diff --git a/src/frontend/translate/translate_arm/translate_arm.h b/src/frontend/translate/translate_arm/translate_arm.h index 07849f68..da5b97a3 100644 --- a/src/frontend/translate/translate_arm/translate_arm.h +++ b/src/frontend/translate/translate_arm/translate_arm.h @@ -7,6 +7,7 @@ #pragma once #include "frontend/ir/ir_emitter.h" +#include "frontend/ir/location_descriptor.h" namespace Dynarmic { namespace Arm { @@ -23,7 +24,7 @@ enum class ConditionalState { }; struct ArmTranslatorVisitor final { - explicit ArmTranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) { + explicit ArmTranslatorVisitor(IR::LocationDescriptor descriptor) : ir(descriptor) { ASSERT_MSG(!descriptor.TFlag(), "The processor must be in Arm mode"); } diff --git a/src/frontend/translate/translate_thumb.cpp b/src/frontend/translate/translate_thumb.cpp index 4d9fa249..c5683d07 100644 --- a/src/frontend/translate/translate_thumb.cpp +++ b/src/frontend/translate/translate_thumb.cpp @@ -12,6 +12,7 @@ #include "frontend/decoder/thumb16.h" #include "frontend/decoder/thumb32.h" #include "frontend/ir/ir_emitter.h" +#include "frontend/ir/location_descriptor.h" #include "frontend/translate/translate.h" namespace Dynarmic { @@ -20,7 +21,7 @@ namespace Arm { namespace { struct ThumbTranslatorVisitor final { - explicit ThumbTranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) { + explicit ThumbTranslatorVisitor(IR::LocationDescriptor descriptor) : ir(descriptor) { ASSERT_MSG(descriptor.TFlag(), "The processor must be in Thumb mode"); } @@ -857,7 +858,7 @@ std::tuple ReadThumbInstruction(u32 arm_pc, MemoryRead32Func } // local namespace -IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) { +IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) { ThumbTranslatorVisitor visitor{descriptor}; bool should_continue = true; diff --git a/tests/arm/fuzz_arm.cpp b/tests/arm/fuzz_arm.cpp index 0e5cb001..da5576d8 100644 --- a/tests/arm/fuzz_arm.cpp +++ b/tests/arm/fuzz_arm.cpp @@ -19,9 +19,9 @@ #include "common/bit_util.h" #include "common/common_types.h" -#include "frontend/arm_types.h" #include "frontend/disassembler/disassembler.h" #include "frontend/ir/basic_block.h" +#include "frontend/ir/location_descriptor.h" #include "frontend/translate/translate.h" #include "ir_opt/passes.h" #include "rand_int.h" @@ -291,7 +291,7 @@ void FuzzJitArm(const size_t instruction_count, const size_t instructions_to_exe size_t num_insts = 0; while (num_insts < instructions_to_execute_count) { - Dynarmic::Arm::LocationDescriptor descriptor = {u32(num_insts * 4), Dynarmic::Arm::PSR{}, Dynarmic::Arm::FPSCR{}}; + Dynarmic::IR::LocationDescriptor descriptor = {u32(num_insts * 4), Dynarmic::Arm::PSR{}, Dynarmic::Arm::FPSCR{}}; Dynarmic::IR::Block ir_block = Dynarmic::Arm::Translate(descriptor, &MemoryRead32); Dynarmic::Optimization::GetSetElimination(ir_block); Dynarmic::Optimization::DeadCodeElimination(ir_block);