2015-05-23 22:55:12 -06:00
|
|
|
// Copyright 2008 Dolphin Emulator Project
|
2021-07-04 19:22:19 -06:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2008-12-14 11:25:33 -07:00
|
|
|
|
2014-02-17 03:18:15 -07:00
|
|
|
#include "Common/x64ABI.h"
|
2021-12-09 19:22:16 -07:00
|
|
|
|
2014-09-07 19:06:58 -06:00
|
|
|
#include "Common/CommonTypes.h"
|
2014-02-17 03:18:15 -07:00
|
|
|
#include "Common/x64Emitter.h"
|
2008-12-07 22:30:24 -07:00
|
|
|
|
2008-07-31 14:22:35 -06:00
|
|
|
using namespace Gen;
|
2008-12-07 22:30:24 -07:00
|
|
|
|
2008-11-23 10:46:14 -07:00
|
|
|
// Shared code between Win64 and Unix64
|
2008-12-07 22:30:24 -07:00
|
|
|
|
2014-10-16 20:21:55 -06: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-29 20:51:07 -06: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 12:06:48 -06:00
|
|
|
size_t shadow = 0;
|
2014-08-03 12:42:06 -06:00
|
|
|
#if defined(_WIN32)
|
2013-09-29 20:51:07 -06: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 12:06:48 -06:00
|
|
|
|
2014-10-16 20:21:55 -06: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 12:06:48 -06:00
|
|
|
rsp_alignment -= count * 8;
|
|
|
|
size_t subtraction = 0;
|
2014-10-16 20:21:55 -06: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 12:06:48 -06:00
|
|
|
{
|
|
|
|
// If we have any XMMs to save, we must align the stack here.
|
|
|
|
subtraction = rsp_alignment & 0xf;
|
|
|
|
}
|
2014-10-16 20:21:55 -06: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 12:06:48 -06: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-16 20:21:55 -06: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 12:06:48 -06:00
|
|
|
{
|
2022-06-24 22:08:18 -06:00
|
|
|
mask[RSP] = false; // Stack pointer is never pushed
|
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 12:06:48 -06:00
|
|
|
size_t shadow, subtraction, xmm_offset;
|
|
|
|
ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction,
|
|
|
|
&xmm_offset);
|
|
|
|
|
2022-06-24 22:08:18 -06:00
|
|
|
if (mask[RBP])
|
|
|
|
{
|
|
|
|
// Make a nice stack frame for any debuggers or profilers that might be looking at this
|
|
|
|
PUSH(RBP);
|
|
|
|
MOV(64, R(RBP), R(RSP));
|
|
|
|
}
|
2022-08-11 22:57:28 -06:00
|
|
|
for (int r : (mask & ABI_ALL_GPRS & ~BitSet32{RBP}))
|
2015-02-15 12:43:31 -07:00
|
|
|
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 12:06:48 -06:00
|
|
|
|
|
|
|
if (subtraction)
|
|
|
|
SUB(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction));
|
|
|
|
|
2022-08-11 22:57:28 -06:00
|
|
|
for (int x : (mask & ABI_ALL_FPRS))
|
2013-09-29 20:51:07 -06:00
|
|
|
{
|
2015-02-15 12:43:31 -07:00
|
|
|
MOVAPD(MDisp(RSP, (int)xmm_offset), (X64Reg)(x - 16));
|
2014-10-16 20:21:55 -06:00
|
|
|
xmm_offset += 16;
|
2013-09-29 20:51:07 -06: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 12:06:48 -06:00
|
|
|
|
|
|
|
return shadow;
|
2013-09-29 20:51:07 -06:00
|
|
|
}
|
|
|
|
|
2014-10-16 20:21:55 -06:00
|
|
|
void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment,
|
|
|
|
size_t needed_frame_size)
|
2013-09-29 20:51:07 -06:00
|
|
|
{
|
2022-06-24 22:08:18 -06:00
|
|
|
mask[RSP] = false; // Stack pointer is never pushed
|
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 12:06:48 -06:00
|
|
|
size_t shadow, subtraction, xmm_offset;
|
|
|
|
ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction,
|
|
|
|
&xmm_offset);
|
|
|
|
|
2022-08-11 22:57:28 -06:00
|
|
|
for (int x : (mask & ABI_ALL_FPRS))
|
2013-09-29 20:51:07 -06:00
|
|
|
{
|
2014-10-16 20:21:55 -06:00
|
|
|
MOVAPD((X64Reg)(x - 16), MDisp(RSP, (int)xmm_offset));
|
|
|
|
xmm_offset += 16;
|
2013-09-29 20:51:07 -06: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 12:06:48 -06:00
|
|
|
if (subtraction)
|
|
|
|
ADD(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction));
|
|
|
|
|
2013-09-29 20:51:07 -06:00
|
|
|
for (int r = 15; r >= 0; r--)
|
|
|
|
{
|
2022-06-24 22:08:18 -06:00
|
|
|
if (r != RBP && mask[r])
|
2015-02-15 12:43:31 -07:00
|
|
|
POP((X64Reg)r);
|
2013-09-29 20:51:07 -06:00
|
|
|
}
|
2022-06-24 22:08:18 -06:00
|
|
|
// RSP is pushed first and popped last to make debuggers/profilers happy
|
|
|
|
if (mask[RBP])
|
|
|
|
POP(RBP);
|
2013-09-29 20:51:07 -06:00
|
|
|
}
|
|
|
|
|
2015-01-02 16:32:23 -07:00
|
|
|
void XEmitter::MOVTwo(int bits, Gen::X64Reg dst1, Gen::X64Reg src1, s32 offset1, Gen::X64Reg dst2,
|
|
|
|
Gen::X64Reg src2)
|
2014-09-03 23:02:21 -06:00
|
|
|
{
|
|
|
|
if (dst1 == src2 && dst2 == src1)
|
|
|
|
{
|
2014-09-10 23:17:38 -06:00
|
|
|
XCHG(bits, R(src1), R(src2));
|
2015-01-02 16:32:23 -07:00
|
|
|
if (offset1)
|
|
|
|
ADD(bits, R(dst1), Imm32(offset1));
|
2014-09-03 23:02:21 -06:00
|
|
|
}
|
2014-09-10 23:17:38 -06:00
|
|
|
else if (src2 != dst1)
|
2014-09-03 23:02:21 -06:00
|
|
|
{
|
2015-01-02 16:32:23 -07:00
|
|
|
if (dst1 != src1 && offset1)
|
|
|
|
LEA(bits, dst1, MDisp(src1, offset1));
|
|
|
|
else if (dst1 != src1)
|
2014-09-03 23:02:21 -06:00
|
|
|
MOV(bits, R(dst1), R(src1));
|
2015-01-02 16:32:23 -07:00
|
|
|
else if (offset1)
|
|
|
|
ADD(bits, R(dst1), Imm32(offset1));
|
2014-09-03 23:02:21 -06:00
|
|
|
if (dst2 != src2)
|
|
|
|
MOV(bits, R(dst2), R(src2));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (dst2 != src2)
|
|
|
|
MOV(bits, R(dst2), R(src2));
|
2015-01-02 16:32:23 -07:00
|
|
|
if (dst1 != src1 && offset1)
|
|
|
|
LEA(bits, dst1, MDisp(src1, offset1));
|
|
|
|
else if (dst1 != src1)
|
2014-09-03 23:02:21 -06:00
|
|
|
MOV(bits, R(dst1), R(src1));
|
2015-01-02 16:32:23 -07:00
|
|
|
else if (offset1)
|
|
|
|
ADD(bits, R(dst1), Imm32(offset1));
|
2014-09-03 23:02:21 -06:00
|
|
|
}
|
|
|
|
}
|