mirror of
https://github.com/libretro/parallel-ps2.git
synced 2026-11-10 17:26:34 -10:00
Two related removals, and one optimisation that fell out of the second.
The cursor accessors go. xGetPtr(), xSetPtr() and
xGetAlignedCallTarget() were macros over x86Ptr, kept -- per their own
comment -- against a future change of storage scheme that never came
in fifteen years; xGetAlignedCallTarget() did no alignment at all, it
was the cursor under a misleading name. 23 files now read and assign
x86Ptr directly.
legacy_instructions.h goes with them. Its jump half (J8Rel/J32Rel and
the JE8/JMP32/... macros over them, plus x86SetJ8/J32/J32A) duplicated
what the C89 core already does with xe_fwd_jcc8/32 and xe_fwd_set8/32:
145 call sites across iFPU, iFPUd, iMMI, iR5900Branch, iR3000Atables
and iR3000A convert mechanically. Its SSE half -- eight
SSE*_XMM_to_XMM wrappers -- had exact xe_* equivalents already, same
prefix and opcode.
Four things needed more than a rename, and they are the reason this is
one commit rather than a sed:
* x86SetJ32A padded to a 16-byte boundary with NOPs before patching.
The core had no equivalent, so xe_fwd_set32_aligned is new rather
than the alignment being quietly dropped.
* The branch bookkeeping was typed u32* because the legacy API
returned that; the C89 slot is e_u8*. recDoBranchImm's signature,
recSetBranchEQ/L's returns, _setupBranchTest's function-pointer
parameter (now a Jcc code) and ~20 locals follow.
* JNS8 mapped to a condition the enum does not spell: there is no
Jcc_NotSigned, the member is Jcc_Unsigned = 0x9. Mapped explicitly
with a comment, since it reads like a typo otherwise.
* The SSE wrappers were stored in function-pointer tables
(recComOpXMM_to_XMM in iFPU, recFPUOpXMM_to_XMM in iFPUd). Macros
have no address, so the tables become switches -- and since op is
a constant at every call site, that removes an indirect call from
the recompiler's emit path and lets the emission inline. That is
the optimisation: the tables were costing a call to save nothing.
tests/emitter/newbind.cpp oracled the eight C wrappers; it now oracles
the macros the recompilers actually call, which is the better test
anyway, and the reference tree drops its include of the deleted
header.
Verification: gates 36/36 in both configurations, byte suites green
(95,692 + 112,118 + 27,337, zero divergent -- the newbind figure is
unchanged because the same 8x16x16 cases are still covered, through
the macros now), Tekken and the 2048 ELF clean at 3000 real-BIOS
frames, and all four JIT region hashes identical to the previous
build. 145 jump sites and two dispatch tables rewritten with no
change to a single emitted byte.
165 lines
3.7 KiB
C++
165 lines
3.7 KiB
C++
/* PCSX2 - PS2 Emulator for PCs
|
|
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
|
*
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* ix86 core v0.9.1
|
|
*
|
|
* Original Authors (v0.6.2 and prior):
|
|
* linuzappz <[email protected]>
|
|
* alexey silinov
|
|
* goldfinger
|
|
* zerofrog(@gmail.com)
|
|
*
|
|
* Authors of v0.9.1:
|
|
* Jake.Stine(@gmail.com)
|
|
* cottonvibes(@gmail.com)
|
|
* sudonim([email protected])
|
|
*/
|
|
|
|
#include "tests/emitter/reference/internal.h"
|
|
|
|
namespace x86Emitter
|
|
{
|
|
|
|
void xImpl_JmpCall::operator()(const xAddressReg& absreg) const
|
|
{
|
|
// Jumps are always wide and don't need the rex.W
|
|
xOpWrite(0, 0xff, isJmp ? 4 : 2, absreg.GetNonWide());
|
|
}
|
|
void xImpl_JmpCall::operator()(const xIndirectNative& src) const
|
|
{
|
|
// Jumps are always wide and don't need the rex.W
|
|
EmitRex(0, xIndirect32(src.Base, src.Index, 1, 0));
|
|
xWrite8(0xff);
|
|
EmitSibMagic(isJmp ? 4 : 2, src);
|
|
}
|
|
|
|
#ifndef PCSX2_C89_EMITTER
|
|
const xImpl_JmpCall xJMP = {true};
|
|
#endif
|
|
#ifndef PCSX2_C89_EMITTER
|
|
const xImpl_JmpCall xCALL = {false};
|
|
|
|
|
|
#endif
|
|
template <typename Reg1, typename Reg2>
|
|
void prepareRegsForFastcall(const Reg1& a1, const Reg2& a2)
|
|
{
|
|
if (a1.IsEmpty())
|
|
return;
|
|
|
|
// Make sure we don't mess up if someone tries to fastcall with a1 in arg2reg and a2 in arg1reg
|
|
if (a2.Id != arg1reg.Id)
|
|
{
|
|
xMOV(Reg1(arg1reg), a1);
|
|
if (!a2.IsEmpty())
|
|
{
|
|
xMOV(Reg2(arg2reg), a2);
|
|
}
|
|
}
|
|
else if (a1.Id != arg2reg.Id)
|
|
{
|
|
xMOV(Reg2(arg2reg), a2);
|
|
xMOV(Reg1(arg1reg), a1);
|
|
}
|
|
else
|
|
{
|
|
xPUSH(a1);
|
|
xMOV(Reg2(arg2reg), a2);
|
|
xPOP(Reg1(arg1reg));
|
|
}
|
|
}
|
|
|
|
void xImpl_FastCall::operator()(const void* f, const xRegister32& a1, const xRegister32& a2) const
|
|
{
|
|
prepareRegsForFastcall(a1, a2);
|
|
uptr disp = ((uptr)x86Ptr + 5) - (uptr)f;
|
|
if ((sptr)disp == (s32)disp)
|
|
{
|
|
xCALL(f);
|
|
}
|
|
else
|
|
{
|
|
xLEA(rax, ptr64[f]);
|
|
xCALL(rax);
|
|
}
|
|
}
|
|
|
|
void xImpl_FastCall::operator()(const void* f, const xRegisterLong& a1, const xRegisterLong& a2) const
|
|
{
|
|
prepareRegsForFastcall(a1, a2);
|
|
uptr disp = ((uptr)x86Ptr + 5) - (uptr)f;
|
|
if ((sptr)disp == (s32)disp)
|
|
{
|
|
xCALL(f);
|
|
}
|
|
else
|
|
{
|
|
xLEA(rax, ptr64[f]);
|
|
xCALL(rax);
|
|
}
|
|
}
|
|
|
|
void xImpl_FastCall::operator()(const void* f, u32 a1, const xRegisterLong& a2) const
|
|
{
|
|
if (!a2.IsEmpty())
|
|
{
|
|
xMOV(arg2reg, a2);
|
|
}
|
|
xMOV(arg1reg, a1);
|
|
(*this)(f, arg1reg, arg2reg);
|
|
}
|
|
|
|
void xImpl_FastCall::operator()(const void* f, void* a1) const
|
|
{
|
|
xLEA(arg1reg, ptr[a1]);
|
|
(*this)(f, arg1reg, arg2reg);
|
|
}
|
|
|
|
void xImpl_FastCall::operator()(const void* f, u32 a1, const xRegister32& a2) const
|
|
{
|
|
if (!a2.IsEmpty())
|
|
{
|
|
xMOV(arg2regd, a2);
|
|
}
|
|
xMOV(arg1regd, a1);
|
|
(*this)(f, arg1regd, arg2regd);
|
|
}
|
|
|
|
void xImpl_FastCall::operator()(const void* f, const xIndirect32& a1) const
|
|
{
|
|
xMOV(arg1regd, a1);
|
|
(*this)(f, arg1regd);
|
|
}
|
|
|
|
void xImpl_FastCall::operator()(const void* f, u32 a1, u32 a2) const
|
|
{
|
|
xMOV(arg1regd, a1);
|
|
xMOV(arg2regd, a2);
|
|
(*this)(f, arg1regd, arg2regd);
|
|
}
|
|
|
|
void xImpl_FastCall::operator()(const xIndirectNative& f, const xRegisterLong& a1, const xRegisterLong& a2) const
|
|
{
|
|
prepareRegsForFastcall(a1, a2);
|
|
xCALL(f);
|
|
}
|
|
|
|
#ifndef PCSX2_C89_EMITTER
|
|
const xImpl_FastCall xFastCall = {};
|
|
#endif
|
|
|
|
} // namespace x86Emitter
|