pcsx2/common/emitter/implement/jmpcall.h

81 lines
2.6 KiB
C++

// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#pragma once
// Implementations found here: CALL and JMP! (unconditional only)
namespace x86Emitter
{
extern void xJccKnownTarget(JccComparisonType comparison, const void* target, bool slideForward);
// ------------------------------------------------------------------------
struct xImpl_JmpCall
{
bool isJmp;
void operator()(const xAddressReg& absreg) const;
void operator()(const xIndirectNative& src) const;
// Special form for calling functions. This form automatically resolves the
// correct displacement based on the size of the instruction being generated.
void operator()(const void* func) const
{
if (isJmp)
xJccKnownTarget(Jcc_Unconditional, (const void*)(uptr)func, false); // double cast to/from (uptr) needed to appease GCC
else
{
// calls are relative to the instruction after this one, and length is
// always 5 bytes (16 bit calls are bad mojo, so no bother to do special logic).
sptr dest = (sptr)func - ((sptr)xGetPtr() + 5);
pxAssertMsg(dest == (s32)dest, "Indirect jump is too far, must use a register!");
xWrite8(0xe8);
xWrite32(dest);
}
}
};
// yes it is awful. Due to template code is in a header with a nice circular dep.
extern const xImpl_Mov xMOV;
extern const xImpl_JmpCall xCALL;
struct xImpl_FastCall
{
// FIXME: current 64 bits is mostly a copy/past potentially it would require to push/pop
// some registers. But I think it is enough to handle the first call.
void operator()(const void* f, const xRegister32& a1 = xEmptyReg, const xRegister32& a2 = xEmptyReg) const;
void operator()(const void* f, u32 a1, const xRegister32& a2) const;
void operator()(const void* f, const xIndirect32& a1) const;
void operator()(const void* f, u32 a1, u32 a2) const;
void operator()(const void* f, void* a1) const;
void operator()(const void* f, const xRegisterLong& a1, const xRegisterLong& a2 = xEmptyReg) const;
void operator()(const void* f, u32 a1, const xRegisterLong& a2) const;
template <typename T>
__fi void operator()(T* func, u32 a1, const xRegisterLong& a2 = xEmptyReg) const
{
(*this)((const void*)func, a1, a2);
}
template <typename T>
__fi void operator()(T* func, const xIndirect32& a1) const
{
(*this)((const void*)func, a1);
}
template <typename T>
__fi void operator()(T* func, u32 a1, u32 a2) const
{
(*this)((const void*)func, a1, a2);
}
void operator()(const xIndirectNative& f, const xRegisterLong& a1 = xEmptyReg, const xRegisterLong& a2 = xEmptyReg) const;
};
} // End namespace x86Emitter