|
|
@ -12,6 +12,7 @@ |
|
|
#include <fmt/ostream.h>
|
|
|
#include <fmt/ostream.h>
|
|
|
#include "common/assert.h"
|
|
|
#include "common/assert.h"
|
|
|
#include "common/common_types.h"
|
|
|
#include "common/common_types.h"
|
|
|
|
|
|
#include "dynarmic/ir/terminal.h"
|
|
|
#include "dynarmic/mcl/integer_of_size.hpp"
|
|
|
#include "dynarmic/mcl/integer_of_size.hpp"
|
|
|
#include <boost/container/static_vector.hpp>
|
|
|
#include <boost/container/static_vector.hpp>
|
|
|
|
|
|
|
|
|
@ -147,7 +148,7 @@ finish_this_inst: |
|
|
if (conf.enable_cycle_counting) |
|
|
if (conf.enable_cycle_counting) |
|
|
EmitAddCycles(block.CycleCount()); |
|
|
EmitAddCycles(block.CycleCount()); |
|
|
code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]); |
|
|
code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]); |
|
|
EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); |
|
|
|
|
|
|
|
|
EmitTerminal(block.terminal, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); |
|
|
code.int3(); |
|
|
code.int3(); |
|
|
for (auto& deferred_emit : ctx.deferred_emits) |
|
|
for (auto& deferred_emit : ctx.deferred_emits) |
|
|
deferred_emit(); |
|
|
deferred_emit(); |
|
|
@ -617,11 +618,12 @@ std::string A64EmitX64::LocationDescriptorToFriendlyName(const IR::LocationDescr |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
namespace { |
|
|
namespace { |
|
|
void EmitTerminalImpl(A64EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) { |
|
|
|
|
|
|
|
|
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) { |
|
|
e.code.ReturnFromRunCode(); |
|
|
e.code.ReturnFromRunCode(); |
|
|
|
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationDescriptor, bool is_single_step) { |
|
|
|
|
|
|
|
|
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationDescriptor, bool is_single_step) { |
|
|
// Used for patches and linking
|
|
|
// Used for patches and linking
|
|
|
if (e.conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) { |
|
|
if (e.conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) { |
|
|
if (e.conf.enable_cycle_counting) { |
|
|
if (e.conf.enable_cycle_counting) { |
|
|
@ -649,9 +651,10 @@ void EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlock terminal, IR::LocationD |
|
|
e.code.mov(qword[e.code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax); |
|
|
e.code.mov(qword[e.code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax); |
|
|
e.code.ReturnFromRunCode(); |
|
|
e.code.ReturnFromRunCode(); |
|
|
} |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlockFast terminal, IR::LocationDescriptor, bool is_single_step) { |
|
|
|
|
|
|
|
|
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlockFast terminal, IR::LocationDescriptor, bool is_single_step) { |
|
|
if (e.conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) { |
|
|
if (e.conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) { |
|
|
e.patch_information[terminal.next].jmp.push_back(e.code.getCurr()); |
|
|
e.patch_information[terminal.next].jmp.push_back(e.code.getCurr()); |
|
|
if (auto next_bb = e.GetBasicBlock(terminal.next)) { |
|
|
if (auto next_bb = e.GetBasicBlock(terminal.next)) { |
|
|
@ -664,63 +667,86 @@ void EmitTerminalImpl(A64EmitX64& e, IR::Term::LinkBlockFast terminal, IR::Locat |
|
|
e.code.mov(qword[e.code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax); |
|
|
e.code.mov(qword[e.code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax); |
|
|
e.code.ReturnFromRunCode(); |
|
|
e.code.ReturnFromRunCode(); |
|
|
} |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void EmitTerminalImpl(A64EmitX64& e, IR::Term::PopRSBHint, IR::LocationDescriptor, bool is_single_step) { |
|
|
|
|
|
|
|
|
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::PopRSBHint, IR::LocationDescriptor, bool is_single_step) { |
|
|
if (e.conf.HasOptimization(OptimizationFlag::ReturnStackBuffer) && !is_single_step) { |
|
|
if (e.conf.HasOptimization(OptimizationFlag::ReturnStackBuffer) && !is_single_step) { |
|
|
e.code.jmp(e.terminal_handler_pop_rsb_hint); |
|
|
e.code.jmp(e.terminal_handler_pop_rsb_hint); |
|
|
} else { |
|
|
} else { |
|
|
e.code.ReturnFromRunCode(); |
|
|
e.code.ReturnFromRunCode(); |
|
|
} |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void EmitTerminalImpl(A64EmitX64& e, IR::Term::FastDispatchHint, IR::LocationDescriptor, bool is_single_step) { |
|
|
|
|
|
|
|
|
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::FastDispatchHint, IR::LocationDescriptor, bool is_single_step) { |
|
|
if (!e.conf.HasOptimization(OptimizationFlag::FastDispatch) || is_single_step) { |
|
|
if (!e.conf.HasOptimization(OptimizationFlag::FastDispatch) || is_single_step) { |
|
|
e.code.ReturnFromRunCode(); |
|
|
e.code.ReturnFromRunCode(); |
|
|
} else { |
|
|
} else { |
|
|
e.code.jmp(e.terminal_handler_fast_dispatch_hint); |
|
|
e.code.jmp(e.terminal_handler_fast_dispatch_hint); |
|
|
} |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void EmitTerminalImpl(A64EmitX64& e, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) { |
|
|
|
|
|
|
|
|
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) { |
|
|
switch (terminal.if_) { |
|
|
switch (terminal.if_) { |
|
|
case IR::Cond::AL: |
|
|
case IR::Cond::AL: |
|
|
case IR::Cond::NV: |
|
|
case IR::Cond::NV: |
|
|
e.EmitTerminal(terminal.then_, initial_location, is_single_step); |
|
|
|
|
|
|
|
|
e.EmitLeafTerminal(terminal.then_, initial_location, is_single_step); |
|
|
break; |
|
|
break; |
|
|
default: |
|
|
default: |
|
|
Xbyak::Label pass = e.EmitCond(terminal.if_); |
|
|
Xbyak::Label pass = e.EmitCond(terminal.if_); |
|
|
e.EmitTerminal(terminal.else_, initial_location, is_single_step); |
|
|
|
|
|
|
|
|
e.EmitLeafTerminal(terminal.else_, initial_location, is_single_step); |
|
|
e.code.L(pass); |
|
|
e.code.L(pass); |
|
|
e.EmitTerminal(terminal.then_, initial_location, is_single_step); |
|
|
|
|
|
|
|
|
e.EmitLeafTerminal(terminal.then_, initial_location, is_single_step); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void EmitTerminalImpl(A64EmitX64& e, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) { |
|
|
|
|
|
|
|
|
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) { |
|
|
Xbyak::Label fail; |
|
|
Xbyak::Label fail; |
|
|
e.code.cmp(e.code.byte[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, check_bit)], u8(0)); |
|
|
e.code.cmp(e.code.byte[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, check_bit)], u8(0)); |
|
|
e.code.jz(fail); |
|
|
e.code.jz(fail); |
|
|
e.EmitTerminal(terminal.then_, initial_location, is_single_step); |
|
|
|
|
|
|
|
|
e.EmitLeafTerminal(terminal.then_, initial_location, is_single_step); |
|
|
e.code.L(fail); |
|
|
e.code.L(fail); |
|
|
e.EmitTerminal(terminal.else_, initial_location, is_single_step); |
|
|
|
|
|
|
|
|
e.EmitLeafTerminal(terminal.else_, initial_location, is_single_step); |
|
|
|
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void EmitTerminalImpl(A64EmitX64& e, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) { |
|
|
|
|
|
|
|
|
bool EmitTerminalImpl(A64EmitX64& e, IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) { |
|
|
e.code.cmp(dword[e.code.ABI_JIT_PTR + offsetof(A64JitState, halt_reason)], 0); |
|
|
e.code.cmp(dword[e.code.ABI_JIT_PTR + offsetof(A64JitState, halt_reason)], 0); |
|
|
e.code.jne(e.code.GetForceReturnFromRunCodeAddress()); |
|
|
e.code.jne(e.code.GetForceReturnFromRunCodeAddress()); |
|
|
e.EmitTerminal(terminal.else_, initial_location, is_single_step); |
|
|
|
|
|
|
|
|
e.EmitLeafTerminal(terminal.else_, initial_location, is_single_step); |
|
|
|
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void EmitTerminalImpl(A64EmitX64&, IR::Term::Invalid, IR::LocationDescriptor, bool) { |
|
|
|
|
|
UNREACHABLE(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool A64EmitX64::EmitLeafTerminal(IR::Term::LeafTerminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept { |
|
|
|
|
|
if (auto const x = std::get_if<IR::Term::ReturnToDispatch>(&terminal)) |
|
|
|
|
|
return EmitTerminalImpl(*this, *x, initial_location, is_single_step); |
|
|
|
|
|
if (auto const x = std::get_if<IR::Term::LinkBlock>(&terminal)) |
|
|
|
|
|
return EmitTerminalImpl(*this, *x, initial_location, is_single_step); |
|
|
|
|
|
if (auto const x = std::get_if<IR::Term::LinkBlockFast>(&terminal)) |
|
|
|
|
|
return EmitTerminalImpl(*this, *x, initial_location, is_single_step); |
|
|
|
|
|
if (auto const x = std::get_if<IR::Term::PopRSBHint>(&terminal)) |
|
|
|
|
|
return EmitTerminalImpl(*this, *x, initial_location, is_single_step); |
|
|
|
|
|
if (auto const x = std::get_if<IR::Term::FastDispatchHint>(&terminal)) |
|
|
|
|
|
return EmitTerminalImpl(*this, *x, initial_location, is_single_step); |
|
|
|
|
|
UNREACHABLE(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void A64EmitX64::EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept { |
|
|
|
|
|
boost::apply_visitor([this, initial_location, is_single_step](auto x) { |
|
|
|
|
|
EmitTerminalImpl(*this, x, initial_location, is_single_step); |
|
|
|
|
|
}, terminal); |
|
|
|
|
|
|
|
|
bool A64EmitX64::EmitTerminal(IR::Term::Terminal const& terminal, IR::LocationDescriptor initial_location, bool is_single_step) noexcept { |
|
|
|
|
|
if (auto const x = std::get_if<IR::Term::LeafTerminal>(&terminal)) |
|
|
|
|
|
return EmitLeafTerminal(*x, initial_location, is_single_step); |
|
|
|
|
|
if (auto const x = std::get_if<IR::Term::If>(&terminal)) |
|
|
|
|
|
return EmitTerminalImpl(*this, *x, initial_location, is_single_step); |
|
|
|
|
|
if (auto const x = std::get_if<IR::Term::CheckBit>(&terminal)) |
|
|
|
|
|
return EmitTerminalImpl(*this, *x, initial_location, is_single_step); |
|
|
|
|
|
if (auto const x = std::get_if<IR::Term::CheckHalt>(&terminal)) |
|
|
|
|
|
return EmitTerminalImpl(*this, *x, initial_location, is_single_step); |
|
|
|
|
|
UNREACHABLE(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void A64EmitX64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) { |
|
|
void A64EmitX64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) { |
|
|
|