// 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 __fi void operator()(T* func, u32 a1, const xRegisterLong& a2 = xEmptyReg) const { (*this)((const void*)func, a1, a2); } template __fi void operator()(T* func, const xIndirect32& a1) const { (*this)((const void*)func, a1); } template __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