clang-format
This commit is contained in:
parent
d459cb6f59
commit
1f302f397f
@ -4,21 +4,21 @@
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "dynarmic/backend/A64/a32_emit_a64.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
#include <dynarmic/interface/A32/coprocessor.h>
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h>
|
||||
#include <mcl/assert.hpp>
|
||||
#include <mcl/bit_cast.hpp>
|
||||
#include <mcl/stdint.hpp>
|
||||
#include <mcl/scope_exit.hpp>
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
#include <dynarmic/interface/A32/coprocessor.h>
|
||||
|
||||
#include "dynarmic/backend/A64/a32_emit_a64.h"
|
||||
#include "dynarmic/backend/A64/a32_jitstate.h"
|
||||
#include "dynarmic/backend/A64/abi.h"
|
||||
#include "dynarmic/backend/A64/block_of_code.h"
|
||||
@ -41,7 +41,7 @@ namespace Dynarmic::BackendA64 {
|
||||
|
||||
// Note that unlike the x64 backend these only returns ONLY the offset to register and not the address!
|
||||
static size_t MJitStateReg(A32::Reg reg) {
|
||||
return offsetof(A32JitState, Reg) + sizeof(u32) * static_cast<size_t>(reg);
|
||||
return offsetof(A32JitState, Reg) + sizeof(u32) * static_cast<size_t>(reg);
|
||||
}
|
||||
|
||||
static size_t MJitStateExtReg(A32::ExtReg reg) {
|
||||
@ -56,7 +56,8 @@ static size_t MJitStateExtReg(A32::ExtReg reg) {
|
||||
ASSERT_FALSE("Should never happen.");
|
||||
}
|
||||
|
||||
A32EmitContext::A32EmitContext(RegAlloc& reg_alloc, IR::Block& block) : EmitContext(reg_alloc, block) {}
|
||||
A32EmitContext::A32EmitContext(RegAlloc& reg_alloc, IR::Block& block)
|
||||
: EmitContext(reg_alloc, block) {}
|
||||
|
||||
A32::LocationDescriptor A32EmitContext::Location() const {
|
||||
return A32::LocationDescriptor{block.Location()};
|
||||
@ -91,8 +92,8 @@ std::ptrdiff_t A32EmitContext::GetInstOffset(IR::Inst* inst) const {
|
||||
}
|
||||
|
||||
A32EmitA64::A32EmitA64(BlockOfCode& code, A32::UserConfig config, A32::Jit* jit_interface)
|
||||
: EmitA64(code), config(std::move(config)), jit_interface(jit_interface) {
|
||||
exception_handler.Register(code, [this](CodePtr PC){FastmemCallback(PC);});
|
||||
: EmitA64(code), config(std::move(config)), jit_interface(jit_interface) {
|
||||
exception_handler.Register(code, [this](CodePtr PC) { FastmemCallback(PC); });
|
||||
GenMemoryAccessors();
|
||||
GenTerminalHandlers();
|
||||
code.PreludeComplete();
|
||||
@ -109,7 +110,7 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) {
|
||||
};
|
||||
|
||||
RegAlloc reg_alloc{code, A32JitState::SpillCount, SpillToOpArg<A32JitState>};
|
||||
A32EmitContext ctx{reg_alloc, block};
|
||||
A32EmitContext ctx{reg_alloc, block};
|
||||
|
||||
const u8* entrypoint = code.AlignCode16();
|
||||
|
||||
@ -121,15 +122,14 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) {
|
||||
|
||||
// Call the relevant Emit* member function.
|
||||
switch (inst->GetOpcode()) {
|
||||
|
||||
#define OPCODE(name, type, ...) \
|
||||
case IR::Opcode::name: \
|
||||
A32EmitA64::Emit##name(ctx, inst); \
|
||||
break;
|
||||
#define A32OPC(name, type, ...) \
|
||||
case IR::Opcode::A32##name: \
|
||||
A32EmitA64::EmitA32##name(ctx, inst); \
|
||||
break;
|
||||
#define OPCODE(name, type, ...) \
|
||||
case IR::Opcode::name: \
|
||||
A32EmitA64::Emit##name(ctx, inst); \
|
||||
break;
|
||||
#define A32OPC(name, type, ...) \
|
||||
case IR::Opcode::A32##name: \
|
||||
A32EmitA64::EmitA32##name(ctx, inst); \
|
||||
break;
|
||||
#define A64OPC(...)
|
||||
#include "dynarmic/backend/A64/opcodes.inc"
|
||||
#undef OPCODE
|
||||
@ -184,7 +184,7 @@ void A32EmitA64::EmitCondPrelude(const A32EmitContext& ctx) {
|
||||
|
||||
FixupBranch pass = EmitCond(ctx.block.GetCondition());
|
||||
EmitAddCycles(ctx.block.ConditionFailedCycleCount());
|
||||
EmitTerminal(IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, ctx.block.Location(), ctx.IsSingleStep());
|
||||
EmitTerminal(IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, ctx.block.Location(), ctx.IsSingleStep());
|
||||
code.SetJumpTarget(pass);
|
||||
}
|
||||
|
||||
@ -343,7 +343,7 @@ void A32EmitA64::GenTerminalHandlers() {
|
||||
code.BR(code.ABI_SCRATCH1);
|
||||
|
||||
code.SetJumpTarget(fast_dispatch_cache_miss);
|
||||
code.STR(INDEX_UNSIGNED, location_descriptor_reg, fast_dispatch_entry_reg, offsetof(FastDispatchEntry, location_descriptor) );
|
||||
code.STR(INDEX_UNSIGNED, location_descriptor_reg, fast_dispatch_entry_reg, offsetof(FastDispatchEntry, location_descriptor));
|
||||
code.LookupBlock();
|
||||
code.STR(INDEX_UNSIGNED, code.ABI_RETURN, fast_dispatch_entry_reg, offsetof(FastDispatchEntry, code_ptr));
|
||||
code.BR(code.ABI_RETURN);
|
||||
@ -359,7 +359,6 @@ void A32EmitA64::GenTerminalHandlers() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void A32EmitA64::EmitA32GetRegister(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
A32::Reg reg = inst->GetArg(0).GetA32RegRef();
|
||||
|
||||
@ -418,8 +417,7 @@ void A32EmitA64::EmitA32SetExtendedRegister64(A32EmitContext& ctx, IR::Inst* ins
|
||||
if (args[1].IsInFpr()) {
|
||||
ARM64Reg to_store = ctx.reg_alloc.UseFpr(args[1]);
|
||||
code.fp_emitter.STR(64, INDEX_UNSIGNED, to_store, X28, MJitStateExtReg(reg));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ARM64Reg to_store = ctx.reg_alloc.UseGpr(args[1]);
|
||||
code.STR(INDEX_UNSIGNED, to_store, X28, MJitStateExtReg(reg));
|
||||
}
|
||||
@ -442,18 +440,18 @@ static void SetCpsrImpl(u32 value, A32JitState* jit_state) {
|
||||
|
||||
void A32EmitA64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
|
||||
// TODO:Inline
|
||||
ctx.reg_alloc.HostCall(nullptr, args[0]);
|
||||
|
||||
// Use an unused HostCall register
|
||||
ARM64Reg host_fpsr = X9;
|
||||
|
||||
|
||||
if (config.always_little_endian) {
|
||||
code.ANDI2R(code.ABI_PARAM1, code.ABI_PARAM1, 0xFFFFFDFF, ctx.reg_alloc.ScratchGpr());
|
||||
}
|
||||
|
||||
// Since this is one of the only places where the ~sticky~
|
||||
// Since this is one of the only places where the ~sticky~
|
||||
// guest's Q flag can be cleared it is also a great place to clear the host's Q flag
|
||||
code.MRS(host_fpsr, FIELD_FPSR);
|
||||
code.ANDI2R(host_fpsr, host_fpsr, ~(1 << 27));
|
||||
@ -496,7 +494,7 @@ void A32EmitA64::EmitA32SetCpsrNZCVQ(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
code.STR(INDEX_UNSIGNED, a, X28, offsetof(A32JitState, cpsr_nzcv));
|
||||
}
|
||||
|
||||
// Since this is one of the only places where the ~sticky~
|
||||
// Since this is one of the only places where the ~sticky~
|
||||
// guest's Q flag can be cleared it is also a great place to clear the host's Q flag.
|
||||
// TODO : possibly a better job at explaining.
|
||||
code.MRS(host_fpsr, FIELD_FPSR);
|
||||
@ -676,7 +674,7 @@ void A32EmitA64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
// cpsr.T = false;
|
||||
// }
|
||||
// We rely on the fact we disallow EFlag from changing within a block.
|
||||
|
||||
|
||||
if (arg.IsImmediate()) {
|
||||
const ARM64Reg scratch = DecodeReg(ctx.reg_alloc.ScratchGpr());
|
||||
u32 new_pc = arg.GetImmediateU32();
|
||||
@ -697,7 +695,7 @@ void A32EmitA64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
code.ADD(new_upper, new_upper, mask);
|
||||
code.STR(INDEX_UNSIGNED, new_upper, X28, offsetof(A32JitState, upper_location_descriptor));
|
||||
code.LSL(mask, mask, 1);
|
||||
code.SUBI2R(mask, mask, 4); // mask = pc & 1 ? 0xFFFFFFFE : 0xFFFFFFFC
|
||||
code.SUBI2R(mask, mask, 4); // mask = pc & 1 ? 0xFFFFFFFE : 0xFFFFFFFC
|
||||
code.AND(new_pc, new_pc, mask);
|
||||
code.STR(INDEX_UNSIGNED, new_pc, X28, MJitStateReg(A32::Reg::PC));
|
||||
}
|
||||
@ -813,7 +811,7 @@ void A32EmitA64::DoNotFastmem(const DoNotFastmemMarker& marker) {
|
||||
InvalidateBasicBlocks({std::get<0>(marker)});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
void A32EmitA64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr callback_fn) {
|
||||
constexpr size_t bit_size = mcl::bitsizeof<T>;
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
@ -836,21 +834,21 @@ void A32EmitA64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr c
|
||||
FixupBranch abort = code.CBZ(result);
|
||||
code.ANDI2R(vaddr, vaddr, 4095);
|
||||
switch (bit_size) {
|
||||
case 8:
|
||||
code.LDRB(DecodeReg(result), result, vaddr);
|
||||
break;
|
||||
case 16:
|
||||
code.LDRH(DecodeReg(result), result, vaddr);
|
||||
break;
|
||||
case 32:
|
||||
code.LDR(DecodeReg(result), result, vaddr);
|
||||
break;
|
||||
case 64:
|
||||
code.LDR(result, result, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
case 8:
|
||||
code.LDRB(DecodeReg(result), result, vaddr);
|
||||
break;
|
||||
case 16:
|
||||
code.LDRH(DecodeReg(result), result, vaddr);
|
||||
break;
|
||||
case 32:
|
||||
code.LDR(DecodeReg(result), result, vaddr);
|
||||
break;
|
||||
case 64:
|
||||
code.LDR(result, result, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
}
|
||||
end = code.B();
|
||||
code.SetJumpTarget(abort);
|
||||
@ -858,54 +856,52 @@ void A32EmitA64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr c
|
||||
code.MOV(result, code.ABI_RETURN);
|
||||
};
|
||||
|
||||
|
||||
if (ShouldFastmem(do_not_fastmem_marker)) {
|
||||
const CodePtr patch_location = code.GetCodePtr();
|
||||
switch (bit_size) {
|
||||
case 8:
|
||||
code.LDRB(DecodeReg(result), X27, vaddr);
|
||||
break;
|
||||
case 16:
|
||||
code.LDRH(DecodeReg(result), X27, vaddr);
|
||||
break;
|
||||
case 32:
|
||||
code.LDR(DecodeReg(result), X27, vaddr);
|
||||
break;
|
||||
case 64:
|
||||
code.LDR(result, X27, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
case 8:
|
||||
code.LDRB(DecodeReg(result), X27, vaddr);
|
||||
break;
|
||||
case 16:
|
||||
code.LDRH(DecodeReg(result), X27, vaddr);
|
||||
break;
|
||||
case 32:
|
||||
code.LDR(DecodeReg(result), X27, vaddr);
|
||||
break;
|
||||
case 64:
|
||||
code.LDR(result, X27, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
}
|
||||
|
||||
fastmem_patch_info.emplace(
|
||||
patch_location,
|
||||
FastmemPatchInfo{
|
||||
[this, patch_location, page_table_lookup, callback_fn, result, do_not_fastmem_marker]{
|
||||
CodePtr save_code_ptr = code.GetCodePtr();
|
||||
code.SetCodePtr(patch_location);
|
||||
FixupBranch thunk = code.B();
|
||||
u8* end_ptr = code.GetWritableCodePtr();
|
||||
code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr);
|
||||
code.SetCodePtr(save_code_ptr);
|
||||
code.SwitchToFarCode();
|
||||
code.SetJumpTarget(thunk);
|
||||
if (config.page_table) {
|
||||
FixupBranch end{};
|
||||
page_table_lookup(end);
|
||||
code.SetJumpTarget(end, end_ptr);
|
||||
} else {
|
||||
code.BL(callback_fn);
|
||||
code.MOV(result, code.ABI_RETURN);
|
||||
}
|
||||
code.B(end_ptr);
|
||||
code.FlushIcache();
|
||||
code.SwitchToNearCode();
|
||||
patch_location,
|
||||
FastmemPatchInfo{
|
||||
[this, patch_location, page_table_lookup, callback_fn, result, do_not_fastmem_marker] {
|
||||
CodePtr save_code_ptr = code.GetCodePtr();
|
||||
code.SetCodePtr(patch_location);
|
||||
FixupBranch thunk = code.B();
|
||||
u8* end_ptr = code.GetWritableCodePtr();
|
||||
code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr);
|
||||
code.SetCodePtr(save_code_ptr);
|
||||
code.SwitchToFarCode();
|
||||
code.SetJumpTarget(thunk);
|
||||
if (config.page_table) {
|
||||
FixupBranch end{};
|
||||
page_table_lookup(end);
|
||||
code.SetJumpTarget(end, end_ptr);
|
||||
} else {
|
||||
code.BL(callback_fn);
|
||||
code.MOV(result, code.ABI_RETURN);
|
||||
}
|
||||
code.B(end_ptr);
|
||||
code.FlushIcache();
|
||||
code.SwitchToNearCode();
|
||||
|
||||
DoNotFastmem(do_not_fastmem_marker);
|
||||
}
|
||||
});
|
||||
DoNotFastmem(do_not_fastmem_marker);
|
||||
}});
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
return;
|
||||
@ -950,21 +946,22 @@ void A32EmitA64::WriteMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr
|
||||
FixupBranch abort = code.CBZ(addr);
|
||||
code.ANDI2R(vaddr, vaddr, 4095);
|
||||
switch (bit_size) {
|
||||
case 8:
|
||||
code.STRB(DecodeReg(value), addr, vaddr);
|
||||
break;
|
||||
case 16:
|
||||
code.STRH(DecodeReg(value), addr, vaddr);
|
||||
break;
|
||||
case 32:
|
||||
code.STR(DecodeReg(value), addr, vaddr);;
|
||||
break;
|
||||
case 64:
|
||||
code.STR(value, addr, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
case 8:
|
||||
code.STRB(DecodeReg(value), addr, vaddr);
|
||||
break;
|
||||
case 16:
|
||||
code.STRH(DecodeReg(value), addr, vaddr);
|
||||
break;
|
||||
case 32:
|
||||
code.STR(DecodeReg(value), addr, vaddr);
|
||||
;
|
||||
break;
|
||||
case 64:
|
||||
code.STR(value, addr, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
}
|
||||
end = code.B();
|
||||
code.SetJumpTarget(abort);
|
||||
@ -974,49 +971,48 @@ void A32EmitA64::WriteMemory(A32EmitContext& ctx, IR::Inst* inst, const CodePtr
|
||||
if (ShouldFastmem(do_not_fastmem_marker)) {
|
||||
const CodePtr patch_location = code.GetCodePtr();
|
||||
switch (bit_size) {
|
||||
case 8:
|
||||
code.STRB(DecodeReg(value), X27, vaddr);
|
||||
break;
|
||||
case 16:
|
||||
code.STRH(DecodeReg(value), X27, vaddr);
|
||||
break;
|
||||
case 32:
|
||||
code.STR(DecodeReg(value), X27, vaddr);
|
||||
break;
|
||||
case 64:
|
||||
code.STR(value, X27, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
case 8:
|
||||
code.STRB(DecodeReg(value), X27, vaddr);
|
||||
break;
|
||||
case 16:
|
||||
code.STRH(DecodeReg(value), X27, vaddr);
|
||||
break;
|
||||
case 32:
|
||||
code.STR(DecodeReg(value), X27, vaddr);
|
||||
break;
|
||||
case 64:
|
||||
code.STR(value, X27, vaddr);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid bit_size");
|
||||
break;
|
||||
}
|
||||
|
||||
fastmem_patch_info.emplace(
|
||||
patch_location,
|
||||
FastmemPatchInfo{
|
||||
[this, patch_location, page_table_lookup, callback_fn, do_not_fastmem_marker]{
|
||||
CodePtr save_code_ptr = code.GetCodePtr();
|
||||
code.SetCodePtr(patch_location);
|
||||
FixupBranch thunk = code.B();
|
||||
u8* end_ptr = code.GetWritableCodePtr();
|
||||
code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr);
|
||||
code.SetCodePtr(save_code_ptr);
|
||||
code.SwitchToFarCode();
|
||||
code.SetJumpTarget(thunk);
|
||||
if (config.page_table) {
|
||||
FixupBranch end{};
|
||||
page_table_lookup(end);
|
||||
code.SetJumpTarget(end, end_ptr);
|
||||
} else {
|
||||
code.BL(callback_fn);
|
||||
}
|
||||
code.B(end_ptr);
|
||||
code.FlushIcache();
|
||||
code.SwitchToNearCode();
|
||||
patch_location,
|
||||
FastmemPatchInfo{
|
||||
[this, patch_location, page_table_lookup, callback_fn, do_not_fastmem_marker] {
|
||||
CodePtr save_code_ptr = code.GetCodePtr();
|
||||
code.SetCodePtr(patch_location);
|
||||
FixupBranch thunk = code.B();
|
||||
u8* end_ptr = code.GetWritableCodePtr();
|
||||
code.FlushIcacheSection(reinterpret_cast<const u8*>(patch_location), end_ptr);
|
||||
code.SetCodePtr(save_code_ptr);
|
||||
code.SwitchToFarCode();
|
||||
code.SetJumpTarget(thunk);
|
||||
if (config.page_table) {
|
||||
FixupBranch end{};
|
||||
page_table_lookup(end);
|
||||
code.SetJumpTarget(end, end_ptr);
|
||||
} else {
|
||||
code.BL(callback_fn);
|
||||
}
|
||||
code.B(end_ptr);
|
||||
code.FlushIcache();
|
||||
code.SwitchToNearCode();
|
||||
|
||||
DoNotFastmem(do_not_fastmem_marker);
|
||||
}
|
||||
});
|
||||
DoNotFastmem(do_not_fastmem_marker);
|
||||
}});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1062,7 +1058,7 @@ void A32EmitA64::EmitA32WriteMemory64(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
WriteMemory<u64>(ctx, inst, write_memory_64);
|
||||
}
|
||||
|
||||
template <typename T, void (A32::UserCallbacks::*fn)(A32::VAddr, T)>
|
||||
template<typename T, void (A32::UserCallbacks::*fn)(A32::VAddr, T)>
|
||||
static void ExclusiveWrite(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* inst, const A32::UserConfig& config) {
|
||||
auto args = reg_alloc.GetArgumentInfo(inst);
|
||||
reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
|
||||
@ -1086,7 +1082,7 @@ static void ExclusiveWrite(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* ins
|
||||
code.MOVI2R(passed, 0);
|
||||
|
||||
for (FixupBranch e : end) {
|
||||
code.SetJumpTarget(e);
|
||||
code.SetJumpTarget(e);
|
||||
}
|
||||
|
||||
reg_alloc.DefineValue(inst, passed);
|
||||
@ -1112,8 +1108,7 @@ static void EmitCoprocessorException() {
|
||||
ASSERT_FALSE("Should raise coproc exception here");
|
||||
}
|
||||
|
||||
static void CallCoprocCallback(BlockOfCode& code, RegAlloc& reg_alloc, A32::Jit* jit_interface, A32::Coprocessor::Callback callback,
|
||||
IR::Inst* inst = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}) {
|
||||
static void CallCoprocCallback(BlockOfCode& code, RegAlloc& reg_alloc, A32::Jit* jit_interface, A32::Coprocessor::Callback callback, IR::Inst* inst = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}) {
|
||||
reg_alloc.HostCall(inst, {}, {}, arg0, arg1);
|
||||
|
||||
code.MOVP2R(code.ABI_PARAM1, jit_interface);
|
||||
@ -1306,7 +1301,7 @@ void A32EmitA64::EmitA32CoprocGetTwoWords(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
code.LDR(INDEX_UNSIGNED, DecodeReg(reg_result), reg_tmp, 0);
|
||||
code.MOVP2R(reg_tmp, source_ptrs[0]);
|
||||
code.LDR(INDEX_UNSIGNED, DecodeReg(reg_tmp), reg_tmp, 0);
|
||||
code.ORR(reg_result, reg_tmp, reg_result, ArithOption{ reg_result , ST_LSL, 32});
|
||||
code.ORR(reg_result, reg_tmp, reg_result, ArithOption{reg_result, ST_LSL, 32});
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, reg_result);
|
||||
|
||||
@ -1331,7 +1326,6 @@ void A32EmitA64::EmitA32CoprocLoadWords(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
option = coproc_info[5];
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<A32::Coprocessor> coproc = config.coprocessors[coproc_num];
|
||||
if (!coproc) {
|
||||
EmitCoprocessorException();
|
||||
@ -1376,7 +1370,6 @@ void A32EmitA64::EmitA32CoprocStoreWords(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
CallCoprocCallback(code, ctx.reg_alloc, jit_interface, *action, nullptr, args[1]);
|
||||
}
|
||||
|
||||
|
||||
std::string A32EmitA64::LocationDescriptorToFriendlyName(const IR::LocationDescriptor& ir_descriptor) const {
|
||||
const A32::LocationDescriptor descriptor{ir_descriptor};
|
||||
return fmt::format("a32_{}{:08X}_{}_fpcr{:08X}", descriptor.TFlag() ? "t" : "a", descriptor.PC(), descriptor.EFlag() ? "be" : "le",
|
||||
@ -1399,7 +1392,7 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDesc
|
||||
code.STR(INDEX_UNSIGNED, DecodeReg(code.ABI_PARAM2), X28, MJitStateReg(A32::Reg::PC));
|
||||
code.SwitchFpscrOnExit();
|
||||
Devirtualize<&A32::UserCallbacks::InterpreterFallback>(config.callbacks).EmitCall(code);
|
||||
code.ReturnFromRunCode(true); // TODO: Check cycles
|
||||
code.ReturnFromRunCode(true); // TODO: Check cycles
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
||||
@ -1407,7 +1400,7 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescri
|
||||
}
|
||||
|
||||
void A32EmitA64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_location, IR::LocationDescriptor old_location) {
|
||||
auto get_upper = [](const IR::LocationDescriptor &desc) -> u32 {
|
||||
auto get_upper = [](const IR::LocationDescriptor& desc) -> u32 {
|
||||
return static_cast<u32>(A32::LocationDescriptor{desc}.SetSingleStepping(false).UniqueHash() >> 32);
|
||||
};
|
||||
|
||||
@ -1432,7 +1425,7 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDesc
|
||||
code.ReturnFromRunCode();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (config.enable_cycle_counting) {
|
||||
code.CMP(X26, ZR);
|
||||
|
||||
@ -1456,7 +1449,7 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDesc
|
||||
|
||||
FixupBranch dest = code.B();
|
||||
|
||||
code.SwitchToFarCode();
|
||||
code.SwitchToFarCode();
|
||||
code.AlignCode16();
|
||||
code.SetJumpTarget(dest);
|
||||
code.MOVI2R(DecodeReg(code.ABI_SCRATCH1), A32::LocationDescriptor{terminal.next}.PC());
|
||||
@ -1472,7 +1465,7 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDesc
|
||||
|
||||
void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) {
|
||||
EmitSetUpperLocationDescriptor(terminal.next, initial_location);
|
||||
|
||||
|
||||
if (!config.HasOptimization(OptimizationFlag::BlockLinking) || is_single_step) {
|
||||
code.MOVI2R(DecodeReg(code.ABI_SCRATCH1), A32::LocationDescriptor{terminal.next}.PC());
|
||||
code.STR(INDEX_UNSIGNED, DecodeReg(code.ABI_SCRATCH1), X28, MJitStateReg(A32::Reg::PC));
|
||||
@ -1532,10 +1525,10 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDesc
|
||||
void A32EmitA64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
|
||||
const CodePtr patch_location = code.GetCodePtr();
|
||||
|
||||
auto long_branch_gt = [this](CodePtr ptr){
|
||||
auto long_branch_gt = [this](CodePtr ptr) {
|
||||
const s64 distance = reinterpret_cast<s64>(ptr) - reinterpret_cast<s64>(code.GetCodePtr());
|
||||
|
||||
if((distance >> 2) >= -0x40000 && (distance >> 2) <= 0x3FFFF) {
|
||||
if ((distance >> 2) >= -0x40000 && (distance >> 2) <= 0x3FFFF) {
|
||||
code.B(CC_GT, ptr);
|
||||
return;
|
||||
}
|
||||
@ -1558,10 +1551,10 @@ void A32EmitA64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr
|
||||
void A32EmitA64::EmitPatchJz(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) {
|
||||
const CodePtr patch_location = code.GetCodePtr();
|
||||
|
||||
auto long_branch_gt = [this](CodePtr ptr){
|
||||
auto long_branch_gt = [this](CodePtr ptr) {
|
||||
const s64 distance = reinterpret_cast<s64>(ptr) - reinterpret_cast<s64>(code.GetCodePtr());
|
||||
|
||||
if((distance >> 2) >= -0x40000 && (distance >> 2) <= 0x3FFFF) {
|
||||
if ((distance >> 2) >= -0x40000 && (distance >> 2) <= 0x3FFFF) {
|
||||
code.B(CC_EQ, ptr);
|
||||
return;
|
||||
}
|
||||
@ -1612,4 +1605,4 @@ void A32EmitA64::Unpatch(const IR::LocationDescriptor& location) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -17,9 +17,9 @@
|
||||
#include "dynarmic/backend/A64/block_range_information.h"
|
||||
#include "dynarmic/backend/A64/emit_a64.h"
|
||||
#include "dynarmic/backend/A64/exception_handler.h"
|
||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||
#include "dynarmic/interface/A32/a32.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||
#include "dynarmic/ir/terminal.h"
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
@ -137,4 +137,4 @@ protected:
|
||||
void EmitPatchMovX0(CodePtr target_code_ptr = nullptr) override;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -7,13 +7,12 @@
|
||||
#include <memory>
|
||||
|
||||
#include <boost/icl/interval_set.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <mcl/assert.hpp>
|
||||
#include <mcl/stdint.hpp>
|
||||
#include <mcl/scope_exit.hpp>
|
||||
|
||||
#include <dynarmic/interface/A32/a32.h>
|
||||
#include <dynarmic/interface/A32/context.h>
|
||||
#include <fmt/format.h>
|
||||
#include <mcl/assert.hpp>
|
||||
#include <mcl/scope_exit.hpp>
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
#include "dynarmic/backend/A64/a32_emit_a64.h"
|
||||
#include "dynarmic/backend/A64/a32_jitstate.h"
|
||||
@ -21,12 +20,12 @@
|
||||
#include "dynarmic/backend/A64/callback.h"
|
||||
#include "dynarmic/backend/A64/devirtualize.h"
|
||||
#include "dynarmic/backend/A64/jitstate_info.h"
|
||||
#include "dynarmic/common/atomic.h"
|
||||
#include "dynarmic/common/llvm_disassemble.h"
|
||||
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/location_descriptor.h"
|
||||
#include "dynarmic/ir/opt/passes.h"
|
||||
#include "dynarmic/common/atomic.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
@ -46,8 +45,7 @@ struct Jit::Impl {
|
||||
: block_of_code(GenRunCodeCallbacks(config, &GetCurrentBlockThunk, this), JitStateInfo{jit_state})
|
||||
, emitter(block_of_code, config, jit)
|
||||
, config(std::move(config))
|
||||
, jit_interface(jit)
|
||||
{}
|
||||
, jit_interface(jit) {}
|
||||
|
||||
A32JitState jit_state;
|
||||
BlockOfCode block_of_code;
|
||||
@ -61,7 +59,7 @@ struct Jit::Impl {
|
||||
bool invalidate_entire_cache = false;
|
||||
|
||||
HaltReason Execute() {
|
||||
const CodePtr current_codeptr = [this]{
|
||||
const CodePtr current_codeptr = [this] {
|
||||
// RSB optimization
|
||||
const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A32JitState::RSBPtrMask;
|
||||
if (jit_state.GetUniqueHash() == jit_state.rsb_location_descriptors[new_rsb_ptr]) {
|
||||
@ -91,7 +89,7 @@ struct Jit::Impl {
|
||||
reinterpret_cast<const u8*>(pos) < reinterpret_cast<const u8*>(block.entrypoint) + block.size; pos += 1) {
|
||||
fmt::print("0x{:02x} 0x{:02x} ", reinterpret_cast<u64>(pos), *pos);
|
||||
fmt::print("{}", Common::DisassembleAArch64(*pos, reinterpret_cast<u64>(pos)));
|
||||
result += Common::DisassembleAArch64(*pos, reinterpret_cast<u64>(pos));
|
||||
result += Common::DisassembleAArch64(*pos, reinterpret_cast<u64>(pos));
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
@ -174,7 +172,8 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
Jit::Jit(UserConfig config) : impl(std::make_unique<Impl>(this, std::move(config))) {}
|
||||
Jit::Jit(UserConfig config)
|
||||
: impl(std::make_unique<Impl>(this, std::move(config))) {}
|
||||
|
||||
Jit::~Jit() = default;
|
||||
|
||||
@ -263,10 +262,15 @@ struct Context::Impl {
|
||||
size_t invalid_cache_generation;
|
||||
};
|
||||
|
||||
Context::Context() : impl(std::make_unique<Context::Impl>()) { impl->jit_state.ResetRSB(); }
|
||||
Context::Context()
|
||||
: impl(std::make_unique<Context::Impl>()) {
|
||||
impl->jit_state.ResetRSB();
|
||||
}
|
||||
Context::~Context() = default;
|
||||
Context::Context(const Context& ctx) : impl(std::make_unique<Context::Impl>(*ctx.impl)) {}
|
||||
Context::Context(Context&& ctx) noexcept : impl(std::move(ctx.impl)) {}
|
||||
Context::Context(const Context& ctx)
|
||||
: impl(std::make_unique<Context::Impl>(*ctx.impl)) {}
|
||||
Context::Context(Context&& ctx) noexcept
|
||||
: impl(std::move(ctx.impl)) {}
|
||||
Context& Context::operator=(const Context& ctx) {
|
||||
*impl = *ctx.impl;
|
||||
return *this;
|
||||
@ -326,4 +330,4 @@ std::vector<std::string> Jit::Disassemble() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
} // namespace Dynarmic::A32
|
||||
|
@ -4,11 +4,12 @@
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "dynarmic/backend/A64/a32_jitstate.h"
|
||||
|
||||
#include <mcl/assert.hpp>
|
||||
#include <mcl/bit_cast.hpp>
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
#include "dynarmic/backend/A64/a32_jitstate.h"
|
||||
#include "dynarmic/backend/A64/block_of_code.h"
|
||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||
|
||||
@ -89,7 +90,7 @@ void A32JitState::SetCpsr(u32 cpsr) {
|
||||
upper_location_descriptor |= mcl::bit::get_bit<9>(cpsr) ? 2 : 0;
|
||||
upper_location_descriptor |= mcl::bit::get_bit<5>(cpsr) ? 1 : 0;
|
||||
// IT state
|
||||
upper_location_descriptor |= (cpsr >> 0) & 0b11111100'00000000;
|
||||
upper_location_descriptor |= (cpsr >> 0) & 0b11111100'00000000;
|
||||
upper_location_descriptor |= (cpsr >> 17) & 0b00000011'00000000;
|
||||
|
||||
// Other flags
|
||||
@ -170,4 +171,4 @@ void A32JitState::SetFpscr(u32 FPSCR) {
|
||||
guest_fpsr |= FPSCR & 0x9F;
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
@ -14,8 +15,8 @@ namespace Dynarmic::BackendA64 {
|
||||
class BlockOfCode;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4324) // Structure was padded due to alignment specifier
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4324) // Structure was padded due to alignment specifier
|
||||
#endif
|
||||
|
||||
struct A32JitState {
|
||||
@ -23,7 +24,7 @@ struct A32JitState {
|
||||
|
||||
A32JitState() { ResetRSB(); }
|
||||
|
||||
std::array<u32, 16> Reg{}; // Current register file.
|
||||
std::array<u32, 16> Reg{}; // Current register file.
|
||||
// TODO: Mode-specific register sets unimplemented.
|
||||
|
||||
u32 upper_location_descriptor = 0;
|
||||
@ -35,10 +36,10 @@ struct A32JitState {
|
||||
u32 Cpsr() const;
|
||||
void SetCpsr(u32 cpsr);
|
||||
|
||||
alignas(u64) std::array<u32, 64> ExtReg{}; // Extension registers.
|
||||
alignas(u64) std::array<u32, 64> ExtReg{}; // Extension registers.
|
||||
|
||||
static constexpr size_t SpillCount = 64;
|
||||
std::array<u64, SpillCount> Spill{}; // Spill.
|
||||
std::array<u64, SpillCount> Spill{}; // Spill.
|
||||
static size_t GetSpillLocationOffsetFromIndex(size_t i) {
|
||||
return static_cast<u64>(offsetof(A32JitState, Spill) + i * sizeof(u64));
|
||||
}
|
||||
@ -57,7 +58,7 @@ struct A32JitState {
|
||||
u32 exclusive_state = 0;
|
||||
u32 exclusive_address = 0;
|
||||
|
||||
static constexpr size_t RSBSize = 8; // MUST be a power of 2.
|
||||
static constexpr size_t RSBSize = 8; // MUST be a power of 2.
|
||||
static constexpr size_t RSBPtrMask = RSBSize - 1;
|
||||
u32 rsb_ptr = 0;
|
||||
std::array<u64, RSBSize> rsb_location_descriptors;
|
||||
@ -65,7 +66,7 @@ struct A32JitState {
|
||||
void ResetRSB();
|
||||
|
||||
u32 fpsr_exc = 0;
|
||||
u32 fpsr_qc = 0; // Dummy value
|
||||
u32 fpsr_qc = 0; // Dummy value
|
||||
u32 fpsr_nzcv = 0;
|
||||
u32 Fpscr() const;
|
||||
void SetFpscr(u32 FPSCR);
|
||||
@ -102,9 +103,9 @@ struct A32JitState {
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
using CodePtr = const void*;
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -14,18 +14,18 @@
|
||||
|
||||
// 20th Sep 2018: This code was modified for Dynarmic.
|
||||
|
||||
#include "dynarmic/backend/A64/abi.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
#include "dynarmic/backend/A64/abi.h"
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
template<typename RegisterArrayT>
|
||||
void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const RegisterArrayT& regs) {
|
||||
u32 gprs = 0 , fprs = 0;
|
||||
u32 gprs = 0, fprs = 0;
|
||||
|
||||
for (HostLoc reg : regs) {
|
||||
if (HostLocIsGPR(reg)) {
|
||||
@ -83,4 +83,4 @@ void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, HostLoc e
|
||||
ABI_PopRegistersAndAdjustStack(code, regs);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendX64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -23,7 +23,7 @@ constexpr HostLoc ABI_PARAM6 = HostLoc::X5;
|
||||
constexpr HostLoc ABI_PARAM7 = HostLoc::X6;
|
||||
constexpr HostLoc ABI_PARAM8 = HostLoc::X7;
|
||||
|
||||
constexpr std::array<HostLoc, 43> ABI_ALL_CALLER_SAVE = {
|
||||
constexpr std::array<HostLoc, 43> ABI_ALL_CALLER_SAVE = {
|
||||
HostLoc::X0,
|
||||
HostLoc::X1,
|
||||
HostLoc::X2,
|
||||
@ -52,7 +52,7 @@ constexpr std::array<HostLoc, 43> ABI_ALL_CALLER_SAVE = {
|
||||
HostLoc::Q5,
|
||||
HostLoc::Q6,
|
||||
HostLoc::Q7,
|
||||
|
||||
|
||||
HostLoc::Q16,
|
||||
HostLoc::Q17,
|
||||
HostLoc::Q18,
|
||||
@ -95,7 +95,7 @@ constexpr std::array<HostLoc, 20> ABI_ALL_CALLEE_SAVE = {
|
||||
HostLoc::Q15,
|
||||
};
|
||||
|
||||
constexpr size_t ABI_SHADOW_SPACE = 0; // bytes
|
||||
constexpr size_t ABI_SHADOW_SPACE = 0; // bytes
|
||||
|
||||
static_assert(ABI_ALL_CALLER_SAVE.size() + ABI_ALL_CALLEE_SAVE.size() == 63, "Invalid total number of registers");
|
||||
|
||||
@ -107,4 +107,4 @@ void ABI_PopCallerSaveRegistersAndAdjustStack(BlockOfCode& code);
|
||||
void ABI_PushCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, HostLoc exception);
|
||||
void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, HostLoc exception);
|
||||
|
||||
} // namespace Dynarmic::BackendX64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -4,6 +4,8 @@
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "dynarmic/backend/A64/block_of_code.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
@ -12,23 +14,22 @@
|
||||
|
||||
#include "dynarmic/backend/A64/a32_jitstate.h"
|
||||
#include "dynarmic/backend/A64/abi.h"
|
||||
#include "dynarmic/interface/halt_reason.h"
|
||||
#include "dynarmic/backend/A64/block_of_code.h"
|
||||
#include "dynarmic/backend/A64/perf_map.h"
|
||||
#include "dynarmic/interface/halt_reason.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
# include <windows.h>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <pthread.h>
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
const Arm64Gen::ARM64Reg BlockOfCode::ABI_RETURN = Arm64Gen::ARM64Reg::X0;
|
||||
const Arm64Gen::ARM64Reg BlockOfCode::ABI_RETURN = Arm64Gen::ARM64Reg::X0;
|
||||
const Arm64Gen::ARM64Reg BlockOfCode::ABI_RETURN2 = Arm64Gen::ARM64Reg::X1;
|
||||
|
||||
const Arm64Gen::ARM64Reg BlockOfCode::ABI_PARAM1 = Arm64Gen::ARM64Reg::X0;
|
||||
@ -43,9 +44,9 @@ const Arm64Gen::ARM64Reg BlockOfCode::ABI_PARAM8 = Arm64Gen::ARM64Reg::X7;
|
||||
const Arm64Gen::ARM64Reg BlockOfCode::ABI_SCRATCH1 = Arm64Gen::ARM64Reg::X30;
|
||||
|
||||
const std::array<Arm64Gen::ARM64Reg, 8> BlockOfCode::ABI_PARAMS = {BlockOfCode::ABI_PARAM1, BlockOfCode::ABI_PARAM2,
|
||||
BlockOfCode::ABI_PARAM3, BlockOfCode::ABI_PARAM4,
|
||||
BlockOfCode::ABI_PARAM5, BlockOfCode::ABI_PARAM6,
|
||||
BlockOfCode::ABI_PARAM7, BlockOfCode::ABI_PARAM8};
|
||||
BlockOfCode::ABI_PARAM3, BlockOfCode::ABI_PARAM4,
|
||||
BlockOfCode::ABI_PARAM5, BlockOfCode::ABI_PARAM6,
|
||||
BlockOfCode::ABI_PARAM7, BlockOfCode::ABI_PARAM8};
|
||||
|
||||
namespace {
|
||||
|
||||
@ -54,22 +55,22 @@ constexpr size_t FAR_CODE_OFFSET = 100 * 1024 * 1024;
|
||||
|
||||
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
|
||||
void ProtectMemory([[maybe_unused]] const void* base, [[maybe_unused]] size_t size, bool is_executable) {
|
||||
#if defined(_WIN32)
|
||||
# if defined(_WIN32)
|
||||
DWORD oldProtect = 0;
|
||||
VirtualProtect(const_cast<void*>(base), size, is_executable ? PAGE_EXECUTE_READ : PAGE_READWRITE, &oldProtect);
|
||||
#elif defined(__APPLE__)
|
||||
# elif defined(__APPLE__)
|
||||
pthread_jit_write_protect_np(is_executable);
|
||||
#else
|
||||
# else
|
||||
static const size_t pageSize = sysconf(_SC_PAGESIZE);
|
||||
const size_t iaddr = reinterpret_cast<size_t>(base);
|
||||
const size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
|
||||
const int mode = is_executable ? (PROT_READ | PROT_EXEC) : (PROT_READ | PROT_WRITE);
|
||||
mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode);
|
||||
#endif
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
} // anonymous namespace
|
||||
} // anonymous namespace
|
||||
|
||||
BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi)
|
||||
: fp_emitter(this)
|
||||
@ -154,7 +155,7 @@ void BlockOfCode::ForceReturnFromRunCode(bool fpscr_already_exited) {
|
||||
}
|
||||
|
||||
void BlockOfCode::GenRunCode() {
|
||||
const u8* loop, *enter_fpscr_then_loop;
|
||||
const u8 *loop, *enter_fpscr_then_loop;
|
||||
std::vector<Arm64Gen::FixupBranch> return_to_caller_fpscr_already_exited;
|
||||
|
||||
AlignCode16();
|
||||
@ -168,7 +169,7 @@ void BlockOfCode::GenRunCode() {
|
||||
|
||||
MOV(Arm64Gen::X28, ABI_PARAM1);
|
||||
MOVI2R(Arm64Gen::X27, cb.value_in_X27);
|
||||
MOV(Arm64Gen::X25, ABI_PARAM2); // save temporarily in non-volatile register
|
||||
MOV(Arm64Gen::X25, ABI_PARAM2); // save temporarily in non-volatile register
|
||||
|
||||
cb.GetTicksRemaining->EmitCall(*this);
|
||||
STR(Arm64Gen::INDEX_UNSIGNED, ABI_RETURN, Arm64Gen::X28, jsi.offsetof_cycles_to_run);
|
||||
@ -250,11 +251,11 @@ void BlockOfCode::GenRunCode() {
|
||||
void BlockOfCode::SwitchFpscrOnEntry() {
|
||||
MRS(ABI_SCRATCH1, Arm64Gen::FIELD_FPCR);
|
||||
STR(Arm64Gen::INDEX_UNSIGNED, ABI_SCRATCH1, Arm64Gen::X28, jsi.offsetof_save_host_FPCR);
|
||||
|
||||
|
||||
LDR(Arm64Gen::INDEX_UNSIGNED, ABI_SCRATCH1, Arm64Gen::X28, jsi.offsetof_guest_fpcr);
|
||||
_MSR(Arm64Gen::FIELD_FPCR, ABI_SCRATCH1);
|
||||
LDR(Arm64Gen::INDEX_UNSIGNED, ABI_SCRATCH1, Arm64Gen::X28, jsi.offsetof_guest_fpsr);
|
||||
_MSR(Arm64Gen::FIELD_FPSR, ABI_SCRATCH1);
|
||||
_MSR(Arm64Gen::FIELD_FPSR, ABI_SCRATCH1);
|
||||
}
|
||||
|
||||
void BlockOfCode::SwitchFpscrOnExit() {
|
||||
@ -321,13 +322,13 @@ std::size_t BlockOfCode::GetRegionSize() const {
|
||||
return total_region_size;
|
||||
}
|
||||
|
||||
void* BlockOfCode::AllocateFromCodeSpace(size_t alloc_size) {
|
||||
void* BlockOfCode::AllocateFromCodeSpace(size_t alloc_size) {
|
||||
ASSERT_MSG(GetSpaceLeft() >= alloc_size, "ERR_CODE_IS_TOO_BIG");
|
||||
|
||||
void* ret = GetWritableCodePtr();
|
||||
region_size += alloc_size;
|
||||
SetCodePtr(GetCodePtr() + alloc_size);
|
||||
memset(ret, 0, alloc_size);
|
||||
memset(ret, 0, alloc_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -353,4 +354,4 @@ void BlockOfCode::EnsurePatchLocationSize(CodePtr begin, size_t size) {
|
||||
//#endif
|
||||
//}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -14,8 +14,8 @@
|
||||
|
||||
#include "dynarmic/backend/A64/callback.h"
|
||||
#include "dynarmic/backend/A64/constant_pool.h"
|
||||
#include "dynarmic/backend/A64/jitstate_info.h"
|
||||
#include "dynarmic/backend/A64/emitter/a64_emitter.h"
|
||||
#include "dynarmic/backend/A64/jitstate_info.h"
|
||||
#include "dynarmic/interface/halt_reason.h"
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
@ -34,7 +34,6 @@ public:
|
||||
BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi);
|
||||
BlockOfCode(const BlockOfCode&) = delete;
|
||||
|
||||
|
||||
/// Call when external emitters have finished emitting their preludes.
|
||||
void PreludeComplete();
|
||||
|
||||
@ -146,4 +145,4 @@ private:
|
||||
//Xbyak::util::Cpu cpu_info;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -4,35 +4,33 @@
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "dynarmic/backend/A64/block_range_information.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
#include <boost/icl/interval_set.hpp>
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
#include "dynarmic/backend/A64/block_range_information.h"
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
template <typename ProgramCounterType>
|
||||
template<typename ProgramCounterType>
|
||||
void BlockRangeInformation<ProgramCounterType>::AddRange(boost::icl::discrete_interval<ProgramCounterType> range, IR::LocationDescriptor location) {
|
||||
block_ranges.add(std::make_pair(range, std::set<IR::LocationDescriptor>{location}));
|
||||
}
|
||||
|
||||
template <typename ProgramCounterType>
|
||||
template<typename ProgramCounterType>
|
||||
void BlockRangeInformation<ProgramCounterType>::ClearCache() {
|
||||
block_ranges.clear();
|
||||
}
|
||||
|
||||
template <typename ProgramCounterType>
|
||||
template<typename ProgramCounterType>
|
||||
std::unordered_set<IR::LocationDescriptor> BlockRangeInformation<ProgramCounterType>::InvalidateRanges(const boost::icl::interval_set<ProgramCounterType>& ranges) {
|
||||
std::unordered_set<IR::LocationDescriptor> erase_locations;
|
||||
for (auto invalidate_interval : ranges) {
|
||||
auto pair = block_ranges.equal_range(invalidate_interval);
|
||||
for (auto it = pair.first; it != pair.second; ++it) {
|
||||
for (const auto &descriptor : it->second) {
|
||||
for (const auto& descriptor : it->second) {
|
||||
erase_locations.insert(descriptor);
|
||||
}
|
||||
}
|
||||
@ -44,4 +42,4 @@ std::unordered_set<IR::LocationDescriptor> BlockRangeInformation<ProgramCounterT
|
||||
template class BlockRangeInformation<u32>;
|
||||
template class BlockRangeInformation<u64>;
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
template <typename ProgramCounterType>
|
||||
template<typename ProgramCounterType>
|
||||
class BlockRangeInformation {
|
||||
public:
|
||||
void AddRange(boost::icl::discrete_interval<ProgramCounterType> range, IR::LocationDescriptor location);
|
||||
@ -26,4 +26,4 @@ private:
|
||||
boost::icl::interval_map<ProgramCounterType, std::set<IR::LocationDescriptor>> block_ranges;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "dynarmic/backend/A64/callback.h"
|
||||
|
||||
#include "dynarmic/backend/A64/block_of_code.h"
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
@ -38,4 +39,4 @@ void ArgCallback::EmitCallWithReturnPointer(BlockOfCode& code, std::function<voi
|
||||
code.QuickCallFunction(fn);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendX64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -23,16 +23,19 @@ class Callback {
|
||||
public:
|
||||
virtual ~Callback();
|
||||
|
||||
virtual void EmitCall(BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const = 0;
|
||||
virtual void EmitCall(
|
||||
BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const = 0;
|
||||
virtual void EmitCallWithReturnPointer(BlockOfCode& code, std::function<void(Arm64Gen::ARM64Reg, RegList)> fn) const = 0;
|
||||
};
|
||||
|
||||
class SimpleCallback final : public Callback {
|
||||
public:
|
||||
template <typename Function>
|
||||
SimpleCallback(Function fn) : fn(reinterpret_cast<void (*)()>(fn)) {}
|
||||
template<typename Function>
|
||||
SimpleCallback(Function fn)
|
||||
: fn(reinterpret_cast<void (*)()>(fn)) {}
|
||||
|
||||
void EmitCall(BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const override;
|
||||
void EmitCall(
|
||||
BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const override;
|
||||
void EmitCallWithReturnPointer(BlockOfCode& code, std::function<void(Arm64Gen::ARM64Reg, RegList)> fn) const override;
|
||||
|
||||
private:
|
||||
@ -41,10 +44,12 @@ private:
|
||||
|
||||
class ArgCallback final : public Callback {
|
||||
public:
|
||||
template <typename Function>
|
||||
ArgCallback(Function fn, u64 arg) : fn(reinterpret_cast<void (*)()>(fn)), arg(arg) {}
|
||||
template<typename Function>
|
||||
ArgCallback(Function fn, u64 arg)
|
||||
: fn(reinterpret_cast<void (*)()>(fn)), arg(arg) {}
|
||||
|
||||
void EmitCall(BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const override;
|
||||
void EmitCall(
|
||||
BlockOfCode& code, std::function<void(RegList)> fn = [](RegList) {}) const override;
|
||||
void EmitCallWithReturnPointer(BlockOfCode& code, std::function<void(Arm64Gen::ARM64Reg, RegList)> fn) const override;
|
||||
|
||||
private:
|
||||
@ -52,4 +57,4 @@ private:
|
||||
u64 arg;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -4,22 +4,24 @@
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "dynarmic/backend/A64/constant_pool.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <mcl/assert.hpp>
|
||||
|
||||
#include "dynarmic/backend/A64/block_of_code.h"
|
||||
#include "dynarmic/backend/A64/constant_pool.h"
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
ConstantPool::ConstantPool(BlockOfCode& code) : code(code) {}
|
||||
ConstantPool::ConstantPool(BlockOfCode& code)
|
||||
: code(code) {}
|
||||
|
||||
void ConstantPool::EmitPatchLDR(Arm64Gen::ARM64Reg Rt, u64 lower, u64 upper) {
|
||||
const auto constant = std::make_tuple(lower, upper);
|
||||
auto iter = constant_info.find(constant);
|
||||
if (iter == constant_info.end()) {
|
||||
struct PatchInfo p = { code.GetCodePtr(), Rt, constant };
|
||||
struct PatchInfo p = {code.GetCodePtr(), Rt, constant};
|
||||
patch_info.emplace_back(p);
|
||||
code.BRK(0);
|
||||
return;
|
||||
@ -29,7 +31,7 @@ void ConstantPool::EmitPatchLDR(Arm64Gen::ARM64Reg Rt, u64 lower, u64 upper) {
|
||||
|
||||
if (!(offset >= -0x40000 && offset <= 0x3FFFF)) {
|
||||
constant_info.erase(constant);
|
||||
struct PatchInfo p = { code.GetCodePtr(), Rt, constant };
|
||||
struct PatchInfo p = {code.GetCodePtr(), Rt, constant};
|
||||
patch_info.emplace_back(p);
|
||||
code.BRK(0x42);
|
||||
return;
|
||||
@ -58,9 +60,9 @@ void ConstantPool::PatchPool() {
|
||||
code.SetCodePtr(pool_ptr);
|
||||
}
|
||||
|
||||
void ConstantPool::Clear() {
|
||||
void ConstantPool::Clear() {
|
||||
constant_info.clear();
|
||||
patch_info.clear();
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
static constexpr size_t align_size = 16; // bytes
|
||||
static constexpr size_t align_size = 16; // bytes
|
||||
|
||||
std::map<std::tuple<u64, u64>, void*> constant_info;
|
||||
|
||||
@ -46,4 +46,4 @@ private:
|
||||
std::vector<PatchInfo> patch_info;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -9,10 +9,10 @@
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include <mcl/type_traits/function_info.hpp>
|
||||
#include <mcl/stdint.hpp>
|
||||
#include <mcl/assert.hpp>
|
||||
#include <mcl/bit_cast.hpp>
|
||||
#include <mcl/stdint.hpp>
|
||||
#include <mcl/type_traits/function_info.hpp>
|
||||
|
||||
#include "dynarmic/backend/A64/callback.h"
|
||||
|
||||
@ -20,20 +20,20 @@ namespace Dynarmic::BackendA64 {
|
||||
|
||||
namespace impl {
|
||||
|
||||
template <typename FunctionType, FunctionType mfp>
|
||||
template<typename FunctionType, FunctionType mfp>
|
||||
struct ThunkBuilder;
|
||||
|
||||
template <typename C, typename R, typename... Args, R(C::*mfp)(Args...)>
|
||||
struct ThunkBuilder<R(C::*)(Args...), mfp> {
|
||||
template<typename C, typename R, typename... Args, R (C::*mfp)(Args...)>
|
||||
struct ThunkBuilder<R (C::*)(Args...), mfp> {
|
||||
static R Thunk(C* this_, Args... args) {
|
||||
return (this_->*mfp)(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
} // namespace impl
|
||||
|
||||
template<auto mfp>
|
||||
ArgCallback DevirtualizeGeneric(mcl::class_type<decltype(mfp)> * this_) {
|
||||
ArgCallback DevirtualizeGeneric(mcl::class_type<decltype(mfp)>* this_) {
|
||||
return ArgCallback{&impl::ThunkBuilder<decltype(mfp), mfp>::Thunk, reinterpret_cast<u64>(this_)};
|
||||
}
|
||||
|
||||
@ -74,4 +74,4 @@ ArgCallback Devirtualize(mcl::class_type<decltype(mfp)>* this_) {
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -4,16 +4,17 @@
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "dynarmic/backend/A64/emit_a64.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <mcl/assert.hpp>
|
||||
#include <mcl/bit/bit_field.hpp>
|
||||
#include <mcl/stdint.hpp>
|
||||
#include <mcl/scope_exit.hpp>
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
#include "dynarmic/backend/A64/block_of_code.h"
|
||||
#include "dynarmic/backend/A64/emit_a64.h"
|
||||
#include "dynarmic/backend/A64/hostloc.h"
|
||||
#include "dynarmic/backend/A64/perf_map.h"
|
||||
#include "dynarmic/backend/A64/reg_alloc.h"
|
||||
@ -28,7 +29,7 @@
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
EmitContext::EmitContext(RegAlloc& reg_alloc, IR::Block& block)
|
||||
: reg_alloc(reg_alloc), block(block) {}
|
||||
: reg_alloc(reg_alloc), block(block) {}
|
||||
|
||||
void EmitContext::EraseInstruction(IR::Inst* inst) {
|
||||
block.Instructions().erase(inst);
|
||||
@ -36,7 +37,7 @@ void EmitContext::EraseInstruction(IR::Inst* inst) {
|
||||
}
|
||||
|
||||
EmitA64::EmitA64(BlockOfCode& code)
|
||||
: code(code) {}
|
||||
: code(code) {}
|
||||
|
||||
EmitA64::~EmitA64() = default;
|
||||
|
||||
@ -64,8 +65,8 @@ void EmitA64::EmitIdentity(EmitContext& ctx, IR::Inst* inst) {
|
||||
void EmitA64::PushRSBHelper(ARM64Reg loc_desc_reg, ARM64Reg index_reg, IR::LocationDescriptor target) {
|
||||
auto iter = block_descriptors.find(target);
|
||||
CodePtr target_code_ptr = iter != block_descriptors.end()
|
||||
? iter->second.entrypoint
|
||||
: code.GetReturnFromRunCodeAddress();
|
||||
? iter->second.entrypoint
|
||||
: code.GetReturnFromRunCodeAddress();
|
||||
|
||||
code.LDR(INDEX_UNSIGNED, DecodeReg(index_reg), X28, code.GetJitStateInfo().offsetof_rsb_ptr);
|
||||
|
||||
@ -80,7 +81,7 @@ void EmitA64::PushRSBHelper(ARM64Reg loc_desc_reg, ARM64Reg index_reg, IR::Locat
|
||||
|
||||
code.ADDI2R(DecodeReg(index_reg), DecodeReg(index_reg), 1);
|
||||
code.ANDI2R(DecodeReg(index_reg), DecodeReg(index_reg), code.GetJitStateInfo().rsb_ptr_mask, code.ABI_SCRATCH1);
|
||||
code.STR(INDEX_UNSIGNED, DecodeReg(index_reg), X28, code.GetJitStateInfo().offsetof_rsb_ptr);
|
||||
code.STR(INDEX_UNSIGNED, DecodeReg(index_reg), X28, code.GetJitStateInfo().offsetof_rsb_ptr);
|
||||
}
|
||||
|
||||
void EmitA64::EmitPushRSB(EmitContext& ctx, IR::Inst* inst) {
|
||||
@ -162,28 +163,28 @@ FixupBranch EmitA64::EmitCond(IR::Cond cond) {
|
||||
code._MSR(FIELD_NZCV, cpsr);
|
||||
|
||||
switch (cond) {
|
||||
case IR::Cond::EQ: //z
|
||||
case IR::Cond::EQ: //z
|
||||
label = code.B(CC_EQ);
|
||||
break;
|
||||
case IR::Cond::NE: //!z
|
||||
case IR::Cond::NE: //!z
|
||||
label = code.B(CC_NEQ);
|
||||
break;
|
||||
case IR::Cond::CS: //c
|
||||
case IR::Cond::CS: //c
|
||||
label = code.B(CC_CS);
|
||||
break;
|
||||
case IR::Cond::CC: //!c
|
||||
case IR::Cond::CC: //!c
|
||||
label = code.B(CC_CC);
|
||||
break;
|
||||
case IR::Cond::MI: //n
|
||||
case IR::Cond::MI: //n
|
||||
label = code.B(CC_MI);
|
||||
break;
|
||||
case IR::Cond::PL: //!n
|
||||
case IR::Cond::PL: //!n
|
||||
label = code.B(CC_PL);
|
||||
break;
|
||||
case IR::Cond::VS: //v
|
||||
case IR::Cond::VS: //v
|
||||
label = code.B(CC_VS);
|
||||
break;
|
||||
case IR::Cond::VC: //!v
|
||||
case IR::Cond::VC: //!v
|
||||
label = code.B(CC_VC);
|
||||
break;
|
||||
case IR::Cond::HI: //c & !z
|
||||
@ -203,7 +204,7 @@ FixupBranch EmitA64::EmitCond(IR::Cond cond) {
|
||||
break;
|
||||
case IR::Cond::LE: // z | (n != v)
|
||||
label = code.B(CC_LE);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
ASSERT_MSG(false, "Unknown cond {}", static_cast<size_t>(cond));
|
||||
break;
|
||||
@ -278,7 +279,7 @@ void EmitA64::InvalidateBasicBlocks(const std::unordered_set<IR::LocationDescrip
|
||||
code.EnableWriting();
|
||||
SCOPE_EXIT { code.DisableWriting(); };
|
||||
|
||||
for (const auto &descriptor : locations) {
|
||||
for (const auto& descriptor : locations) {
|
||||
auto it = block_descriptors.find(descriptor);
|
||||
if (it == block_descriptors.end()) {
|
||||
continue;
|
||||
@ -291,4 +292,4 @@ void EmitA64::InvalidateBasicBlocks(const std::unordered_set<IR::LocationDescrip
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -24,7 +24,7 @@
|
||||
namespace Dynarmic::IR {
|
||||
class Block;
|
||||
class Inst;
|
||||
} // namespace Dynarmic::IR
|
||||
} // namespace Dynarmic::IR
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
@ -38,7 +38,7 @@ using A64FullVectorWidth = std::integral_constant<size_t, 128>;
|
||||
// Array alias that always sizes itself according to the given type T
|
||||
// relative to the size of a vector register. e.g. T = u32 would result
|
||||
// in a std::array<u32, 4>.
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
using VectorArray = std::array<T, A64FullVectorWidth::value / mcl::bitsizeof<T>>;
|
||||
|
||||
struct EmitContext {
|
||||
@ -124,4 +124,4 @@ protected:
|
||||
std::unordered_map<IR::LocationDescriptor, PatchInformation> patch_information;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::BackendX64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
#include "dynarmic/backend/A64/block_of_code.h"
|
||||
#include "dynarmic/backend/A64/reg_alloc.h"
|
||||
#include "dynarmic/backend/A64/emit_a64.h"
|
||||
#include "dynarmic/backend/A64/reg_alloc.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/microinstruction.h"
|
||||
#include "dynarmic/ir/opcodes.h"
|
||||
@ -61,7 +61,7 @@ void EmitA64::EmitMostSignificantWord(EmitContext& ctx, IR::Inst* inst) {
|
||||
code.UBFX(carry, result, 31, 1);
|
||||
ctx.reg_alloc.DefineValue(carry_inst, carry);
|
||||
ctx.EraseInstruction(carry_inst);
|
||||
}
|
||||
}
|
||||
|
||||
code.LSR(result, result, 32);
|
||||
|
||||
@ -82,7 +82,7 @@ void EmitA64::EmitMostSignificantBit(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
Arm64Gen::ARM64Reg result = DecodeReg(ctx.reg_alloc.UseScratchGpr(args[0]));
|
||||
// TODO: Flag optimization
|
||||
code.LSR(result,result, 31);
|
||||
code.LSR(result, result, 31);
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
@ -127,46 +127,46 @@ static void EmitConditionalSelect(BlockOfCode& code, EmitContext& ctx, IR::Inst*
|
||||
code._MSR(FIELD_NZCV, nzcv);
|
||||
|
||||
switch (args[0].GetImmediateCond()) {
|
||||
case IR::Cond::EQ: //z
|
||||
code.CSEL(else_, else_, then_ , CC_EQ);
|
||||
case IR::Cond::EQ: //z
|
||||
code.CSEL(else_, else_, then_, CC_EQ);
|
||||
break;
|
||||
case IR::Cond::NE: //!z
|
||||
case IR::Cond::NE: //!z
|
||||
code.CSEL(else_, else_, then_, CC_NEQ);
|
||||
break;
|
||||
case IR::Cond::CS: //c
|
||||
case IR::Cond::CS: //c
|
||||
code.CSEL(else_, else_, then_, CC_CS);
|
||||
break;
|
||||
case IR::Cond::CC: //!c
|
||||
code.CSEL(else_, else_, then_ , CC_CC);
|
||||
case IR::Cond::CC: //!c
|
||||
code.CSEL(else_, else_, then_, CC_CC);
|
||||
break;
|
||||
case IR::Cond::MI: //n
|
||||
case IR::Cond::MI: //n
|
||||
code.CSEL(else_, else_, then_, CC_MI);
|
||||
break;
|
||||
case IR::Cond::PL: //!n
|
||||
case IR::Cond::PL: //!n
|
||||
code.CSEL(else_, else_, then_, CC_PL);
|
||||
break;
|
||||
case IR::Cond::VS: //v
|
||||
case IR::Cond::VS: //v
|
||||
code.CSEL(else_, else_, then_, CC_VS);
|
||||
break;
|
||||
case IR::Cond::VC: //!v
|
||||
case IR::Cond::VC: //!v
|
||||
code.CSEL(else_, else_, then_, CC_VC);
|
||||
break;
|
||||
case IR::Cond::HI: //c & !z
|
||||
case IR::Cond::HI: //c & !z
|
||||
code.CSEL(else_, else_, then_, CC_HI);
|
||||
break;
|
||||
case IR::Cond::LS: //!c | z
|
||||
case IR::Cond::LS: //!c | z
|
||||
code.CSEL(else_, else_, then_, CC_LS);
|
||||
break;
|
||||
case IR::Cond::GE: // n == v
|
||||
case IR::Cond::GE: // n == v
|
||||
code.CSEL(else_, else_, then_, CC_GE);
|
||||
break;
|
||||
case IR::Cond::LT: // n != v
|
||||
case IR::Cond::LT: // n != v
|
||||
code.CSEL(else_, else_, then_, CC_LT);
|
||||
break;
|
||||
case IR::Cond::GT: // !z & (n == v)
|
||||
case IR::Cond::GT: // !z & (n == v)
|
||||
code.CSEL(else_, else_, then_, CC_GT);
|
||||
break;
|
||||
case IR::Cond::LE: // z | (n != v)
|
||||
case IR::Cond::LE: // z | (n != v)
|
||||
code.CSEL(else_, else_, then_, CC_LE);
|
||||
break;
|
||||
case IR::Cond::AL:
|
||||
@ -218,7 +218,7 @@ void EmitA64::EmitLogicalShiftLeft32(EmitContext& ctx, IR::Inst* inst) {
|
||||
Arm64Gen::ARM64Reg result = ctx.reg_alloc.UseScratchGpr(operand_arg);
|
||||
|
||||
code.ANDI2R(shift, shift, 0xFF);
|
||||
code.LSLV(result, result, shift);
|
||||
code.LSLV(result, result, shift);
|
||||
code.CMPI2R(shift, 32);
|
||||
code.CSEL(result, WZR, DecodeReg(result), CC_GE);
|
||||
ctx.reg_alloc.DefineValue(inst, DecodeReg(result));
|
||||
@ -239,7 +239,7 @@ void EmitA64::EmitLogicalShiftLeft32(EmitContext& ctx, IR::Inst* inst) {
|
||||
code.MOV(carry, WZR);
|
||||
} else {
|
||||
code.ANDI2R(carry, result, 1);
|
||||
code.MOV(result, WZR);
|
||||
code.MOV(result, WZR);
|
||||
}
|
||||
|
||||
ctx.reg_alloc.DefineValue(carry_inst, carry);
|
||||
@ -257,7 +257,7 @@ void EmitA64::EmitLogicalShiftLeft32(EmitContext& ctx, IR::Inst* inst) {
|
||||
end = code.B(CC_EQ);
|
||||
|
||||
code.CMPI2R(shift, 32);
|
||||
code.SUBI2R(shift, shift, 1); // Subtract 1 to get the bit that is shiftedout, into the MSB.
|
||||
code.SUBI2R(shift, shift, 1); // Subtract 1 to get the bit that is shiftedout, into the MSB.
|
||||
code.LSLV(result, result, shift);
|
||||
code.UBFX(carry, result, 31, 1);
|
||||
code.LSL(result, result, 1);
|
||||
@ -344,7 +344,7 @@ void EmitA64::EmitLogicalShiftRight32(EmitContext& ctx, IR::Inst* inst) {
|
||||
} else if (shift < 32) {
|
||||
code.LSR(carry, result, shift - 1);
|
||||
code.ANDI2R(carry, carry, 1);
|
||||
code.LSR(result,result, shift);
|
||||
code.LSR(result, result, shift);
|
||||
} else if (shift == 32) {
|
||||
code.UBFX(carry, result, 31, 1);
|
||||
code.MOV(result, WZR);
|
||||
@ -369,15 +369,15 @@ void EmitA64::EmitLogicalShiftRight32(EmitContext& ctx, IR::Inst* inst) {
|
||||
end = code.B(CC_EQ);
|
||||
|
||||
code.CMPI2R(shift, 32);
|
||||
code.SUBI2R(shift, shift, 1); // Subtract 1 to get the bit that is shifted out to the carry.
|
||||
code.SUBI2R(shift, shift, 1); // Subtract 1 to get the bit that is shifted out to the carry.
|
||||
code.LSRV(result, result, shift);
|
||||
code.ANDI2R(carry, result, 1);
|
||||
code.LSR(result, result, 1);
|
||||
|
||||
code.CSEL(result, result, WZR, CC_LT);
|
||||
code.CSEL(carry, carry, WZR, CC_LE);
|
||||
|
||||
code.SetJumpTarget(end);
|
||||
|
||||
code.SetJumpTarget(end);
|
||||
|
||||
ctx.reg_alloc.DefineValue(carry_inst, carry);
|
||||
ctx.EraseInstruction(carry_inst);
|
||||
@ -490,8 +490,8 @@ void EmitA64::EmitArithmeticShiftRight32(EmitContext& ctx, IR::Inst* inst) {
|
||||
code.ANDI2R(carry, result, 1);
|
||||
code.ASR(result, result, 1);
|
||||
// }
|
||||
|
||||
code.SetJumpTarget(end);
|
||||
|
||||
code.SetJumpTarget(end);
|
||||
|
||||
ctx.reg_alloc.DefineValue(carry_inst, carry);
|
||||
ctx.EraseInstruction(carry_inst);
|
||||
@ -582,7 +582,7 @@ void EmitA64::EmitRotateRight32(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
// TODO: Optimize
|
||||
|
||||
std::vector<FixupBranch> end;
|
||||
std::vector<FixupBranch> end;
|
||||
FixupBranch zero_1F;
|
||||
|
||||
code.ANDSI2R(shift, shift, u32(0xFF));
|
||||
@ -649,8 +649,8 @@ void EmitA64::EmitRotateRightExtended(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
// Set carry to the LSB and perform ROR.
|
||||
code.BFI(result, carry, 0, 1);
|
||||
code.ROR(result, result, 1);
|
||||
|
||||
code.ROR(result, result, 1);
|
||||
|
||||
if (carry_inst) {
|
||||
code.ANDI2R(carry, temp, 1);
|
||||
|
||||
@ -684,7 +684,7 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
|
||||
|
||||
result = bitsize == 64 ? result : DecodeReg(result);
|
||||
|
||||
if (args[1].IsImmediate() && args[1].GetType() == IR::Type::U32) {
|
||||
if (args[1].IsImmediate() && args[1].GetType() == IR::Type::U32) {
|
||||
if (carry_in.IsImmediate()) {
|
||||
if (carry_in.GetImmediateU1()) {
|
||||
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
|
||||
@ -706,7 +706,7 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
|
||||
code.CMP(DecodeReg(op_arg), DecodeReg(op_arg));
|
||||
code.ADCS(result, result, op_arg);
|
||||
} else {
|
||||
code.ADDS(result,result, op_arg);
|
||||
code.ADDS(result, result, op_arg);
|
||||
}
|
||||
} else {
|
||||
code.CMPI2R(DecodeReg(carry), 1);
|
||||
@ -759,7 +759,7 @@ static void EmitSub(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
|
||||
|
||||
result = bitsize == 64 ? result : DecodeReg(result);
|
||||
|
||||
if (args[1].IsImmediate() && args[1].GetType() == IR::Type::U32) {
|
||||
if (args[1].IsImmediate() && args[1].GetType() == IR::Type::U32) {
|
||||
if (carry_in.IsImmediate()) {
|
||||
if (carry_in.GetImmediateU1()) {
|
||||
u32 op_arg = args[1].GetImmediateU32();
|
||||
@ -767,7 +767,7 @@ static void EmitSub(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
|
||||
} else {
|
||||
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
|
||||
|
||||
code.ADDSI2R(op_arg, op_arg, 0); // Clear carry
|
||||
code.ADDSI2R(op_arg, op_arg, 0); // Clear carry
|
||||
code.SBCS(result, result, op_arg);
|
||||
}
|
||||
} else {
|
||||
@ -781,12 +781,12 @@ static void EmitSub(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
|
||||
if (carry_in.GetImmediateU1()) {
|
||||
code.SUBS(result, result, op_arg);
|
||||
} else {
|
||||
code.ADDSI2R(DecodeReg(op_arg), DecodeReg(op_arg), 0); // Clear carry
|
||||
code.SBCS(result,result, op_arg);
|
||||
code.ADDSI2R(DecodeReg(op_arg), DecodeReg(op_arg), 0); // Clear carry
|
||||
code.SBCS(result, result, op_arg);
|
||||
}
|
||||
} else {
|
||||
code.CMPI2R(DecodeReg(carry), 0x1);
|
||||
code.SBCS(result,result, op_arg);
|
||||
code.SBCS(result, result, op_arg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -822,7 +822,7 @@ void EmitA64::EmitMul32(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
ARM64Reg result = DecodeReg(ctx.reg_alloc.UseScratchGpr(args[0]));
|
||||
ARM64Reg op_arg = DecodeReg(ctx.reg_alloc.UseGpr(args[1]));
|
||||
|
||||
|
||||
code.MUL(result, result, op_arg);
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
@ -839,7 +839,6 @@ void EmitA64::EmitMul64(EmitContext& ctx, IR::Inst* inst) {
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
|
||||
void EmitA64::EmitUnsignedDiv32(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
@ -880,7 +879,6 @@ void EmitA64::EmitSignedDiv64(EmitContext& ctx, IR::Inst* inst) {
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
|
||||
void EmitA64::EmitAnd32(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
@ -890,7 +888,7 @@ void EmitA64::EmitAnd32(EmitContext& ctx, IR::Inst* inst) {
|
||||
u32 op_arg = args[1].GetImmediateU32();
|
||||
code.ANDI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
|
||||
} else {
|
||||
Arm64Gen::ARM64Reg op_arg = DecodeReg(ctx.reg_alloc.UseGpr(args[1]));
|
||||
Arm64Gen::ARM64Reg op_arg = DecodeReg(ctx.reg_alloc.UseGpr(args[1]));
|
||||
code.AND(result, result, op_arg);
|
||||
}
|
||||
|
||||
@ -905,8 +903,7 @@ void EmitA64::EmitAnd64(EmitContext& ctx, IR::Inst* inst) {
|
||||
if (args[1].IsImmediate()) {
|
||||
u32 op_arg = args[1].GetImmediateU32();
|
||||
code.ANDI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
|
||||
code.AND(result, result, op_arg);
|
||||
}
|
||||
@ -938,8 +935,7 @@ void EmitA64::EmitEor64(EmitContext& ctx, IR::Inst* inst) {
|
||||
if (args[1].IsImmediate()) {
|
||||
u32 op_arg = args[1].GetImmediateU32();
|
||||
code.EORI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
|
||||
code.EOR(result, result, op_arg);
|
||||
}
|
||||
@ -957,7 +953,7 @@ void EmitA64::EmitOr32(EmitContext& ctx, IR::Inst* inst) {
|
||||
code.ORRI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
|
||||
} else {
|
||||
Arm64Gen::ARM64Reg op_arg = DecodeReg(ctx.reg_alloc.UseGpr(args[1]));
|
||||
code.ORR(result, result , op_arg);
|
||||
code.ORR(result, result, op_arg);
|
||||
}
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
@ -971,8 +967,7 @@ void EmitA64::EmitOr64(EmitContext& ctx, IR::Inst* inst) {
|
||||
if (args[1].IsImmediate()) {
|
||||
u32 op_arg = args[1].GetImmediateU32();
|
||||
code.ORRI2R(result, result, op_arg, ctx.reg_alloc.ScratchGpr());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Arm64Gen::ARM64Reg op_arg = ctx.reg_alloc.UseGpr(args[1]);
|
||||
code.ORR(result, result, op_arg);
|
||||
}
|
||||
@ -1001,8 +996,7 @@ void EmitA64::EmitNot64(EmitContext& ctx, IR::Inst* inst) {
|
||||
if (args[0].IsImmediate()) {
|
||||
result = ctx.reg_alloc.ScratchGpr();
|
||||
code.MOVI2R(result, u32(~args[0].GetImmediateU32()));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
result = ctx.reg_alloc.UseScratchGpr(args[0]);
|
||||
code.MVN(result, result);
|
||||
}
|
||||
@ -1116,15 +1110,15 @@ void EmitA64::EmitCountLeadingZeros32(EmitContext& ctx, IR::Inst* inst) {
|
||||
ARM64Reg result = DecodeReg(ctx.reg_alloc.ScratchGpr());
|
||||
|
||||
code.CLZ(result, source);
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
void EmitA64::EmitCountLeadingZeros64(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ARM64Reg source = ctx.reg_alloc.UseGpr(args[0]);
|
||||
ARM64Reg result = ctx.reg_alloc.ScratchGpr();
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ARM64Reg source = ctx.reg_alloc.UseGpr(args[0]);
|
||||
ARM64Reg result = ctx.reg_alloc.ScratchGpr();
|
||||
|
||||
code.CLZ(result, source);
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
code.CLZ(result, source);
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -46,7 +46,7 @@ Arm64Gen::RoundingMode ConvertRoundingModeToA64RoundingMode(FP::RoundingMode rou
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t fsize, typename Function>
|
||||
template<size_t fsize, typename Function>
|
||||
void FPTwoOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
@ -61,7 +61,7 @@ void FPTwoOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
template <size_t fsize, typename Function>
|
||||
template<size_t fsize, typename Function>
|
||||
void FPThreeOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
@ -72,14 +72,13 @@ void FPThreeOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn)
|
||||
|
||||
if constexpr (std::is_member_function_pointer_v<Function>) {
|
||||
(code.fp_emitter.*fn)(result, result, operand);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
fn(result, result, operand);
|
||||
}
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
} // anonymous namespace
|
||||
} // anonymous namespace
|
||||
|
||||
//void EmitA64::EmitFPAbs16(EmitContext& ctx, IR::Inst* inst) {
|
||||
// auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
@ -136,27 +135,27 @@ void EmitA64::EmitFPNeg64(EmitContext& ctx, IR::Inst* inst) {
|
||||
}
|
||||
|
||||
void EmitA64::EmitFPAdd32(EmitContext& ctx, IR::Inst* inst) {
|
||||
FPThreeOp<32, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FADD);
|
||||
FPThreeOp<32, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FADD);
|
||||
}
|
||||
|
||||
void EmitA64::EmitFPAdd64(EmitContext& ctx, IR::Inst* inst) {
|
||||
FPThreeOp<64, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FADD);
|
||||
FPThreeOp<64, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FADD);
|
||||
}
|
||||
|
||||
void EmitA64::EmitFPDiv32(EmitContext& ctx, IR::Inst* inst) {
|
||||
FPThreeOp<32, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FDIV);
|
||||
FPThreeOp<32, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FDIV);
|
||||
}
|
||||
|
||||
void EmitA64::EmitFPDiv64(EmitContext& ctx, IR::Inst* inst) {
|
||||
FPThreeOp<64, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FDIV);
|
||||
FPThreeOp<64, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FDIV);
|
||||
}
|
||||
|
||||
void EmitA64::EmitFPMul32(EmitContext& ctx, IR::Inst* inst) {
|
||||
FPThreeOp<32, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FMUL);
|
||||
FPThreeOp<32, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FMUL);
|
||||
}
|
||||
|
||||
void EmitA64::EmitFPMul64(EmitContext& ctx, IR::Inst* inst) {
|
||||
FPThreeOp<64, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FMUL);
|
||||
FPThreeOp<64, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FMUL);
|
||||
}
|
||||
void EmitA64::EmitFPSqrt32(EmitContext& ctx, IR::Inst* inst) {
|
||||
FPTwoOp<32>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FSQRT);
|
||||
@ -167,16 +166,16 @@ void EmitA64::EmitFPSqrt64(EmitContext& ctx, IR::Inst* inst) {
|
||||
}
|
||||
|
||||
void EmitA64::EmitFPSub32(EmitContext& ctx, IR::Inst* inst) {
|
||||
FPThreeOp<32, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FSUB);
|
||||
FPThreeOp<32, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FSUB);
|
||||
}
|
||||
|
||||
void EmitA64::EmitFPSub64(EmitContext& ctx, IR::Inst* inst) {
|
||||
FPThreeOp<64, void(Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FSUB);
|
||||
FPThreeOp<64, void (Arm64Gen::ARM64FloatEmitter::*)(ARM64Reg, ARM64Reg, ARM64Reg)>(code, ctx, inst, &Arm64Gen::ARM64FloatEmitter::FSUB);
|
||||
}
|
||||
|
||||
static ARM64Reg SetFpscrNzcvFromFlags(BlockOfCode& code, EmitContext& ctx) {
|
||||
ARM64Reg nzcv = ctx.reg_alloc.ScratchGpr();
|
||||
// Fpsr's nzcv is copied across integer nzcv
|
||||
// Fpsr's nzcv is copied across integer nzcv
|
||||
code.MRS(nzcv, FIELD_NZCV);
|
||||
return nzcv;
|
||||
}
|
||||
@ -276,13 +275,11 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
if constexpr (unsigned_) {
|
||||
code.fp_emitter.FCVTU(result, src, round_imm);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
code.fp_emitter.FCVTS(result, src, round_imm);
|
||||
}
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
|
||||
}
|
||||
|
||||
void EmitA64::EmitFPDoubleToFixedS32(EmitContext& ctx, IR::Inst* inst) {
|
||||
@ -328,8 +325,7 @@ void EmitA64::EmitFPFixedS32ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
if (fbits != 0) {
|
||||
code.fp_emitter.SCVTF(result, from, fbits);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
code.fp_emitter.SCVTF(result, from);
|
||||
}
|
||||
|
||||
@ -338,7 +334,7 @@ void EmitA64::EmitFPFixedS32ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
void EmitA64::EmitFPFixedU32ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
|
||||
const ARM64Reg from = DecodeReg(ctx.reg_alloc.UseGpr(args[0]));
|
||||
const ARM64Reg result = EncodeRegToSingle(ctx.reg_alloc.ScratchFpr());
|
||||
const size_t fbits = args[1].GetImmediateU8();
|
||||
@ -347,8 +343,7 @@ void EmitA64::EmitFPFixedU32ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
if (fbits != 0) {
|
||||
code.fp_emitter.UCVTF(result, from, fbits);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
code.fp_emitter.UCVTF(result, from);
|
||||
}
|
||||
|
||||
@ -366,8 +361,7 @@ void EmitA64::EmitFPFixedS32ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
if (fbits != 0) {
|
||||
code.fp_emitter.SCVTF(result, from, fbits);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
code.fp_emitter.SCVTF(result, from);
|
||||
}
|
||||
|
||||
@ -385,8 +379,7 @@ void EmitA64::EmitFPFixedS64ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
if (fbits != 0) {
|
||||
code.fp_emitter.SCVTF(result, from, fbits);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
code.fp_emitter.SCVTF(result, from);
|
||||
}
|
||||
|
||||
@ -404,8 +397,7 @@ void EmitA64::EmitFPFixedS64ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
if (fbits != 0) {
|
||||
code.fp_emitter.SCVTF(result, from, fbits);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
code.fp_emitter.SCVTF(result, from);
|
||||
}
|
||||
|
||||
@ -423,8 +415,7 @@ void EmitA64::EmitFPFixedU32ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
if (fbits != 0) {
|
||||
code.fp_emitter.UCVTF(result, from, fbits);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
code.fp_emitter.UCVTF(result, from);
|
||||
}
|
||||
|
||||
@ -434,7 +425,6 @@ void EmitA64::EmitFPFixedU32ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||
void EmitA64::EmitFPFixedU64ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
|
||||
const ARM64Reg from = ctx.reg_alloc.UseGpr(args[0]);
|
||||
const ARM64Reg result = EncodeRegToDouble(ctx.reg_alloc.ScratchFpr());
|
||||
const size_t fbits = args[1].GetImmediateU8();
|
||||
@ -443,8 +433,7 @@ void EmitA64::EmitFPFixedU64ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
if (fbits != 0) {
|
||||
code.fp_emitter.UCVTF(result, from, fbits);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
code.fp_emitter.UCVTF(result, from);
|
||||
}
|
||||
|
||||
@ -454,7 +443,6 @@ void EmitA64::EmitFPFixedU64ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||
void EmitA64::EmitFPFixedU64ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
|
||||
const ARM64Reg from = ctx.reg_alloc.UseGpr(args[0]);
|
||||
const ARM64Reg result = EncodeRegToSingle(ctx.reg_alloc.ScratchFpr());
|
||||
const size_t fbits = args[1].GetImmediateU8();
|
||||
@ -463,11 +451,10 @@ void EmitA64::EmitFPFixedU64ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
if (fbits != 0) {
|
||||
code.fp_emitter.UCVTF(result, from, fbits);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
code.fp_emitter.UCVTF(result, from);
|
||||
}
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -468,4 +468,4 @@ void EmitA64::EmitPackedSelect(EmitContext& ctx, IR::Inst* inst) {
|
||||
ctx.reg_alloc.DefineValue(inst, ge);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -37,8 +37,7 @@ void EmitSignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst)
|
||||
|
||||
if constexpr (op == Op::Add) {
|
||||
code.fp_emitter.SQADD(size, result, result, addend);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
code.fp_emitter.SQSUB(size, result, result, addend);
|
||||
}
|
||||
|
||||
@ -54,7 +53,7 @@ void EmitSignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst)
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
} // anonymous namespace
|
||||
} // anonymous namespace
|
||||
|
||||
void EmitA64::EmitSignedSaturatedAdd8(EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitSignedSaturatedOp<Op::Add, 8>(code, ctx, inst);
|
||||
@ -166,4 +165,4 @@ void EmitA64::EmitUnsignedSaturation(EmitContext& ctx, IR::Inst* inst) {
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -265,7 +265,11 @@ constexpr ARM64Reg EncodeRegToQuad(ARM64Reg reg) {
|
||||
return static_cast<ARM64Reg>(reg | 0xC0);
|
||||
}
|
||||
|
||||
enum OpType { TYPE_IMM = 0, TYPE_REG, TYPE_IMMSREG, TYPE_RSR, TYPE_MEM };
|
||||
enum OpType { TYPE_IMM = 0,
|
||||
TYPE_REG,
|
||||
TYPE_IMMSREG,
|
||||
TYPE_RSR,
|
||||
TYPE_MEM };
|
||||
|
||||
enum ShiftType {
|
||||
ST_LSL = 0,
|
||||
@ -474,8 +478,7 @@ private:
|
||||
void EncodeUnconditionalBranchInst(u32 opc, u32 op2, u32 op3, u32 op4, ARM64Reg Rn);
|
||||
void EncodeExceptionInst(u32 instenc, u32 imm);
|
||||
void EncodeSystemInst(u32 op0, u32 op1, u32 CRn, u32 CRm, u32 op2, ARM64Reg Rt);
|
||||
void EncodeArithmeticInst(u32 instenc, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm,
|
||||
ArithOption Option);
|
||||
void EncodeArithmeticInst(u32 instenc, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option);
|
||||
void EncodeArithmeticCarryInst(u32 op, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EncodeCondCompareImmInst(u32 op, ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond);
|
||||
void EncodeCondCompareRegInst(u32 op, ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond);
|
||||
@ -494,8 +497,7 @@ private:
|
||||
void EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void EncodeAddSubImmInst(u32 op, bool flags, u32 shift, u32 imm, ARM64Reg Rn, ARM64Reg Rd);
|
||||
void EncodeLogicalImmInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, int n);
|
||||
void EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2,
|
||||
ARM64Reg Rn, s32 imm);
|
||||
void EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
|
||||
void EncodeAddressInst(u32 op, ARM64Reg Rd, s32 imm);
|
||||
void EncodeLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
|
||||
|
||||
@ -503,7 +505,8 @@ protected:
|
||||
void Write32(u32 value);
|
||||
|
||||
public:
|
||||
ARM64XEmitter() : m_code(nullptr), m_lastCacheFlushEnd(nullptr) {
|
||||
ARM64XEmitter()
|
||||
: m_code(nullptr), m_lastCacheFlushEnd(nullptr) {
|
||||
}
|
||||
|
||||
ARM64XEmitter(u8* code_ptr) {
|
||||
@ -831,7 +834,7 @@ public:
|
||||
// Wrapper around MOVZ+MOVK
|
||||
void MOVI2R(ARM64Reg Rd, u64 imm, bool optimize = true);
|
||||
bool MOVI2R2(ARM64Reg Rd, u64 imm1, u64 imm2);
|
||||
template <class P>
|
||||
template<class P>
|
||||
void MOVP2R(ARM64Reg Rd, P* ptr) {
|
||||
ASSERT_MSG(Is64Bit(Rd), "Can't store pointers in 32-bit registers");
|
||||
MOVI2R(Rd, (uintptr_t)ptr);
|
||||
@ -848,8 +851,7 @@ public:
|
||||
void EORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
|
||||
void CMPI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
|
||||
|
||||
void ADDI2R_internal(ARM64Reg Rd, ARM64Reg Rn, u64 imm, bool negative, bool flags,
|
||||
ARM64Reg scratch);
|
||||
void ADDI2R_internal(ARM64Reg Rd, ARM64Reg Rn, u64 imm, bool negative, bool flags, ARM64Reg scratch);
|
||||
void ADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
|
||||
void ADDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
|
||||
void SUBI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG);
|
||||
@ -872,14 +874,14 @@ public:
|
||||
// Unfortunately, calling operator() directly is undefined behavior in C++
|
||||
// (this method might be a thunk in the case of multi-inheritance) so we
|
||||
// have to go through a trampoline function.
|
||||
template <typename T, typename... Args>
|
||||
template<typename T, typename... Args>
|
||||
static T CallLambdaTrampoline(const std::function<T(Args...)>* f, Args... args) {
|
||||
return (*f)(args...);
|
||||
}
|
||||
|
||||
// This function expects you to have set up the state.
|
||||
// Overwrites X0 and X30
|
||||
template <typename T, typename... Args>
|
||||
template<typename T, typename... Args>
|
||||
ARM64Reg ABI_SetupLambda(const std::function<T(Args...)>* f) {
|
||||
auto trampoline = &ARM64XEmitter::CallLambdaTrampoline<T, Args...>;
|
||||
MOVI2R(X30, (uintptr_t)trampoline);
|
||||
@ -889,7 +891,7 @@ public:
|
||||
|
||||
// Plain function call
|
||||
void QuickCallFunction(const void* func, ARM64Reg scratchreg = X16);
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
void QuickCallFunction(T func, ARM64Reg scratchreg = X16) {
|
||||
QuickCallFunction((const void*)func, scratchreg);
|
||||
}
|
||||
@ -897,7 +899,8 @@ public:
|
||||
|
||||
class ARM64FloatEmitter {
|
||||
public:
|
||||
ARM64FloatEmitter(ARM64XEmitter* emit) : m_emit(emit) {
|
||||
ARM64FloatEmitter(ARM64XEmitter* emit)
|
||||
: m_emit(emit) {
|
||||
}
|
||||
|
||||
void LDR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
|
||||
@ -935,7 +938,7 @@ public:
|
||||
void FABS(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FNEG(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FSQRT(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FMOV(ARM64Reg Rd, ARM64Reg Rn, bool top = false); // Also generalized move between GPR/FP
|
||||
void FMOV(ARM64Reg Rd, ARM64Reg Rn, bool top = false); // Also generalized move between GPR/FP
|
||||
|
||||
// Scalar - 2 Source
|
||||
void FADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
@ -959,7 +962,7 @@ public:
|
||||
void UQADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void SQSUB(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void UQSUB(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
|
||||
|
||||
// Scalar floating point immediate
|
||||
void FMOV(ARM64Reg Rd, uint8_t imm8);
|
||||
|
||||
@ -1110,22 +1113,17 @@ private:
|
||||
}
|
||||
|
||||
// Emitting functions
|
||||
void EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, ARM64Reg Rn,
|
||||
s32 imm);
|
||||
void EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn,
|
||||
ARM64Reg Rm);
|
||||
void EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
|
||||
void EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EmitThreeSame(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EmitScalarThreeSame(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EmitCopy(bool Q, u32 op, u32 imm5, u32 imm4, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void Emit2RegMisc(bool Q, bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt,
|
||||
ARM64Reg Rn);
|
||||
void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt,
|
||||
ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn);
|
||||
void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitConversion2(bool sf, bool S, bool direction, u32 type, u32 rmode, u32 opcode,
|
||||
int scale, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitConversion2(bool sf, bool S, bool direction, u32 type, u32 rmode, u32 opcode, int scale, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EmitPermute(u32 size, u32 op, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
@ -1133,19 +1131,14 @@ private:
|
||||
void EmitShiftImm(bool Q, bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitScalarShiftImm(bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitLoadStoreMultipleStructure(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn);
|
||||
void EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn,
|
||||
ARM64Reg Rm);
|
||||
void EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EmitScalar1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, ARM64Reg Rd, ARM64Reg Rn,
|
||||
ARM64Reg Rm);
|
||||
void EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EmitLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
|
||||
void EmitConvertScalarToInt(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round, bool sign);
|
||||
void EmitScalar3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra,
|
||||
int opcode);
|
||||
void EncodeLoadStorePair(u32 size, bool load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2,
|
||||
ARM64Reg Rn, s32 imm);
|
||||
void EncodeLoadStoreRegisterOffset(u32 size, bool load, ARM64Reg Rt, ARM64Reg Rn,
|
||||
ArithOption Rm);
|
||||
void EmitScalar3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra, int opcode);
|
||||
void EncodeLoadStorePair(u32 size, bool load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
|
||||
void EncodeLoadStoreRegisterOffset(u32 size, bool load, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void EncodeModImm(bool Q, u8 op, u8 cmode, u8 o2, ARM64Reg Rd, u8 abcdefgh);
|
||||
|
||||
void SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper);
|
||||
@ -1170,4 +1163,4 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::BackendA64::Arm64Gen
|
||||
} // namespace Dynarmic::BackendA64::Arm64Gen
|
||||
|
@ -6,23 +6,23 @@
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
enum CCFlags {
|
||||
CC_EQ = 0, // Equal
|
||||
CC_NEQ, // Not equal
|
||||
CC_CS, // Carry Set
|
||||
CC_CC, // Carry Clear
|
||||
CC_MI, // Minus (Negative)
|
||||
CC_PL, // Plus
|
||||
CC_VS, // Overflow
|
||||
CC_VC, // No Overflow
|
||||
CC_HI, // Unsigned higher
|
||||
CC_LS, // Unsigned lower or same
|
||||
CC_GE, // Signed greater than or equal
|
||||
CC_LT, // Signed less than
|
||||
CC_GT, // Signed greater than
|
||||
CC_LE, // Signed less than or equal
|
||||
CC_AL, // Always (unconditional) 14
|
||||
CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same
|
||||
CC_LO = CC_CC, // Alias of CC_CC Unsigned lower
|
||||
CC_EQ = 0, // Equal
|
||||
CC_NEQ, // Not equal
|
||||
CC_CS, // Carry Set
|
||||
CC_CC, // Carry Clear
|
||||
CC_MI, // Minus (Negative)
|
||||
CC_PL, // Plus
|
||||
CC_VS, // Overflow
|
||||
CC_VC, // No Overflow
|
||||
CC_HI, // Unsigned higher
|
||||
CC_LS, // Unsigned lower or same
|
||||
CC_GE, // Signed greater than or equal
|
||||
CC_LT, // Signed less than
|
||||
CC_GT, // Signed greater than
|
||||
CC_LE, // Signed less than or equal
|
||||
CC_AL, // Always (unconditional) 14
|
||||
CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same
|
||||
CC_LO = CC_CC, // Alias of CC_CC Unsigned lower
|
||||
};
|
||||
const u32 NO_COND = 0xE0000000;
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -8,9 +8,9 @@
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
# include <windows.h>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <mcl/assert.hpp>
|
||||
@ -21,7 +21,7 @@ namespace Dynarmic::BackendA64 {
|
||||
// You get memory management for free, plus, you can use all emitter functions
|
||||
// without having to prefix them with gen-> or something similar. Example
|
||||
// implementation: class JIT : public CodeBlock<ARMXEmitter> {}
|
||||
template <class T>
|
||||
template<class T>
|
||||
class CodeBlock : public T {
|
||||
private:
|
||||
// A privately used function to set the executable RAM space to something
|
||||
@ -57,11 +57,11 @@ public:
|
||||
#if defined(_WIN32)
|
||||
void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#else
|
||||
#if defined(__APPLE__)
|
||||
# if defined(__APPLE__)
|
||||
void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE | MAP_JIT, -1, 0);
|
||||
#else
|
||||
# else
|
||||
void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
#endif
|
||||
# endif
|
||||
|
||||
if (ptr == MAP_FAILED)
|
||||
ptr = nullptr;
|
||||
@ -137,4 +137,4 @@ public:
|
||||
m_children.emplace_back(child);
|
||||
}
|
||||
};
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -7,8 +7,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
@ -32,9 +32,10 @@ public:
|
||||
void Register(BlockOfCode& code, std::function<void(CodePtr)> segv_callback = nullptr);
|
||||
|
||||
bool SupportsFastmem() const;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -22,4 +22,4 @@ bool ExceptionHandler::SupportsFastmem() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -8,14 +8,13 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <csignal>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <csignal>
|
||||
#ifdef __APPLE__
|
||||
#include <sys/ucontext.h>
|
||||
# include <sys/ucontext.h>
|
||||
#else
|
||||
#include <ucontext.h>
|
||||
# include <ucontext.h>
|
||||
#endif
|
||||
|
||||
#include <mcl/assert.hpp>
|
||||
@ -117,8 +116,7 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
|
||||
"dynarmic: POSIX SigHandler: Exception was not in registered code blocks (PC {})\n",
|
||||
PC);
|
||||
|
||||
struct sigaction* retry_sa =
|
||||
sig == SIGSEGV ? &sig_handler.old_sa_segv : &sig_handler.old_sa_bus;
|
||||
struct sigaction* retry_sa = sig == SIGSEGV ? &sig_handler.old_sa_segv : &sig_handler.old_sa_bus;
|
||||
if (retry_sa->sa_flags & SA_SIGINFO) {
|
||||
retry_sa->sa_sigaction(sig, info, raw_context);
|
||||
return;
|
||||
@ -133,7 +131,7 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
|
||||
retry_sa->sa_handler(sig);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
} // anonymous namespace
|
||||
|
||||
struct ExceptionHandler::Impl final {
|
||||
Impl(BlockOfCode& code, std::function<void(CodePtr)> cb) {
|
||||
@ -162,4 +160,4 @@ bool ExceptionHandler::SupportsFastmem() const {
|
||||
return static_cast<bool>(impl);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -18,4 +18,4 @@ Arm64Gen::ARM64Reg HostLocToFpr(HostLoc loc) {
|
||||
return EncodeRegToQuad(static_cast<Arm64Gen::ARM64Reg>(static_cast<int>(loc) - static_cast<int>(HostLoc::Q0)));
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendX64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -48,7 +48,7 @@ enum class HostLoc {
|
||||
X29,
|
||||
X30,
|
||||
|
||||
SP, // 64bit stack pointer
|
||||
SP, // 64bit stack pointer
|
||||
|
||||
// Qword FPR registers
|
||||
Q0,
|
||||
@ -138,32 +138,76 @@ using HostLocList = std::initializer_list<HostLoc>;
|
||||
// X30 is the link register.
|
||||
// In order of desireablity based first on ABI
|
||||
constexpr HostLocList any_gpr = {
|
||||
HostLoc::X19, HostLoc::X20, HostLoc::X21, HostLoc::X22, HostLoc::X23,
|
||||
HostLoc::X24, HostLoc::X25,
|
||||
HostLoc::X19,
|
||||
HostLoc::X20,
|
||||
HostLoc::X21,
|
||||
HostLoc::X22,
|
||||
HostLoc::X23,
|
||||
HostLoc::X24,
|
||||
HostLoc::X25,
|
||||
|
||||
HostLoc::X8, HostLoc::X9, HostLoc::X10, HostLoc::X11, HostLoc::X12,
|
||||
HostLoc::X13, HostLoc::X14, HostLoc::X15, HostLoc::X16, HostLoc::X17,
|
||||
HostLoc::X8,
|
||||
HostLoc::X9,
|
||||
HostLoc::X10,
|
||||
HostLoc::X11,
|
||||
HostLoc::X12,
|
||||
HostLoc::X13,
|
||||
HostLoc::X14,
|
||||
HostLoc::X15,
|
||||
HostLoc::X16,
|
||||
HostLoc::X17,
|
||||
|
||||
HostLoc::X7, HostLoc::X6, HostLoc::X5, HostLoc::X4, HostLoc::X3,
|
||||
HostLoc::X2, HostLoc::X1, HostLoc::X0,
|
||||
HostLoc::X7,
|
||||
HostLoc::X6,
|
||||
HostLoc::X5,
|
||||
HostLoc::X4,
|
||||
HostLoc::X3,
|
||||
HostLoc::X2,
|
||||
HostLoc::X1,
|
||||
HostLoc::X0,
|
||||
};
|
||||
|
||||
constexpr HostLocList any_fpr = {
|
||||
HostLoc::Q8, HostLoc::Q9, HostLoc::Q10, HostLoc::Q11, HostLoc::Q12, HostLoc::Q13,
|
||||
HostLoc::Q14, HostLoc::Q15,
|
||||
HostLoc::Q8,
|
||||
HostLoc::Q9,
|
||||
HostLoc::Q10,
|
||||
HostLoc::Q11,
|
||||
HostLoc::Q12,
|
||||
HostLoc::Q13,
|
||||
HostLoc::Q14,
|
||||
HostLoc::Q15,
|
||||
|
||||
HostLoc::Q16, HostLoc::Q17, HostLoc::Q18, HostLoc::Q19, HostLoc::Q20, HostLoc::Q21,
|
||||
HostLoc::Q22, HostLoc::Q23, HostLoc::Q24, HostLoc::Q25, HostLoc::Q26, HostLoc::Q27,
|
||||
HostLoc::Q28, HostLoc::Q29, HostLoc::Q30, HostLoc::Q31,
|
||||
HostLoc::Q16,
|
||||
HostLoc::Q17,
|
||||
HostLoc::Q18,
|
||||
HostLoc::Q19,
|
||||
HostLoc::Q20,
|
||||
HostLoc::Q21,
|
||||
HostLoc::Q22,
|
||||
HostLoc::Q23,
|
||||
HostLoc::Q24,
|
||||
HostLoc::Q25,
|
||||
HostLoc::Q26,
|
||||
HostLoc::Q27,
|
||||
HostLoc::Q28,
|
||||
HostLoc::Q29,
|
||||
HostLoc::Q30,
|
||||
HostLoc::Q31,
|
||||
|
||||
HostLoc::Q7, HostLoc::Q6, HostLoc::Q5, HostLoc::Q4, HostLoc::Q3, HostLoc::Q2,
|
||||
HostLoc::Q1, HostLoc::Q0,
|
||||
HostLoc::Q7,
|
||||
HostLoc::Q6,
|
||||
HostLoc::Q5,
|
||||
HostLoc::Q4,
|
||||
HostLoc::Q3,
|
||||
HostLoc::Q2,
|
||||
HostLoc::Q1,
|
||||
HostLoc::Q0,
|
||||
};
|
||||
|
||||
Arm64Gen::ARM64Reg HostLocToReg64(HostLoc loc);
|
||||
Arm64Gen::ARM64Reg HostLocToFpr(HostLoc loc);
|
||||
|
||||
template <typename JitStateType>
|
||||
template<typename JitStateType>
|
||||
size_t SpillToOpArg(HostLoc loc) {
|
||||
ASSERT(HostLocIsSpill(loc));
|
||||
|
||||
@ -174,4 +218,4 @@ size_t SpillToOpArg(HostLoc loc) {
|
||||
return JitStateType::GetSpillLocationOffsetFromIndex(i);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -11,22 +11,21 @@
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
struct JitStateInfo {
|
||||
template <typename JitStateType>
|
||||
template<typename JitStateType>
|
||||
JitStateInfo(const JitStateType&)
|
||||
: offsetof_cycles_remaining(offsetof(JitStateType, cycles_remaining))
|
||||
, offsetof_cycles_to_run(offsetof(JitStateType, cycles_to_run))
|
||||
, offsetof_save_host_FPCR(offsetof(JitStateType, save_host_FPCR))
|
||||
, offsetof_guest_fpcr(offsetof(JitStateType, guest_fpcr))
|
||||
, offsetof_guest_fpsr(offsetof(JitStateType, guest_fpsr))
|
||||
, offsetof_rsb_ptr(offsetof(JitStateType, rsb_ptr))
|
||||
, rsb_ptr_mask(JitStateType::RSBPtrMask)
|
||||
, offsetof_rsb_location_descriptors(offsetof(JitStateType, rsb_location_descriptors))
|
||||
, offsetof_rsb_codeptrs(offsetof(JitStateType, rsb_codeptrs))
|
||||
, offsetof_cpsr_nzcv(offsetof(JitStateType, cpsr_nzcv))
|
||||
, offsetof_fpsr_exc(offsetof(JitStateType, fpsr_exc))
|
||||
, offsetof_fpsr_qc(offsetof(JitStateType, fpsr_qc))
|
||||
, offsetof_halt_reason(offsetof(JitStateType, halt_reason))
|
||||
{}
|
||||
: offsetof_cycles_remaining(offsetof(JitStateType, cycles_remaining))
|
||||
, offsetof_cycles_to_run(offsetof(JitStateType, cycles_to_run))
|
||||
, offsetof_save_host_FPCR(offsetof(JitStateType, save_host_FPCR))
|
||||
, offsetof_guest_fpcr(offsetof(JitStateType, guest_fpcr))
|
||||
, offsetof_guest_fpsr(offsetof(JitStateType, guest_fpsr))
|
||||
, offsetof_rsb_ptr(offsetof(JitStateType, rsb_ptr))
|
||||
, rsb_ptr_mask(JitStateType::RSBPtrMask)
|
||||
, offsetof_rsb_location_descriptors(offsetof(JitStateType, rsb_location_descriptors))
|
||||
, offsetof_rsb_codeptrs(offsetof(JitStateType, rsb_codeptrs))
|
||||
, offsetof_cpsr_nzcv(offsetof(JitStateType, cpsr_nzcv))
|
||||
, offsetof_fpsr_exc(offsetof(JitStateType, fpsr_exc))
|
||||
, offsetof_fpsr_qc(offsetof(JitStateType, fpsr_qc))
|
||||
, offsetof_halt_reason(offsetof(JitStateType, halt_reason)) {}
|
||||
|
||||
const size_t offsetof_cycles_remaining;
|
||||
const size_t offsetof_cycles_to_run;
|
||||
@ -43,4 +42,4 @@ struct JitStateInfo {
|
||||
const size_t offsetof_halt_reason;
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -9,14 +9,14 @@
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
# include <cstdio>
|
||||
# include <cstdlib>
|
||||
# include <mutex>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <mcl/stdint.hpp>
|
||||
# include <fmt/format.h>
|
||||
# include <mcl/stdint.hpp>
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
@ -41,7 +41,7 @@ void OpenFile() {
|
||||
|
||||
std::setvbuf(file, nullptr, _IONBF, 0);
|
||||
}
|
||||
} // anonymous namespace
|
||||
} // anonymous namespace
|
||||
|
||||
namespace detail {
|
||||
void PerfMapRegister(const void* start, const void* end, const std::string& friendly_name) {
|
||||
@ -57,7 +57,7 @@ void PerfMapRegister(const void* start, const void* end, const std::string& frie
|
||||
const std::string line = fmt::format("{:016x} {:016x} {:s}\n", reinterpret_cast<u64>(start), reinterpret_cast<u64>(end) - reinterpret_cast<u64>(start), friendly_name);
|
||||
std::fwrite(line.data(), sizeof *line.data(), line.size(), file);
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace detail
|
||||
|
||||
void PerfMapClear() {
|
||||
std::lock_guard guard{mutex};
|
||||
@ -71,7 +71,7 @@ void PerfMapClear() {
|
||||
OpenFile();
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendX64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
||||
#else
|
||||
|
||||
@ -79,10 +79,10 @@ namespace Dynarmic::BackendA64 {
|
||||
|
||||
namespace detail {
|
||||
void PerfMapRegister(const void*, const void*, const std::string&) {}
|
||||
} // namespace detail
|
||||
} // namespace detail
|
||||
|
||||
void PerfMapClear() {}
|
||||
|
||||
} // namespace Dynarmic::BackendX64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
||||
#endif
|
||||
|
@ -15,7 +15,7 @@ namespace Dynarmic::BackendA64 {
|
||||
|
||||
namespace detail {
|
||||
void PerfMapRegister(const void* start, const void* end, const std::string& friendly_name);
|
||||
} // namespace detail
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
void PerfMapRegister(T start, const void* end, const std::string& friendly_name) {
|
||||
@ -24,4 +24,4 @@ void PerfMapRegister(T start, const void* end, const std::string& friendly_name)
|
||||
|
||||
void PerfMapClear();
|
||||
|
||||
} // namespace Dynarmic::BackendX64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -4,6 +4,8 @@
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "dynarmic/backend/A64/reg_alloc.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
@ -12,7 +14,6 @@
|
||||
#include <mcl/assert.hpp>
|
||||
|
||||
#include "dynarmic/backend/A64/abi.h"
|
||||
#include "dynarmic/backend/A64/reg_alloc.h"
|
||||
|
||||
namespace Dynarmic::BackendA64 {
|
||||
|
||||
@ -67,7 +68,7 @@ static size_t GetBitWidth(IR::Type type) {
|
||||
case IR::Type::U128:
|
||||
return 128;
|
||||
case IR::Type::NZCVFlags:
|
||||
return 32; // TODO: Update to 16 when flags optimization is done
|
||||
return 32; // TODO: Update to 16 when flags optimization is done
|
||||
}
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
@ -379,16 +380,9 @@ HostLoc RegAlloc::ScratchImpl(HostLocList desired_locations) {
|
||||
return location;
|
||||
}
|
||||
|
||||
void RegAlloc::HostCall(IR::Inst* result_def, std::optional<Argument::copyable_reference> arg0,
|
||||
std::optional<Argument::copyable_reference> arg1,
|
||||
std::optional<Argument::copyable_reference> arg2,
|
||||
std::optional<Argument::copyable_reference> arg3,
|
||||
std::optional<Argument::copyable_reference> arg4,
|
||||
std::optional<Argument::copyable_reference> arg5,
|
||||
std::optional<Argument::copyable_reference> arg6,
|
||||
std::optional<Argument::copyable_reference> arg7) {
|
||||
void RegAlloc::HostCall(IR::Inst* result_def, std::optional<Argument::copyable_reference> arg0, std::optional<Argument::copyable_reference> arg1, std::optional<Argument::copyable_reference> arg2, std::optional<Argument::copyable_reference> arg3, std::optional<Argument::copyable_reference> arg4, std::optional<Argument::copyable_reference> arg5, std::optional<Argument::copyable_reference> arg6, std::optional<Argument::copyable_reference> arg7) {
|
||||
constexpr size_t args_count = 8;
|
||||
constexpr std::array<HostLoc, args_count> args_hostloc = { ABI_PARAM1, ABI_PARAM2, ABI_PARAM3, ABI_PARAM4, ABI_PARAM5, ABI_PARAM6, ABI_PARAM7, ABI_PARAM8 };
|
||||
constexpr std::array<HostLoc, args_count> args_hostloc = {ABI_PARAM1, ABI_PARAM2, ABI_PARAM3, ABI_PARAM4, ABI_PARAM5, ABI_PARAM6, ABI_PARAM7, ABI_PARAM8};
|
||||
const std::array<std::optional<Argument::copyable_reference>, args_count> args = {arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7};
|
||||
|
||||
static const std::vector<HostLoc> other_caller_save = [args_hostloc]() {
|
||||
@ -417,7 +411,7 @@ void RegAlloc::HostCall(IR::Inst* result_def, std::optional<Argument::copyable_r
|
||||
ScratchImpl({caller_saved});
|
||||
}
|
||||
|
||||
if (result_def) {
|
||||
if (result_def) {
|
||||
DefineValueImpl(result_def, ABI_RETURN);
|
||||
}
|
||||
}
|
||||
@ -433,10 +427,10 @@ void RegAlloc::AssertNoMoreUses() {
|
||||
}
|
||||
|
||||
HostLoc RegAlloc::SelectARegister(HostLocList desired_locations) const {
|
||||
std::vector<HostLoc> candidates = desired_locations;
|
||||
std::vector<HostLoc> candidates = desired_locations;
|
||||
|
||||
// Find all locations that have not been allocated..
|
||||
const auto allocated_locs = std::partition(candidates.begin(), candidates.end(), [this](auto loc){
|
||||
const auto allocated_locs = std::partition(candidates.begin(), candidates.end(), [this](auto loc) {
|
||||
return !this->LocInfo(loc).IsLocked();
|
||||
});
|
||||
candidates.erase(allocated_locs, candidates.end());
|
||||
@ -445,7 +439,7 @@ HostLoc RegAlloc::SelectARegister(HostLocList desired_locations) const {
|
||||
// Selects the best location out of the available locations.
|
||||
// TODO: Actually do LRU or something. Currently we just try to pick something without a value if possible.
|
||||
|
||||
std::partition(candidates.begin(), candidates.end(), [this](auto loc){
|
||||
std::partition(candidates.begin(), candidates.end(), [this](auto loc) {
|
||||
return this->LocInfo(loc).IsEmpty();
|
||||
});
|
||||
|
||||
@ -648,4 +642,4 @@ void RegAlloc::EmitExchange(HostLoc a, HostLoc b) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -8,9 +8,9 @@
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
#include <mcl/stdint.hpp>
|
||||
|
||||
@ -84,7 +84,8 @@ public:
|
||||
|
||||
private:
|
||||
friend class RegAlloc;
|
||||
explicit Argument(RegAlloc& reg_alloc) : reg_alloc(reg_alloc) {}
|
||||
explicit Argument(RegAlloc& reg_alloc)
|
||||
: reg_alloc(reg_alloc) {}
|
||||
|
||||
bool allocated = false;
|
||||
RegAlloc& reg_alloc;
|
||||
@ -96,7 +97,7 @@ public:
|
||||
using ArgumentInfo = std::array<Argument, IR::max_arg_count>;
|
||||
|
||||
explicit RegAlloc(BlockOfCode& code, size_t num_spills, std::function<u64(HostLoc)> spill_to_addr)
|
||||
: hostloc_info(NonSpillHostLocCount + num_spills), code(code), spill_to_addr(std::move(spill_to_addr)) {}
|
||||
: hostloc_info(NonSpillHostLocCount + num_spills), code(code), spill_to_addr(std::move(spill_to_addr)) {}
|
||||
|
||||
ArgumentInfo GetArgumentInfo(IR::Inst* inst);
|
||||
|
||||
@ -117,14 +118,7 @@ public:
|
||||
Arm64Gen::ARM64Reg ScratchGpr(HostLocList desired_locations = any_gpr);
|
||||
Arm64Gen::ARM64Reg ScratchFpr(HostLocList desired_locations = any_fpr);
|
||||
|
||||
void HostCall(IR::Inst* result_def = nullptr, std::optional<Argument::copyable_reference> arg0 = {},
|
||||
std::optional<Argument::copyable_reference> arg1 = {},
|
||||
std::optional<Argument::copyable_reference> arg2 = {},
|
||||
std::optional<Argument::copyable_reference> arg3 = {},
|
||||
std::optional<Argument::copyable_reference> arg4 = {},
|
||||
std::optional<Argument::copyable_reference> arg5 = {},
|
||||
std::optional<Argument::copyable_reference> arg6 = {},
|
||||
std::optional<Argument::copyable_reference> arg7 = {});
|
||||
void HostCall(IR::Inst* result_def = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}, std::optional<Argument::copyable_reference> arg2 = {}, std::optional<Argument::copyable_reference> arg3 = {}, std::optional<Argument::copyable_reference> arg4 = {}, std::optional<Argument::copyable_reference> arg5 = {}, std::optional<Argument::copyable_reference> arg6 = {}, std::optional<Argument::copyable_reference> arg7 = {});
|
||||
|
||||
// TODO: Values in host flags
|
||||
|
||||
@ -163,4 +157,4 @@ private:
|
||||
void EmitExchange(HostLoc a, HostLoc b);
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::BackendA64
|
||||
} // namespace Dynarmic::BackendA64
|
||||
|
@ -44,8 +44,8 @@ u8 RecipEstimate(u64 a);
|
||||
*/
|
||||
u8 RecipSqrtEstimate(u64 a);
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsPow2(T imm){
|
||||
template<typename T>
|
||||
constexpr bool IsPow2(T imm) {
|
||||
return imm > 0 && (imm & (imm - 1)) == 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user