arm_types: Split out LocationDescriptor (#20)

This isn't really an ARM-specific type, since it's used to indicate a
Block location.
This commit is contained in:
Mat M 2016-09-05 06:54:09 -04:00 committed by Merry
parent 84336cf29d
commit 6d53bb6d7e
19 changed files with 175 additions and 153 deletions

View file

@ -15,8 +15,8 @@
namespace Dynarmic { namespace Dynarmic {
namespace Arm { namespace IR {
struct LocationDescriptor; class LocationDescriptor;
} }
class Jit final { class Jit final {
@ -76,7 +76,7 @@ public:
* @param descriptor Basic block descriptor. * @param descriptor Basic block descriptor.
* @return A string containing disassembly of the host machine code produced for the basic block. * @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: private:
bool is_executing = false; bool is_executing = false;

View file

@ -64,6 +64,7 @@ set(HEADERS
frontend/disassembler/disassembler.h frontend/disassembler/disassembler.h
frontend/ir/basic_block.h frontend/ir/basic_block.h
frontend/ir/ir_emitter.h frontend/ir/ir_emitter.h
frontend/ir/location_descriptor.h
frontend/ir/microinstruction.h frontend/ir/microinstruction.h
frontend/ir/opcodes.h frontend/ir/opcodes.h
frontend/ir/terminal.h frontend/ir/terminal.h

View file

@ -14,6 +14,7 @@
#include "backend_x64/jitstate.h" #include "backend_x64/jitstate.h"
#include "frontend/arm_types.h" #include "frontend/arm_types.h"
#include "frontend/ir/basic_block.h" #include "frontend/ir/basic_block.h"
#include "frontend/ir/location_descriptor.h"
#include "frontend/ir/microinstruction.h" #include "frontend/ir/microinstruction.h"
// TODO: Have ARM flags in host flags and not have them use up GPR registers unless necessary. // 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) { EmitX64::BlockDescriptor EmitX64::Emit(IR::Block& block) {
const Arm::LocationDescriptor descriptor = block.Location(); const IR::LocationDescriptor descriptor = block.Location();
reg_alloc.Reset(); reg_alloc.Reset();
@ -2156,7 +2157,7 @@ void EmitX64::EmitCondPrelude(const IR::Block& block) {
code->L(pass); 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()) { switch (terminal.which()) {
case 1: case 1:
EmitTerminalInterpret(boost::get<IR::Term::Interpret>(terminal), initial_location); EmitTerminalInterpret(boost::get<IR::Term::Interpret>(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.TFlag() == initial_location.TFlag(), "Unimplemented");
ASSERT_MSG(terminal.next.EFlag() == initial_location.EFlag(), "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 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(); 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; using namespace Xbyak::util;
if (terminal.next.TFlag() != initial_location.TFlag()) { 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 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; using namespace Xbyak::util;
if (terminal.next.TFlag() != initial_location.TFlag()) { 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; using namespace Xbyak::util;
// This calculation has to match up with IREmitter::PushRSB // This calculation has to match up with IREmitter::PushRSB
@ -2284,14 +2285,14 @@ void EmitX64::EmitTerminalPopRSBHint(IR::Term::PopRSBHint, Arm::LocationDescript
code->jmp(rax); 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_); Xbyak::Label pass = EmitCond(code, terminal.if_);
EmitTerminal(terminal.else_, initial_location); EmitTerminal(terminal.else_, initial_location);
code->L(pass); code->L(pass);
EmitTerminal(terminal.then_, initial_location); 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; using namespace Xbyak::util;
code->cmp(code->byte[r15 + offsetof(JitState, halt_requested)], u8(0)); 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); 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; using namespace Xbyak::util;
const CodePtr save_code_ptr = code->getCurr(); const CodePtr save_code_ptr = code->getCurr();

View file

@ -14,7 +14,7 @@
#include "backend_x64/block_of_code.h" #include "backend_x64/block_of_code.h"
#include "backend_x64/reg_alloc.h" #include "backend_x64/reg_alloc.h"
#include "dynarmic/callbacks.h" #include "dynarmic/callbacks.h"
#include "frontend/arm_types.h" #include "frontend/ir/location_descriptor.h"
#include "frontend/ir/terminal.h" #include "frontend/ir/terminal.h"
namespace Dynarmic { namespace Dynarmic {
@ -45,7 +45,7 @@ public:
BlockDescriptor Emit(IR::Block& ir); BlockDescriptor Emit(IR::Block& ir);
/// Looks up an emitted host block in the cache. /// Looks up an emitted host block in the cache.
boost::optional<BlockDescriptor> GetBasicBlock(Arm::LocationDescriptor descriptor) { boost::optional<BlockDescriptor> GetBasicBlock(IR::LocationDescriptor descriptor) {
auto iter = basic_blocks.find(descriptor); auto iter = basic_blocks.find(descriptor);
if (iter == basic_blocks.end()) if (iter == basic_blocks.end())
return boost::none; return boost::none;
@ -66,15 +66,15 @@ private:
void EmitCondPrelude(const IR::Block& block); void EmitCondPrelude(const IR::Block& block);
// Terminal instruction emitters // Terminal instruction emitters
void EmitTerminal(IR::Terminal terminal, Arm::LocationDescriptor initial_location); void EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location);
void EmitTerminalInterpret(IR::Term::Interpret terminal, Arm::LocationDescriptor initial_location); void EmitTerminalInterpret(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location);
void EmitTerminalReturnToDispatch(IR::Term::ReturnToDispatch terminal, Arm::LocationDescriptor initial_location); void EmitTerminalReturnToDispatch(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location);
void EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, Arm::LocationDescriptor initial_location); void EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location);
void EmitTerminalLinkBlockFast(IR::Term::LinkBlockFast terminal, Arm::LocationDescriptor initial_location); void EmitTerminalLinkBlockFast(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location);
void EmitTerminalPopRSBHint(IR::Term::PopRSBHint terminal, Arm::LocationDescriptor initial_location); void EmitTerminalPopRSBHint(IR::Term::PopRSBHint terminal, IR::LocationDescriptor initial_location);
void EmitTerminalIf(IR::Term::If terminal, Arm::LocationDescriptor initial_location); void EmitTerminalIf(IR::Term::If terminal, IR::LocationDescriptor initial_location);
void EmitTerminalCheckHalt(IR::Term::CheckHalt terminal, Arm::LocationDescriptor initial_location); void EmitTerminalCheckHalt(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location);
void Patch(Arm::LocationDescriptor desc, CodePtr bb); void Patch(IR::LocationDescriptor desc, CodePtr bb);
// Per-block state // Per-block state
RegAlloc reg_alloc; RegAlloc reg_alloc;
@ -85,9 +85,9 @@ private:
Jit* jit_interface; Jit* jit_interface;
std::unordered_map<u64, CodePtr> unique_hash_to_code_ptr; std::unordered_map<u64, CodePtr> unique_hash_to_code_ptr;
std::unordered_map<u64, std::vector<CodePtr>> patch_unique_hash_locations; std::unordered_map<u64, std::vector<CodePtr>> patch_unique_hash_locations;
std::unordered_map<Arm::LocationDescriptor, BlockDescriptor> basic_blocks; std::unordered_map<IR::LocationDescriptor, BlockDescriptor> basic_blocks;
std::unordered_map<Arm::LocationDescriptor, std::vector<CodePtr>> patch_jg_locations; std::unordered_map<IR::LocationDescriptor, std::vector<CodePtr>> patch_jg_locations;
std::unordered_map<Arm::LocationDescriptor, std::vector<CodePtr>> patch_jmp_locations; std::unordered_map<IR::LocationDescriptor, std::vector<CodePtr>> patch_jmp_locations;
}; };
} // namespace BackendX64 } // namespace BackendX64

View file

@ -20,8 +20,8 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "dynarmic/dynarmic.h" #include "dynarmic/dynarmic.h"
#include "frontend/arm_types.h"
#include "frontend/ir/basic_block.h" #include "frontend/ir/basic_block.h"
#include "frontend/ir/location_descriptor.h"
#include "frontend/translate/translate.h" #include "frontend/translate/translate.h"
#include "ir_opt/passes.h" #include "ir_opt/passes.h"
@ -47,13 +47,13 @@ struct Jit::Impl {
size_t Execute(size_t cycle_count) { size_t Execute(size_t cycle_count) {
u32 pc = jit_state.Reg[15]; 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; CodePtr code_ptr = GetBasicBlock(descriptor).code_ptr;
return block_of_code.RunCode(&jit_state, code_ptr, cycle_count); 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); auto block = GetBasicBlock(descriptor);
std::string result = fmt::format("address: {}\nsize: {} bytes\n", block.code_ptr, block.size); std::string result = fmt::format("address: {}\nsize: {} bytes\n", block.code_ptr, block.size);
@ -98,7 +98,7 @@ struct Jit::Impl {
} }
private: private:
EmitX64::BlockDescriptor GetBasicBlock(Arm::LocationDescriptor descriptor) { EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
auto block = emitter.GetBasicBlock(descriptor); auto block = emitter.GetBasicBlock(descriptor);
if (block) if (block)
return *block; return *block;
@ -187,7 +187,7 @@ void Jit::SetFpscr(u32 value) const {
return impl->jit_state.SetFpscr(value); 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); return impl->Disassemble(descriptor);
} }

View file

@ -9,7 +9,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/bit_util.h" #include "common/bit_util.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "frontend/arm_types.h" #include "frontend/ir/location_descriptor.h"
namespace Dynarmic { namespace Dynarmic {
namespace BackendX64 { namespace BackendX64 {
@ -75,7 +75,7 @@ void JitState::ResetRSB() {
*/ */
// NZCV; QC (ASMID only), AHP; DN, FZ, RMode, Stride; SBZP; Len; trap enables; cumulative bits // 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; constexpr u32 FPSCR_NZCV_MASK = 0xF0000000;
u32 JitState::Fpscr() const { u32 JitState::Fpscr() const {

View file

@ -6,15 +6,11 @@
#pragma once #pragma once
#include <functional>
#include <string> #include <string>
#include <tuple>
#include <utility> #include <utility>
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "frontend/arm/FPSCR.h"
#include "frontend/arm/PSR.h"
namespace Dynarmic { namespace Dynarmic {
namespace Arm { namespace Arm {
@ -66,77 +62,6 @@ enum class SignExtendRotation {
ROR_24 ///< ROR #24 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<u32>(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* CondToString(Cond cond, bool explicit_al = false);
const char* RegToString(Reg reg); const char* RegToString(Reg reg);
const char* ExtRegToString(ExtReg reg); const char* ExtRegToString(ExtReg reg);
@ -177,12 +102,3 @@ inline ExtReg operator+(ExtReg reg, size_t number) {
} // namespace Arm } // namespace Arm
} // namespace Dynarmic } // namespace Dynarmic
namespace std {
template <>
struct hash<Dynarmic::Arm::LocationDescriptor> {
size_t operator()(const Dynarmic::Arm::LocationDescriptor& x) const {
return std::hash<u64>()(x.UniqueHash());
}
};
} // namespace std

View file

@ -30,7 +30,7 @@ void Block::AppendNewInst(Opcode opcode, std::initializer_list<IR::Value> args)
instructions.push_back(inst); instructions.push_back(inst);
} }
Arm::LocationDescriptor Block::Location() const { LocationDescriptor Block::Location() const {
return location; return location;
} }
@ -42,11 +42,11 @@ void Block::SetCondition(Arm::Cond condition) {
cond = condition; cond = condition;
} }
Arm::LocationDescriptor Block::ConditionFailedLocation() const { LocationDescriptor Block::ConditionFailedLocation() const {
return cond_failed.get(); return cond_failed.get();
} }
void Block::SetConditionFailedLocation(Arm::LocationDescriptor fail_location) { void Block::SetConditionFailedLocation(LocationDescriptor fail_location) {
cond_failed = fail_location; cond_failed = fail_location;
} }
@ -91,7 +91,7 @@ const size_t& Block::CycleCount() const {
return cycle_count; return cycle_count;
} }
static std::string LocDescToString(const Arm::LocationDescriptor& loc) { static std::string LocDescToString(const LocationDescriptor& loc) {
return fmt::format("{{{},{},{},{}}}", return fmt::format("{{{},{},{},{}}}",
loc.PC(), loc.PC(),
loc.TFlag() ? "T" : "!T", loc.TFlag() ? "T" : "!T",

View file

@ -15,7 +15,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/intrusive_list.h" #include "common/intrusive_list.h"
#include "common/memory_pool.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/microinstruction.h"
#include "frontend/ir/terminal.h" #include "frontend/ir/terminal.h"
#include "frontend/ir/value.h" #include "frontend/ir/value.h"
@ -40,7 +40,7 @@ public:
using reverse_iterator = InstructionList::reverse_iterator; using reverse_iterator = InstructionList::reverse_iterator;
using const_reverse_iterator = InstructionList::const_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(); } bool empty() const { return instructions.empty(); }
size_type size() const { return instructions.size(); } size_type size() const { return instructions.size(); }
@ -77,7 +77,7 @@ public:
void AppendNewInst(Opcode op, std::initializer_list<Value> args); void AppendNewInst(Opcode op, std::initializer_list<Value> args);
/// Gets the starting location for this basic block. /// 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. /// Gets the condition required to pass in order to execute this block.
Arm::Cond GetCondition() const; Arm::Cond GetCondition() const;
@ -85,9 +85,9 @@ public:
void SetCondition(Arm::Cond condition); void SetCondition(Arm::Cond condition);
/// Gets the location of the block to execute if the predicated condition fails. /// 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. /// 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. /// Determines whether or not a prediated condition failure block is present.
bool HasConditionFailedLocation() const; bool HasConditionFailedLocation() const;
@ -115,11 +115,11 @@ public:
private: private:
/// Description of the starting location of this block /// Description of the starting location of this block
Arm::LocationDescriptor location; LocationDescriptor location;
/// Conditional to pass in order to execute this block /// Conditional to pass in order to execute this block
Arm::Cond cond = Arm::Cond::AL; Arm::Cond cond = Arm::Cond::AL;
/// Block to execute next if `cond` did not pass. /// Block to execute next if `cond` did not pass.
boost::optional<Arm::LocationDescriptor> cond_failed = {}; boost::optional<LocationDescriptor> cond_failed = {};
/// Number of cycles this block takes to execute if the conditional fails. /// Number of cycles this block takes to execute if the conditional fails.
size_t cond_failed_cycle_count = 0; size_t cond_failed_cycle_count = 0;

View file

@ -99,7 +99,7 @@ void IREmitter::CallSupervisor(const Value& value) {
Inst(Opcode::CallSupervisor, {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())}); Inst(Opcode::PushRSB, {Value(return_location.UniqueHash())});
} }

View file

@ -9,8 +9,8 @@
#include <initializer_list> #include <initializer_list>
#include "common/common_types.h" #include "common/common_types.h"
#include "frontend/arm_types.h"
#include "frontend/ir/basic_block.h" #include "frontend/ir/basic_block.h"
#include "frontend/ir/location_descriptor.h"
#include "frontend/ir/terminal.h" #include "frontend/ir/terminal.h"
#include "frontend/ir/value.h" #include "frontend/ir/value.h"
@ -33,10 +33,10 @@ enum class Opcode;
*/ */
class IREmitter { class IREmitter {
public: public:
explicit IREmitter(Arm::LocationDescriptor descriptor) : block(descriptor), current_location(descriptor) {} explicit IREmitter(LocationDescriptor descriptor) : block(descriptor), current_location(descriptor) {}
Block block; Block block;
Arm::LocationDescriptor current_location; LocationDescriptor current_location;
struct ResultAndCarry { struct ResultAndCarry {
Value result; Value result;
@ -67,7 +67,7 @@ public:
void BXWritePC(const Value& value); void BXWritePC(const Value& value);
void LoadWritePC(const Value& value); void LoadWritePC(const Value& value);
void CallSupervisor(const Value& value); void CallSupervisor(const Value& value);
void PushRSB(const Arm::LocationDescriptor& return_location); void PushRSB(const LocationDescriptor& return_location);
Value GetCpsr(); Value GetCpsr();
void SetCpsr(const Value& value); void SetCpsr(const Value& value);

View file

@ -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 <functional>
#include <tuple>
#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<u32>(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<Dynarmic::IR::LocationDescriptor> {
size_t operator()(const Dynarmic::IR::LocationDescriptor& x) const {
return std::hash<u64>()(x.UniqueHash());
}
};
} // namespace std

View file

@ -9,7 +9,7 @@
#include <boost/variant.hpp> #include <boost/variant.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "frontend/arm_types.h" #include "frontend/ir/location_descriptor.h"
namespace Dynarmic { namespace Dynarmic {
namespace IR { namespace IR {
@ -22,8 +22,8 @@ struct Invalid {};
* The interpreter must interpret exactly one instruction. * The interpreter must interpret exactly one instruction.
*/ */
struct Interpret { struct Interpret {
explicit Interpret(const Arm::LocationDescriptor& next_) : next(next_) {} explicit Interpret(const LocationDescriptor& next_) : next(next_) {}
Arm::LocationDescriptor next; ///< Location at which interpretation starts. LocationDescriptor next; ///< Location at which interpretation starts.
}; };
/** /**
@ -38,8 +38,8 @@ struct ReturnToDispatch {};
* dispatcher, which will return control to the host. * dispatcher, which will return control to the host.
*/ */
struct LinkBlock { struct LinkBlock {
explicit LinkBlock(const Arm::LocationDescriptor& next_) : next(next_) {} explicit LinkBlock(const LocationDescriptor& next_) : next(next_) {}
Arm::LocationDescriptor next; ///< Location descriptor for next block. LocationDescriptor next; ///< Location descriptor for next block.
}; };
/** /**
@ -51,8 +51,8 @@ struct LinkBlock {
* as LinkBlock. * as LinkBlock.
*/ */
struct LinkBlockFast { struct LinkBlockFast {
explicit LinkBlockFast(const Arm::LocationDescriptor& next_) : next(next_) {} explicit LinkBlockFast(const LocationDescriptor& next_) : next(next_) {}
Arm::LocationDescriptor next; ///< Location descriptor for next block. LocationDescriptor next; ///< Location descriptor for next block.
}; };
/** /**

View file

@ -4,17 +4,17 @@
* General Public License version 2 or any later version. * General Public License version 2 or any later version.
*/ */
#include "frontend/arm_types.h"
#include "frontend/ir/basic_block.h" #include "frontend/ir/basic_block.h"
#include "frontend/ir/location_descriptor.h"
#include "frontend/translate/translate.h" #include "frontend/translate/translate.h"
namespace Dynarmic { namespace Dynarmic {
namespace Arm { namespace Arm {
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32); IR::Block TranslateArm(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
IR::Block TranslateThumb(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); return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_32);
} }

View file

@ -10,7 +10,8 @@
namespace Dynarmic { namespace Dynarmic {
namespace IR { namespace IR {
class Block; class Block;
class LocationDescriptor;
} // namespace IR } // namespace IR
namespace Arm { namespace Arm {
@ -25,7 +26,7 @@ using MemoryRead32FuncType = u32 (*)(u32 vaddr);
* @param memory_read_32 The function we should use to read emulated memory. * @param memory_read_32 The function we should use to read emulated memory.
* @return A translated basic block in the intermediate representation. * @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 Arm
} // namespace Dynarmic } // namespace Dynarmic

View file

@ -11,6 +11,7 @@
#include "frontend/decoder/arm.h" #include "frontend/decoder/arm.h"
#include "frontend/decoder/vfp2.h" #include "frontend/decoder/vfp2.h"
#include "frontend/ir/basic_block.h" #include "frontend/ir/basic_block.h"
#include "frontend/ir/location_descriptor.h"
#include "frontend/translate/translate.h" #include "frontend/translate/translate.h"
#include "frontend/translate/translate_arm/translate_arm.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(); }); 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}; ArmTranslatorVisitor visitor{descriptor};
bool should_continue = true; bool should_continue = true;

View file

@ -7,6 +7,7 @@
#pragma once #pragma once
#include "frontend/ir/ir_emitter.h" #include "frontend/ir/ir_emitter.h"
#include "frontend/ir/location_descriptor.h"
namespace Dynarmic { namespace Dynarmic {
namespace Arm { namespace Arm {
@ -23,7 +24,7 @@ enum class ConditionalState {
}; };
struct ArmTranslatorVisitor final { 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"); ASSERT_MSG(!descriptor.TFlag(), "The processor must be in Arm mode");
} }

View file

@ -12,6 +12,7 @@
#include "frontend/decoder/thumb16.h" #include "frontend/decoder/thumb16.h"
#include "frontend/decoder/thumb32.h" #include "frontend/decoder/thumb32.h"
#include "frontend/ir/ir_emitter.h" #include "frontend/ir/ir_emitter.h"
#include "frontend/ir/location_descriptor.h"
#include "frontend/translate/translate.h" #include "frontend/translate/translate.h"
namespace Dynarmic { namespace Dynarmic {
@ -20,7 +21,7 @@ namespace Arm {
namespace { namespace {
struct ThumbTranslatorVisitor final { 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"); ASSERT_MSG(descriptor.TFlag(), "The processor must be in Thumb mode");
} }
@ -857,7 +858,7 @@ std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryRead32Func
} // local namespace } // local namespace
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) { IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
ThumbTranslatorVisitor visitor{descriptor}; ThumbTranslatorVisitor visitor{descriptor};
bool should_continue = true; bool should_continue = true;

View file

@ -19,9 +19,9 @@
#include "common/bit_util.h" #include "common/bit_util.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "frontend/arm_types.h"
#include "frontend/disassembler/disassembler.h" #include "frontend/disassembler/disassembler.h"
#include "frontend/ir/basic_block.h" #include "frontend/ir/basic_block.h"
#include "frontend/ir/location_descriptor.h"
#include "frontend/translate/translate.h" #include "frontend/translate/translate.h"
#include "ir_opt/passes.h" #include "ir_opt/passes.h"
#include "rand_int.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; size_t num_insts = 0;
while (num_insts < instructions_to_execute_count) { 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::IR::Block ir_block = Dynarmic::Arm::Translate(descriptor, &MemoryRead32);
Dynarmic::Optimization::GetSetElimination(ir_block); Dynarmic::Optimization::GetSetElimination(ir_block);
Dynarmic::Optimization::DeadCodeElimination(ir_block); Dynarmic::Optimization::DeadCodeElimination(ir_block);