clang-format

This commit is contained in:
SachinVin 2022-05-30 21:20:47 +05:30
parent d459cb6f59
commit 1f302f397f
37 changed files with 746 additions and 813 deletions

View File

@ -4,21 +4,21 @@
* General Public License version 2 or any later version.
*/
#include "dynarmic/backend/A64/a32_emit_a64.h"
#include <iterator>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <dynarmic/interface/A32/coprocessor.h>
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <mcl/assert.hpp>
#include <mcl/bit_cast.hpp>
#include <mcl/stdint.hpp>
#include <mcl/scope_exit.hpp>
#include <mcl/stdint.hpp>
#include <dynarmic/interface/A32/coprocessor.h>
#include "dynarmic/backend/A64/a32_emit_a64.h"
#include "dynarmic/backend/A64/a32_jitstate.h"
#include "dynarmic/backend/A64/abi.h"
#include "dynarmic/backend/A64/block_of_code.h"
@ -56,7 +56,8 @@ static size_t MJitStateExtReg(A32::ExtReg reg) {
ASSERT_FALSE("Should never happen.");
}
A32EmitContext::A32EmitContext(RegAlloc& reg_alloc, IR::Block& block) : EmitContext(reg_alloc, block) {}
A32EmitContext::A32EmitContext(RegAlloc& reg_alloc, IR::Block& block)
: EmitContext(reg_alloc, block) {}
A32::LocationDescriptor A32EmitContext::Location() const {
return A32::LocationDescriptor{block.Location()};
@ -91,8 +92,8 @@ std::ptrdiff_t A32EmitContext::GetInstOffset(IR::Inst* inst) const {
}
A32EmitA64::A32EmitA64(BlockOfCode& code, A32::UserConfig config, A32::Jit* jit_interface)
: EmitA64(code), config(std::move(config)), jit_interface(jit_interface) {
exception_handler.Register(code, [this](CodePtr PC){FastmemCallback(PC);});
: EmitA64(code), config(std::move(config)), jit_interface(jit_interface) {
exception_handler.Register(code, [this](CodePtr PC) { FastmemCallback(PC); });
GenMemoryAccessors();
GenTerminalHandlers();
code.PreludeComplete();
@ -121,15 +122,14 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) {
// Call the relevant Emit* member function.
switch (inst->GetOpcode()) {
#define OPCODE(name, type, ...) \
case IR::Opcode::name: \
A32EmitA64::Emit##name(ctx, inst); \
break;
#define A32OPC(name, type, ...) \
case IR::Opcode::A32##name: \
A32EmitA64::EmitA32##name(ctx, inst); \
break;
#define OPCODE(name, type, ...) \
case IR::Opcode::name: \
A32EmitA64::Emit##name(ctx, inst); \
break;
#define A32OPC(name, type, ...) \
case IR::Opcode::A32##name: \
A32EmitA64::EmitA32##name(ctx, inst); \
break;
#define A64OPC(...)
#include "dynarmic/backend/A64/opcodes.inc"
#undef OPCODE
@ -184,7 +184,7 @@ void A32EmitA64::EmitCondPrelude(const A32EmitContext& ctx) {
FixupBranch pass = EmitCond(ctx.block.GetCondition());
EmitAddCycles(ctx.block.ConditionFailedCycleCount());
EmitTerminal(IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, ctx.block.Location(), ctx.IsSingleStep());
EmitTerminal(IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, ctx.block.Location(), ctx.IsSingleStep());
code.SetJumpTarget(pass);
}
@ -343,7 +343,7 @@ void A32EmitA64::GenTerminalHandlers() {
code.BR(code.ABI_SCRATCH1);
code.SetJumpTarget(fast_dispatch_cache_miss);
code.STR(INDEX_UNSIGNED, location_descriptor_reg, fast_dispatch_entry_reg, offsetof(FastDispatchEntry, location_descriptor) );
code.STR(INDEX_UNSIGNED, location_descriptor_reg, fast_dispatch_entry_reg, offsetof(FastDispatchEntry, location_descriptor));
code.LookupBlock();
code.STR(INDEX_UNSIGNED, code.ABI_RETURN, fast_dispatch_entry_reg, offsetof(FastDispatchEntry, code_ptr));
code.BR(code.ABI_RETURN);
@ -359,7 +359,6 @@ void A32EmitA64::GenTerminalHandlers() {
}
}
void A32EmitA64::EmitA32GetRegister(A32EmitContext& ctx, IR::Inst* inst) {
A32::Reg reg = inst->GetArg(0).GetA32RegRef();
@ -418,8 +417,7 @@ void A32EmitA64::EmitA32SetExtendedRegister64(A32EmitContext& ctx, IR::Inst* ins
if (args[1].IsInFpr()) {
ARM64Reg to_store = ctx.reg_alloc.UseFpr(args[1]);
code.fp_emitter.STR(64, INDEX_UNSIGNED, to_store, X28, MJitStateExtReg(reg));
}
else {
} else {
ARM64Reg to_store = ctx.reg_alloc.UseGpr(args[1]);
code.STR(INDEX_UNSIGNED, to_store, X28, MJitStateExtReg(reg));
}
@ -697,7 +695,7 @@ void A32EmitA64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) {
code.ADD(new_upper, new_upper, mask);
code.STR(INDEX_UNSIGNED, new_upper, X28, offsetof(A32JitState, upper_location_descriptor));
code.LSL(mask, mask, 1);
code.SUBI2R(mask, mask, 4); // mask = pc & 1 ? 0xFFFFFFFE : 0xFFFFFFFC
code.SUBI2R(mask, mask, 4); // mask = pc & 1 ? 0xFFFFFFFE : 0xFFFFFFFC
code.AND(new_pc, new_pc, mask);
code.STR(INDEX_UNSIGNED, new_pc, X28, MJitStateReg(A32::Reg::PC));
}
@ -813,7 +811,7 @@ void A32EmitA64::DoNotFastmem(const DoNotFastmemMarker& marker) {
InvalidateBasicBlocks({std::get<0>(marker)});
}
template <typename T>
template<typename T>
void A32EmitA64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr callback_fn) {
constexpr size_t bit_size = mcl::bitsizeof<T>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -836,21 +834,21 @@ void A32EmitA64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr c
FixupBranch abort = code.CBZ(result);
code.ANDI2R(vaddr, vaddr, 4095);
switch (bit_size) {
case 8:
code.LDRB(DecodeReg(result), result, vaddr);
break;
case 16:
code.LDRH(DecodeReg(result), result, vaddr);
break;
case 32:
code.LDR(DecodeReg(result), result, vaddr);
break;
case 64:
code.LDR(result, result, vaddr);
break;
default:
ASSERT_FALSE("Invalid bit_size");
break;
case 8:
code.LDRB(DecodeReg(result), result, vaddr);
break;
case 16:
code.LDRH(DecodeReg(result), result, vaddr);
break;
case 32:
code.LDR(DecodeReg(result), result, vaddr);
break;
case 64:
code.LDR(result, result, vaddr);
break;
default:
ASSERT_FALSE("Invalid bit_size");
break;
}
end = code.B();
code.SetJumpTarget(abort);
@ -858,54 +856,52 @@ void A32EmitA64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr c
code.MOV(result, code.ABI_RETURN);
};
if (ShouldFastmem(do_not_fastmem_marker)) {
const CodePtr patch_location = code.GetCodePtr();
switch (bit_size) {
case 8:
code.LDRB(DecodeReg(result), X27, vaddr);
break;
case 16:
code.LDRH(DecodeReg(result), X27, vaddr);
break;
case 32:
code.LDR(DecodeReg(result), X27, vaddr);
break;
case 64:
code.LDR(result, X27, vaddr);
break;
default:
ASSERT_FALSE("Invalid bit_size");
break;
case 8:
code.LDRB(DecodeReg(result), X27, vaddr);
break;
case 16:
code.LDRH(DecodeReg(result), X27, vaddr);
break;
case 32:
code.LDR(DecodeReg(result), X27, vaddr);
break;
case 64:
code.LDR(result, X27, vaddr);
break;
default:
ASSERT_FALSE("Invalid bit_size");
break;
}
fastmem_patch_info.emplace(
patch_location,
FastmemPatchInfo{
[this, patch_location, page_table_lookup, callback_fn, result, do_not_fastmem_marker]{
CodePtr save_code_ptr = code.GetCodePtr();
code.SetCodePtr(patch_location);
FixupBranch thunk = code.B();
u8* end_ptr = code.GetWritableCodePtr();
code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr);
code.SetCodePtr(save_code_ptr);
code.SwitchToFarCode();
code.SetJumpTarget(thunk);
if (config.page_table) {
FixupBranch end{};
page_table_lookup(end);
code.SetJumpTarget(end, end_ptr);
} else {
code.BL(callback_fn);
code.MOV(result, code.ABI_RETURN);
}
code.B(end_ptr);
code.FlushIcache();
code.SwitchToNearCode();
patch_location,
FastmemPatchInfo{
[this, patch_location, page_table_lookup, callback_fn, result, do_not_fastmem_marker] {
CodePtr save_code_ptr = code.GetCodePtr();
code.SetCodePtr(patch_location);
FixupBranch thunk = code.B();
u8* end_ptr = code.GetWritableCodePtr();
code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr);
code.SetCodePtr(save_code_ptr);
code.SwitchToFarCode();
code.SetJumpTarget(thunk);
if (config.page_table) {
FixupBranch end{};
page_table_lookup(end);
code.SetJumpTarget(end, end_ptr);
} else {
code.BL(callback_fn);
code.MOV(result, code.ABI_RETURN);
}
code.B(end_ptr);
code.FlushIcache();
code.SwitchToNearCode();
DoNotFastmem(do_not_fastmem_marker);
}
});
DoNotFastmem(do_not_fastmem_marker);
}});
ctx.reg_alloc.DefineValue(inst, result);
return;
@ -950,21 +946,22 @@ void A32EmitA64::WriteMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr
FixupBranch abort = code.CBZ(addr);
code.ANDI2R(vaddr, vaddr, 4095);
switch (bit_size) {
case 8:
code.STRB(DecodeReg(value), addr, vaddr);
break;
case 16:
code.STRH(DecodeReg(value), addr, vaddr);
break;
case 32:
code.STR(DecodeReg(value), addr, vaddr);;
break;
case 64:
code.STR(value, addr, vaddr);
break;
default:
ASSERT_FALSE("Invalid bit_size");
break;
case 8:
code.STRB(DecodeReg(value), addr, vaddr);
break;
case 16:
code.STRH(DecodeReg(value), addr, vaddr);
break;
case 32:
code.STR(DecodeReg(value), addr, vaddr);
;
break;
case 64:
code.STR(value, addr, vaddr);
break;
default:
ASSERT_FALSE("Invalid bit_size");
break;
}
end = code.B();
code.SetJumpTarget(abort);
@ -974,49 +971,48 @@ void A32EmitA64::WriteMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr
if (ShouldFastmem(do_not_fastmem_marker)) {
const CodePtr patch_location = code.GetCodePtr();
switch (bit_size) {
case 8:
code.STRB(DecodeReg(value), X27, vaddr);
break;
case 16:
code.STRH(DecodeReg(value), X27, vaddr);
break;
case 32:
code.STR(DecodeReg(value), X27, vaddr);
break;
case 64:
code.STR(value, X27, vaddr);
break;
default:
ASSERT_FALSE("Invalid bit_size");
break;
case 8:
code.STRB(DecodeReg(value), X27, vaddr);
break;
case 16:
code.STRH(DecodeReg(value), X27, vaddr);
break;
case 32:
code.STR(DecodeReg(value), X27, vaddr);
break;
case 64:
code.STR(value, X27, vaddr);
break;
default:
ASSERT_FALSE("Invalid bit_size");
break;
}
fastmem_patch_info.emplace(
patch_location,
FastmemPatchInfo{
[this, patch_location, page_table_lookup, callback_fn, do_not_fastmem_marker]{
CodePtr save_code_ptr = code.GetCodePtr();
code.SetCodePtr(patch_location);
FixupBranch thunk = code.B();
u8* end_ptr = code.GetWritableCodePtr();
code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr);
code.SetCodePtr(save_code_ptr);
code.SwitchToFarCode();
code.SetJumpTarget(thunk);
if (config.page_table) {
FixupBranch end{};
page_table_lookup(end);
code.SetJumpTarget(end, end_ptr);
} else {
code.BL(callback_fn);
}
code.B(end_ptr);
code.FlushIcache();
code.SwitchToNearCode();
patch_location,
FastmemPatchInfo{
[this, patch_location, page_table_lookup, callback_fn, do_not_fastmem_marker] {
CodePtr save_code_ptr = code.GetCodePtr();
code.SetCodePtr(patch_location);
FixupBranch thunk = code.B();
u8* end_ptr = code.GetWritableCodePtr();
code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr);
code.SetCodePtr(save_code_ptr);
code.SwitchToFarCode();
code.SetJumpTarget(thunk);
if (config.page_table) {
FixupBranch end{};
page_table_lookup(end);
code.SetJumpTarget(end, end_ptr);
} else {
code.BL(callback_fn);
}
code.B(end_ptr);
code.FlushIcache();
code.SwitchToNearCode();
DoNotFastmem(do_not_fastmem_marker);
}
});
DoNotFastmem(do_not_fastmem_marker);
}});
return;
}
@ -1062,7 +1058,7 @@ void A32EmitA64::EmitA32WriteMemory64(A32EmitContext& ctx, IR::Inst* inst) {
WriteMemory<u64>(ctx, inst, write_memory_64);
}
template <typename T, void (A32::UserCallbacks::*fn)(A32::VAddr, T)>
template<typename T, void (A32::UserCallbacks::*fn)(A32::VAddr, T)>
static void ExclusiveWrite(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* inst, const A32::UserConfig& config) {
auto args = reg_alloc.GetArgumentInfo(inst);
reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
@ -1086,7 +1082,7 @@ static void ExclusiveWrite(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* ins
code.MOVI2R(passed, 0);
for (FixupBranch e : end) {
code.SetJumpTarget(e);
code.SetJumpTarget(e);
}
reg_alloc.DefineValue(inst, passed);
@ -1112,8 +1108,7 @@ static void EmitCoprocessorException() {
ASSERT_FALSE("Should raise coproc exception here");
}
static void CallCoprocCallback(BlockOfCode& code, RegAlloc& reg_alloc, A32::Jit* jit_interface, A32::Coprocessor::Callback callback,
IR::Inst* inst = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}) {
static void CallCoprocCallback(BlockOfCode& code, RegAlloc& reg_alloc, A32::Jit* jit_interface, A32::Coprocessor::Callback callback, IR::Inst* inst = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}) {
reg_alloc.HostCall(inst, {}, {}, arg0, arg1);
code.MOVP2R(code.ABI_PARAM1, jit_interface);
@ -1306,7 +1301,7 @@ void A32EmitA64::EmitA32CoprocGetTwoWords(A32EmitContext& ctx, IR::Inst* inst) {
code.LDR(INDEX_UNSIGNED, DecodeReg(reg_result), reg_tmp, 0);
code.MOVP2R(reg_tmp, source_ptrs[0]);
code.LDR(INDEX_UNSIGNED, DecodeReg(reg_tmp), reg_tmp, 0);
code.ORR(reg_result, reg_tmp, reg_result, ArithOption{ reg_result , ST_LSL, 32});
code.ORR(reg_result, reg_tmp, reg_result, ArithOption{reg_result, ST_LSL, 32});
ctx.reg_alloc.DefineValue(inst, reg_result);
@ -1331,7 +1326,6 @@ void A32EmitA64::EmitA32CoprocLoadWords(A32EmitContext& ctx, IR::Inst* inst) {
option = coproc_info[5];
}
std::shared_ptr<A32::Coprocessor> coproc = config.coprocessors[coproc_num];
if (!coproc) {
EmitCoprocessorException();
@ -1376,7 +1370,6 @@ void A32EmitA64::EmitA32CoprocStoreWords(A32EmitContext& ctx, IR::Inst* inst) {
CallCoprocCallback(code, ctx.reg_alloc, jit_interface, *action, nullptr, args[1]);
}
std::string A32EmitA64::LocationDescriptorToFriendlyName(const IR::LocationDescriptor& ir_descriptor) const {
const A32::LocationDescriptor descriptor{ir_descriptor};
return fmt::format("a32_{}{:08X}_{}_fpcr{:08X}", descriptor.TFlag() ? "t" : "a", descriptor.PC(), descriptor.EFlag() ? "be" : "le",
@ -1399,7 +1392,7 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDesc
code.STR(INDEX_UNSIGNED, DecodeReg(code.ABI_PARAM2), X28, MJitStateReg(A32::Reg::PC));
code.SwitchFpscrOnExit();
Devirtualize<&A32::UserCallbacks::InterpreterFallback>(config.callbacks).EmitCall(code);
code.ReturnFromRunCode(true); // TODO: Check cycles
code.ReturnFromRunCode(true); // TODO: Check cycles
}
void A32EmitA64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
@ -1407,7 +1400,7 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescri
}
void A32EmitA64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_location, IR::LocationDescriptor old_location) {
auto get_upper = [](const IR::LocationDescriptor &desc) -> u32 {
auto get_upper = [](const IR::LocationDescriptor& desc) -> u32 {
return static_cast<u32>(A32::LocationDescriptor{desc}.SetSingleStepping(false).UniqueHash() >> 32);
};
@ -1532,10 +1525,10 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDesc
void A32EmitA64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
const CodePtr patch_location = code.GetCodePtr();
auto long_branch_gt = [this](CodePtr ptr){
auto long_branch_gt = [this](CodePtr ptr) {
const s64 distance = reinterpret_cast<s64>(ptr) - reinterpret_cast<s64>(code.GetCodePtr());
if((distance >> 2) >= -0x40000 && (distance >> 2) <= 0x3FFFF) {
if ((distance >> 2) >= -0x40000 && (distance >> 2) <= 0x3FFFF) {
code.B(CC_GT, ptr);
return;
}
@ -1558,10 +1551,10 @@ void A32EmitA64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr
void A32EmitA64::EmitPatchJz(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
const CodePtr patch_location = code.GetCodePtr();
auto long_branch_gt = [this](CodePtr ptr){
auto long_branch_gt = [this](CodePtr ptr) {
const s64 distance = reinterpret_cast<s64>(ptr) - reinterpret_cast<s64>(code.GetCodePtr());
if((distance >> 2) >= -0x40000 && (distance >> 2) <= 0x3FFFF) {
if ((distance >> 2) >= -0x40000 && (distance >> 2) <= 0x3FFFF) {
code.B(CC_EQ, ptr);
return;
}
@ -1612,4 +1605,4 @@ void A32EmitA64::Unpatch(const IR::LocationDescriptor& location) {
}
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -17,9 +17,9 @@
#include "dynarmic/backend/A64/block_range_information.h"
#include "dynarmic/backend/A64/emit_a64.h"
#include "dynarmic/backend/A64/exception_handler.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/interface/A32/a32.h"
#include "dynarmic/interface/A32/config.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/ir/terminal.h"
namespace Dynarmic::BackendA64 {
@ -137,4 +137,4 @@ protected:
void EmitPatchMovX0(CodePtr target_code_ptr = nullptr) override;
};
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -7,13 +7,12 @@
#include <memory>
#include <boost/icl/interval_set.hpp>
#include <fmt/format.h>
#include <mcl/assert.hpp>
#include <mcl/stdint.hpp>
#include <mcl/scope_exit.hpp>
#include <dynarmic/interface/A32/a32.h>
#include <dynarmic/interface/A32/context.h>
#include <fmt/format.h>
#include <mcl/assert.hpp>
#include <mcl/scope_exit.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/A64/a32_emit_a64.h"
#include "dynarmic/backend/A64/a32_jitstate.h"
@ -21,12 +20,12 @@
#include "dynarmic/backend/A64/callback.h"
#include "dynarmic/backend/A64/devirtualize.h"
#include "dynarmic/backend/A64/jitstate_info.h"
#include "dynarmic/common/atomic.h"
#include "dynarmic/common/llvm_disassemble.h"
#include "dynarmic/frontend/A32/translate/a32_translate.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/location_descriptor.h"
#include "dynarmic/ir/opt/passes.h"
#include "dynarmic/common/atomic.h"
namespace Dynarmic::A32 {
@ -46,8 +45,7 @@ struct Jit::Impl {
: block_of_code(GenRunCodeCallbacks(config, &GetCurrentBlockThunk, this), JitStateInfo{jit_state})
, emitter(block_of_code, config, jit)
, config(std::move(config))
, jit_interface(jit)
{}
, jit_interface(jit) {}
A32JitState jit_state;
BlockOfCode block_of_code;
@ -61,7 +59,7 @@ struct Jit::Impl {
bool invalidate_entire_cache = false;
HaltReason Execute() {
const CodePtr current_codeptr = [this]{
const CodePtr current_codeptr = [this] {
// RSB optimization
const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A32JitState::RSBPtrMask;
if (jit_state.GetUniqueHash() == jit_state.rsb_location_descriptors[new_rsb_ptr]) {
@ -174,7 +172,8 @@ private:
}
};
Jit::Jit(UserConfig config) : impl(std::make_unique<Impl>(this, std::move(config))) {}
Jit::Jit(UserConfig config)
: impl(std::make_unique<Impl>(this, std::move(config))) {}
Jit::~Jit() = default;
@ -263,10 +262,15 @@ struct Context::Impl {
size_t invalid_cache_generation;
};
Context::Context() : impl(std::make_unique<Context::Impl>()) { impl->jit_state.ResetRSB(); }
Context::Context()
: impl(std::make_unique<Context::Impl>()) {
impl->jit_state.ResetRSB();
}
Context::~Context() = default;
Context::Context(const Context& ctx) : impl(std::make_unique<Context::Impl>(*ctx.impl)) {}
Context::Context(Context&& ctx) noexcept : impl(std::move(ctx.impl)) {}
Context::Context(const Context& ctx)
: impl(std::make_unique<Context::Impl>(*ctx.impl)) {}
Context::Context(Context&& ctx) noexcept
: impl(std::move(ctx.impl)) {}
Context& Context::operator=(const Context& ctx) {
*impl = *ctx.impl;
return *this;
@ -326,4 +330,4 @@ std::vector<std::string> Jit::Disassemble() const {
return result;
}
} // namespace Dynarmic::A32
} // namespace Dynarmic::A32

View File

@ -4,11 +4,12 @@
* General Public License version 2 or any later version.
*/
#include "dynarmic/backend/A64/a32_jitstate.h"
#include <mcl/assert.hpp>
#include <mcl/bit_cast.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/A64/a32_jitstate.h"
#include "dynarmic/backend/A64/block_of_code.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
@ -89,7 +90,7 @@ void A32JitState::SetCpsr(u32 cpsr) {
upper_location_descriptor |= mcl::bit::get_bit<9>(cpsr) ? 2 : 0;
upper_location_descriptor |= mcl::bit::get_bit<5>(cpsr) ? 1 : 0;
// IT state
upper_location_descriptor |= (cpsr >> 0) & 0b11111100'00000000;
upper_location_descriptor |= (cpsr >> 0) & 0b11111100'00000000;
upper_location_descriptor |= (cpsr >> 17) & 0b00000011'00000000;
// Other flags
@ -170,4 +171,4 @@ void A32JitState::SetFpscr(u32 FPSCR) {
guest_fpsr |= FPSCR & 0x9F;
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -7,6 +7,7 @@
#pragma once
#include <array>
#include <mcl/stdint.hpp>
namespace Dynarmic::BackendA64 {
@ -14,8 +15,8 @@ namespace Dynarmic::BackendA64 {
class BlockOfCode;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4324) // Structure was padded due to alignment specifier
# pragma warning(push)
# pragma warning(disable : 4324) // Structure was padded due to alignment specifier
#endif
struct A32JitState {
@ -23,7 +24,7 @@ struct A32JitState {
A32JitState() { ResetRSB(); }
std::array<u32, 16> Reg{}; // Current register file.
std::array<u32, 16> Reg{}; // Current register file.
// TODO: Mode-specific register sets unimplemented.
u32 upper_location_descriptor = 0;
@ -35,10 +36,10 @@ struct A32JitState {
u32 Cpsr() const;
void SetCpsr(u32 cpsr);
alignas(u64) std::array<u32, 64> ExtReg{}; // Extension registers.
alignas(u64) std::array<u32, 64> ExtReg{}; // Extension registers.
static constexpr size_t SpillCount = 64;
std::array<u64, SpillCount> Spill{}; // Spill.
std::array<u64, SpillCount> Spill{}; // Spill.
static size_t GetSpillLocationOffsetFromIndex(size_t i) {
return static_cast<u64>(offsetof(A32JitState, Spill) + i * sizeof(u64));
}
@ -57,7 +58,7 @@ struct A32JitState {
u32 exclusive_state = 0;
u32 exclusive_address = 0;
static constexpr size_t RSBSize = 8; // MUST be a power of 2.
static constexpr size_t RSBSize = 8; // MUST be a power of 2.
static constexpr size_t RSBPtrMask = RSBSize - 1;
u32 rsb_ptr = 0;
std::array<u64, RSBSize> rsb_location_descriptors;
@ -65,7 +66,7 @@ struct A32JitState {
void ResetRSB();
u32 fpsr_exc = 0;
u32 fpsr_qc = 0; // Dummy value
u32 fpsr_qc = 0; // Dummy value
u32 fpsr_nzcv = 0;
u32 Fpscr() const;
void SetFpscr(u32 FPSCR);
@ -102,9 +103,9 @@ struct A32JitState {
};
#ifdef _MSC_VER
#pragma warning(pop)
# pragma warning(pop)
#endif
using CodePtr = const void*;
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -14,18 +14,18 @@
// 20th Sep 2018: This code was modified for Dynarmic.
#include "dynarmic/backend/A64/abi.h"
#include <algorithm>
#include <vector>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/A64/abi.h"
namespace Dynarmic::BackendA64 {
template<typename RegisterArrayT>
void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const RegisterArrayT& regs) {
u32 gprs = 0 , fprs = 0;
u32 gprs = 0, fprs = 0;
for (HostLoc reg : regs) {
if (HostLocIsGPR(reg)) {
@ -83,4 +83,4 @@ void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, HostLoc e
ABI_PopRegistersAndAdjustStack(code, regs);
}
} // namespace Dynarmic::BackendX64
} // namespace Dynarmic::BackendA64

View File

@ -95,7 +95,7 @@ constexpr std::array<HostLoc, 20> ABI_ALL_CALLEE_SAVE = {
HostLoc::Q15,
};
constexpr size_t ABI_SHADOW_SPACE = 0; // bytes
constexpr size_t ABI_SHADOW_SPACE = 0; // bytes
static_assert(ABI_ALL_CALLER_SAVE.size() + ABI_ALL_CALLEE_SAVE.size() == 63, "Invalid total number of registers");
@ -107,4 +107,4 @@ void ABI_PopCallerSaveRegistersAndAdjustStack(BlockOfCode& code);
void ABI_PushCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, HostLoc exception);
void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, HostLoc exception);
} // namespace Dynarmic::BackendX64
} // namespace Dynarmic::BackendA64

View File

@ -4,6 +4,8 @@
* General Public License version 2 or any later version.
*/
#include "dynarmic/backend/A64/block_of_code.h"
#include <array>
#include <cstring>
#include <limits>
@ -12,23 +14,22 @@
#include "dynarmic/backend/A64/a32_jitstate.h"
#include "dynarmic/backend/A64/abi.h"
#include "dynarmic/interface/halt_reason.h"
#include "dynarmic/backend/A64/block_of_code.h"
#include "dynarmic/backend/A64/perf_map.h"
#include "dynarmic/interface/halt_reason.h"
#ifdef _WIN32
#include <windows.h>
# include <windows.h>
#else
#include <sys/mman.h>
# include <sys/mman.h>
#endif
#ifdef __APPLE__
#include <pthread.h>
# include <pthread.h>
#endif
namespace Dynarmic::BackendA64 {
const Arm64Gen::ARM64Reg BlockOfCode::ABI_RETURN = Arm64Gen::ARM64Reg::X0;
const Arm64Gen::ARM64Reg BlockOfCode::ABI_RETURN = Arm64Gen::ARM64Reg::X0;
const Arm64Gen::ARM64Reg BlockOfCode::ABI_RETURN2 = Arm64Gen::ARM64Reg::X1;
const Arm64Gen::ARM64Reg BlockOfCode::ABI_PARAM1 = Arm64Gen::ARM64Reg::X0;
@ -43,9 +44,9 @@ const Arm64Gen::ARM64Reg BlockOfCode::ABI_PARAM8 = Arm64Gen::ARM64Reg::X7;
const Arm64Gen::ARM64Reg BlockOfCode::ABI_SCRATCH1 = Arm64Gen::ARM64Reg::X30;
const std::array<Arm64Gen::ARM64Reg, 8> BlockOfCode::ABI_PARAMS = {BlockOfCode::ABI_PARAM1, BlockOfCode::ABI_PARAM2,
BlockOfCode::ABI_PARAM3, BlockOfCode::ABI_PARAM4,
BlockOfCode::ABI_PARAM5, BlockOfCode::ABI_PARAM6,
BlockOfCode::ABI_PARAM7, BlockOfCode::ABI_PARAM8};
BlockOfCode::ABI_PARAM3, BlockOfCode::ABI_PARAM4,
BlockOfCode::ABI_PARAM5, BlockOfCode::ABI_PARAM6,
BlockOfCode::ABI_PARAM7, BlockOfCode::ABI_PARAM8};
namespace {
@ -54,22 +55,22 @@ constexpr size_t FAR_CODE_OFFSET = 100 * 1024 * 1024;
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
void ProtectMemory([[maybe_unused]] const void* base, [[maybe_unused]] size_t size, bool is_executable) {
#if defined(_WIN32)
# if defined(_WIN32)
DWORD oldProtect = 0;
VirtualProtect(const_cast<void*>(base), size, is_executable ? PAGE_EXECUTE_READ : PAGE_READWRITE, &oldProtect);
#elif defined(__APPLE__)
# elif defined(__APPLE__)
pthread_jit_write_protect_np(is_executable);
#else
# else
static const size_t pageSize = sysconf(_SC_PAGESIZE);
const size_t iaddr = reinterpret_cast<size_t>(base);
const size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
const int mode = is_executable ? (PROT_READ | PROT_EXEC) : (PROT_READ | PROT_WRITE);
mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode);
#endif
# endif
}
#endif
} // anonymous namespace
} // anonymous namespace
BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi)
: fp_emitter(this)
@ -154,7 +155,7 @@ void BlockOfCode::ForceReturnFromRunCode(bool fpscr_already_exited) {
}
void BlockOfCode::GenRunCode() {
const u8* loop, *enter_fpscr_then_loop;
const u8 *loop, *enter_fpscr_then_loop;
std::vector<Arm64Gen::FixupBranch> return_to_caller_fpscr_already_exited;
AlignCode16();
@ -168,7 +169,7 @@ void BlockOfCode::GenRunCode() {
MOV(Arm64Gen::X28, ABI_PARAM1);
MOVI2R(Arm64Gen::X27, cb.value_in_X27);
MOV(Arm64Gen::X25, ABI_PARAM2); // save temporarily in non-volatile register
MOV(Arm64Gen::X25, ABI_PARAM2); // save temporarily in non-volatile register
cb.GetTicksRemaining->EmitCall(*this);
STR(Arm64Gen::INDEX_UNSIGNED, ABI_RETURN, Arm64Gen::X28, jsi.offsetof_cycles_to_run);
@ -353,4 +354,4 @@ void BlockOfCode::EnsurePatchLocationSize(CodePtr begin, size_t size) {
//#endif
//}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -14,8 +14,8 @@
#include "dynarmic/backend/A64/callback.h"
#include "dynarmic/backend/A64/constant_pool.h"
#include "dynarmic/backend/A64/jitstate_info.h"
#include "dynarmic/backend/A64/emitter/a64_emitter.h"
#include "dynarmic/backend/A64/jitstate_info.h"
#include "dynarmic/interface/halt_reason.h"
namespace Dynarmic::BackendA64 {
@ -34,7 +34,6 @@ public:
BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi);
BlockOfCode(const BlockOfCode&) = delete;
/// Call when external emitters have finished emitting their preludes.
void PreludeComplete();
@ -146,4 +145,4 @@ private:
//Xbyak::util::Cpu cpu_info;
};
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -4,35 +4,33 @@
* General Public License version 2 or any later version.
*/
#include "dynarmic/backend/A64/block_range_information.h"
#include <unordered_set>
#include <boost/icl/interval_map.hpp>
#include <boost/icl/interval_set.hpp>
#include <mcl/stdint.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/A64/block_range_information.h"
namespace Dynarmic::BackendA64 {
template <typename ProgramCounterType>
template<typename ProgramCounterType>
void BlockRangeInformation<ProgramCounterType>::AddRange(boost::icl::discrete_interval<ProgramCounterType> range, IR::LocationDescriptor location) {
block_ranges.add(std::make_pair(range, std::set<IR::LocationDescriptor>{location}));
}
template <typename ProgramCounterType>
template<typename ProgramCounterType>
void BlockRangeInformation<ProgramCounterType>::ClearCache() {
block_ranges.clear();
}
template <typename ProgramCounterType>
template<typename ProgramCounterType>
std::unordered_set<IR::LocationDescriptor> BlockRangeInformation<ProgramCounterType>::InvalidateRanges(const boost::icl::interval_set<ProgramCounterType>& ranges) {
std::unordered_set<IR::LocationDescriptor> erase_locations;
for (auto invalidate_interval : ranges) {
auto pair = block_ranges.equal_range(invalidate_interval);
for (auto it = pair.first; it != pair.second; ++it) {
for (const auto &descriptor : it->second) {
for (const auto& descriptor : it->second) {
erase_locations.insert(descriptor);
}
}
@ -44,4 +42,4 @@ std::unordered_set<IR::LocationDescriptor> BlockRangeInformation<ProgramCounterT
template class BlockRangeInformation<u32>;
template class BlockRangeInformation<u64>;
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -15,7 +15,7 @@
namespace Dynarmic::BackendA64 {
template <typename ProgramCounterType>
template<typename ProgramCounterType>
class BlockRangeInformation {
public:
void AddRange(boost::icl::discrete_interval<ProgramCounterType> range, IR::LocationDescriptor location);
@ -26,4 +26,4 @@ private:
boost::icl::interval_map<ProgramCounterType, std::set<IR::LocationDescriptor>> block_ranges;
};
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -5,6 +5,7 @@
*/
#include "dynarmic/backend/A64/callback.h"
#include "dynarmic/backend/A64/block_of_code.h"
namespace Dynarmic::BackendA64 {
@ -38,4 +39,4 @@ void ArgCallback::EmitCallWithReturnPointer(BlockOfCode& code, std::function<voi
code.QuickCallFunction(fn);
}
} // namespace Dynarmic::BackendX64
} // namespace Dynarmic::BackendA64

View File

@ -23,16 +23,19 @@ class Callback {
public:
virtual ~Callback();
virtual void EmitCall(BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const = 0;
virtual void EmitCall(
BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const = 0;
virtual void EmitCallWithReturnPointer(BlockOfCode& code, std::function<void(Arm64Gen::ARM64Reg, RegList)> fn) const = 0;
};
class SimpleCallback final : public Callback {
public:
template <typename Function>
SimpleCallback(Function fn) : fn(reinterpret_cast<void (*)()>(fn)) {}
template<typename Function>
SimpleCallback(Function fn)
: fn(reinterpret_cast<void (*)()>(fn)) {}
void EmitCall(BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const override;
void EmitCall(
BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const override;
void EmitCallWithReturnPointer(BlockOfCode& code, std::function<void(Arm64Gen::ARM64Reg, RegList)> fn) const override;
private:
@ -41,10 +44,12 @@ private:
class ArgCallback final : public Callback {
public:
template <typename Function>
ArgCallback(Function fn, u64 arg) : fn(reinterpret_cast<void (*)()>(fn)), arg(arg) {}
template<typename Function>
ArgCallback(Function fn, u64 arg)
: fn(reinterpret_cast<void (*)()>(fn)), arg(arg) {}
void EmitCall(BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const override;
void EmitCall(
BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const override;
void EmitCallWithReturnPointer(BlockOfCode& code, std::function<void(Arm64Gen::ARM64Reg, RegList)> fn) const override;
private:
@ -52,4 +57,4 @@ private:
u64 arg;
};
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -4,22 +4,24 @@
* General Public License version 2 or any later version.
*/
#include "dynarmic/backend/A64/constant_pool.h"
#include <cstring>
#include <mcl/assert.hpp>
#include "dynarmic/backend/A64/block_of_code.h"
#include "dynarmic/backend/A64/constant_pool.h"
namespace Dynarmic::BackendA64 {
ConstantPool::ConstantPool(BlockOfCode& code) : code(code) {}
ConstantPool::ConstantPool(BlockOfCode& code)
: code(code) {}
void ConstantPool::EmitPatchLDR(Arm64Gen::ARM64Reg Rt, u64 lower, u64 upper) {
const auto constant = std::make_tuple(lower, upper);
auto iter = constant_info.find(constant);
if (iter == constant_info.end()) {
struct PatchInfo p = { code.GetCodePtr(), Rt, constant };
struct PatchInfo p = {code.GetCodePtr(), Rt, constant};
patch_info.emplace_back(p);
code.BRK(0);
return;
@ -29,7 +31,7 @@ void ConstantPool::EmitPatchLDR(Arm64Gen::ARM64Reg Rt, u64 lower, u64 upper) {
if (!(offset >= -0x40000 && offset <= 0x3FFFF)) {
constant_info.erase(constant);
struct PatchInfo p = { code.GetCodePtr(), Rt, constant };
struct PatchInfo p = {code.GetCodePtr(), Rt, constant};
patch_info.emplace_back(p);
code.BRK(0x42);
return;
@ -58,9 +60,9 @@ void ConstantPool::PatchPool() {
code.SetCodePtr(pool_ptr);
}
void ConstantPool::Clear() {
void ConstantPool::Clear() {
constant_info.clear();
patch_info.clear();
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -31,7 +31,7 @@ public:
void Clear();
private:
static constexpr size_t align_size = 16; // bytes
static constexpr size_t align_size = 16; // bytes
std::map<std::tuple<u64, u64>, void*> constant_info;
@ -46,4 +46,4 @@ private:
std::vector<PatchInfo> patch_info;
};
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -9,10 +9,10 @@
#include <cstring>
#include <memory>
#include <mcl/type_traits/function_info.hpp>
#include <mcl/stdint.hpp>
#include <mcl/assert.hpp>
#include <mcl/bit_cast.hpp>
#include <mcl/stdint.hpp>
#include <mcl/type_traits/function_info.hpp>
#include "dynarmic/backend/A64/callback.h"
@ -20,20 +20,20 @@ namespace Dynarmic::BackendA64 {
namespace impl {
template <typename FunctionType, FunctionType mfp>
template<typename FunctionType, FunctionType mfp>
struct ThunkBuilder;
template <typename C, typename R, typename... Args, R(C::*mfp)(Args...)>
struct ThunkBuilder<R(C::*)(Args...), mfp> {
template<typename C, typename R, typename... Args, R (C::*mfp)(Args...)>
struct ThunkBuilder<R (C::*)(Args...), mfp> {
static R Thunk(C* this_, Args... args) {
return (this_->*mfp)(std::forward<Args>(args)...);
}
};
} // namespace impl
} // namespace impl
template<auto mfp>
ArgCallback DevirtualizeGeneric(mcl::class_type<decltype(mfp)> * this_) {
ArgCallback DevirtualizeGeneric(mcl::class_type<decltype(mfp)>* this_) {
return ArgCallback{&impl::ThunkBuilder<decltype(mfp), mfp>::Thunk, reinterpret_cast<u64>(this_)};
}
@ -74,4 +74,4 @@ ArgCallback Devirtualize(mcl::class_type<decltype(mfp)>* this_) {
#endif
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -4,16 +4,17 @@
* General Public License version 2 or any later version.
*/
#include "dynarmic/backend/A64/emit_a64.h"
#include <unordered_map>
#include <unordered_set>
#include <mcl/assert.hpp>
#include <mcl/bit/bit_field.hpp>
#include <mcl/stdint.hpp>
#include <mcl/scope_exit.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/A64/block_of_code.h"
#include "dynarmic/backend/A64/emit_a64.h"
#include "dynarmic/backend/A64/hostloc.h"
#include "dynarmic/backend/A64/perf_map.h"
#include "dynarmic/backend/A64/reg_alloc.h"
@ -28,7 +29,7 @@
namespace Dynarmic::BackendA64 {
EmitContext::EmitContext(RegAlloc& reg_alloc, IR::Block& block)
: reg_alloc(reg_alloc), block(block) {}
: reg_alloc(reg_alloc), block(block) {}
void EmitContext::EraseInstruction(IR::Inst* inst) {
block.Instructions().erase(inst);
@ -36,7 +37,7 @@ void EmitContext::EraseInstruction(IR::Inst* inst) {
}
EmitA64::EmitA64(BlockOfCode& code)
: code(code) {}
: code(code) {}
EmitA64::~EmitA64() = default;
@ -64,8 +65,8 @@ void EmitA64::EmitIdentity(EmitContext& ctx, IR::Inst* inst) {
void EmitA64::PushRSBHelper(ARM64Reg loc_desc_reg, ARM64Reg index_reg, IR::LocationDescriptor target) {
auto iter = block_descriptors.find(target);
CodePtr target_code_ptr = iter != block_descriptors.end()
? iter->second.entrypoint
: code.GetReturnFromRunCodeAddress();
? iter->second.entrypoint
: code.GetReturnFromRunCodeAddress();
code.LDR(INDEX_UNSIGNED, DecodeReg(index_reg), X28, code.GetJitStateInfo().offsetof_rsb_ptr);
@ -162,28 +163,28 @@ FixupBranch EmitA64::EmitCond(IR::Cond cond) {
code._MSR(FIELD_NZCV, cpsr);
switch (cond) {
case IR::Cond::EQ: //z
case IR::Cond::EQ: //z
label = code.B(CC_EQ);
break;
case IR::Cond::NE: //!z
case IR::Cond::NE: //!z
label = code.B(CC_NEQ);
break;
case IR::Cond::CS: //c
case IR::Cond::CS: //c
label = code.B(CC_CS);
break;
case IR::Cond::CC: //!c
case IR::Cond::CC: //!c
label = code.B(CC_CC);
break;
case IR::Cond::MI: //n
case IR::Cond::MI: //n
label = code.B(CC_MI);
break;
case IR::Cond::PL: //!n
case IR::Cond::PL: //!n
label = code.B(CC_PL);
break;
case IR::Cond::VS: //v
case IR::Cond::VS: //v
label = code.B(CC_VS);
break;
case IR::Cond::VC: //!v
case IR::Cond::VC: //!v
label = code.B(CC_VC);
break;
case IR::Cond::HI: //c & !z
@ -278,7 +279,7 @@ void EmitA64::InvalidateBasicBlocks(const std::unordered_set<IR::LocationDescrip
code.EnableWriting();
SCOPE_EXIT { code.DisableWriting(); };
for (const auto &descriptor : locations) {
for (const auto& descriptor : locations) {
auto it = block_descriptors.find(descriptor);
if (it == block_descriptors.end()) {
continue;
@ -291,4 +292,4 @@ void EmitA64::InvalidateBasicBlocks(const std::unordered_set<IR::LocationDescrip
}
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -24,7 +24,7 @@
namespace Dynarmic::IR {
class Block;
class Inst;
} // namespace Dynarmic::IR
} // namespace Dynarmic::IR
namespace Dynarmic::BackendA64 {
@ -38,7 +38,7 @@ using A64FullVectorWidth = std::integral_constant<size_t, 128>;
// Array alias that always sizes itself according to the given type T
// relative to the size of a vector register. e.g. T = u32 would result
// in a std::array<u32, 4>.
template <typename T>
template<typename T>
using VectorArray = std::array<T, A64FullVectorWidth::value / mcl::bitsizeof<T>>;
struct EmitContext {
@ -124,4 +124,4 @@ protected:
std::unordered_map<IR::LocationDescriptor, PatchInformation> patch_information;
};
} // namespace Dynarmic::BackendX64
} // namespace Dynarmic::BackendA64

View File

@ -8,8 +8,8 @@
#include <mcl/stdint.hpp>
#include "dynarmic/backend/A64/block_of_code.h"
#include "dynarmic/backend/A64/reg_alloc.h"
#include "dynarmic/backend/A64/emit_a64.h"
#include "dynarmic/backend/A64/reg_alloc.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.h"
@ -82,7 +82,7 @@ void EmitA64::EmitMostSignificantBit(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Arm64Gen::ARM64Reg result = DecodeReg(ctx.reg_alloc.UseScratchGpr(args[0]));
// TODO: Flag optimization
code.LSR(result,result, 31);
code.LSR(result, result, 31);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -127,46 +127,46 @@ static void EmitConditionalSelect(BlockOfCode& code, EmitContext& ctx, IR::Inst*
code._MSR(FIELD_NZCV, nzcv);
switch (args[0].GetImmediateCond()) {
case IR::Cond::EQ: //z
code.CSEL(else_, else_, then_ , CC_EQ);
case IR::Cond::EQ: //z
code.CSEL(else_, else_, then_, CC_EQ);
break;
case IR::Cond::NE: //!z
case IR::Cond::NE: //!z
code.CSEL(else_, else_, then_, CC_NEQ);
break;
case IR::Cond::CS: //c
case IR::Cond::CS: //c
code.CSEL(else_, else_, then_, CC_CS);
break;
case IR::Cond::CC: //!c
code.CSEL(else_, else_, then_ , CC_CC);
case IR::Cond::CC: //!c
code.CSEL(else_, else_, then_, CC_CC);
break;
case IR::Cond::MI: //n
case IR::Cond::MI: //n
code.CSEL(else_, else_, then_, CC_MI);
break;
case IR::Cond::PL: //!n
case IR::Cond::PL: //!n
code.CSEL(else_, else_, then_, CC_PL);
break;
case IR::Cond::VS: //v
case IR::Cond::VS: //v
code.CSEL(else_, else_, then_, CC_VS);
break;
case IR::Cond::VC: //!v
case IR::Cond::VC: //!v
code.CSEL(else_, else_, then_, CC_VC);
break;
case IR::Cond::HI: //c & !z
case IR::Cond::HI: //c & !z
code.CSEL(else_, else_, then_, CC_HI);
break;
case IR::Cond::LS: //!c | z
case IR::Cond::LS: //!c | z
code.CSEL(else_, else_, then_, CC_LS);
break;
case IR::Cond::GE: // n == v
case IR::Cond::GE: // n == v
code.CSEL(else_, else_, then_, CC_GE);
break;
case IR::Cond::LT: // n != v
case IR::Cond::LT: // n != v
code.CSEL(else_, else_, then_, CC_LT);
break;
case IR::Cond::GT: // !z & (n == v)
case IR::Cond::GT: // !z & (n == v)
code.CSEL(else_, else_, then_, CC_GT);
break;
case IR::Cond::LE: // z | (n != v)
case IR::Cond::LE: // z | (n != v)
code.CSEL(else_, else_, then_, CC_LE);
break;
case IR::Cond::AL:
@ -257,7 +257,7 @@ void EmitA64::EmitLogicalShiftLeft32(EmitContext& ctx, IR::Inst* inst) {
end = code.B(CC_EQ);
code.CMPI2R(shift, 32);
code.SUBI2R(shift, shift, 1); // Subtract 1 to get the bit that is shiftedout, into the MSB.
code.SUBI2R(shift, shift, 1); // Subtract 1 to get the bit that is shiftedout, into the MSB.
code.LSLV(result, result, shift);
code.UBFX(carry, result, 31, 1);
code.LSL(result, result, 1);
@ -344,7 +344,7 @@ void EmitA64::EmitLogicalShiftRight32(EmitContext& ctx, IR::Inst* inst) {
} else if (shift < 32) {
code.LSR(carry, result, shift - 1);
code.ANDI2R(carry, carry, 1);
code.LSR(result,result, shift);
code.LSR(result, result, shift);
} else if (shift == 32) {
code.UBFX(carry, result, 31, 1);
code.MOV(result, WZR);
@ -369,7 +369,7 @@ void EmitA64::EmitLogicalShiftRight32(EmitContext& ctx, IR::Inst* inst) {
end = code.B(CC_EQ);
code.CMPI2R(shift, 32);
code.SUBI2R(shift, shift, 1); // Subtract 1 to get the bit that is shifted out to the carry.
code.SUBI2R(shift, shift, 1); // Subtract 1 to get the bit that is shifted out to the carry.
code.LSRV(result, result, shift);
code.ANDI2R(carry, result, 1);
code.LSR(result, result, 1);
@ -706,7 +706,7 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
code.CMP(DecodeReg(op_arg), DecodeReg(op_arg));
code.ADCS(result, result, op_arg);
} else {
code.ADDS(result,result, op_arg);
code.ADDS(result, result, op_arg);
}
} else {
code.CMPI2R(DecodeReg(carry), 1);
@ -767,7 +767,7 @@ static void EmitSub(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
} else {
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
code.ADDSI2R(op_arg, op_arg, 0); // Clear carry
code.ADDSI2R(op_arg, op_arg, 0); // Clear carry
code.SBCS(result, result, op_arg);
}
} else {
@ -781,12 +781,12 @@ static void EmitSub(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
if (carry_in.GetImmediateU1()) {
code.SUBS(result, result, op_arg);
} else {
code.ADDSI2R(DecodeReg(op_arg), DecodeReg(op_arg), 0); // Clear carry
code.SBCS(result,result, op_arg);
code.ADDSI2R(DecodeReg(op_arg), DecodeReg(op_arg), 0); // Clear carry
code.SBCS(result, result, op_arg);
}
} else {
code.CMPI2R(DecodeReg(carry), 0x1);
code.SBCS(result,result, op_arg);
code.SBCS(result, result, op_arg);
}
}
@ -839,7 +839,6 @@ void EmitA64::EmitMul64(EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(inst, result);
}
void EmitA64::EmitUnsignedDiv32(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -880,7 +879,6 @@ void EmitA64::EmitSignedDiv64(EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(inst, result);
}
void EmitA64::EmitAnd32(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -905,8 +903,7 @@ void EmitA64::EmitAnd64(EmitContext& ctx, IR::Inst* inst) {
if (args[1].IsImmediate()) {
u32 op_arg = args[1].GetImmediateU32();
code.ANDI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
}
else {
} else {
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
code.AND(result, result, op_arg);
}
@ -938,8 +935,7 @@ void EmitA64::EmitEor64(EmitContext& ctx, IR::Inst* inst) {
if (args[1].IsImmediate()) {
u32 op_arg = args[1].GetImmediateU32();
code.EORI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
}
else {
} else {
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
code.EOR(result, result, op_arg);
}
@ -957,7 +953,7 @@ void EmitA64::EmitOr32(EmitContext& ctx, IR::Inst* inst) {
code.ORRI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
} else {
Arm64Gen::ARM64Reg op_arg = DecodeReg(ctx.reg_alloc.UseGpr(args[1]));
code.ORR(result, result , op_arg);
code.ORR(result, result, op_arg);
}
ctx.reg_alloc.DefineValue(inst, result);
@ -971,8 +967,7 @@ void EmitA64::EmitOr64(EmitContext& ctx, IR::Inst* inst) {
if (args[1].IsImmediate()) {
u32 op_arg = args[1].GetImmediateU32();
code.ORRI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
}
else {
} else {
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
code.ORR(result, result, op_arg);
}
@ -1001,8 +996,7 @@ void EmitA64::EmitNot64(EmitContext& ctx, IR::Inst* inst) {
if (args[0].IsImmediate()) {
result = ctx.reg_alloc.ScratchGpr();
code.MOVI2R(result, u32(~args[0].GetImmediateU32()));
}
else {
} else {
result = ctx.reg_alloc.UseScratchGpr(args[0]);
code.MVN(result, result);
}
@ -1120,11 +1114,11 @@ void EmitA64::EmitCountLeadingZeros32(EmitContext& ctx, IR::Inst* inst) {
}
void EmitA64::EmitCountLeadingZeros64(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ARM64Reg source = ctx.reg_alloc.UseGpr(args[0]);
ARM64Reg result = ctx.reg_alloc.ScratchGpr();
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ARM64Reg source = ctx.reg_alloc.UseGpr(args[0]);
ARM64Reg result = ctx.reg_alloc.ScratchGpr();
code.CLZ(result, source);
ctx.reg_alloc.DefineValue(inst, result);
code.CLZ(result, source);
ctx.reg_alloc.DefineValue(inst, result);
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -46,7 +46,7 @@ Arm64Gen::RoundingMode ConvertRoundingModeToA64RoundingMode(FP::RoundingMode rou
}
}
template <size_t fsize, typename Function>
template<size_t fsize, typename Function>
void FPTwoOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -61,7 +61,7 @@ void FPTwoOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
ctx.reg_alloc.DefineValue(inst, result);
}
template <size_t fsize, typename Function>
template<size_t fsize, typename Function>
void FPThreeOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -72,14 +72,13 @@ void FPThreeOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn)
if constexpr (std::is_member_function_pointer_v<Function>) {
(code.fp_emitter.*fn)(result, result, operand);
}
else {
} else {
fn(result, result, operand);
}
ctx.reg_alloc.DefineValue(inst, result);
}
} // anonymous namespace
} // anonymous namespace
//void EmitA64::EmitFPAbs16(EmitContext& ctx, IR::Inst* inst) {
// auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -136,27 +135,27 @@ void EmitA64::EmitFPNeg64(EmitContext& ctx, IR::Inst* inst) {
}
void EmitA64::EmitFPAdd32(EmitContext& ctx, IR::Inst* inst) {
FPThreeOp<32, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FADD);
FPThreeOp<32, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FADD);
}
void EmitA64::EmitFPAdd64(EmitContext& ctx, IR::Inst* inst) {
FPThreeOp<64, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FADD);
FPThreeOp<64, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FADD);
}
void EmitA64::EmitFPDiv32(EmitContext& ctx, IR::Inst* inst) {
FPThreeOp<32, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FDIV);
FPThreeOp<32, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FDIV);
}
void EmitA64::EmitFPDiv64(EmitContext& ctx, IR::Inst* inst) {
FPThreeOp<64, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FDIV);
FPThreeOp<64, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FDIV);
}
void EmitA64::EmitFPMul32(EmitContext& ctx, IR::Inst* inst) {
FPThreeOp<32, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FMUL);
FPThreeOp<32, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FMUL);
}
void EmitA64::EmitFPMul64(EmitContext& ctx, IR::Inst* inst) {
FPThreeOp<64, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FMUL);
FPThreeOp<64, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FMUL);
}
void EmitA64::EmitFPSqrt32(EmitContext& ctx, IR::Inst* inst) {
FPTwoOp<32>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FSQRT);
@ -167,11 +166,11 @@ void EmitA64::EmitFPSqrt64(EmitContext& ctx, IR::Inst* inst) {
}
void EmitA64::EmitFPSub32(EmitContext& ctx, IR::Inst* inst) {
FPThreeOp<32, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FSUB);
FPThreeOp<32, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FSUB);
}
void EmitA64::EmitFPSub64(EmitContext& ctx, IR::Inst* inst) {
FPThreeOp<64, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FSUB);
FPThreeOp<64, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FSUB);
}
static ARM64Reg SetFpscrNzcvFromFlags(BlockOfCode& code, EmitContext& ctx) {
@ -276,13 +275,11 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
if constexpr (unsigned_) {
code.fp_emitter.FCVTU(result, src, round_imm);
}
else {
} else {
code.fp_emitter.FCVTS(result, src, round_imm);
}
ctx.reg_alloc.DefineValue(inst, result);
}
void EmitA64::EmitFPDoubleToFixedS32(EmitContext& ctx, IR::Inst* inst) {
@ -328,8 +325,7 @@ void EmitA64::EmitFPFixedS32ToSingle(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) {
code.fp_emitter.SCVTF(result, from, fbits);
}
else {
} else {
code.fp_emitter.SCVTF(result, from);
}
@ -347,8 +343,7 @@ void EmitA64::EmitFPFixedU32ToSingle(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) {
code.fp_emitter.UCVTF(result, from, fbits);
}
else {
} else {
code.fp_emitter.UCVTF(result, from);
}
@ -366,8 +361,7 @@ void EmitA64::EmitFPFixedS32ToDouble(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) {
code.fp_emitter.SCVTF(result, from, fbits);
}
else {
} else {
code.fp_emitter.SCVTF(result, from);
}
@ -385,8 +379,7 @@ void EmitA64::EmitFPFixedS64ToDouble(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) {
code.fp_emitter.SCVTF(result, from, fbits);
}
else {
} else {
code.fp_emitter.SCVTF(result, from);
}
@ -404,8 +397,7 @@ void EmitA64::EmitFPFixedS64ToSingle(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) {
code.fp_emitter.SCVTF(result, from, fbits);
}
else {
} else {
code.fp_emitter.SCVTF(result, from);
}
@ -423,8 +415,7 @@ void EmitA64::EmitFPFixedU32ToDouble(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) {
code.fp_emitter.UCVTF(result, from, fbits);
}
else {
} else {
code.fp_emitter.UCVTF(result, from);
}
@ -434,7 +425,6 @@ void EmitA64::EmitFPFixedU32ToDouble(EmitContext& ctx, IR::Inst* inst) {
void EmitA64::EmitFPFixedU64ToDouble(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const ARM64Reg from = ctx.reg_alloc.UseGpr(args[0]);
const ARM64Reg result = EncodeRegToDouble(ctx.reg_alloc.ScratchFpr());
const size_t fbits = args[1].GetImmediateU8();
@ -443,8 +433,7 @@ void EmitA64::EmitFPFixedU64ToDouble(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) {
code.fp_emitter.UCVTF(result, from, fbits);
}
else {
} else {
code.fp_emitter.UCVTF(result, from);
}
@ -454,7 +443,6 @@ void EmitA64::EmitFPFixedU64ToDouble(EmitContext& ctx, IR::Inst* inst) {
void EmitA64::EmitFPFixedU64ToSingle(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const ARM64Reg from = ctx.reg_alloc.UseGpr(args[0]);
const ARM64Reg result = EncodeRegToSingle(ctx.reg_alloc.ScratchFpr());
const size_t fbits = args[1].GetImmediateU8();
@ -463,11 +451,10 @@ void EmitA64::EmitFPFixedU64ToSingle(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) {
code.fp_emitter.UCVTF(result, from, fbits);
}
else {
} else {
code.fp_emitter.UCVTF(result, from);
}
ctx.reg_alloc.DefineValue(inst, result);
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -468,4 +468,4 @@ void EmitA64::EmitPackedSelect(EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(inst, ge);
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -37,8 +37,7 @@ void EmitSignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst)
if constexpr (op == Op::Add) {
code.fp_emitter.SQADD(size, result, result, addend);
}
else {
} else {
code.fp_emitter.SQSUB(size, result, result, addend);
}
@ -54,7 +53,7 @@ void EmitSignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst)
ctx.reg_alloc.DefineValue(inst, result);
}
} // anonymous namespace
} // anonymous namespace
void EmitA64::EmitSignedSaturatedAdd8(EmitContext& ctx, IR::Inst* inst) {
EmitSignedSaturatedOp<Op::Add, 8>(code, ctx, inst);
@ -166,4 +165,4 @@ void EmitA64::EmitUnsignedSaturation(EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(inst, result);
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

File diff suppressed because it is too large Load Diff

View File

@ -265,7 +265,11 @@ constexpr ARM64Reg EncodeRegToQuad(ARM64Reg reg) {
return static_cast<ARM64Reg>(reg | 0xC0);
}
enum OpType { TYPE_IMM = 0, TYPE_REG, TYPE_IMMSREG, TYPE_RSR, TYPE_MEM };
enum OpType { TYPE_IMM = 0,
TYPE_REG,
TYPE_IMMSREG,
TYPE_RSR,
TYPE_MEM };
enum ShiftType {
ST_LSL = 0,
@ -474,8 +478,7 @@ private:
void EncodeUnconditionalBranchInst(u32 opc, u32 op2, u32 op3, u32 op4, ARM64Reg Rn);
void EncodeExceptionInst(u32 instenc, u32 imm);
void EncodeSystemInst(u32 op0, u32 op1, u32 CRn, u32 CRm, u32 op2, ARM64Reg Rt);
void EncodeArithmeticInst(u32 instenc, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm,
ArithOption Option);
void EncodeArithmeticInst(u32 instenc, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option);
void EncodeArithmeticCarryInst(u32 op, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void EncodeCondCompareImmInst(u32 op, ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond);
void EncodeCondCompareRegInst(u32 op, ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond);
@ -494,8 +497,7 @@ private:
void EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
void EncodeAddSubImmInst(u32 op, bool flags, u32 shift, u32 imm, ARM64Reg Rn, ARM64Reg Rd);
void EncodeLogicalImmInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, int n);
void EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2,
ARM64Reg Rn, s32 imm);
void EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
void EncodeAddressInst(u32 op, ARM64Reg Rd, s32 imm);
void EncodeLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
@ -503,7 +505,8 @@ protected:
void Write32(u32 value);
public:
ARM64XEmitter() : m_code(nullptr), m_lastCacheFlushEnd(nullptr) {
ARM64XEmitter()
: m_code(nullptr), m_lastCacheFlushEnd(nullptr) {
}
ARM64XEmitter(u8* code_ptr) {
@ -831,7 +834,7 @@ public:
// Wrapper around MOVZ+MOVK
void MOVI2R(ARM64Reg Rd, u64 imm, bool optimize = true);
bool MOVI2R2(ARM64Reg Rd, u64 imm1, u64 imm2);
template <class P>
template<class P>
void MOVP2R(ARM64Reg Rd, P* ptr) {
ASSERT_MSG(Is64Bit(Rd), "Can't store pointers in 32-bit registers");
MOVI2R(Rd, (uintptr_t)ptr);
@ -848,8 +851,7 @@ public:
void EORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
void CMPI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
void ADDI2R_internal(ARM64Reg Rd, ARM64Reg Rn, u64 imm, bool negative, bool flags,
ARM64Reg scratch);
void ADDI2R_internal(ARM64Reg Rd, ARM64Reg Rn, u64 imm, bool negative, bool flags, ARM64Reg scratch);
void ADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
void ADDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
void SUBI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
@ -872,14 +874,14 @@ public:
// Unfortunately, calling operator() directly is undefined behavior in C++
// (this method might be a thunk in the case of multi-inheritance) so we
// have to go through a trampoline function.
template <typename T, typename... Args>
template<typename T, typename... Args>
static T CallLambdaTrampoline(const std::function<T(Args...)>* f, Args... args) {
return (*f)(args...);
}
// This function expects you to have set up the state.
// Overwrites X0 and X30
template <typename T, typename... Args>
template<typename T, typename... Args>
ARM64Reg ABI_SetupLambda(const std::function<T(Args...)>* f) {
auto trampoline = &ARM64XEmitter::CallLambdaTrampoline<T, Args...>;
MOVI2R(X30, (uintptr_t)trampoline);
@ -889,7 +891,7 @@ public:
// Plain function call
void QuickCallFunction(const void* func, ARM64Reg scratchreg = X16);
template <typename T>
template<typename T>
void QuickCallFunction(T func, ARM64Reg scratchreg = X16) {
QuickCallFunction((const void*)func, scratchreg);
}
@ -897,7 +899,8 @@ public:
class ARM64FloatEmitter {
public:
ARM64FloatEmitter(ARM64XEmitter* emit) : m_emit(emit) {
ARM64FloatEmitter(ARM64XEmitter* emit)
: m_emit(emit) {
}
void LDR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
@ -935,7 +938,7 @@ public:
void FABS(ARM64Reg Rd, ARM64Reg Rn);
void FNEG(ARM64Reg Rd, ARM64Reg Rn);
void FSQRT(ARM64Reg Rd, ARM64Reg Rn);
void FMOV(ARM64Reg Rd, ARM64Reg Rn, bool top = false); // Also generalized move between GPR/FP
void FMOV(ARM64Reg Rd, ARM64Reg Rn, bool top = false); // Also generalized move between GPR/FP
// Scalar - 2 Source
void FADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
@ -1110,22 +1113,17 @@ private:
}
// Emitting functions
void EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, ARM64Reg Rn,
s32 imm);
void EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn,
ARM64Reg Rm);
void EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
void EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void EmitThreeSame(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void EmitScalarThreeSame(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void EmitCopy(bool Q, u32 op, u32 imm5, u32 imm4, ARM64Reg Rd, ARM64Reg Rn);
void Emit2RegMisc(bool Q, bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt,
ARM64Reg Rn);
void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt,
ARM64Reg Rn, ARM64Reg Rm);
void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn);
void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm);
void Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
void EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
void EmitConversion2(bool sf, bool S, bool direction, u32 type, u32 rmode, u32 opcode,
int scale, ARM64Reg Rd, ARM64Reg Rn);
void EmitConversion2(bool sf, bool S, bool direction, u32 type, u32 rmode, u32 opcode, int scale, ARM64Reg Rd, ARM64Reg Rn);
void EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Reg Rn, ARM64Reg Rm);
void EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void EmitPermute(u32 size, u32 op, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
@ -1133,19 +1131,14 @@ private:
void EmitShiftImm(bool Q, bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
void EmitScalarShiftImm(bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
void EmitLoadStoreMultipleStructure(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn);
void EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn,
ARM64Reg Rm);
void EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm);
void EmitScalar1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
void EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, ARM64Reg Rd, ARM64Reg Rn,
ARM64Reg Rm);
void EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void EmitLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
void EmitConvertScalarToInt(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round, bool sign);
void EmitScalar3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra,
int opcode);
void EncodeLoadStorePair(u32 size, bool load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2,
ARM64Reg Rn, s32 imm);
void EncodeLoadStoreRegisterOffset(u32 size, bool load, ARM64Reg Rt, ARM64Reg Rn,
ArithOption Rm);
void EmitScalar3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra, int opcode);
void EncodeLoadStorePair(u32 size, bool load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
void EncodeLoadStoreRegisterOffset(u32 size, bool load, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
void EncodeModImm(bool Q, u8 op, u8 cmode, u8 o2, ARM64Reg Rd, u8 abcdefgh);
void SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper);
@ -1170,4 +1163,4 @@ private:
}
};
} // namespace Dynarmic::BackendA64::Arm64Gen
} // namespace Dynarmic::BackendA64::Arm64Gen

View File

@ -6,23 +6,23 @@
namespace Dynarmic::BackendA64 {
enum CCFlags {
CC_EQ = 0, // Equal
CC_NEQ, // Not equal
CC_CS, // Carry Set
CC_CC, // Carry Clear
CC_MI, // Minus (Negative)
CC_PL, // Plus
CC_VS, // Overflow
CC_VC, // No Overflow
CC_HI, // Unsigned higher
CC_LS, // Unsigned lower or same
CC_GE, // Signed greater than or equal
CC_LT, // Signed less than
CC_GT, // Signed greater than
CC_LE, // Signed less than or equal
CC_AL, // Always (unconditional) 14
CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same
CC_LO = CC_CC, // Alias of CC_CC Unsigned lower
CC_EQ = 0, // Equal
CC_NEQ, // Not equal
CC_CS, // Carry Set
CC_CC, // Carry Clear
CC_MI, // Minus (Negative)
CC_PL, // Plus
CC_VS, // Overflow
CC_VC, // No Overflow
CC_HI, // Unsigned higher
CC_LS, // Unsigned lower or same
CC_GE, // Signed greater than or equal
CC_LT, // Signed less than
CC_GT, // Signed greater than
CC_LE, // Signed less than or equal
CC_AL, // Always (unconditional) 14
CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same
CC_LO = CC_CC, // Alias of CC_CC Unsigned lower
};
const u32 NO_COND = 0xE0000000;
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -8,9 +8,9 @@
#include <vector>
#ifdef _WIN32
#include <windows.h>
# include <windows.h>
#else
#include <sys/mman.h>
# include <sys/mman.h>
#endif
#include <mcl/assert.hpp>
@ -21,7 +21,7 @@ namespace Dynarmic::BackendA64 {
// You get memory management for free, plus, you can use all emitter functions
// without having to prefix them with gen-> or something similar. Example
// implementation: class JIT : public CodeBlock<ARMXEmitter> {}
template <class T>
template<class T>
class CodeBlock : public T {
private:
// A privately used function to set the executable RAM space to something
@ -57,11 +57,11 @@ public:
#if defined(_WIN32)
void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#else
#if defined(__APPLE__)
# if defined(__APPLE__)
void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE | MAP_JIT, -1, 0);
#else
# else
void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
#endif
# endif
if (ptr == MAP_FAILED)
ptr = nullptr;
@ -137,4 +137,4 @@ public:
m_children.emplace_back(child);
}
};
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -7,8 +7,8 @@
#pragma once
#include <array>
#include <memory>
#include <functional>
#include <memory>
#include <mcl/stdint.hpp>
@ -32,9 +32,10 @@ public:
void Register(BlockOfCode& code, std::function<void(CodePtr)> segv_callback = nullptr);
bool SupportsFastmem() const;
private:
struct Impl;
std::unique_ptr<Impl> impl;
};
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -22,4 +22,4 @@ bool ExceptionHandler::SupportsFastmem() const {
return false;
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -8,14 +8,13 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <csignal>
#include <mutex>
#include <vector>
#include <csignal>
#ifdef __APPLE__
#include <sys/ucontext.h>
# include <sys/ucontext.h>
#else
#include <ucontext.h>
# include <ucontext.h>
#endif
#include <mcl/assert.hpp>
@ -117,8 +116,7 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
"dynarmic: POSIX SigHandler: Exception was not in registered code blocks (PC {})\n",
PC);
struct sigaction* retry_sa =
sig == SIGSEGV ? &sig_handler.old_sa_segv : &sig_handler.old_sa_bus;
struct sigaction* retry_sa = sig == SIGSEGV ? &sig_handler.old_sa_segv : &sig_handler.old_sa_bus;
if (retry_sa->sa_flags & SA_SIGINFO) {
retry_sa->sa_sigaction(sig, info, raw_context);
return;
@ -133,7 +131,7 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
retry_sa->sa_handler(sig);
}
} // anonymous namespace
} // anonymous namespace
struct ExceptionHandler::Impl final {
Impl(BlockOfCode& code, std::function<void(CodePtr)> cb) {
@ -162,4 +160,4 @@ bool ExceptionHandler::SupportsFastmem() const {
return static_cast<bool>(impl);
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -18,4 +18,4 @@ Arm64Gen::ARM64Reg HostLocToFpr(HostLoc loc) {
return EncodeRegToQuad(static_cast<Arm64Gen::ARM64Reg>(static_cast<int>(loc) - static_cast<int>(HostLoc::Q0)));
}
} // namespace Dynarmic::BackendX64
} // namespace Dynarmic::BackendA64

View File

@ -48,7 +48,7 @@ enum class HostLoc {
X29,
X30,
SP, // 64bit stack pointer
SP, // 64bit stack pointer
// Qword FPR registers
Q0,
@ -138,32 +138,76 @@ using HostLocList = std::initializer_list<HostLoc>;
// X30 is the link register.
// In order of desireablity based first on ABI
constexpr HostLocList any_gpr = {
HostLoc::X19, HostLoc::X20, HostLoc::X21, HostLoc::X22, HostLoc::X23,
HostLoc::X24, HostLoc::X25,
HostLoc::X19,
HostLoc::X20,
HostLoc::X21,
HostLoc::X22,
HostLoc::X23,
HostLoc::X24,
HostLoc::X25,
HostLoc::X8, HostLoc::X9, HostLoc::X10, HostLoc::X11, HostLoc::X12,
HostLoc::X13, HostLoc::X14, HostLoc::X15, HostLoc::X16, HostLoc::X17,
HostLoc::X8,
HostLoc::X9,
HostLoc::X10,
HostLoc::X11,
HostLoc::X12,
HostLoc::X13,
HostLoc::X14,
HostLoc::X15,
HostLoc::X16,
HostLoc::X17,
HostLoc::X7, HostLoc::X6, HostLoc::X5, HostLoc::X4, HostLoc::X3,
HostLoc::X2, HostLoc::X1, HostLoc::X0,
HostLoc::X7,
HostLoc::X6,
HostLoc::X5,
HostLoc::X4,
HostLoc::X3,
HostLoc::X2,
HostLoc::X1,
HostLoc::X0,
};
constexpr HostLocList any_fpr = {
HostLoc::Q8, HostLoc::Q9, HostLoc::Q10, HostLoc::Q11, HostLoc::Q12, HostLoc::Q13,
HostLoc::Q14, HostLoc::Q15,
HostLoc::Q8,
HostLoc::Q9,
HostLoc::Q10,
HostLoc::Q11,
HostLoc::Q12,
HostLoc::Q13,
HostLoc::Q14,
HostLoc::Q15,
HostLoc::Q16, HostLoc::Q17, HostLoc::Q18, HostLoc::Q19, HostLoc::Q20, HostLoc::Q21,
HostLoc::Q22, HostLoc::Q23, HostLoc::Q24, HostLoc::Q25, HostLoc::Q26, HostLoc::Q27,
HostLoc::Q28, HostLoc::Q29, HostLoc::Q30, HostLoc::Q31,
HostLoc::Q16,
HostLoc::Q17,
HostLoc::Q18,
HostLoc::Q19,
HostLoc::Q20,
HostLoc::Q21,
HostLoc::Q22,
HostLoc::Q23,
HostLoc::Q24,
HostLoc::Q25,
HostLoc::Q26,
HostLoc::Q27,
HostLoc::Q28,
HostLoc::Q29,
HostLoc::Q30,
HostLoc::Q31,
HostLoc::Q7, HostLoc::Q6, HostLoc::Q5, HostLoc::Q4, HostLoc::Q3, HostLoc::Q2,
HostLoc::Q1, HostLoc::Q0,
HostLoc::Q7,
HostLoc::Q6,
HostLoc::Q5,
HostLoc::Q4,
HostLoc::Q3,
HostLoc::Q2,
HostLoc::Q1,
HostLoc::Q0,
};
Arm64Gen::ARM64Reg HostLocToReg64(HostLoc loc);
Arm64Gen::ARM64Reg HostLocToFpr(HostLoc loc);
template <typename JitStateType>
template<typename JitStateType>
size_t SpillToOpArg(HostLoc loc) {
ASSERT(HostLocIsSpill(loc));
@ -174,4 +218,4 @@ size_t SpillToOpArg(HostLoc loc) {
return JitStateType::GetSpillLocationOffsetFromIndex(i);
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -11,22 +11,21 @@
namespace Dynarmic::BackendA64 {
struct JitStateInfo {
template <typename JitStateType>
template<typename JitStateType>
JitStateInfo(const JitStateType&)
: offsetof_cycles_remaining(offsetof(JitStateType, cycles_remaining))
, offsetof_cycles_to_run(offsetof(JitStateType, cycles_to_run))
, offsetof_save_host_FPCR(offsetof(JitStateType, save_host_FPCR))
, offsetof_guest_fpcr(offsetof(JitStateType, guest_fpcr))
, offsetof_guest_fpsr(offsetof(JitStateType, guest_fpsr))
, offsetof_rsb_ptr(offsetof(JitStateType, rsb_ptr))
, rsb_ptr_mask(JitStateType::RSBPtrMask)
, offsetof_rsb_location_descriptors(offsetof(JitStateType, rsb_location_descriptors))
, offsetof_rsb_codeptrs(offsetof(JitStateType, rsb_codeptrs))
, offsetof_cpsr_nzcv(offsetof(JitStateType, cpsr_nzcv))
, offsetof_fpsr_exc(offsetof(JitStateType, fpsr_exc))
, offsetof_fpsr_qc(offsetof(JitStateType, fpsr_qc))
, offsetof_halt_reason(offsetof(JitStateType, halt_reason))
{}
: offsetof_cycles_remaining(offsetof(JitStateType, cycles_remaining))
, offsetof_cycles_to_run(offsetof(JitStateType, cycles_to_run))
, offsetof_save_host_FPCR(offsetof(JitStateType, save_host_FPCR))
, offsetof_guest_fpcr(offsetof(JitStateType, guest_fpcr))
, offsetof_guest_fpsr(offsetof(JitStateType, guest_fpsr))
, offsetof_rsb_ptr(offsetof(JitStateType, rsb_ptr))
, rsb_ptr_mask(JitStateType::RSBPtrMask)
, offsetof_rsb_location_descriptors(offsetof(JitStateType, rsb_location_descriptors))
, offsetof_rsb_codeptrs(offsetof(JitStateType, rsb_codeptrs))
, offsetof_cpsr_nzcv(offsetof(JitStateType, cpsr_nzcv))
, offsetof_fpsr_exc(offsetof(JitStateType, fpsr_exc))
, offsetof_fpsr_qc(offsetof(JitStateType, fpsr_qc))
, offsetof_halt_reason(offsetof(JitStateType, halt_reason)) {}
const size_t offsetof_cycles_remaining;
const size_t offsetof_cycles_to_run;
@ -43,4 +42,4 @@ struct JitStateInfo {
const size_t offsetof_halt_reason;
};
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -9,14 +9,14 @@
#ifdef __linux__
#include <cstdio>
#include <cstdlib>
#include <mutex>
#include <sys/types.h>
#include <unistd.h>
# include <cstdio>
# include <cstdlib>
# include <mutex>
#include <fmt/format.h>
#include <mcl/stdint.hpp>
# include <fmt/format.h>
# include <mcl/stdint.hpp>
# include <sys/types.h>
# include <unistd.h>
namespace Dynarmic::BackendA64 {
@ -41,7 +41,7 @@ void OpenFile() {
std::setvbuf(file, nullptr, _IONBF, 0);
}
} // anonymous namespace
} // anonymous namespace
namespace detail {
void PerfMapRegister(const void* start, const void* end, const std::string& friendly_name) {
@ -57,7 +57,7 @@ void PerfMapRegister(const void* start, const void* end, const std::string& frie
const std::string line = fmt::format("{:016x} {:016x} {:s}\n", reinterpret_cast<u64>(start), reinterpret_cast<u64>(end) - reinterpret_cast<u64>(start), friendly_name);
std::fwrite(line.data(), sizeof *line.data(), line.size(), file);
}
} // namespace detail
} // namespace detail
void PerfMapClear() {
std::lock_guard guard{mutex};
@ -71,7 +71,7 @@ void PerfMapClear() {
OpenFile();
}
} // namespace Dynarmic::BackendX64
} // namespace Dynarmic::BackendA64
#else
@ -79,10 +79,10 @@ namespace Dynarmic::BackendA64 {
namespace detail {
void PerfMapRegister(const void*, const void*, const std::string&) {}
} // namespace detail
} // namespace detail
void PerfMapClear() {}
} // namespace Dynarmic::BackendX64
} // namespace Dynarmic::BackendA64
#endif

View File

@ -15,7 +15,7 @@ namespace Dynarmic::BackendA64 {
namespace detail {
void PerfMapRegister(const void* start, const void* end, const std::string& friendly_name);
} // namespace detail
} // namespace detail
template<typename T>
void PerfMapRegister(T start, const void* end, const std::string& friendly_name) {
@ -24,4 +24,4 @@ void PerfMapRegister(T start, const void* end, const std::string& friendly_name)
void PerfMapClear();
} // namespace Dynarmic::BackendX64
} // namespace Dynarmic::BackendA64

View File

@ -4,6 +4,8 @@
* General Public License version 2 or any later version.
*/
#include "dynarmic/backend/A64/reg_alloc.h"
#include <algorithm>
#include <numeric>
#include <utility>
@ -12,7 +14,6 @@
#include <mcl/assert.hpp>
#include "dynarmic/backend/A64/abi.h"
#include "dynarmic/backend/A64/reg_alloc.h"
namespace Dynarmic::BackendA64 {
@ -67,7 +68,7 @@ static size_t GetBitWidth(IR::Type type) {
case IR::Type::U128:
return 128;
case IR::Type::NZCVFlags:
return 32; // TODO: Update to 16 when flags optimization is done
return 32; // TODO: Update to 16 when flags optimization is done
}
UNREACHABLE();
return 0;
@ -379,16 +380,9 @@ HostLoc RegAlloc::ScratchImpl(HostLocList desired_locations) {
return location;
}
void RegAlloc::HostCall(IR::Inst* result_def, std::optional<Argument::copyable_reference> arg0,
std::optional<Argument::copyable_reference> arg1,
std::optional<Argument::copyable_reference> arg2,
std::optional<Argument::copyable_reference> arg3,
std::optional<Argument::copyable_reference> arg4,
std::optional<Argument::copyable_reference> arg5,
std::optional<Argument::copyable_reference> arg6,
std::optional<Argument::copyable_reference> arg7) {
void RegAlloc::HostCall(IR::Inst* result_def, std::optional<Argument::copyable_reference> arg0, std::optional<Argument::copyable_reference> arg1, std::optional<Argument::copyable_reference> arg2, std::optional<Argument::copyable_reference> arg3, std::optional<Argument::copyable_reference> arg4, std::optional<Argument::copyable_reference> arg5, std::optional<Argument::copyable_reference> arg6, std::optional<Argument::copyable_reference> arg7) {
constexpr size_t args_count = 8;
constexpr std::array<HostLoc, args_count> args_hostloc = { ABI_PARAM1, ABI_PARAM2, ABI_PARAM3, ABI_PARAM4, ABI_PARAM5, ABI_PARAM6, ABI_PARAM7, ABI_PARAM8 };
constexpr std::array<HostLoc, args_count> args_hostloc = {ABI_PARAM1, ABI_PARAM2, ABI_PARAM3, ABI_PARAM4, ABI_PARAM5, ABI_PARAM6, ABI_PARAM7, ABI_PARAM8};
const std::array<std::optional<Argument::copyable_reference>, args_count> args = {arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7};
static const std::vector<HostLoc> other_caller_save = [args_hostloc]() {
@ -417,7 +411,7 @@ void RegAlloc::HostCall(IR::Inst* result_def, std::optional<Argument::copyable_r
ScratchImpl({caller_saved});
}
if (result_def) {
if (result_def) {
DefineValueImpl(result_def, ABI_RETURN);
}
}
@ -433,10 +427,10 @@ void RegAlloc::AssertNoMoreUses() {
}
HostLoc RegAlloc::SelectARegister(HostLocList desired_locations) const {
std::vector<HostLoc> candidates = desired_locations;
std::vector<HostLoc> candidates = desired_locations;
// Find all locations that have not been allocated..
const auto allocated_locs = std::partition(candidates.begin(), candidates.end(), [this](auto loc){
const auto allocated_locs = std::partition(candidates.begin(), candidates.end(), [this](auto loc) {
return !this->LocInfo(loc).IsLocked();
});
candidates.erase(allocated_locs, candidates.end());
@ -445,7 +439,7 @@ HostLoc RegAlloc::SelectARegister(HostLocList desired_locations) const {
// Selects the best location out of the available locations.
// TODO: Actually do LRU or something. Currently we just try to pick something without a value if possible.
std::partition(candidates.begin(), candidates.end(), [this](auto loc){
std::partition(candidates.begin(), candidates.end(), [this](auto loc) {
return this->LocInfo(loc).IsEmpty();
});
@ -648,4 +642,4 @@ void RegAlloc::EmitExchange(HostLoc a, HostLoc b) {
}
}
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -8,9 +8,9 @@
#include <array>
#include <functional>
#include <optional>
#include <utility>
#include <vector>
#include <optional>
#include <mcl/stdint.hpp>
@ -84,7 +84,8 @@ public:
private:
friend class RegAlloc;
explicit Argument(RegAlloc& reg_alloc) : reg_alloc(reg_alloc) {}
explicit Argument(RegAlloc& reg_alloc)
: reg_alloc(reg_alloc) {}
bool allocated = false;
RegAlloc& reg_alloc;
@ -96,7 +97,7 @@ public:
using ArgumentInfo = std::array<Argument, IR::max_arg_count>;
explicit RegAlloc(BlockOfCode& code, size_t num_spills, std::function<u64(HostLoc)> spill_to_addr)
: hostloc_info(NonSpillHostLocCount + num_spills), code(code), spill_to_addr(std::move(spill_to_addr)) {}
: hostloc_info(NonSpillHostLocCount + num_spills), code(code), spill_to_addr(std::move(spill_to_addr)) {}
ArgumentInfo GetArgumentInfo(IR::Inst* inst);
@ -117,14 +118,7 @@ public:
Arm64Gen::ARM64Reg ScratchGpr(HostLocList desired_locations = any_gpr);
Arm64Gen::ARM64Reg ScratchFpr(HostLocList desired_locations = any_fpr);
void HostCall(IR::Inst* result_def = nullptr, std::optional<Argument::copyable_reference> arg0 = {},
std::optional<Argument::copyable_reference> arg1 = {},
std::optional<Argument::copyable_reference> arg2 = {},
std::optional<Argument::copyable_reference> arg3 = {},
std::optional<Argument::copyable_reference> arg4 = {},
std::optional<Argument::copyable_reference> arg5 = {},
std::optional<Argument::copyable_reference> arg6 = {},
std::optional<Argument::copyable_reference> arg7 = {});
void HostCall(IR::Inst* result_def = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}, std::optional<Argument::copyable_reference> arg2 = {}, std::optional<Argument::copyable_reference> arg3 = {}, std::optional<Argument::copyable_reference> arg4 = {}, std::optional<Argument::copyable_reference> arg5 = {}, std::optional<Argument::copyable_reference> arg6 = {}, std::optional<Argument::copyable_reference> arg7 = {});
// TODO: Values in host flags
@ -163,4 +157,4 @@ private:
void EmitExchange(HostLoc a, HostLoc b);
};
} // namespace Dynarmic::BackendA64
} // namespace Dynarmic::BackendA64

View File

@ -44,8 +44,8 @@ u8 RecipEstimate(u64 a);
*/
u8 RecipSqrtEstimate(u64 a);
template <typename T>
constexpr bool IsPow2(T imm){
template<typename T>
constexpr bool IsPow2(T imm) {
return imm > 0 && (imm & (imm - 1)) == 0;
}