From 2ffd6a09aff19a677c64d0ad0feec87901a7209e Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Wed, 15 Jan 2025 00:48:19 +1100 Subject: -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. --- src/devices/cpu/drcbearm64.cpp | 2 +- src/devices/cpu/drcbex64.cpp | 48 +++++++++++++++++++++--------------------- src/devices/cpu/drcbex86.cpp | 44 +++++++++++++++++++------------------- src/lib/util/delegate.cpp | 4 ++-- src/lib/util/mfpresolve.h | 12 +++++------ 5 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/devices/cpu/drcbearm64.cpp b/src/devices/cpu/drcbearm64.cpp index bc956d84c38..d6e5e03d024 100644 --- a/src/devices/cpu/drcbearm64.cpp +++ b/src/devices/cpu/drcbearm64.cpp @@ -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(entrypoint); handler.obj = adjusted; }; diff --git a/src/devices/cpu/drcbex64.cpp b/src/devices/cpu/drcbex64.cpp index aa7b3dc68e2..880ad231868 100644 --- a/src/devices/cpu/drcbex64.cpp +++ b/src/devices/cpu/drcbex64.cpp @@ -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(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); diff --git a/src/devices/cpu/drcbex86.cpp b/src/devices/cpu/drcbex86.cpp index f97ef780468..6d7c6c1de1d 100644 --- a/src/devices/cpu/drcbex86.cpp +++ b/src/devices/cpu/drcbex86.cpp @@ -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(); } } diff --git a/src/lib/util/delegate.cpp b/src/lib/util/delegate.cpp index 67fb7e72d42..fb2fd4e2091 100644 --- a/src/lib/util/delegate.cpp +++ b/src/lib/util/delegate.cpp @@ -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(adjusted); return reinterpret_cast(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(adjusted); return reinterpret_cast(entrypoint); } diff --git a/src/lib/util/mfpresolve.h b/src/lib/util/mfpresolve.h index eee3711ebea..7661623572a 100644 --- a/src/lib/util/mfpresolve.h +++ b/src/lib/util/mfpresolve.h @@ -42,18 +42,18 @@ inline T bypass_member_function_thunks(T entrypoint, U const *object) noexcept template -inline std::pair resolve_member_function(Ret (T::*function)(Params...), T *object) noexcept +inline std::pair 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(&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 resolve_member_function(Ret (T: template -inline std::pair resolve_member_function(Ret (T::*function)(Params...) const, T const *object) noexcept +inline std::pair 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(&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 { -- cgit v1.2.3