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. * General Public License version 2 or any later version.
*/ */
#include "dynarmic/backend/A64/a32_emit_a64.h"
#include <iterator> #include <iterator>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <utility> #include <utility>
#include <dynarmic/interface/A32/coprocessor.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <fmt/ostream.h> #include <fmt/ostream.h>
#include <mcl/assert.hpp> #include <mcl/assert.hpp>
#include <mcl/bit_cast.hpp> #include <mcl/bit_cast.hpp>
#include <mcl/stdint.hpp>
#include <mcl/scope_exit.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/a32_jitstate.h"
#include "dynarmic/backend/A64/abi.h" #include "dynarmic/backend/A64/abi.h"
#include "dynarmic/backend/A64/block_of_code.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."); 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 { A32::LocationDescriptor A32EmitContext::Location() const {
return A32::LocationDescriptor{block.Location()}; 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) A32EmitA64::A32EmitA64(BlockOfCode& code, A32::UserConfig config, A32::Jit* jit_interface)
: EmitA64(code), config(std::move(config)), jit_interface(jit_interface) { : EmitA64(code), config(std::move(config)), jit_interface(jit_interface) {
exception_handler.Register(code, [this](CodePtr PC){FastmemCallback(PC);}); exception_handler.Register(code, [this](CodePtr PC) { FastmemCallback(PC); });
GenMemoryAccessors(); GenMemoryAccessors();
GenTerminalHandlers(); GenTerminalHandlers();
code.PreludeComplete(); code.PreludeComplete();
@ -121,15 +122,14 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) {
// Call the relevant Emit* member function. // Call the relevant Emit* member function.
switch (inst->GetOpcode()) { switch (inst->GetOpcode()) {
#define OPCODE(name, type, ...) \
#define OPCODE(name, type, ...) \ case IR::Opcode::name: \
case IR::Opcode::name: \ A32EmitA64::Emit##name(ctx, inst); \
A32EmitA64::Emit##name(ctx, inst); \ break;
break; #define A32OPC(name, type, ...) \
#define A32OPC(name, type, ...) \ case IR::Opcode::A32##name: \
case IR::Opcode::A32##name: \ A32EmitA64::EmitA32##name(ctx, inst); \
A32EmitA64::EmitA32##name(ctx, inst); \ break;
break;
#define A64OPC(...) #define A64OPC(...)
#include "dynarmic/backend/A64/opcodes.inc" #include "dynarmic/backend/A64/opcodes.inc"
#undef OPCODE #undef OPCODE
@ -184,7 +184,7 @@ void A32EmitA64::EmitCondPrelude(const A32EmitContext& ctx) {
FixupBranch pass = EmitCond(ctx.block.GetCondition()); FixupBranch pass = EmitCond(ctx.block.GetCondition());
EmitAddCycles(ctx.block.ConditionFailedCycleCount()); 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); code.SetJumpTarget(pass);
} }
@ -343,7 +343,7 @@ void A32EmitA64::GenTerminalHandlers() {
code.BR(code.ABI_SCRATCH1); code.BR(code.ABI_SCRATCH1);
code.SetJumpTarget(fast_dispatch_cache_miss); 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.LookupBlock();
code.STR(INDEX_UNSIGNED, code.ABI_RETURN, fast_dispatch_entry_reg, offsetof(FastDispatchEntry, code_ptr)); code.STR(INDEX_UNSIGNED, code.ABI_RETURN, fast_dispatch_entry_reg, offsetof(FastDispatchEntry, code_ptr));
code.BR(code.ABI_RETURN); code.BR(code.ABI_RETURN);
@ -359,7 +359,6 @@ void A32EmitA64::GenTerminalHandlers() {
} }
} }
void A32EmitA64::EmitA32GetRegister(A32EmitContext& ctx, IR::Inst* inst) { void A32EmitA64::EmitA32GetRegister(A32EmitContext& ctx, IR::Inst* inst) {
A32::Reg reg = inst->GetArg(0).GetA32RegRef(); A32::Reg reg = inst->GetArg(0).GetA32RegRef();
@ -418,8 +417,7 @@ void A32EmitA64::EmitA32SetExtendedRegister64(A32EmitContext& ctx, IR::Inst* ins
if (args[1].IsInFpr()) { if (args[1].IsInFpr()) {
ARM64Reg to_store = ctx.reg_alloc.UseFpr(args[1]); ARM64Reg to_store = ctx.reg_alloc.UseFpr(args[1]);
code.fp_emitter.STR(64, INDEX_UNSIGNED, to_store, X28, MJitStateExtReg(reg)); code.fp_emitter.STR(64, INDEX_UNSIGNED, to_store, X28, MJitStateExtReg(reg));
} } else {
else {
ARM64Reg to_store = ctx.reg_alloc.UseGpr(args[1]); ARM64Reg to_store = ctx.reg_alloc.UseGpr(args[1]);
code.STR(INDEX_UNSIGNED, to_store, X28, MJitStateExtReg(reg)); 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.ADD(new_upper, new_upper, mask);
code.STR(INDEX_UNSIGNED, new_upper, X28, offsetof(A32JitState, upper_location_descriptor)); code.STR(INDEX_UNSIGNED, new_upper, X28, offsetof(A32JitState, upper_location_descriptor));
code.LSL(mask, mask, 1); 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.AND(new_pc, new_pc, mask);
code.STR(INDEX_UNSIGNED, new_pc, X28, MJitStateReg(A32::Reg::PC)); 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)}); InvalidateBasicBlocks({std::get<0>(marker)});
} }
template <typename T> template<typename T>
void A32EmitA64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr callback_fn) { void A32EmitA64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr callback_fn) {
constexpr size_t bit_size = mcl::bitsizeof<T>; constexpr size_t bit_size = mcl::bitsizeof<T>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst); 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); FixupBranch abort = code.CBZ(result);
code.ANDI2R(vaddr, vaddr, 4095); code.ANDI2R(vaddr, vaddr, 4095);
switch (bit_size) { switch (bit_size) {
case 8: case 8:
code.LDRB(DecodeReg(result), result, vaddr); code.LDRB(DecodeReg(result), result, vaddr);
break; break;
case 16: case 16:
code.LDRH(DecodeReg(result), result, vaddr); code.LDRH(DecodeReg(result), result, vaddr);
break; break;
case 32: case 32:
code.LDR(DecodeReg(result), result, vaddr); code.LDR(DecodeReg(result), result, vaddr);
break; break;
case 64: case 64:
code.LDR(result, result, vaddr); code.LDR(result, result, vaddr);
break; break;
default: default:
ASSERT_FALSE("Invalid bit_size"); ASSERT_FALSE("Invalid bit_size");
break; break;
} }
end = code.B(); end = code.B();
code.SetJumpTarget(abort); code.SetJumpTarget(abort);
@ -858,54 +856,52 @@ void A32EmitA64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr c
code.MOV(result, code.ABI_RETURN); code.MOV(result, code.ABI_RETURN);
}; };
if (ShouldFastmem(do_not_fastmem_marker)) { if (ShouldFastmem(do_not_fastmem_marker)) {
const CodePtr patch_location = code.GetCodePtr(); const CodePtr patch_location = code.GetCodePtr();
switch (bit_size) { switch (bit_size) {
case 8: case 8:
code.LDRB(DecodeReg(result), X27, vaddr); code.LDRB(DecodeReg(result), X27, vaddr);
break; break;
case 16: case 16:
code.LDRH(DecodeReg(result), X27, vaddr); code.LDRH(DecodeReg(result), X27, vaddr);
break; break;
case 32: case 32:
code.LDR(DecodeReg(result), X27, vaddr); code.LDR(DecodeReg(result), X27, vaddr);
break; break;
case 64: case 64:
code.LDR(result, X27, vaddr); code.LDR(result, X27, vaddr);
break; break;
default: default:
ASSERT_FALSE("Invalid bit_size"); ASSERT_FALSE("Invalid bit_size");
break; break;
} }
fastmem_patch_info.emplace( fastmem_patch_info.emplace(
patch_location, patch_location,
FastmemPatchInfo{ FastmemPatchInfo{
[this, patch_location, page_table_lookup, callback_fn, result, do_not_fastmem_marker]{ [this, patch_location, page_table_lookup, callback_fn, result, do_not_fastmem_marker] {
CodePtr save_code_ptr = code.GetCodePtr(); CodePtr save_code_ptr = code.GetCodePtr();
code.SetCodePtr(patch_location); code.SetCodePtr(patch_location);
FixupBranch thunk = code.B(); FixupBranch thunk = code.B();
u8* end_ptr = code.GetWritableCodePtr(); u8* end_ptr = code.GetWritableCodePtr();
code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr); code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr);
code.SetCodePtr(save_code_ptr); code.SetCodePtr(save_code_ptr);
code.SwitchToFarCode(); code.SwitchToFarCode();
code.SetJumpTarget(thunk); code.SetJumpTarget(thunk);
if (config.page_table) { if (config.page_table) {
FixupBranch end{}; FixupBranch end{};
page_table_lookup(end); page_table_lookup(end);
code.SetJumpTarget(end, end_ptr); code.SetJumpTarget(end, end_ptr);
} else { } else {
code.BL(callback_fn); code.BL(callback_fn);
code.MOV(result, code.ABI_RETURN); code.MOV(result, code.ABI_RETURN);
} }
code.B(end_ptr); code.B(end_ptr);
code.FlushIcache(); code.FlushIcache();
code.SwitchToNearCode(); code.SwitchToNearCode();
DoNotFastmem(do_not_fastmem_marker); DoNotFastmem(do_not_fastmem_marker);
} }});
});
ctx.reg_alloc.DefineValue(inst, result); ctx.reg_alloc.DefineValue(inst, result);
return; return;
@ -950,21 +946,22 @@ void A32EmitA64::WriteMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr
FixupBranch abort = code.CBZ(addr); FixupBranch abort = code.CBZ(addr);
code.ANDI2R(vaddr, vaddr, 4095); code.ANDI2R(vaddr, vaddr, 4095);
switch (bit_size) { switch (bit_size) {
case 8: case 8:
code.STRB(DecodeReg(value), addr, vaddr); code.STRB(DecodeReg(value), addr, vaddr);
break; break;
case 16: case 16:
code.STRH(DecodeReg(value), addr, vaddr); code.STRH(DecodeReg(value), addr, vaddr);
break; break;
case 32: case 32:
code.STR(DecodeReg(value), addr, vaddr);; code.STR(DecodeReg(value), addr, vaddr);
break; ;
case 64: break;
code.STR(value, addr, vaddr); case 64:
break; code.STR(value, addr, vaddr);
default: break;
ASSERT_FALSE("Invalid bit_size"); default:
break; ASSERT_FALSE("Invalid bit_size");
break;
} }
end = code.B(); end = code.B();
code.SetJumpTarget(abort); code.SetJumpTarget(abort);
@ -974,49 +971,48 @@ void A32EmitA64::WriteMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr
if (ShouldFastmem(do_not_fastmem_marker)) { if (ShouldFastmem(do_not_fastmem_marker)) {
const CodePtr patch_location = code.GetCodePtr(); const CodePtr patch_location = code.GetCodePtr();
switch (bit_size) { switch (bit_size) {
case 8: case 8:
code.STRB(DecodeReg(value), X27, vaddr); code.STRB(DecodeReg(value), X27, vaddr);
break; break;
case 16: case 16:
code.STRH(DecodeReg(value), X27, vaddr); code.STRH(DecodeReg(value), X27, vaddr);
break; break;
case 32: case 32:
code.STR(DecodeReg(value), X27, vaddr); code.STR(DecodeReg(value), X27, vaddr);
break; break;
case 64: case 64:
code.STR(value, X27, vaddr); code.STR(value, X27, vaddr);
break; break;
default: default:
ASSERT_FALSE("Invalid bit_size"); ASSERT_FALSE("Invalid bit_size");
break; break;
} }
fastmem_patch_info.emplace( fastmem_patch_info.emplace(
patch_location, patch_location,
FastmemPatchInfo{ FastmemPatchInfo{
[this, patch_location, page_table_lookup, callback_fn, do_not_fastmem_marker]{ [this, patch_location, page_table_lookup, callback_fn, do_not_fastmem_marker] {
CodePtr save_code_ptr = code.GetCodePtr(); CodePtr save_code_ptr = code.GetCodePtr();
code.SetCodePtr(patch_location); code.SetCodePtr(patch_location);
FixupBranch thunk = code.B(); FixupBranch thunk = code.B();
u8* end_ptr = code.GetWritableCodePtr(); u8* end_ptr = code.GetWritableCodePtr();
code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr); code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr);
code.SetCodePtr(save_code_ptr); code.SetCodePtr(save_code_ptr);
code.SwitchToFarCode(); code.SwitchToFarCode();
code.SetJumpTarget(thunk); code.SetJumpTarget(thunk);
if (config.page_table) { if (config.page_table) {
FixupBranch end{}; FixupBranch end{};
page_table_lookup(end); page_table_lookup(end);
code.SetJumpTarget(end, end_ptr); code.SetJumpTarget(end, end_ptr);
} else { } else {
code.BL(callback_fn); code.BL(callback_fn);
} }
code.B(end_ptr); code.B(end_ptr);
code.FlushIcache(); code.FlushIcache();
code.SwitchToNearCode(); code.SwitchToNearCode();
DoNotFastmem(do_not_fastmem_marker); DoNotFastmem(do_not_fastmem_marker);
} }});
});
return; return;
} }
@ -1062,7 +1058,7 @@ void A32EmitA64::EmitA32WriteMemory64(A32EmitContext& ctx, IR::Inst* inst) {
WriteMemory<u64>(ctx, inst, write_memory_64); 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) { static void ExclusiveWrite(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* inst, const A32::UserConfig& config) {
auto args = reg_alloc.GetArgumentInfo(inst); auto args = reg_alloc.GetArgumentInfo(inst);
reg_alloc.HostCall(nullptr, {}, args[0], args[1]); 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); code.MOVI2R(passed, 0);
for (FixupBranch e : end) { for (FixupBranch e : end) {
code.SetJumpTarget(e); code.SetJumpTarget(e);
} }
reg_alloc.DefineValue(inst, passed); reg_alloc.DefineValue(inst, passed);
@ -1112,8 +1108,7 @@ static void EmitCoprocessorException() {
ASSERT_FALSE("Should raise coproc exception here"); ASSERT_FALSE("Should raise coproc exception here");
} }
static void CallCoprocCallback(BlockOfCode& code, RegAlloc& reg_alloc, A32::Jit* jit_interface, A32::Coprocessor::Callback callback, 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 = {}) {
IR::Inst* inst = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}) {
reg_alloc.HostCall(inst, {}, {}, arg0, arg1); reg_alloc.HostCall(inst, {}, {}, arg0, arg1);
code.MOVP2R(code.ABI_PARAM1, jit_interface); 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.LDR(INDEX_UNSIGNED, DecodeReg(reg_result), reg_tmp, 0);
code.MOVP2R(reg_tmp, source_ptrs[0]); code.MOVP2R(reg_tmp, source_ptrs[0]);
code.LDR(INDEX_UNSIGNED, DecodeReg(reg_tmp), reg_tmp, 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); ctx.reg_alloc.DefineValue(inst, reg_result);
@ -1331,7 +1326,6 @@ void A32EmitA64::EmitA32CoprocLoadWords(A32EmitContext& ctx, IR::Inst* inst) {
option = coproc_info[5]; option = coproc_info[5];
} }
std::shared_ptr<A32::Coprocessor> coproc = config.coprocessors[coproc_num]; std::shared_ptr<A32::Coprocessor> coproc = config.coprocessors[coproc_num];
if (!coproc) { if (!coproc) {
EmitCoprocessorException(); EmitCoprocessorException();
@ -1376,7 +1370,6 @@ void A32EmitA64::EmitA32CoprocStoreWords(A32EmitContext& ctx, IR::Inst* inst) {
CallCoprocCallback(code, ctx.reg_alloc, jit_interface, *action, nullptr, args[1]); CallCoprocCallback(code, ctx.reg_alloc, jit_interface, *action, nullptr, args[1]);
} }
std::string A32EmitA64::LocationDescriptorToFriendlyName(const IR::LocationDescriptor& ir_descriptor) const { std::string A32EmitA64::LocationDescriptorToFriendlyName(const IR::LocationDescriptor& ir_descriptor) const {
const A32::LocationDescriptor descriptor{ir_descriptor}; const A32::LocationDescriptor descriptor{ir_descriptor};
return fmt::format("a32_{}{:08X}_{}_fpcr{:08X}", descriptor.TFlag() ? "t" : "a", descriptor.PC(), descriptor.EFlag() ? "be" : "le", 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.STR(INDEX_UNSIGNED, DecodeReg(code.ABI_PARAM2), X28, MJitStateReg(A32::Reg::PC));
code.SwitchFpscrOnExit(); code.SwitchFpscrOnExit();
Devirtualize<&A32::UserCallbacks::InterpreterFallback>(config.callbacks).EmitCall(code); 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) { 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) { 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); 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) { void A32EmitA64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
const CodePtr patch_location = code.GetCodePtr(); 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()); 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); code.B(CC_GT, ptr);
return; 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) { void A32EmitA64::EmitPatchJz(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
const CodePtr patch_location = code.GetCodePtr(); 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()); 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); code.B(CC_EQ, ptr);
return; 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/block_range_information.h"
#include "dynarmic/backend/A64/emit_a64.h" #include "dynarmic/backend/A64/emit_a64.h"
#include "dynarmic/backend/A64/exception_handler.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/a32.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/ir/terminal.h" #include "dynarmic/ir/terminal.h"
namespace Dynarmic::BackendA64 { namespace Dynarmic::BackendA64 {
@ -137,4 +137,4 @@ protected:
void EmitPatchMovX0(CodePtr target_code_ptr = nullptr) override; void EmitPatchMovX0(CodePtr target_code_ptr = nullptr) override;
}; };
} // namespace Dynarmic::BackendA64 } // namespace Dynarmic::BackendA64

View File

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

View File

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

View File

@ -7,6 +7,7 @@
#pragma once #pragma once
#include <array> #include <array>
#include <mcl/stdint.hpp> #include <mcl/stdint.hpp>
namespace Dynarmic::BackendA64 { namespace Dynarmic::BackendA64 {
@ -14,8 +15,8 @@ namespace Dynarmic::BackendA64 {
class BlockOfCode; class BlockOfCode;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) # pragma warning(push)
#pragma warning(disable:4324) // Structure was padded due to alignment specifier # pragma warning(disable : 4324) // Structure was padded due to alignment specifier
#endif #endif
struct A32JitState { struct A32JitState {
@ -23,7 +24,7 @@ struct A32JitState {
A32JitState() { ResetRSB(); } A32JitState() { ResetRSB(); }
std::array<u32, 16> Reg{}; // Current register file. std::array<u32, 16> Reg{}; // Current register file.
// TODO: Mode-specific register sets unimplemented. // TODO: Mode-specific register sets unimplemented.
u32 upper_location_descriptor = 0; u32 upper_location_descriptor = 0;
@ -35,10 +36,10 @@ struct A32JitState {
u32 Cpsr() const; u32 Cpsr() const;
void SetCpsr(u32 cpsr); 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; 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) { static size_t GetSpillLocationOffsetFromIndex(size_t i) {
return static_cast<u64>(offsetof(A32JitState, Spill) + i * sizeof(u64)); return static_cast<u64>(offsetof(A32JitState, Spill) + i * sizeof(u64));
} }
@ -57,7 +58,7 @@ struct A32JitState {
u32 exclusive_state = 0; u32 exclusive_state = 0;
u32 exclusive_address = 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; static constexpr size_t RSBPtrMask = RSBSize - 1;
u32 rsb_ptr = 0; u32 rsb_ptr = 0;
std::array<u64, RSBSize> rsb_location_descriptors; std::array<u64, RSBSize> rsb_location_descriptors;
@ -65,7 +66,7 @@ struct A32JitState {
void ResetRSB(); void ResetRSB();
u32 fpsr_exc = 0; u32 fpsr_exc = 0;
u32 fpsr_qc = 0; // Dummy value u32 fpsr_qc = 0; // Dummy value
u32 fpsr_nzcv = 0; u32 fpsr_nzcv = 0;
u32 Fpscr() const; u32 Fpscr() const;
void SetFpscr(u32 FPSCR); void SetFpscr(u32 FPSCR);
@ -102,9 +103,9 @@ struct A32JitState {
}; };
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) # pragma warning(pop)
#endif #endif
using CodePtr = const void*; 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. // 20th Sep 2018: This code was modified for Dynarmic.
#include "dynarmic/backend/A64/abi.h"
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <mcl/stdint.hpp> #include <mcl/stdint.hpp>
#include "dynarmic/backend/A64/abi.h"
namespace Dynarmic::BackendA64 { namespace Dynarmic::BackendA64 {
template<typename RegisterArrayT> template<typename RegisterArrayT>
void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const RegisterArrayT& regs) { void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const RegisterArrayT& regs) {
u32 gprs = 0 , fprs = 0; u32 gprs = 0, fprs = 0;
for (HostLoc reg : regs) { for (HostLoc reg : regs) {
if (HostLocIsGPR(reg)) { if (HostLocIsGPR(reg)) {
@ -83,4 +83,4 @@ void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, HostLoc e
ABI_PopRegistersAndAdjustStack(code, regs); 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, 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"); 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_PushCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, HostLoc exception);
void ABI_PopCallerSaveRegistersAndAdjustStackExcept(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. * General Public License version 2 or any later version.
*/ */
#include "dynarmic/backend/A64/block_of_code.h"
#include <array> #include <array>
#include <cstring> #include <cstring>
#include <limits> #include <limits>
@ -12,23 +14,22 @@
#include "dynarmic/backend/A64/a32_jitstate.h" #include "dynarmic/backend/A64/a32_jitstate.h"
#include "dynarmic/backend/A64/abi.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/backend/A64/perf_map.h"
#include "dynarmic/interface/halt_reason.h"
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> # include <windows.h>
#else #else
#include <sys/mman.h> # include <sys/mman.h>
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
#include <pthread.h> # include <pthread.h>
#endif #endif
namespace Dynarmic::BackendA64 { 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_RETURN2 = Arm64Gen::ARM64Reg::X1;
const Arm64Gen::ARM64Reg BlockOfCode::ABI_PARAM1 = Arm64Gen::ARM64Reg::X0; 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 Arm64Gen::ARM64Reg BlockOfCode::ABI_SCRATCH1 = Arm64Gen::ARM64Reg::X30;
const std::array<Arm64Gen::ARM64Reg, 8> BlockOfCode::ABI_PARAMS = {BlockOfCode::ABI_PARAM1, BlockOfCode::ABI_PARAM2, const std::array<Arm64Gen::ARM64Reg, 8> BlockOfCode::ABI_PARAMS = {BlockOfCode::ABI_PARAM1, BlockOfCode::ABI_PARAM2,
BlockOfCode::ABI_PARAM3, BlockOfCode::ABI_PARAM4, BlockOfCode::ABI_PARAM3, BlockOfCode::ABI_PARAM4,
BlockOfCode::ABI_PARAM5, BlockOfCode::ABI_PARAM6, BlockOfCode::ABI_PARAM5, BlockOfCode::ABI_PARAM6,
BlockOfCode::ABI_PARAM7, BlockOfCode::ABI_PARAM8}; BlockOfCode::ABI_PARAM7, BlockOfCode::ABI_PARAM8};
namespace { namespace {
@ -54,22 +55,22 @@ constexpr size_t FAR_CODE_OFFSET = 100 * 1024 * 1024;
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
void ProtectMemory([[maybe_unused]] const void* base, [[maybe_unused]] size_t size, bool is_executable) { void ProtectMemory([[maybe_unused]] const void* base, [[maybe_unused]] size_t size, bool is_executable) {
#if defined(_WIN32) # if defined(_WIN32)
DWORD oldProtect = 0; DWORD oldProtect = 0;
VirtualProtect(const_cast<void*>(base), size, is_executable ? PAGE_EXECUTE_READ : PAGE_READWRITE, &oldProtect); 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); pthread_jit_write_protect_np(is_executable);
#else # else
static const size_t pageSize = sysconf(_SC_PAGESIZE); static const size_t pageSize = sysconf(_SC_PAGESIZE);
const size_t iaddr = reinterpret_cast<size_t>(base); const size_t iaddr = reinterpret_cast<size_t>(base);
const size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1)); const size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
const int mode = is_executable ? (PROT_READ | PROT_EXEC) : (PROT_READ | PROT_WRITE); const int mode = is_executable ? (PROT_READ | PROT_EXEC) : (PROT_READ | PROT_WRITE);
mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode); mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode);
#endif # endif
} }
#endif #endif
} // anonymous namespace } // anonymous namespace
BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi) BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi)
: fp_emitter(this) : fp_emitter(this)
@ -154,7 +155,7 @@ void BlockOfCode::ForceReturnFromRunCode(bool fpscr_already_exited) {
} }
void BlockOfCode::GenRunCode() { 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; std::vector<Arm64Gen::FixupBranch> return_to_caller_fpscr_already_exited;
AlignCode16(); AlignCode16();
@ -168,7 +169,7 @@ void BlockOfCode::GenRunCode() {
MOV(Arm64Gen::X28, ABI_PARAM1); MOV(Arm64Gen::X28, ABI_PARAM1);
MOVI2R(Arm64Gen::X27, cb.value_in_X27); 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); cb.GetTicksRemaining->EmitCall(*this);
STR(Arm64Gen::INDEX_UNSIGNED, ABI_RETURN, Arm64Gen::X28, jsi.offsetof_cycles_to_run); 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 //#endif
//} //}
} // namespace Dynarmic::BackendA64 } // namespace Dynarmic::BackendA64

View File

@ -14,8 +14,8 @@
#include "dynarmic/backend/A64/callback.h" #include "dynarmic/backend/A64/callback.h"
#include "dynarmic/backend/A64/constant_pool.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/emitter/a64_emitter.h"
#include "dynarmic/backend/A64/jitstate_info.h"
#include "dynarmic/interface/halt_reason.h" #include "dynarmic/interface/halt_reason.h"
namespace Dynarmic::BackendA64 { namespace Dynarmic::BackendA64 {
@ -34,7 +34,6 @@ public:
BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi); BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi);
BlockOfCode(const BlockOfCode&) = delete; BlockOfCode(const BlockOfCode&) = delete;
/// Call when external emitters have finished emitting their preludes. /// Call when external emitters have finished emitting their preludes.
void PreludeComplete(); void PreludeComplete();
@ -146,4 +145,4 @@ private:
//Xbyak::util::Cpu cpu_info; //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. * General Public License version 2 or any later version.
*/ */
#include "dynarmic/backend/A64/block_range_information.h"
#include <unordered_set> #include <unordered_set>
#include <boost/icl/interval_map.hpp> #include <boost/icl/interval_map.hpp>
#include <boost/icl/interval_set.hpp> #include <boost/icl/interval_set.hpp>
#include <mcl/stdint.hpp> #include <mcl/stdint.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/A64/block_range_information.h"
namespace Dynarmic::BackendA64 { namespace Dynarmic::BackendA64 {
template <typename ProgramCounterType> template<typename ProgramCounterType>
void BlockRangeInformation<ProgramCounterType>::AddRange(boost::icl::discrete_interval<ProgramCounterType> range, IR::LocationDescriptor location) { 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})); block_ranges.add(std::make_pair(range, std::set<IR::LocationDescriptor>{location}));
} }
template <typename ProgramCounterType> template<typename ProgramCounterType>
void BlockRangeInformation<ProgramCounterType>::ClearCache() { void BlockRangeInformation<ProgramCounterType>::ClearCache() {
block_ranges.clear(); 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> BlockRangeInformation<ProgramCounterType>::InvalidateRanges(const boost::icl::interval_set<ProgramCounterType>& ranges) {
std::unordered_set<IR::LocationDescriptor> erase_locations; std::unordered_set<IR::LocationDescriptor> erase_locations;
for (auto invalidate_interval : ranges) { for (auto invalidate_interval : ranges) {
auto pair = block_ranges.equal_range(invalidate_interval); auto pair = block_ranges.equal_range(invalidate_interval);
for (auto it = pair.first; it != pair.second; ++it) { 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); erase_locations.insert(descriptor);
} }
} }
@ -44,4 +42,4 @@ std::unordered_set<IR::LocationDescriptor> BlockRangeInformation<ProgramCounterT
template class BlockRangeInformation<u32>; template class BlockRangeInformation<u32>;
template class BlockRangeInformation<u64>; template class BlockRangeInformation<u64>;
} // namespace Dynarmic::BackendA64 } // namespace Dynarmic::BackendA64

View File

@ -15,7 +15,7 @@
namespace Dynarmic::BackendA64 { namespace Dynarmic::BackendA64 {
template <typename ProgramCounterType> template<typename ProgramCounterType>
class BlockRangeInformation { class BlockRangeInformation {
public: public:
void AddRange(boost::icl::discrete_interval<ProgramCounterType> range, IR::LocationDescriptor location); 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; 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/callback.h"
#include "dynarmic/backend/A64/block_of_code.h" #include "dynarmic/backend/A64/block_of_code.h"
namespace Dynarmic::BackendA64 { namespace Dynarmic::BackendA64 {
@ -38,4 +39,4 @@ void ArgCallback::EmitCallWithReturnPointer(BlockOfCode& code, std::function<voi
code.QuickCallFunction(fn); code.QuickCallFunction(fn);
} }
} // namespace Dynarmic::BackendX64 } // namespace Dynarmic::BackendA64

View File

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

View File

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

View File

@ -31,7 +31,7 @@ public:
void Clear(); void Clear();
private: 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; std::map<std::tuple<u64, u64>, void*> constant_info;
@ -46,4 +46,4 @@ private:
std::vector<PatchInfo> patch_info; std::vector<PatchInfo> patch_info;
}; };
} // namespace Dynarmic::BackendA64 } // namespace Dynarmic::BackendA64

View File

@ -9,10 +9,10 @@
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <mcl/type_traits/function_info.hpp>
#include <mcl/stdint.hpp>
#include <mcl/assert.hpp> #include <mcl/assert.hpp>
#include <mcl/bit_cast.hpp> #include <mcl/bit_cast.hpp>
#include <mcl/stdint.hpp>
#include <mcl/type_traits/function_info.hpp>
#include "dynarmic/backend/A64/callback.h" #include "dynarmic/backend/A64/callback.h"
@ -20,20 +20,20 @@ namespace Dynarmic::BackendA64 {
namespace impl { namespace impl {
template <typename FunctionType, FunctionType mfp> template<typename FunctionType, FunctionType mfp>
struct ThunkBuilder; struct ThunkBuilder;
template <typename C, typename R, typename... Args, R(C::*mfp)(Args...)> template<typename C, typename R, typename... Args, R (C::*mfp)(Args...)>
struct ThunkBuilder<R(C::*)(Args...), mfp> { struct ThunkBuilder<R (C::*)(Args...), mfp> {
static R Thunk(C* this_, Args... args) { static R Thunk(C* this_, Args... args) {
return (this_->*mfp)(std::forward<Args>(args)...); return (this_->*mfp)(std::forward<Args>(args)...);
} }
}; };
} // namespace impl } // namespace impl
template<auto mfp> 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_)}; 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 #endif
} }
} // namespace Dynarmic::BackendA64 } // namespace Dynarmic::BackendA64

View File

@ -4,16 +4,17 @@
* General Public License version 2 or any later version. * General Public License version 2 or any later version.
*/ */
#include "dynarmic/backend/A64/emit_a64.h"
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <mcl/assert.hpp> #include <mcl/assert.hpp>
#include <mcl/bit/bit_field.hpp> #include <mcl/bit/bit_field.hpp>
#include <mcl/stdint.hpp>
#include <mcl/scope_exit.hpp> #include <mcl/scope_exit.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/A64/block_of_code.h" #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/hostloc.h"
#include "dynarmic/backend/A64/perf_map.h" #include "dynarmic/backend/A64/perf_map.h"
#include "dynarmic/backend/A64/reg_alloc.h" #include "dynarmic/backend/A64/reg_alloc.h"
@ -28,7 +29,7 @@
namespace Dynarmic::BackendA64 { namespace Dynarmic::BackendA64 {
EmitContext::EmitContext(RegAlloc& reg_alloc, IR::Block& block) 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) { void EmitContext::EraseInstruction(IR::Inst* inst) {
block.Instructions().erase(inst); block.Instructions().erase(inst);
@ -36,7 +37,7 @@ void EmitContext::EraseInstruction(IR::Inst* inst) {
} }
EmitA64::EmitA64(BlockOfCode& code) EmitA64::EmitA64(BlockOfCode& code)
: code(code) {} : code(code) {}
EmitA64::~EmitA64() = default; 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) { void EmitA64::PushRSBHelper(ARM64Reg loc_desc_reg, ARM64Reg index_reg, IR::LocationDescriptor target) {
auto iter = block_descriptors.find(target); auto iter = block_descriptors.find(target);
CodePtr target_code_ptr = iter != block_descriptors.end() CodePtr target_code_ptr = iter != block_descriptors.end()
? iter->second.entrypoint ? iter->second.entrypoint
: code.GetReturnFromRunCodeAddress(); : code.GetReturnFromRunCodeAddress();
code.LDR(INDEX_UNSIGNED, DecodeReg(index_reg), X28, code.GetJitStateInfo().offsetof_rsb_ptr); 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); code._MSR(FIELD_NZCV, cpsr);
switch (cond) { switch (cond) {
case IR::Cond::EQ: //z case IR::Cond::EQ: //z
label = code.B(CC_EQ); label = code.B(CC_EQ);
break; break;
case IR::Cond::NE: //!z case IR::Cond::NE: //!z
label = code.B(CC_NEQ); label = code.B(CC_NEQ);
break; break;
case IR::Cond::CS: //c case IR::Cond::CS: //c
label = code.B(CC_CS); label = code.B(CC_CS);
break; break;
case IR::Cond::CC: //!c case IR::Cond::CC: //!c
label = code.B(CC_CC); label = code.B(CC_CC);
break; break;
case IR::Cond::MI: //n case IR::Cond::MI: //n
label = code.B(CC_MI); label = code.B(CC_MI);
break; break;
case IR::Cond::PL: //!n case IR::Cond::PL: //!n
label = code.B(CC_PL); label = code.B(CC_PL);
break; break;
case IR::Cond::VS: //v case IR::Cond::VS: //v
label = code.B(CC_VS); label = code.B(CC_VS);
break; break;
case IR::Cond::VC: //!v case IR::Cond::VC: //!v
label = code.B(CC_VC); label = code.B(CC_VC);
break; break;
case IR::Cond::HI: //c & !z case IR::Cond::HI: //c & !z
@ -278,7 +279,7 @@ void EmitA64::InvalidateBasicBlocks(const std::unordered_set<IR::LocationDescrip
code.EnableWriting(); code.EnableWriting();
SCOPE_EXIT { code.DisableWriting(); }; SCOPE_EXIT { code.DisableWriting(); };
for (const auto &descriptor : locations) { for (const auto& descriptor : locations) {
auto it = block_descriptors.find(descriptor); auto it = block_descriptors.find(descriptor);
if (it == block_descriptors.end()) { if (it == block_descriptors.end()) {
continue; 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 { namespace Dynarmic::IR {
class Block; class Block;
class Inst; class Inst;
} // namespace Dynarmic::IR } // namespace Dynarmic::IR
namespace Dynarmic::BackendA64 { 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 // 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 // relative to the size of a vector register. e.g. T = u32 would result
// in a std::array<u32, 4>. // in a std::array<u32, 4>.
template <typename T> template<typename T>
using VectorArray = std::array<T, A64FullVectorWidth::value / mcl::bitsizeof<T>>; using VectorArray = std::array<T, A64FullVectorWidth::value / mcl::bitsizeof<T>>;
struct EmitContext { struct EmitContext {
@ -124,4 +124,4 @@ protected:
std::unordered_map<IR::LocationDescriptor, PatchInformation> patch_information; 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 <mcl/stdint.hpp>
#include "dynarmic/backend/A64/block_of_code.h" #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/emit_a64.h"
#include "dynarmic/backend/A64/reg_alloc.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.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); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Arm64Gen::ARM64Reg result = DecodeReg(ctx.reg_alloc.UseScratchGpr(args[0])); Arm64Gen::ARM64Reg result = DecodeReg(ctx.reg_alloc.UseScratchGpr(args[0]));
// TODO: Flag optimization // TODO: Flag optimization
code.LSR(result,result, 31); code.LSR(result, result, 31);
ctx.reg_alloc.DefineValue(inst, result); ctx.reg_alloc.DefineValue(inst, result);
} }
@ -127,46 +127,46 @@ static void EmitConditionalSelect(BlockOfCode& code, EmitContext& ctx, IR::Inst*
code._MSR(FIELD_NZCV, nzcv); code._MSR(FIELD_NZCV, nzcv);
switch (args[0].GetImmediateCond()) { switch (args[0].GetImmediateCond()) {
case IR::Cond::EQ: //z case IR::Cond::EQ: //z
code.CSEL(else_, else_, then_ , CC_EQ); code.CSEL(else_, else_, then_, CC_EQ);
break; break;
case IR::Cond::NE: //!z case IR::Cond::NE: //!z
code.CSEL(else_, else_, then_, CC_NEQ); code.CSEL(else_, else_, then_, CC_NEQ);
break; break;
case IR::Cond::CS: //c case IR::Cond::CS: //c
code.CSEL(else_, else_, then_, CC_CS); code.CSEL(else_, else_, then_, CC_CS);
break; break;
case IR::Cond::CC: //!c case IR::Cond::CC: //!c
code.CSEL(else_, else_, then_ , CC_CC); code.CSEL(else_, else_, then_, CC_CC);
break; break;
case IR::Cond::MI: //n case IR::Cond::MI: //n
code.CSEL(else_, else_, then_, CC_MI); code.CSEL(else_, else_, then_, CC_MI);
break; break;
case IR::Cond::PL: //!n case IR::Cond::PL: //!n
code.CSEL(else_, else_, then_, CC_PL); code.CSEL(else_, else_, then_, CC_PL);
break; break;
case IR::Cond::VS: //v case IR::Cond::VS: //v
code.CSEL(else_, else_, then_, CC_VS); code.CSEL(else_, else_, then_, CC_VS);
break; break;
case IR::Cond::VC: //!v case IR::Cond::VC: //!v
code.CSEL(else_, else_, then_, CC_VC); code.CSEL(else_, else_, then_, CC_VC);
break; break;
case IR::Cond::HI: //c & !z case IR::Cond::HI: //c & !z
code.CSEL(else_, else_, then_, CC_HI); code.CSEL(else_, else_, then_, CC_HI);
break; break;
case IR::Cond::LS: //!c | z case IR::Cond::LS: //!c | z
code.CSEL(else_, else_, then_, CC_LS); code.CSEL(else_, else_, then_, CC_LS);
break; break;
case IR::Cond::GE: // n == v case IR::Cond::GE: // n == v
code.CSEL(else_, else_, then_, CC_GE); code.CSEL(else_, else_, then_, CC_GE);
break; break;
case IR::Cond::LT: // n != v case IR::Cond::LT: // n != v
code.CSEL(else_, else_, then_, CC_LT); code.CSEL(else_, else_, then_, CC_LT);
break; break;
case IR::Cond::GT: // !z & (n == v) case IR::Cond::GT: // !z & (n == v)
code.CSEL(else_, else_, then_, CC_GT); code.CSEL(else_, else_, then_, CC_GT);
break; break;
case IR::Cond::LE: // z | (n != v) case IR::Cond::LE: // z | (n != v)
code.CSEL(else_, else_, then_, CC_LE); code.CSEL(else_, else_, then_, CC_LE);
break; break;
case IR::Cond::AL: case IR::Cond::AL:
@ -257,7 +257,7 @@ void EmitA64::EmitLogicalShiftLeft32(EmitContext& ctx, IR::Inst* inst) {
end = code.B(CC_EQ); end = code.B(CC_EQ);
code.CMPI2R(shift, 32); 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.LSLV(result, result, shift);
code.UBFX(carry, result, 31, 1); code.UBFX(carry, result, 31, 1);
code.LSL(result, result, 1); code.LSL(result, result, 1);
@ -344,7 +344,7 @@ void EmitA64::EmitLogicalShiftRight32(EmitContext& ctx, IR::Inst* inst) {
} else if (shift < 32) { } else if (shift < 32) {
code.LSR(carry, result, shift - 1); code.LSR(carry, result, shift - 1);
code.ANDI2R(carry, carry, 1); code.ANDI2R(carry, carry, 1);
code.LSR(result,result, shift); code.LSR(result, result, shift);
} else if (shift == 32) { } else if (shift == 32) {
code.UBFX(carry, result, 31, 1); code.UBFX(carry, result, 31, 1);
code.MOV(result, WZR); code.MOV(result, WZR);
@ -369,7 +369,7 @@ void EmitA64::EmitLogicalShiftRight32(EmitContext& ctx, IR::Inst* inst) {
end = code.B(CC_EQ); end = code.B(CC_EQ);
code.CMPI2R(shift, 32); 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.LSRV(result, result, shift);
code.ANDI2R(carry, result, 1); code.ANDI2R(carry, result, 1);
code.LSR(result, 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.CMP(DecodeReg(op_arg), DecodeReg(op_arg));
code.ADCS(result, result, op_arg); code.ADCS(result, result, op_arg);
} else { } else {
code.ADDS(result,result, op_arg); code.ADDS(result, result, op_arg);
} }
} else { } else {
code.CMPI2R(DecodeReg(carry), 1); code.CMPI2R(DecodeReg(carry), 1);
@ -767,7 +767,7 @@ static void EmitSub(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
} else { } else {
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]); 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); code.SBCS(result, result, op_arg);
} }
} else { } else {
@ -781,12 +781,12 @@ static void EmitSub(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
if (carry_in.GetImmediateU1()) { if (carry_in.GetImmediateU1()) {
code.SUBS(result, result, op_arg); code.SUBS(result, result, op_arg);
} else { } else {
code.ADDSI2R(DecodeReg(op_arg), DecodeReg(op_arg), 0); // Clear carry code.ADDSI2R(DecodeReg(op_arg), DecodeReg(op_arg), 0); // Clear carry
code.SBCS(result,result, op_arg); code.SBCS(result, result, op_arg);
} }
} else { } else {
code.CMPI2R(DecodeReg(carry), 0x1); 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); ctx.reg_alloc.DefineValue(inst, result);
} }
void EmitA64::EmitUnsignedDiv32(EmitContext& ctx, IR::Inst* inst) { void EmitA64::EmitUnsignedDiv32(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(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); ctx.reg_alloc.DefineValue(inst, result);
} }
void EmitA64::EmitAnd32(EmitContext& ctx, IR::Inst* inst) { void EmitA64::EmitAnd32(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -905,8 +903,7 @@ void EmitA64::EmitAnd64(EmitContext& ctx, IR::Inst* inst) {
if (args[1].IsImmediate()) { if (args[1].IsImmediate()) {
u32 op_arg = args[1].GetImmediateU32(); u32 op_arg = args[1].GetImmediateU32();
code.ANDI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr()); code.ANDI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
} } else {
else {
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]); Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
code.AND(result, result, op_arg); code.AND(result, result, op_arg);
} }
@ -938,8 +935,7 @@ void EmitA64::EmitEor64(EmitContext& ctx, IR::Inst* inst) {
if (args[1].IsImmediate()) { if (args[1].IsImmediate()) {
u32 op_arg = args[1].GetImmediateU32(); u32 op_arg = args[1].GetImmediateU32();
code.EORI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr()); code.EORI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
} } else {
else {
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]); Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
code.EOR(result, result, op_arg); 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()); code.ORRI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
} else { } else {
Arm64Gen::ARM64Reg op_arg = DecodeReg(ctx.reg_alloc.UseGpr(args[1])); 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); ctx.reg_alloc.DefineValue(inst, result);
@ -971,8 +967,7 @@ void EmitA64::EmitOr64(EmitContext& ctx, IR::Inst* inst) {
if (args[1].IsImmediate()) { if (args[1].IsImmediate()) {
u32 op_arg = args[1].GetImmediateU32(); u32 op_arg = args[1].GetImmediateU32();
code.ORRI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr()); code.ORRI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
} } else {
else {
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]); Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
code.ORR(result, result, op_arg); code.ORR(result, result, op_arg);
} }
@ -1001,8 +996,7 @@ void EmitA64::EmitNot64(EmitContext& ctx, IR::Inst* inst) {
if (args[0].IsImmediate()) { if (args[0].IsImmediate()) {
result = ctx.reg_alloc.ScratchGpr(); result = ctx.reg_alloc.ScratchGpr();
code.MOVI2R(result, u32(~args[0].GetImmediateU32())); code.MOVI2R(result, u32(~args[0].GetImmediateU32()));
} } else {
else {
result = ctx.reg_alloc.UseScratchGpr(args[0]); result = ctx.reg_alloc.UseScratchGpr(args[0]);
code.MVN(result, result); code.MVN(result, result);
} }
@ -1120,11 +1114,11 @@ void EmitA64::EmitCountLeadingZeros32(EmitContext& ctx, IR::Inst* inst) {
} }
void EmitA64::EmitCountLeadingZeros64(EmitContext& ctx, IR::Inst* inst) { void EmitA64::EmitCountLeadingZeros64(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ARM64Reg source = ctx.reg_alloc.UseGpr(args[0]); ARM64Reg source = ctx.reg_alloc.UseGpr(args[0]);
ARM64Reg result = ctx.reg_alloc.ScratchGpr(); ARM64Reg result = ctx.reg_alloc.ScratchGpr();
code.CLZ(result, source); code.CLZ(result, source);
ctx.reg_alloc.DefineValue(inst, result); 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) { void FPTwoOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); 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); 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) { void FPThreeOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); 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>) { if constexpr (std::is_member_function_pointer_v<Function>) {
(code.fp_emitter.*fn)(result, result, operand); (code.fp_emitter.*fn)(result, result, operand);
} } else {
else {
fn(result, result, operand); fn(result, result, operand);
} }
ctx.reg_alloc.DefineValue(inst, result); ctx.reg_alloc.DefineValue(inst, result);
} }
} // anonymous namespace } // anonymous namespace
//void EmitA64::EmitFPAbs16(EmitContext& ctx, IR::Inst* inst) { //void EmitA64::EmitFPAbs16(EmitContext& ctx, IR::Inst* inst) {
// auto args = ctx.reg_alloc.GetArgumentInfo(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) { 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) { 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) { 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) { 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) { 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) { 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) { void EmitA64::EmitFPSqrt32(EmitContext& ctx, IR::Inst* inst) {
FPTwoOp<32>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FSQRT); 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) { 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) { 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) { static ARM64Reg SetFpscrNzcvFromFlags(BlockOfCode& code, EmitContext& ctx) {
@ -276,13 +275,11 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
if constexpr (unsigned_) { if constexpr (unsigned_) {
code.fp_emitter.FCVTU(result, src, round_imm); code.fp_emitter.FCVTU(result, src, round_imm);
} } else {
else {
code.fp_emitter.FCVTS(result, src, round_imm); code.fp_emitter.FCVTS(result, src, round_imm);
} }
ctx.reg_alloc.DefineValue(inst, result); ctx.reg_alloc.DefineValue(inst, result);
} }
void EmitA64::EmitFPDoubleToFixedS32(EmitContext& ctx, IR::Inst* inst) { void EmitA64::EmitFPDoubleToFixedS32(EmitContext& ctx, IR::Inst* inst) {
@ -328,8 +325,7 @@ void EmitA64::EmitFPFixedS32ToSingle(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) { if (fbits != 0) {
code.fp_emitter.SCVTF(result, from, fbits); code.fp_emitter.SCVTF(result, from, fbits);
} } else {
else {
code.fp_emitter.SCVTF(result, from); code.fp_emitter.SCVTF(result, from);
} }
@ -347,8 +343,7 @@ void EmitA64::EmitFPFixedU32ToSingle(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) { if (fbits != 0) {
code.fp_emitter.UCVTF(result, from, fbits); code.fp_emitter.UCVTF(result, from, fbits);
} } else {
else {
code.fp_emitter.UCVTF(result, from); code.fp_emitter.UCVTF(result, from);
} }
@ -366,8 +361,7 @@ void EmitA64::EmitFPFixedS32ToDouble(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) { if (fbits != 0) {
code.fp_emitter.SCVTF(result, from, fbits); code.fp_emitter.SCVTF(result, from, fbits);
} } else {
else {
code.fp_emitter.SCVTF(result, from); code.fp_emitter.SCVTF(result, from);
} }
@ -385,8 +379,7 @@ void EmitA64::EmitFPFixedS64ToDouble(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) { if (fbits != 0) {
code.fp_emitter.SCVTF(result, from, fbits); code.fp_emitter.SCVTF(result, from, fbits);
} } else {
else {
code.fp_emitter.SCVTF(result, from); code.fp_emitter.SCVTF(result, from);
} }
@ -404,8 +397,7 @@ void EmitA64::EmitFPFixedS64ToSingle(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) { if (fbits != 0) {
code.fp_emitter.SCVTF(result, from, fbits); code.fp_emitter.SCVTF(result, from, fbits);
} } else {
else {
code.fp_emitter.SCVTF(result, from); code.fp_emitter.SCVTF(result, from);
} }
@ -423,8 +415,7 @@ void EmitA64::EmitFPFixedU32ToDouble(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) { if (fbits != 0) {
code.fp_emitter.UCVTF(result, from, fbits); code.fp_emitter.UCVTF(result, from, fbits);
} } else {
else {
code.fp_emitter.UCVTF(result, from); 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) { void EmitA64::EmitFPFixedU64ToDouble(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const ARM64Reg from = ctx.reg_alloc.UseGpr(args[0]); const ARM64Reg from = ctx.reg_alloc.UseGpr(args[0]);
const ARM64Reg result = EncodeRegToDouble(ctx.reg_alloc.ScratchFpr()); const ARM64Reg result = EncodeRegToDouble(ctx.reg_alloc.ScratchFpr());
const size_t fbits = args[1].GetImmediateU8(); const size_t fbits = args[1].GetImmediateU8();
@ -443,8 +433,7 @@ void EmitA64::EmitFPFixedU64ToDouble(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) { if (fbits != 0) {
code.fp_emitter.UCVTF(result, from, fbits); code.fp_emitter.UCVTF(result, from, fbits);
} } else {
else {
code.fp_emitter.UCVTF(result, from); 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) { void EmitA64::EmitFPFixedU64ToSingle(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const ARM64Reg from = ctx.reg_alloc.UseGpr(args[0]); const ARM64Reg from = ctx.reg_alloc.UseGpr(args[0]);
const ARM64Reg result = EncodeRegToSingle(ctx.reg_alloc.ScratchFpr()); const ARM64Reg result = EncodeRegToSingle(ctx.reg_alloc.ScratchFpr());
const size_t fbits = args[1].GetImmediateU8(); const size_t fbits = args[1].GetImmediateU8();
@ -463,11 +451,10 @@ void EmitA64::EmitFPFixedU64ToSingle(EmitContext& ctx, IR::Inst* inst) {
if (fbits != 0) { if (fbits != 0) {
code.fp_emitter.UCVTF(result, from, fbits); code.fp_emitter.UCVTF(result, from, fbits);
} } else {
else {
code.fp_emitter.UCVTF(result, from); code.fp_emitter.UCVTF(result, from);
} }
ctx.reg_alloc.DefineValue(inst, result); 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); 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) { if constexpr (op == Op::Add) {
code.fp_emitter.SQADD(size, result, result, addend); code.fp_emitter.SQADD(size, result, result, addend);
} } else {
else {
code.fp_emitter.SQSUB(size, result, result, addend); 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); ctx.reg_alloc.DefineValue(inst, result);
} }
} // anonymous namespace } // anonymous namespace
void EmitA64::EmitSignedSaturatedAdd8(EmitContext& ctx, IR::Inst* inst) { void EmitA64::EmitSignedSaturatedAdd8(EmitContext& ctx, IR::Inst* inst) {
EmitSignedSaturatedOp<Op::Add, 8>(code, ctx, 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); 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); 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 { enum ShiftType {
ST_LSL = 0, ST_LSL = 0,
@ -474,8 +478,7 @@ private:
void EncodeUnconditionalBranchInst(u32 opc, u32 op2, u32 op3, u32 op4, ARM64Reg Rn); void EncodeUnconditionalBranchInst(u32 opc, u32 op2, u32 op3, u32 op4, ARM64Reg Rn);
void EncodeExceptionInst(u32 instenc, u32 imm); void EncodeExceptionInst(u32 instenc, u32 imm);
void EncodeSystemInst(u32 op0, u32 op1, u32 CRn, u32 CRm, u32 op2, ARM64Reg Rt); 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, void EncodeArithmeticInst(u32 instenc, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option);
ArithOption Option);
void EncodeArithmeticCarryInst(u32 op, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); 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 EncodeCondCompareImmInst(u32 op, ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond);
void EncodeCondCompareRegInst(u32 op, ARM64Reg Rn, ARM64Reg Rm, 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 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 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 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, void EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
ARM64Reg Rn, s32 imm);
void EncodeAddressInst(u32 op, ARM64Reg Rd, s32 imm); void EncodeAddressInst(u32 op, ARM64Reg Rd, s32 imm);
void EncodeLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm); void EncodeLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
@ -503,7 +505,8 @@ protected:
void Write32(u32 value); void Write32(u32 value);
public: public:
ARM64XEmitter() : m_code(nullptr), m_lastCacheFlushEnd(nullptr) { ARM64XEmitter()
: m_code(nullptr), m_lastCacheFlushEnd(nullptr) {
} }
ARM64XEmitter(u8* code_ptr) { ARM64XEmitter(u8* code_ptr) {
@ -831,7 +834,7 @@ public:
// Wrapper around MOVZ+MOVK // Wrapper around MOVZ+MOVK
void MOVI2R(ARM64Reg Rd, u64 imm, bool optimize = true); void MOVI2R(ARM64Reg Rd, u64 imm, bool optimize = true);
bool MOVI2R2(ARM64Reg Rd, u64 imm1, u64 imm2); bool MOVI2R2(ARM64Reg Rd, u64 imm1, u64 imm2);
template <class P> template<class P>
void MOVP2R(ARM64Reg Rd, P* ptr) { void MOVP2R(ARM64Reg Rd, P* ptr) {
ASSERT_MSG(Is64Bit(Rd), "Can't store pointers in 32-bit registers"); ASSERT_MSG(Is64Bit(Rd), "Can't store pointers in 32-bit registers");
MOVI2R(Rd, (uintptr_t)ptr); MOVI2R(Rd, (uintptr_t)ptr);
@ -848,8 +851,7 @@ public:
void EORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); void EORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
void CMPI2R(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, void ADDI2R_internal(ARM64Reg Rd, ARM64Reg Rn, u64 imm, bool negative, bool flags, ARM64Reg scratch);
ARM64Reg scratch);
void ADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); 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 ADDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
void SUBI2R(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++ // Unfortunately, calling operator() directly is undefined behavior in C++
// (this method might be a thunk in the case of multi-inheritance) so we // (this method might be a thunk in the case of multi-inheritance) so we
// have to go through a trampoline function. // 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) { static T CallLambdaTrampoline(const std::function<T(Args...)>* f, Args... args) {
return (*f)(args...); return (*f)(args...);
} }
// This function expects you to have set up the state. // This function expects you to have set up the state.
// Overwrites X0 and X30 // Overwrites X0 and X30
template <typename T, typename... Args> template<typename T, typename... Args>
ARM64Reg ABI_SetupLambda(const std::function<T(Args...)>* f) { ARM64Reg ABI_SetupLambda(const std::function<T(Args...)>* f) {
auto trampoline = &ARM64XEmitter::CallLambdaTrampoline<T, Args...>; auto trampoline = &ARM64XEmitter::CallLambdaTrampoline<T, Args...>;
MOVI2R(X30, (uintptr_t)trampoline); MOVI2R(X30, (uintptr_t)trampoline);
@ -889,7 +891,7 @@ public:
// Plain function call // Plain function call
void QuickCallFunction(const void* func, ARM64Reg scratchreg = X16); void QuickCallFunction(const void* func, ARM64Reg scratchreg = X16);
template <typename T> template<typename T>
void QuickCallFunction(T func, ARM64Reg scratchreg = X16) { void QuickCallFunction(T func, ARM64Reg scratchreg = X16) {
QuickCallFunction((const void*)func, scratchreg); QuickCallFunction((const void*)func, scratchreg);
} }
@ -897,7 +899,8 @@ public:
class ARM64FloatEmitter { class ARM64FloatEmitter {
public: 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); void LDR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
@ -935,7 +938,7 @@ public:
void FABS(ARM64Reg Rd, ARM64Reg Rn); void FABS(ARM64Reg Rd, ARM64Reg Rn);
void FNEG(ARM64Reg Rd, ARM64Reg Rn); void FNEG(ARM64Reg Rd, ARM64Reg Rn);
void FSQRT(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 // Scalar - 2 Source
void FADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); void FADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
@ -1110,22 +1113,17 @@ private:
} }
// Emitting functions // Emitting functions
void EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, ARM64Reg Rn, void EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
s32 imm); void EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
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 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 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 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 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, void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn);
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, ARM64Reg Rm);
void Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); 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 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, void EmitConversion2(bool sf, bool S, bool direction, u32 type, u32 rmode, u32 opcode, int scale, ARM64Reg Rd, ARM64Reg Rn);
int scale, ARM64Reg Rd, ARM64Reg Rn);
void EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Reg Rn, ARM64Reg Rm); 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 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); 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 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 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 EmitLoadStoreMultipleStructure(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn);
void EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn, void EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm);
ARM64Reg Rm);
void EmitScalar1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); 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, void EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
ARM64Reg Rm);
void EmitLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm); void EmitLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
void EmitConvertScalarToInt(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round, bool sign); void EmitConvertScalarToInt(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round, bool sign);
void EmitScalar3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra, void EmitScalar3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra, int opcode);
int opcode); void EncodeLoadStorePair(u32 size, bool load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
void EncodeLoadStorePair(u32 size, bool load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, void EncodeLoadStoreRegisterOffset(u32 size, bool load, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
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 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); 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 { namespace Dynarmic::BackendA64 {
enum CCFlags { enum CCFlags {
CC_EQ = 0, // Equal CC_EQ = 0, // Equal
CC_NEQ, // Not equal CC_NEQ, // Not equal
CC_CS, // Carry Set CC_CS, // Carry Set
CC_CC, // Carry Clear CC_CC, // Carry Clear
CC_MI, // Minus (Negative) CC_MI, // Minus (Negative)
CC_PL, // Plus CC_PL, // Plus
CC_VS, // Overflow CC_VS, // Overflow
CC_VC, // No Overflow CC_VC, // No Overflow
CC_HI, // Unsigned higher CC_HI, // Unsigned higher
CC_LS, // Unsigned lower or same CC_LS, // Unsigned lower or same
CC_GE, // Signed greater than or equal CC_GE, // Signed greater than or equal
CC_LT, // Signed less than CC_LT, // Signed less than
CC_GT, // Signed greater than CC_GT, // Signed greater than
CC_LE, // Signed less than or equal CC_LE, // Signed less than or equal
CC_AL, // Always (unconditional) 14 CC_AL, // Always (unconditional) 14
CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same
CC_LO = CC_CC, // Alias of CC_CC Unsigned lower CC_LO = CC_CC, // Alias of CC_CC Unsigned lower
}; };
const u32 NO_COND = 0xE0000000; const u32 NO_COND = 0xE0000000;
} // namespace Dynarmic::BackendA64 } // namespace Dynarmic::BackendA64

View File

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

View File

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

View File

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

View File

@ -8,14 +8,13 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <csignal>
#include <mutex> #include <mutex>
#include <vector> #include <vector>
#include <csignal>
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/ucontext.h> # include <sys/ucontext.h>
#else #else
#include <ucontext.h> # include <ucontext.h>
#endif #endif
#include <mcl/assert.hpp> #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", "dynarmic: POSIX SigHandler: Exception was not in registered code blocks (PC {})\n",
PC); PC);
struct sigaction* retry_sa = struct sigaction* retry_sa = sig == SIGSEGV ? &sig_handler.old_sa_segv : &sig_handler.old_sa_bus;
sig == SIGSEGV ? &sig_handler.old_sa_segv : &sig_handler.old_sa_bus;
if (retry_sa->sa_flags & SA_SIGINFO) { if (retry_sa->sa_flags & SA_SIGINFO) {
retry_sa->sa_sigaction(sig, info, raw_context); retry_sa->sa_sigaction(sig, info, raw_context);
return; return;
@ -133,7 +131,7 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
retry_sa->sa_handler(sig); retry_sa->sa_handler(sig);
} }
} // anonymous namespace } // anonymous namespace
struct ExceptionHandler::Impl final { struct ExceptionHandler::Impl final {
Impl(BlockOfCode& code, std::function<void(CodePtr)> cb) { Impl(BlockOfCode& code, std::function<void(CodePtr)> cb) {
@ -162,4 +160,4 @@ bool ExceptionHandler::SupportsFastmem() const {
return static_cast<bool>(impl); 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))); 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, X29,
X30, X30,
SP, // 64bit stack pointer SP, // 64bit stack pointer
// Qword FPR registers // Qword FPR registers
Q0, Q0,
@ -138,32 +138,76 @@ using HostLocList = std::initializer_list<HostLoc>;
// X30 is the link register. // X30 is the link register.
// In order of desireablity based first on ABI // In order of desireablity based first on ABI
constexpr HostLocList any_gpr = { constexpr HostLocList any_gpr = {
HostLoc::X19, HostLoc::X20, HostLoc::X21, HostLoc::X22, HostLoc::X23, HostLoc::X19,
HostLoc::X24, HostLoc::X25, HostLoc::X20,
HostLoc::X21,
HostLoc::X22,
HostLoc::X23,
HostLoc::X24,
HostLoc::X25,
HostLoc::X8, HostLoc::X9, HostLoc::X10, HostLoc::X11, HostLoc::X12, HostLoc::X8,
HostLoc::X13, HostLoc::X14, HostLoc::X15, HostLoc::X16, HostLoc::X17, 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::X7,
HostLoc::X2, HostLoc::X1, HostLoc::X0, HostLoc::X6,
HostLoc::X5,
HostLoc::X4,
HostLoc::X3,
HostLoc::X2,
HostLoc::X1,
HostLoc::X0,
}; };
constexpr HostLocList any_fpr = { constexpr HostLocList any_fpr = {
HostLoc::Q8, HostLoc::Q9, HostLoc::Q10, HostLoc::Q11, HostLoc::Q12, HostLoc::Q13, HostLoc::Q8,
HostLoc::Q14, HostLoc::Q15, 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::Q16,
HostLoc::Q22, HostLoc::Q23, HostLoc::Q24, HostLoc::Q25, HostLoc::Q26, HostLoc::Q27, HostLoc::Q17,
HostLoc::Q28, HostLoc::Q29, HostLoc::Q30, HostLoc::Q31, 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::Q7,
HostLoc::Q1, HostLoc::Q0, HostLoc::Q6,
HostLoc::Q5,
HostLoc::Q4,
HostLoc::Q3,
HostLoc::Q2,
HostLoc::Q1,
HostLoc::Q0,
}; };
Arm64Gen::ARM64Reg HostLocToReg64(HostLoc loc); Arm64Gen::ARM64Reg HostLocToReg64(HostLoc loc);
Arm64Gen::ARM64Reg HostLocToFpr(HostLoc loc); Arm64Gen::ARM64Reg HostLocToFpr(HostLoc loc);
template <typename JitStateType> template<typename JitStateType>
size_t SpillToOpArg(HostLoc loc) { size_t SpillToOpArg(HostLoc loc) {
ASSERT(HostLocIsSpill(loc)); ASSERT(HostLocIsSpill(loc));
@ -174,4 +218,4 @@ size_t SpillToOpArg(HostLoc loc) {
return JitStateType::GetSpillLocationOffsetFromIndex(i); return JitStateType::GetSpillLocationOffsetFromIndex(i);
} }
} // namespace Dynarmic::BackendA64 } // namespace Dynarmic::BackendA64

View File

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

View File

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

View File

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

View File

@ -4,6 +4,8 @@
* General Public License version 2 or any later version. * General Public License version 2 or any later version.
*/ */
#include "dynarmic/backend/A64/reg_alloc.h"
#include <algorithm> #include <algorithm>
#include <numeric> #include <numeric>
#include <utility> #include <utility>
@ -12,7 +14,6 @@
#include <mcl/assert.hpp> #include <mcl/assert.hpp>
#include "dynarmic/backend/A64/abi.h" #include "dynarmic/backend/A64/abi.h"
#include "dynarmic/backend/A64/reg_alloc.h"
namespace Dynarmic::BackendA64 { namespace Dynarmic::BackendA64 {
@ -67,7 +68,7 @@ static size_t GetBitWidth(IR::Type type) {
case IR::Type::U128: case IR::Type::U128:
return 128; return 128;
case IR::Type::NZCVFlags: 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(); UNREACHABLE();
return 0; return 0;
@ -379,16 +380,9 @@ HostLoc RegAlloc::ScratchImpl(HostLocList desired_locations) {
return location; return location;
} }
void RegAlloc::HostCall(IR::Inst* result_def, std::optional<Argument::copyable_reference> arg0, 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) {
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 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}; 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]() { 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}); ScratchImpl({caller_saved});
} }
if (result_def) { if (result_def) {
DefineValueImpl(result_def, ABI_RETURN); DefineValueImpl(result_def, ABI_RETURN);
} }
} }
@ -433,10 +427,10 @@ void RegAlloc::AssertNoMoreUses() {
} }
HostLoc RegAlloc::SelectARegister(HostLocList desired_locations) const { 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.. // 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(); return !this->LocInfo(loc).IsLocked();
}); });
candidates.erase(allocated_locs, candidates.end()); 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. // 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. // 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(); 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 <array>
#include <functional> #include <functional>
#include <optional>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <optional>
#include <mcl/stdint.hpp> #include <mcl/stdint.hpp>
@ -84,7 +84,8 @@ public:
private: private:
friend class RegAlloc; friend class RegAlloc;
explicit Argument(RegAlloc& reg_alloc) : reg_alloc(reg_alloc) {} explicit Argument(RegAlloc& reg_alloc)
: reg_alloc(reg_alloc) {}
bool allocated = false; bool allocated = false;
RegAlloc& reg_alloc; RegAlloc& reg_alloc;
@ -96,7 +97,7 @@ public:
using ArgumentInfo = std::array<Argument, IR::max_arg_count>; using ArgumentInfo = std::array<Argument, IR::max_arg_count>;
explicit RegAlloc(BlockOfCode& code, size_t num_spills, std::function<u64(HostLoc)> spill_to_addr) 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); ArgumentInfo GetArgumentInfo(IR::Inst* inst);
@ -117,14 +118,7 @@ public:
Arm64Gen::ARM64Reg ScratchGpr(HostLocList desired_locations = any_gpr); Arm64Gen::ARM64Reg ScratchGpr(HostLocList desired_locations = any_gpr);
Arm64Gen::ARM64Reg ScratchFpr(HostLocList desired_locations = any_fpr); Arm64Gen::ARM64Reg ScratchFpr(HostLocList desired_locations = any_fpr);
void HostCall(IR::Inst* result_def = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, 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 = {});
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 // TODO: Values in host flags
@ -163,4 +157,4 @@ private:
void EmitExchange(HostLoc a, HostLoc b); 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); u8 RecipSqrtEstimate(u64 a);
template <typename T> template<typename T>
constexpr bool IsPow2(T imm){ constexpr bool IsPow2(T imm) {
return imm > 0 && (imm & (imm - 1)) == 0; return imm > 0 && (imm & (imm - 1)) == 0;
} }