dolphin/Source/Core/Common/x64ABI.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

131 lines
3.6 KiB
C++
Raw Normal View History

// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Common/x64ABI.h"
2021-12-10 03:22:16 +01:00
#include "Common/CommonTypes.h"
#include "Common/x64Emitter.h"
using namespace Gen;
// Shared code between Win64 and Unix64
2014-10-17 04:21:55 +02: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)
{
size_t shadow = 0;
#if defined(_WIN32)
shadow = 0x20;
#endif
2014-10-17 04:21:55 +02:00
int count = (mask & ABI_ALL_GPRS).Count();
rsp_alignment -= count * 8;
size_t subtraction = 0;
2014-10-17 04:21:55 +02:00
int fpr_count = (mask & ABI_ALL_FPRS).Count();
if (fpr_count)
{
// If we have any XMMs to save, we must align the stack here.
subtraction = rsp_alignment & 0xf;
}
2014-10-17 04:21:55 +02:00
subtraction += 16 * fpr_count;
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 04:21:55 +02:00
size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment,
size_t needed_frame_size)
{
mask[RSP] = false; // Stack pointer is never pushed
size_t shadow, subtraction, xmm_offset;
ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction,
&xmm_offset);
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));
}
for (int r : (mask & ABI_ALL_GPRS & ~BitSet32{RBP}))
PUSH((X64Reg)r);
if (subtraction)
SUB(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction));
for (int x : (mask & ABI_ALL_FPRS))
{
MOVAPD(MDisp(RSP, (int)xmm_offset), (X64Reg)(x - 16));
2014-10-17 04:21:55 +02:00
xmm_offset += 16;
}
return shadow;
}
2014-10-17 04:21:55 +02:00
void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment,
size_t needed_frame_size)
{
mask[RSP] = false; // Stack pointer is never pushed
size_t shadow, subtraction, xmm_offset;
ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction,
&xmm_offset);
for (int x : (mask & ABI_ALL_FPRS))
{
2014-10-17 04:21:55 +02:00
MOVAPD((X64Reg)(x - 16), MDisp(RSP, (int)xmm_offset));
xmm_offset += 16;
}
if (subtraction)
ADD(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction));
for (int r = 15; r >= 0; r--)
{
if (r != RBP && mask[r])
POP((X64Reg)r);
}
// RSP is pushed first and popped last to make debuggers/profilers happy
if (mask[RBP])
POP(RBP);
}
void XEmitter::MOVTwo(int bits, Gen::X64Reg dst1, Gen::X64Reg src1, s32 offset1, Gen::X64Reg dst2,
Gen::X64Reg src2)
{
if (dst1 == src2 && dst2 == src1)
{
XCHG(bits, R(src1), R(src2));
if (offset1)
ADD(bits, R(dst1), Imm32(offset1));
}
else if (src2 != dst1)
{
if (dst1 != src1 && offset1)
LEA(bits, dst1, MDisp(src1, offset1));
else if (dst1 != src1)
MOV(bits, R(dst1), R(src1));
else if (offset1)
ADD(bits, R(dst1), Imm32(offset1));
if (dst2 != src2)
MOV(bits, R(dst2), R(src2));
}
else
{
if (dst2 != src2)
MOV(bits, R(dst2), R(src2));
if (dst1 != src1 && offset1)
LEA(bits, dst1, MDisp(src1, offset1));
else if (dst1 != src1)
MOV(bits, R(dst1), R(src1));
else if (offset1)
ADD(bits, R(dst1), Imm32(offset1));
}
}