2013-04-18 03:09:55 +00:00
|
|
|
// Copyright 2013 Dolphin Emulator Project
|
|
|
|
// Licensed under GPLv2
|
|
|
|
// Refer to the license.txt file included.
|
2008-12-14 18:25:33 +00:00
|
|
|
|
2014-09-08 01:06:58 +00:00
|
|
|
#include "Common/CommonTypes.h"
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "Common/x64ABI.h"
|
|
|
|
#include "Common/x64Emitter.h"
|
2008-12-08 05:30:24 +00:00
|
|
|
|
|
|
|
using namespace Gen;
|
|
|
|
|
|
|
|
// Shared code between Win64 and Unix64
|
|
|
|
|
2014-10-17 02:21:55 +00:00
|
|
|
void XEmitter::ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp)
|
2013-09-30 02:51:07 +00:00
|
|
|
{
|
Improve code and clarify parameters to ABI_Push/PopRegistersAndAdjustStack.
- Factor common work into a helper function.
- Replace confusingly named "noProlog" with "rsp_alignment". Now that
x86 is not supported, we can just specify it explicitly as 8 for
clarity.
- Add the option to include more frame size, which I'll need later.
- Revert a change by magumagu in March which replaced MOVAPD with MOVUPD
on account of 32-bit Windows, since it's no longer supported. True,
apparently recent processors don't execute the former any faster if the
pointer is, in fact, aligned, but there's no point using MOVUPD for
something that's guaranteed to be aligned...
(I discovered that GenFrsqrte and GenFres were incorrectly passing false
to noProlog - they were, in fact, functions without prologs, the
original meaning of the parameter - which caused the previous change to
break. This is now fixed.)
2014-09-07 18:06:48 +00:00
|
|
|
size_t shadow = 0;
|
2014-08-03 18:42:06 +00:00
|
|
|
#if defined(_WIN32)
|
2013-09-30 02:51:07 +00:00
|
|
|
shadow = 0x20;
|
|
|
|
#endif
|
Improve code and clarify parameters to ABI_Push/PopRegistersAndAdjustStack.
- Factor common work into a helper function.
- Replace confusingly named "noProlog" with "rsp_alignment". Now that
x86 is not supported, we can just specify it explicitly as 8 for
clarity.
- Add the option to include more frame size, which I'll need later.
- Revert a change by magumagu in March which replaced MOVAPD with MOVUPD
on account of 32-bit Windows, since it's no longer supported. True,
apparently recent processors don't execute the former any faster if the
pointer is, in fact, aligned, but there's no point using MOVUPD for
something that's guaranteed to be aligned...
(I discovered that GenFrsqrte and GenFres were incorrectly passing false
to noProlog - they were, in fact, functions without prologs, the
original meaning of the parameter - which caused the previous change to
break. This is now fixed.)
2014-09-07 18:06:48 +00:00
|
|
|
|
2014-10-17 02:21:55 +00:00
|
|
|
int count = (mask & ABI_ALL_GPRS).Count();
|
Improve code and clarify parameters to ABI_Push/PopRegistersAndAdjustStack.
- Factor common work into a helper function.
- Replace confusingly named "noProlog" with "rsp_alignment". Now that
x86 is not supported, we can just specify it explicitly as 8 for
clarity.
- Add the option to include more frame size, which I'll need later.
- Revert a change by magumagu in March which replaced MOVAPD with MOVUPD
on account of 32-bit Windows, since it's no longer supported. True,
apparently recent processors don't execute the former any faster if the
pointer is, in fact, aligned, but there's no point using MOVUPD for
something that's guaranteed to be aligned...
(I discovered that GenFrsqrte and GenFres were incorrectly passing false
to noProlog - they were, in fact, functions without prologs, the
original meaning of the parameter - which caused the previous change to
break. This is now fixed.)
2014-09-07 18:06:48 +00:00
|
|
|
rsp_alignment -= count * 8;
|
|
|
|
size_t subtraction = 0;
|
2014-10-17 02:21:55 +00:00
|
|
|
int fpr_count = (mask & ABI_ALL_FPRS).Count();
|
|
|
|
if (fpr_count)
|
Improve code and clarify parameters to ABI_Push/PopRegistersAndAdjustStack.
- Factor common work into a helper function.
- Replace confusingly named "noProlog" with "rsp_alignment". Now that
x86 is not supported, we can just specify it explicitly as 8 for
clarity.
- Add the option to include more frame size, which I'll need later.
- Revert a change by magumagu in March which replaced MOVAPD with MOVUPD
on account of 32-bit Windows, since it's no longer supported. True,
apparently recent processors don't execute the former any faster if the
pointer is, in fact, aligned, but there's no point using MOVUPD for
something that's guaranteed to be aligned...
(I discovered that GenFrsqrte and GenFres were incorrectly passing false
to noProlog - they were, in fact, functions without prologs, the
original meaning of the parameter - which caused the previous change to
break. This is now fixed.)
2014-09-07 18:06:48 +00:00
|
|
|
{
|
|
|
|
// If we have any XMMs to save, we must align the stack here.
|
|
|
|
subtraction = rsp_alignment & 0xf;
|
|
|
|
}
|
2014-10-17 02:21:55 +00:00
|
|
|
subtraction += 16 * fpr_count;
|
Improve code and clarify parameters to ABI_Push/PopRegistersAndAdjustStack.
- Factor common work into a helper function.
- Replace confusingly named "noProlog" with "rsp_alignment". Now that
x86 is not supported, we can just specify it explicitly as 8 for
clarity.
- Add the option to include more frame size, which I'll need later.
- Revert a change by magumagu in March which replaced MOVAPD with MOVUPD
on account of 32-bit Windows, since it's no longer supported. True,
apparently recent processors don't execute the former any faster if the
pointer is, in fact, aligned, but there's no point using MOVUPD for
something that's guaranteed to be aligned...
(I discovered that GenFrsqrte and GenFres were incorrectly passing false
to noProlog - they were, in fact, functions without prologs, the
original meaning of the parameter - which caused the previous change to
break. This is now fixed.)
2014-09-07 18:06:48 +00:00
|
|
|
size_t xmm_base_subtraction = subtraction;
|
|
|
|
subtraction += needed_frame_size;
|
|
|
|
subtraction += shadow;
|
|
|
|
// Final alignment.
|
|
|
|
rsp_alignment -= subtraction;
|
|
|
|
subtraction += rsp_alignment & 0xf;
|
|
|
|
|
|
|
|
*shadowp = shadow;
|
|
|
|
*subtractionp = subtraction;
|
|
|
|
*xmm_offsetp = subtraction - xmm_base_subtraction;
|
|
|
|
}
|
|
|
|
|
2014-10-17 02:21:55 +00:00
|
|
|
size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size)
|
Improve code and clarify parameters to ABI_Push/PopRegistersAndAdjustStack.
- Factor common work into a helper function.
- Replace confusingly named "noProlog" with "rsp_alignment". Now that
x86 is not supported, we can just specify it explicitly as 8 for
clarity.
- Add the option to include more frame size, which I'll need later.
- Revert a change by magumagu in March which replaced MOVAPD with MOVUPD
on account of 32-bit Windows, since it's no longer supported. True,
apparently recent processors don't execute the former any faster if the
pointer is, in fact, aligned, but there's no point using MOVUPD for
something that's guaranteed to be aligned...
(I discovered that GenFrsqrte and GenFres were incorrectly passing false
to noProlog - they were, in fact, functions without prologs, the
original meaning of the parameter - which caused the previous change to
break. This is now fixed.)
2014-09-07 18:06:48 +00:00
|
|
|
{
|
|
|
|
size_t shadow, subtraction, xmm_offset;
|
|
|
|
ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, &xmm_offset);
|
|
|
|
|
2014-10-17 02:21:55 +00:00
|
|
|
for (int r : mask & ABI_ALL_GPRS)
|
|
|
|
PUSH((X64Reg) r);
|
Improve code and clarify parameters to ABI_Push/PopRegistersAndAdjustStack.
- Factor common work into a helper function.
- Replace confusingly named "noProlog" with "rsp_alignment". Now that
x86 is not supported, we can just specify it explicitly as 8 for
clarity.
- Add the option to include more frame size, which I'll need later.
- Revert a change by magumagu in March which replaced MOVAPD with MOVUPD
on account of 32-bit Windows, since it's no longer supported. True,
apparently recent processors don't execute the former any faster if the
pointer is, in fact, aligned, but there's no point using MOVUPD for
something that's guaranteed to be aligned...
(I discovered that GenFrsqrte and GenFres were incorrectly passing false
to noProlog - they were, in fact, functions without prologs, the
original meaning of the parameter - which caused the previous change to
break. This is now fixed.)
2014-09-07 18:06:48 +00:00
|
|
|
|
|
|
|
if (subtraction)
|
|
|
|
SUB(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction));
|
|
|
|
|
2014-10-17 02:21:55 +00:00
|
|
|
for (int x : mask & ABI_ALL_FPRS)
|
2013-09-30 02:51:07 +00:00
|
|
|
{
|
2014-10-17 02:21:55 +00:00
|
|
|
MOVAPD(MDisp(RSP, (int)xmm_offset), (X64Reg) (x - 16));
|
|
|
|
xmm_offset += 16;
|
2013-09-30 02:51:07 +00:00
|
|
|
}
|
Improve code and clarify parameters to ABI_Push/PopRegistersAndAdjustStack.
- Factor common work into a helper function.
- Replace confusingly named "noProlog" with "rsp_alignment". Now that
x86 is not supported, we can just specify it explicitly as 8 for
clarity.
- Add the option to include more frame size, which I'll need later.
- Revert a change by magumagu in March which replaced MOVAPD with MOVUPD
on account of 32-bit Windows, since it's no longer supported. True,
apparently recent processors don't execute the former any faster if the
pointer is, in fact, aligned, but there's no point using MOVUPD for
something that's guaranteed to be aligned...
(I discovered that GenFrsqrte and GenFres were incorrectly passing false
to noProlog - they were, in fact, functions without prologs, the
original meaning of the parameter - which caused the previous change to
break. This is now fixed.)
2014-09-07 18:06:48 +00:00
|
|
|
|
|
|
|
return shadow;
|
2013-09-30 02:51:07 +00:00
|
|
|
}
|
|
|
|
|
2014-10-17 02:21:55 +00:00
|
|
|
void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size)
|
2013-09-30 02:51:07 +00:00
|
|
|
{
|
Improve code and clarify parameters to ABI_Push/PopRegistersAndAdjustStack.
- Factor common work into a helper function.
- Replace confusingly named "noProlog" with "rsp_alignment". Now that
x86 is not supported, we can just specify it explicitly as 8 for
clarity.
- Add the option to include more frame size, which I'll need later.
- Revert a change by magumagu in March which replaced MOVAPD with MOVUPD
on account of 32-bit Windows, since it's no longer supported. True,
apparently recent processors don't execute the former any faster if the
pointer is, in fact, aligned, but there's no point using MOVUPD for
something that's guaranteed to be aligned...
(I discovered that GenFrsqrte and GenFres were incorrectly passing false
to noProlog - they were, in fact, functions without prologs, the
original meaning of the parameter - which caused the previous change to
break. This is now fixed.)
2014-09-07 18:06:48 +00:00
|
|
|
size_t shadow, subtraction, xmm_offset;
|
|
|
|
ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, &xmm_offset);
|
|
|
|
|
2014-10-17 02:21:55 +00:00
|
|
|
for (int x : mask & ABI_ALL_FPRS)
|
2013-09-30 02:51:07 +00:00
|
|
|
{
|
2014-10-17 02:21:55 +00:00
|
|
|
MOVAPD((X64Reg) (x - 16), MDisp(RSP, (int)xmm_offset));
|
|
|
|
xmm_offset += 16;
|
2013-09-30 02:51:07 +00:00
|
|
|
}
|
|
|
|
|
Improve code and clarify parameters to ABI_Push/PopRegistersAndAdjustStack.
- Factor common work into a helper function.
- Replace confusingly named "noProlog" with "rsp_alignment". Now that
x86 is not supported, we can just specify it explicitly as 8 for
clarity.
- Add the option to include more frame size, which I'll need later.
- Revert a change by magumagu in March which replaced MOVAPD with MOVUPD
on account of 32-bit Windows, since it's no longer supported. True,
apparently recent processors don't execute the former any faster if the
pointer is, in fact, aligned, but there's no point using MOVUPD for
something that's guaranteed to be aligned...
(I discovered that GenFrsqrte and GenFres were incorrectly passing false
to noProlog - they were, in fact, functions without prologs, the
original meaning of the parameter - which caused the previous change to
break. This is now fixed.)
2014-09-07 18:06:48 +00:00
|
|
|
if (subtraction)
|
|
|
|
ADD(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction));
|
|
|
|
|
2013-09-30 02:51:07 +00:00
|
|
|
for (int r = 15; r >= 0; r--)
|
|
|
|
{
|
2014-10-17 02:21:55 +00:00
|
|
|
if (mask[r])
|
2013-09-30 02:51:07 +00:00
|
|
|
POP((X64Reg) r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-28 01:26:56 +00:00
|
|
|
// Common functions
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunction(const void *func)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2010-10-02 20:04:03 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2010-10-02 20:04:03 +00:00
|
|
|
}
|
2010-03-24 11:22:33 +00:00
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionC16(const void *func, u16 param1)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2010-03-24 20:27:09 +00:00
|
|
|
MOV(32, R(ABI_PARAM1), Imm32((u32)param1));
|
2010-10-02 20:04:03 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2010-10-02 20:04:03 +00:00
|
|
|
}
|
2008-12-25 22:10:36 +00:00
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionCC16(const void *func, u32 param1, u16 param2)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2010-12-15 01:42:32 +00:00
|
|
|
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
|
|
|
MOV(32, R(ABI_PARAM2), Imm32((u32)param2));
|
2010-12-17 05:16:51 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-12-17 05:16:51 +00:00
|
|
|
CALL(func);
|
|
|
|
}
|
2010-12-15 01:42:32 +00:00
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionC(const void *func, u32 param1)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2008-12-08 05:30:24 +00:00
|
|
|
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
2010-10-02 20:04:03 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2010-10-02 20:04:03 +00:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionCC(const void *func, u32 param1, u32 param2)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2008-12-08 05:30:24 +00:00
|
|
|
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
|
|
|
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
2010-10-02 20:04:03 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2010-10-02 20:04:03 +00:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionCP(const void *func, u32 param1, void *param2)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2014-02-27 21:51:39 +00:00
|
|
|
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
|
|
|
MOV(64, R(ABI_PARAM2), Imm64((u64)param2));
|
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2014-02-27 21:51:39 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-02-27 21:51:39 +00:00
|
|
|
CALL(func);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionCCC(const void *func, u32 param1, u32 param2, u32 param3)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2009-07-11 10:18:25 +00:00
|
|
|
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
|
|
|
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
|
|
|
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
2010-10-02 20:04:03 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2010-10-02 20:04:03 +00:00
|
|
|
}
|
2009-07-11 10:18:25 +00:00
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionCCP(const void *func, u32 param1, u32 param2, void *param3)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2009-07-11 10:18:25 +00:00
|
|
|
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
|
|
|
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
|
|
|
MOV(64, R(ABI_PARAM3), Imm64((u64)param3));
|
2010-10-02 20:04:03 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2010-10-02 20:04:03 +00:00
|
|
|
}
|
2009-07-11 10:18:25 +00:00
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionCCCP(const void *func, u32 param1, u32 param2, u32 param3, void *param4)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2010-08-29 23:08:56 +00:00
|
|
|
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
|
|
|
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
|
|
|
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
|
|
|
MOV(64, R(ABI_PARAM4), Imm64((u64)param4));
|
2010-10-02 20:04:03 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2011-02-25 20:35:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionPC(const void *func, void *param1, u32 param2)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2014-02-27 21:51:39 +00:00
|
|
|
MOV(64, R(ABI_PARAM1), Imm64((u64)param1));
|
|
|
|
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2014-02-27 21:51:39 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-02-27 21:51:39 +00:00
|
|
|
CALL(func);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2, u32 param3)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2011-02-25 20:35:05 +00:00
|
|
|
MOV(64, R(ABI_PARAM1), Imm64((u64)param1));
|
|
|
|
MOV(64, R(ABI_PARAM2), Imm64((u64)param2));
|
|
|
|
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2010-10-02 20:04:03 +00:00
|
|
|
}
|
2010-08-29 23:08:56 +00:00
|
|
|
}
|
|
|
|
|
2010-04-13 10:18:05 +00:00
|
|
|
// Pass a register as a parameter.
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2008-12-08 05:30:24 +00:00
|
|
|
if (reg1 != ABI_PARAM1)
|
|
|
|
MOV(32, R(ABI_PARAM1), R(reg1));
|
2010-10-02 20:04:03 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2010-10-02 20:04:03 +00:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2010-04-13 10:18:05 +00:00
|
|
|
// Pass two registers as parameters.
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2)
|
2014-08-30 20:14:56 +00:00
|
|
|
{
|
2014-09-11 05:17:38 +00:00
|
|
|
MOVTwo(64, ABI_PARAM1, reg1, ABI_PARAM2, reg2);
|
2010-10-02 20:04:03 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2010-10-02 20:04:03 +00:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2014-09-11 05:17:38 +00:00
|
|
|
void XEmitter::MOVTwo(int bits, Gen::X64Reg dst1, Gen::X64Reg src1, Gen::X64Reg dst2, Gen::X64Reg src2)
|
2014-09-04 05:02:21 +00:00
|
|
|
{
|
|
|
|
if (dst1 == src2 && dst2 == src1)
|
|
|
|
{
|
2014-09-11 05:17:38 +00:00
|
|
|
XCHG(bits, R(src1), R(src2));
|
2014-09-04 05:02:21 +00:00
|
|
|
}
|
2014-09-11 05:17:38 +00:00
|
|
|
else if (src2 != dst1)
|
2014-09-04 05:02:21 +00:00
|
|
|
{
|
|
|
|
if (dst1 != src1)
|
|
|
|
MOV(bits, R(dst1), R(src1));
|
|
|
|
if (dst2 != src2)
|
|
|
|
MOV(bits, R(dst2), R(src2));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (dst2 != src2)
|
|
|
|
MOV(bits, R(dst2), R(src2));
|
|
|
|
if (dst1 != src1)
|
|
|
|
MOV(bits, R(dst1), R(src1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionAC(const void *func, const Gen::OpArg &arg1, u32 param2)
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
|
|
|
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
|
|
|
MOV(32, R(ABI_PARAM1), arg1);
|
|
|
|
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
2010-10-02 20:04:03 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2010-10-02 20:04:03 +00:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2014-10-10 15:56:17 +00:00
|
|
|
void XEmitter::ABI_CallFunctionA(const void *func, const Gen::OpArg &arg1)
|
2010-08-23 22:26:00 +00:00
|
|
|
{
|
|
|
|
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
|
|
|
MOV(32, R(ABI_PARAM1), arg1);
|
2010-10-02 20:04:03 +00:00
|
|
|
u64 distance = u64(func) - (u64(code) + 5);
|
2014-03-10 11:30:55 +00:00
|
|
|
if (distance >= 0x0000000080000000ULL &&
|
|
|
|
distance < 0xFFFFFFFF80000000ULL)
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
// Far call
|
|
|
|
MOV(64, R(RAX), Imm64((u64)func));
|
|
|
|
CALLptr(R(RAX));
|
2014-03-10 11:30:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-20 01:51:12 +00:00
|
|
|
CALL(func);
|
2010-10-02 20:04:03 +00:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|