mirror of
https://github.com/holub/mame
synced 2025-06-04 03:46:29 +03:00
-cpu/drcbex64.cpp: Be nicer to the return address predictor.
-cpu/drcbex86.cpp: Give hints to use short displacements for jumps to local unbound labels. -util/mfpresolve.h: Use references for some things that must not be null pointers.
This commit is contained in:
parent
96736e433e
commit
2ffd6a09af
@ -911,7 +911,7 @@ drcbe_arm64::drcbe_arm64(drcuml_state &drcuml, device_t &device, drc_cache &cach
|
||||
auto const resolve_accessor =
|
||||
[] (resolved_handler &handler, address_space &space, auto accessor)
|
||||
{
|
||||
auto const [entrypoint, adjusted] = util::resolve_member_function(accessor, &space);
|
||||
auto const [entrypoint, adjusted] = util::resolve_member_function(accessor, space);
|
||||
handler.func = reinterpret_cast<uint8_t *>(entrypoint);
|
||||
handler.obj = adjusted;
|
||||
};
|
||||
|
@ -2,7 +2,7 @@
|
||||
// copyright-holders:Aaron Giles
|
||||
/***************************************************************************
|
||||
|
||||
drcbex64.c
|
||||
drcbex64.cpp
|
||||
|
||||
64-bit x64 back-end for the universal machine language.
|
||||
|
||||
@ -158,10 +158,10 @@
|
||||
[rsp+48] - saved r14
|
||||
[rsp+56] - saved r13
|
||||
[rsp+64] - saved r12
|
||||
[rsp+72] - saved ebp
|
||||
[rsp+80] - saved edi
|
||||
[rsp+88] - saved esi
|
||||
[rsp+96] - saved ebx
|
||||
[rsp+72] - saved rbp
|
||||
[rsp+80] - saved rdi
|
||||
[rsp+88] - saved rsi
|
||||
[rsp+96] - saved rbx
|
||||
[rsp+104] - ret
|
||||
|
||||
***************************************************************************/
|
||||
@ -696,7 +696,7 @@ drcbe_x64::drcbe_x64(drcuml_state &drcuml, device_t &device, drc_cache &cache, u
|
||||
auto const resolve_accessor =
|
||||
[] (resolved_handler &handler, address_space &space, auto accessor)
|
||||
{
|
||||
auto const [entrypoint, adjusted] = util::resolve_member_function(accessor, &space);
|
||||
auto const [entrypoint, adjusted] = util::resolve_member_function(accessor, space);
|
||||
handler.func = reinterpret_cast<x86code *>(entrypoint);
|
||||
handler.obj = adjusted;
|
||||
};
|
||||
@ -837,9 +837,8 @@ void drcbe_x64::reset()
|
||||
a.emitProlog(frame);
|
||||
a.emitArgsAssignment(frame, args);
|
||||
|
||||
a.sub(rsp, 32);
|
||||
a.sub(rsp, 40);
|
||||
a.mov(MABS(&m_near.hashstacksave), rsp);
|
||||
a.sub(rsp, 8);
|
||||
a.mov(MABS(&m_near.stacksave), rsp);
|
||||
a.stmxcsr(MABS(&m_near.ssemode));
|
||||
a.jmp(Gpq(REG_PARAM2));
|
||||
@ -849,13 +848,13 @@ void drcbe_x64::reset()
|
||||
a.bind(a.newNamedLabel("exit_point"));
|
||||
a.ldmxcsr(MABS(&m_near.ssemode));
|
||||
a.mov(rsp, MABS(&m_near.hashstacksave));
|
||||
a.add(rsp, 32);
|
||||
a.add(rsp, 40);
|
||||
a.emitEpilog(frame);
|
||||
|
||||
// generate a no code point
|
||||
m_nocode = dst + a.offset();
|
||||
a.bind(a.newNamedLabel("nocode_point"));
|
||||
a.ret();
|
||||
a.jmp(Gpq(REG_PARAM1));
|
||||
|
||||
// emit the generated code
|
||||
size_t bytes = emit(ch);
|
||||
@ -1612,30 +1611,32 @@ void drcbe_x64::op_hashjmp(Assembler &a, const instruction &inst)
|
||||
smart_call_m64(a, &m_near.debug_log_hashjmp);
|
||||
}
|
||||
|
||||
// load the stack base one word early so we end up at the right spot after our call below
|
||||
// load the stack base
|
||||
Label nocode = a.newLabel();
|
||||
a.mov(rsp, MABS(&m_near.hashstacksave)); // mov rsp,[hashstacksave]
|
||||
|
||||
// fixed mode cases
|
||||
if (modep.is_immediate() && m_hash.is_mode_populated(modep.immediate()))
|
||||
{
|
||||
// a straight immediate jump is direct, though we need the PC in EAX in case of failure
|
||||
if (pcp.is_immediate())
|
||||
{
|
||||
// a straight immediate jump is direct, though we need the PC in EAX in case of failure
|
||||
uint32_t l1val = (pcp.immediate() >> m_hash.l1shift()) & m_hash.l1mask();
|
||||
uint32_t l2val = (pcp.immediate() >> m_hash.l2shift()) & m_hash.l2mask();
|
||||
a.call(MABS(&m_hash.base()[modep.immediate()][l1val][l2val])); // call hash[modep][l1val][l2val]
|
||||
a.short_().lea(Gpq(REG_PARAM1), ptr(nocode)); // lea rcx,[rip+nocode]
|
||||
a.jmp(MABS(&m_hash.base()[modep.immediate()][l1val][l2val])); // jmp hash[modep][l1val][l2val]
|
||||
}
|
||||
|
||||
// a fixed mode but variable PC
|
||||
else
|
||||
{
|
||||
// a fixed mode but variable PC
|
||||
mov_reg_param(a, eax, pcp); // mov eax,pcp
|
||||
a.mov(edx, eax); // mov edx,eax
|
||||
a.shr(edx, m_hash.l1shift()); // shr edx,l1shift
|
||||
a.and_(eax, m_hash.l2mask() << m_hash.l2shift()); // and eax,l2mask << l2shift
|
||||
a.mov(rdx, ptr(rbp, rdx, 3, offset_from_rbp(&m_hash.base()[modep.immediate()][0])));
|
||||
// mov rdx,hash[modep+edx*8]
|
||||
a.call(ptr(rdx, rax, 3 - m_hash.l2shift())); // call [rdx+rax*shift]
|
||||
a.short_().lea(Gpq(REG_PARAM1), ptr(nocode)); // lea rcx,[rip+nocode]
|
||||
a.jmp(ptr(rdx, rax, 3 - m_hash.l2shift())); // jmp [rdx+rax*shift]
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1645,31 +1646,30 @@ void drcbe_x64::op_hashjmp(Assembler &a, const instruction &inst)
|
||||
mov_reg_param(a, modereg, modep); // mov modereg,modep
|
||||
a.mov(rcx, ptr(rbp, modereg, 3, offset_from_rbp(m_hash.base()))); // mov rcx,hash[modereg*8]
|
||||
|
||||
// fixed PC
|
||||
if (pcp.is_immediate())
|
||||
{
|
||||
// fixed PC
|
||||
uint32_t l1val = (pcp.immediate() >> m_hash.l1shift()) & m_hash.l1mask();
|
||||
uint32_t l2val = (pcp.immediate() >> m_hash.l2shift()) & m_hash.l2mask();
|
||||
a.mov(rdx, ptr(rcx, l1val * 8)); // mov rdx,[rcx+l1val*8]
|
||||
a.call(ptr(rdx, l2val * 8)); // call [l2val*8]
|
||||
a.short_().lea(Gpq(REG_PARAM1), ptr(nocode)); // lea rcx,[rip+nocode]
|
||||
a.jmp(ptr(rdx, l2val * 8)); // jmp [l2val*8]
|
||||
}
|
||||
|
||||
// variable PC
|
||||
else
|
||||
{
|
||||
// variable PC
|
||||
mov_reg_param(a, eax, pcp); // mov eax,pcp
|
||||
a.mov(edx, eax); // mov edx,eax
|
||||
a.shr(edx, m_hash.l1shift()); // shr edx,l1shift
|
||||
a.mov(rdx, ptr(rcx, rdx, 3)); // mov rdx,[rcx+rdx*8]
|
||||
a.and_(eax, m_hash.l2mask() << m_hash.l2shift()); // and eax,l2mask << l2shift
|
||||
a.call(ptr(rdx, rax, 3 - m_hash.l2shift())); // call [rdx+rax*shift]
|
||||
a.short_().lea(Gpq(REG_PARAM1), ptr(nocode)); // lea rcx,[rip+nocode]
|
||||
a.jmp(ptr(rdx, rax, 3 - m_hash.l2shift())); // jmp [rdx+rax*shift]
|
||||
}
|
||||
}
|
||||
|
||||
// fix stack alignment if "no code" landing returned from abuse of call with misaligned stack
|
||||
a.sub(rsp, 8); // sub rsp,8
|
||||
|
||||
// in all cases, if there is no code, we return here to generate the exception
|
||||
a.bind(nocode);
|
||||
if (LOG_HASHJMPS)
|
||||
smart_call_m64(a, &m_near.debug_log_hashjmp_fail);
|
||||
|
||||
|
@ -2173,11 +2173,11 @@ void drcbe_x86::emit_rcl_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi,
|
||||
a.and_(ecx, 63);
|
||||
a.popfd();
|
||||
|
||||
a.jecxz(skipall);
|
||||
a.short_().jecxz(skipall);
|
||||
a.lea(ecx, ptr(ecx, -1));
|
||||
|
||||
a.bind(loop);
|
||||
a.jecxz(skiploop);
|
||||
a.short_().jecxz(skiploop);
|
||||
a.lea(ecx, ptr(ecx, -1));
|
||||
a.rcl(reglo, 1);
|
||||
a.rcl(reghi, 1);
|
||||
@ -2231,11 +2231,11 @@ void drcbe_x86::emit_rcr_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi,
|
||||
a.and_(ecx, 63);
|
||||
a.popfd();
|
||||
|
||||
a.jecxz(skipall);
|
||||
a.short_().jecxz(skipall);
|
||||
a.lea(ecx, ptr(ecx, -1));
|
||||
|
||||
a.bind(loop);
|
||||
a.jecxz(skiploop);
|
||||
a.short_().jecxz(skiploop);
|
||||
a.lea(ecx, ptr(ecx, -1));
|
||||
a.rcr(reghi, 1);
|
||||
a.rcr(reglo, 1);
|
||||
@ -2674,9 +2674,9 @@ void drcbe_x86::op_jmp(Assembler &a, const instruction &inst)
|
||||
jmptarget = a.newNamedLabel(labelName.c_str());
|
||||
|
||||
if (inst.condition() == uml::COND_ALWAYS)
|
||||
a.jmp(jmptarget); // jmp target
|
||||
a.jmp(jmptarget);
|
||||
else
|
||||
a.j(X86_CONDITION(inst.condition()), jmptarget); // jcc target
|
||||
a.j(X86_CONDITION(inst.condition()), jmptarget);
|
||||
}
|
||||
|
||||
|
||||
@ -2774,7 +2774,7 @@ void drcbe_x86::op_ret(Assembler &a, const instruction &inst)
|
||||
if (inst.condition() != uml::COND_ALWAYS)
|
||||
{
|
||||
skip = a.newLabel();
|
||||
a.j(X86_NOT_CONDITION(inst.condition()), skip); // jcc skip
|
||||
a.short_().j(X86_NOT_CONDITION(inst.condition()), skip);
|
||||
}
|
||||
|
||||
// return
|
||||
@ -2811,17 +2811,17 @@ void drcbe_x86::op_callc(Assembler &a, const instruction &inst)
|
||||
if (inst.condition() != uml::COND_ALWAYS)
|
||||
{
|
||||
skip = a.newLabel();
|
||||
a.j(X86_NOT_CONDITION(inst.condition()), skip); // jcc skip
|
||||
a.short_().j(X86_NOT_CONDITION(inst.condition()), skip);
|
||||
}
|
||||
|
||||
// perform the call
|
||||
a.mov(dword_ptr(esp, 0), imm(paramp.memory())); // mov [esp],paramp
|
||||
a.call(imm(funcp.cfunc())); // call funcp
|
||||
a.mov(dword_ptr(esp, 0), imm(paramp.memory()));
|
||||
a.call(imm(funcp.cfunc()));
|
||||
|
||||
// resolve the conditional link
|
||||
if (inst.condition() != uml::COND_ALWAYS)
|
||||
{
|
||||
a.bind(skip); // skip:
|
||||
a.bind(skip);
|
||||
reset_last_upper_lower_reg();
|
||||
}
|
||||
}
|
||||
@ -3738,7 +3738,7 @@ void drcbe_x86::op_carry(Assembler &a, const instruction &inst)
|
||||
Label higher = a.newLabel();
|
||||
|
||||
a.cmp(ecx, 32);
|
||||
a.jge(higher);
|
||||
a.short_().jge(higher);
|
||||
|
||||
if (srcp.is_memory())
|
||||
{
|
||||
@ -4795,7 +4795,7 @@ void drcbe_x86::op_divu(Assembler &a, const instruction &inst)
|
||||
a.add(eax, eax); // add eax,eax
|
||||
}
|
||||
Label skip = a.newLabel();
|
||||
a.jecxz(skip); // jecxz skip
|
||||
a.short_().jecxz(skip); // jecxz skip
|
||||
emit_mov_r32_p32(a, eax, src1p); // mov eax,src1p
|
||||
a.xor_(edx, edx); // xor edx,edx
|
||||
a.div(ecx); // div ecx
|
||||
@ -4866,7 +4866,7 @@ void drcbe_x86::op_divs(Assembler &a, const instruction &inst)
|
||||
a.add(eax, eax); // add eax,eax
|
||||
}
|
||||
Label skip = a.newLabel();
|
||||
a.jecxz(skip); // jecxz skip
|
||||
a.short_().jecxz(skip); // jecxz skip
|
||||
emit_mov_r32_p32(a, eax, src1p); // mov eax,src1p
|
||||
a.cdq(); // cdq
|
||||
a.idiv(ecx); // idiv ecx
|
||||
@ -5430,7 +5430,7 @@ void drcbe_x86::op_lzcnt(Assembler &a, const instruction &inst)
|
||||
Label end = a.newLabel();
|
||||
|
||||
a.bsr(edx, edx);
|
||||
a.jz(skip);
|
||||
a.short_().jz(skip);
|
||||
a.xor_(edx, 31 ^ 63);
|
||||
a.mov(dstreg, edx);
|
||||
a.short_().jmp(end);
|
||||
@ -5494,7 +5494,7 @@ void drcbe_x86::op_tzcnt(Assembler &a, const instruction &inst)
|
||||
Label skip = a.newLabel();
|
||||
emit_mov_r64_p64(a, dstreg, edx, srcp); // mov dstreg:edx,srcp
|
||||
a.bsf(dstreg, dstreg); // bsf dstreg,dstreg
|
||||
a.jnz(skip); // jnz skip
|
||||
a.short_().jnz(skip); // jnz skip
|
||||
a.mov(ecx, 32); // mov ecx,32
|
||||
a.bsf(dstreg, edx); // bsf dstreg,edx
|
||||
a.cmovz(dstreg, ecx); // cmovz dstreg,ecx
|
||||
@ -6126,21 +6126,21 @@ void drcbe_x86::op_fmov(Assembler &a, const instruction &inst)
|
||||
if (inst.condition() != uml::COND_ALWAYS)
|
||||
{
|
||||
skip = a.newLabel();
|
||||
a.j(X86_NOT_CONDITION(inst.condition()), skip); // jcc skip
|
||||
a.short_().j(X86_NOT_CONDITION(inst.condition()), skip);
|
||||
}
|
||||
|
||||
// general case
|
||||
a.mov(eax, MABS(srcp.memory(0))); // mov eax,[srcp]
|
||||
a.mov(eax, MABS(srcp.memory(0)));
|
||||
if (inst.size() == 8)
|
||||
a.mov(edx, MABS(srcp.memory(4))); // mov edx,[srcp + 4]
|
||||
a.mov(MABS(dstp.memory(0)), eax); // mov [dstp],eax
|
||||
a.mov(edx, MABS(srcp.memory(4)));
|
||||
a.mov(MABS(dstp.memory(0)), eax);
|
||||
if (inst.size() == 8)
|
||||
a.mov(MABS(dstp.memory(4)), edx); // mov [dstp + 4],edx
|
||||
a.mov(MABS(dstp.memory(4)), edx);
|
||||
|
||||
// resolve the jump
|
||||
if (inst.condition() != uml::COND_ALWAYS)
|
||||
{
|
||||
a.bind(skip); // skip:
|
||||
a.bind(skip);
|
||||
reset_last_upper_lower_reg();
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ const delegate_mfp_compatible::raw_mfp_data delegate_mfp_compatible::s_null_mfp
|
||||
|
||||
delegate_generic_function delegate_mfp_itanium::convert_to_generic(delegate_generic_class *&object) const
|
||||
{
|
||||
auto const [entrypoint, adjusted] = detail::resolve_member_function_itanium(m_function, m_this_delta, object);
|
||||
auto const [entrypoint, adjusted] = resolve_member_function_itanium(m_function, m_this_delta, object);
|
||||
object = reinterpret_cast<delegate_generic_class *>(adjusted);
|
||||
return reinterpret_cast<delegate_generic_function>(entrypoint);
|
||||
}
|
||||
@ -87,7 +87,7 @@ delegate_generic_function delegate_mfp_itanium::convert_to_generic(delegate_gene
|
||||
|
||||
delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generic_class *&object) const
|
||||
{
|
||||
auto const [entrypoint, adjusted] = detail::resolve_member_function_msvc(&m_function, m_size, object);
|
||||
auto const [entrypoint, adjusted] = resolve_member_function_msvc(&m_function, m_size, object);
|
||||
object = reinterpret_cast<delegate_generic_class *>(adjusted);
|
||||
return reinterpret_cast<delegate_generic_function>(entrypoint);
|
||||
}
|
||||
|
@ -42,18 +42,18 @@ inline T bypass_member_function_thunks(T entrypoint, U const *object) noexcept
|
||||
|
||||
|
||||
template <typename T, typename Ret, typename... Params>
|
||||
inline std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function(Ret (T::*function)(Params...), T *object) noexcept
|
||||
inline std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function(Ret (T::*function)(Params...), T &object) noexcept
|
||||
{
|
||||
if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_ITANIUM)
|
||||
{
|
||||
struct { std::uintptr_t ptr; std::ptrdiff_t adj; } equiv;
|
||||
assert(sizeof(function) == sizeof(equiv));
|
||||
*reinterpret_cast<decltype(function) *>(&equiv) = function;
|
||||
return detail::resolve_member_function_itanium(equiv.ptr, equiv.adj, object);
|
||||
return detail::resolve_member_function_itanium(equiv.ptr, equiv.adj, &object);
|
||||
}
|
||||
else if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_MSVC)
|
||||
{
|
||||
return detail::resolve_member_function_msvc(&function, sizeof(function), object);
|
||||
return detail::resolve_member_function_msvc(&function, sizeof(function), &object);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -63,18 +63,18 @@ inline std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function(Ret (T:
|
||||
|
||||
|
||||
template <typename T, typename Ret, typename... Params>
|
||||
inline std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function(Ret (T::*function)(Params...) const, T const *object) noexcept
|
||||
inline std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function(Ret (T::*function)(Params...) const, T const &object) noexcept
|
||||
{
|
||||
if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_ITANIUM)
|
||||
{
|
||||
struct { std::uintptr_t ptr; std::ptrdiff_t adj; } equiv;
|
||||
assert(sizeof(function) == sizeof(equiv));
|
||||
*reinterpret_cast<decltype(function) *>(&equiv) = function;
|
||||
return detail::resolve_member_function_itanium(equiv.ptr, equiv.adj, object);
|
||||
return detail::resolve_member_function_itanium(equiv.ptr, equiv.adj, &object);
|
||||
}
|
||||
else if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_MSVC)
|
||||
{
|
||||
return detail::resolve_member_function_msvc(&function, sizeof(function), object);
|
||||
return detail::resolve_member_function_msvc(&function, sizeof(function), &object);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user