@ -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 . Ge tT erminal( ) , 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 . EmitLeaf Terminal ( 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 . EmitLeaf Terminal ( 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 . EmitLeaf Terminal ( 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 . EmitLeaf Terminal ( 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 ) {