2016-08-24 20:07:08 +01:00
|
|
|
// Copyright (C) 2003 Dolphin Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// 24th August 2016: This code was modified for Dynarmic.
|
|
|
|
|
2018-03-29 12:46:29 +01:00
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
|
|
|
|
2016-08-24 20:07:08 +01:00
|
|
|
#include <xbyak.h>
|
|
|
|
|
2018-08-14 19:13:47 +01:00
|
|
|
#include "backend/x64/abi.h"
|
2018-09-28 21:12:17 +01:00
|
|
|
#include "backend/x64/block_of_code.h"
|
2016-08-24 20:07:08 +01:00
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "common/iterator_util.h"
|
|
|
|
|
2020-04-08 11:46:36 +01:00
|
|
|
namespace Dynarmic::Backend::X64 {
|
2016-08-24 20:07:08 +01:00
|
|
|
|
|
|
|
constexpr size_t GPR_SIZE = 8;
|
|
|
|
constexpr size_t XMM_SIZE = 16;
|
|
|
|
|
|
|
|
struct FrameInfo {
|
|
|
|
size_t stack_subtraction = 0;
|
|
|
|
size_t xmm_offset = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
static FrameInfo CalculateFrameInfo(size_t num_gprs, size_t num_xmms, size_t frame_size) {
|
|
|
|
FrameInfo frame_info = {};
|
|
|
|
|
|
|
|
size_t rsp_alignment = 8; // We are always 8-byte aligned initially
|
|
|
|
rsp_alignment -= num_gprs * GPR_SIZE;
|
|
|
|
|
|
|
|
if (num_xmms > 0) {
|
|
|
|
frame_info.stack_subtraction = rsp_alignment & 0xF;
|
|
|
|
frame_info.stack_subtraction += num_xmms * XMM_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t xmm_base = frame_info.stack_subtraction;
|
|
|
|
|
|
|
|
frame_info.stack_subtraction += frame_size;
|
|
|
|
frame_info.stack_subtraction += ABI_SHADOW_SPACE;
|
|
|
|
|
|
|
|
rsp_alignment -= frame_info.stack_subtraction;
|
|
|
|
frame_info.stack_subtraction += rsp_alignment & 0xF;
|
|
|
|
|
|
|
|
frame_info.xmm_offset = frame_info.stack_subtraction - xmm_base;
|
|
|
|
|
|
|
|
return frame_info;
|
|
|
|
}
|
|
|
|
|
2016-08-31 23:53:16 +01:00
|
|
|
template<typename RegisterArrayT>
|
2018-09-28 21:12:17 +01:00
|
|
|
void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, size_t frame_size, const RegisterArrayT& regs) {
|
2016-08-24 20:07:08 +01:00
|
|
|
using namespace Xbyak::util;
|
|
|
|
|
2016-08-31 23:53:16 +01:00
|
|
|
const size_t num_gprs = std::count_if(regs.begin(), regs.end(), HostLocIsGPR);
|
|
|
|
const size_t num_xmms = std::count_if(regs.begin(), regs.end(), HostLocIsXMM);
|
2016-08-24 20:07:08 +01:00
|
|
|
|
|
|
|
FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size);
|
|
|
|
|
2016-08-31 23:53:16 +01:00
|
|
|
for (HostLoc gpr : regs) {
|
2016-08-24 20:07:08 +01:00
|
|
|
if (HostLocIsGPR(gpr)) {
|
2018-02-03 14:28:57 +00:00
|
|
|
code.push(HostLocToReg64(gpr));
|
2016-08-24 20:07:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frame_info.stack_subtraction != 0) {
|
2018-02-03 14:28:57 +00:00
|
|
|
code.sub(rsp, u32(frame_info.stack_subtraction));
|
2016-08-24 20:07:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t xmm_offset = frame_info.xmm_offset;
|
2016-08-31 23:53:16 +01:00
|
|
|
for (HostLoc xmm : regs) {
|
2016-08-24 20:07:08 +01:00
|
|
|
if (HostLocIsXMM(xmm)) {
|
2018-09-28 21:12:17 +01:00
|
|
|
if (code.DoesCpuSupport(Xbyak::util::Cpu::tAVX)) {
|
|
|
|
code.vmovaps(code.xword[rsp + xmm_offset], HostLocToXmm(xmm));
|
|
|
|
} else {
|
|
|
|
code.movaps(code.xword[rsp + xmm_offset], HostLocToXmm(xmm));
|
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
xmm_offset += XMM_SIZE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-31 23:53:16 +01:00
|
|
|
template<typename RegisterArrayT>
|
2018-09-28 21:12:17 +01:00
|
|
|
void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, size_t frame_size, const RegisterArrayT& regs) {
|
2016-08-24 20:07:08 +01:00
|
|
|
using namespace Xbyak::util;
|
|
|
|
|
2016-08-31 23:53:16 +01:00
|
|
|
const size_t num_gprs = std::count_if(regs.begin(), regs.end(), HostLocIsGPR);
|
|
|
|
const size_t num_xmms = std::count_if(regs.begin(), regs.end(), HostLocIsXMM);
|
2016-08-24 20:07:08 +01:00
|
|
|
|
|
|
|
FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size);
|
|
|
|
|
|
|
|
size_t xmm_offset = frame_info.xmm_offset;
|
2016-08-31 23:53:16 +01:00
|
|
|
for (HostLoc xmm : regs) {
|
2016-08-24 20:07:08 +01:00
|
|
|
if (HostLocIsXMM(xmm)) {
|
2018-09-28 21:12:17 +01:00
|
|
|
if (code.DoesCpuSupport(Xbyak::util::Cpu::tAVX)) {
|
|
|
|
code.vmovaps(HostLocToXmm(xmm), code.xword[rsp + xmm_offset]);
|
|
|
|
} else {
|
|
|
|
code.movaps(HostLocToXmm(xmm), code.xword[rsp + xmm_offset]);
|
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
xmm_offset += XMM_SIZE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frame_info.stack_subtraction != 0) {
|
2018-02-03 14:28:57 +00:00
|
|
|
code.add(rsp, u32(frame_info.stack_subtraction));
|
2016-08-24 20:07:08 +01:00
|
|
|
}
|
|
|
|
|
2016-08-31 23:53:16 +01:00
|
|
|
for (HostLoc gpr : Common::Reverse(regs)) {
|
2016-08-24 20:07:08 +01:00
|
|
|
if (HostLocIsGPR(gpr)) {
|
2018-02-03 14:28:57 +00:00
|
|
|
code.pop(HostLocToReg64(gpr));
|
2016-08-24 20:07:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-28 21:12:17 +01:00
|
|
|
void ABI_PushCalleeSaveRegistersAndAdjustStack(BlockOfCode& code, size_t frame_size) {
|
2016-08-31 23:53:16 +01:00
|
|
|
ABI_PushRegistersAndAdjustStack(code, frame_size, ABI_ALL_CALLEE_SAVE);
|
|
|
|
}
|
|
|
|
|
2018-09-28 21:12:17 +01:00
|
|
|
void ABI_PopCalleeSaveRegistersAndAdjustStack(BlockOfCode& code, size_t frame_size) {
|
2016-08-31 23:53:16 +01:00
|
|
|
ABI_PopRegistersAndAdjustStack(code, frame_size, ABI_ALL_CALLEE_SAVE);
|
|
|
|
}
|
|
|
|
|
2018-09-28 21:12:17 +01:00
|
|
|
void ABI_PushCallerSaveRegistersAndAdjustStack(BlockOfCode& code, size_t frame_size) {
|
2016-08-31 23:53:16 +01:00
|
|
|
ABI_PushRegistersAndAdjustStack(code, frame_size, ABI_ALL_CALLER_SAVE);
|
|
|
|
}
|
|
|
|
|
2018-09-28 21:12:17 +01:00
|
|
|
void ABI_PopCallerSaveRegistersAndAdjustStack(BlockOfCode& code, size_t frame_size) {
|
2016-08-31 23:53:16 +01:00
|
|
|
ABI_PopRegistersAndAdjustStack(code, frame_size, ABI_ALL_CALLER_SAVE);
|
|
|
|
}
|
|
|
|
|
2018-09-28 21:12:17 +01:00
|
|
|
void ABI_PushCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, HostLoc exception) {
|
2018-02-12 18:17:39 +00:00
|
|
|
std::vector<HostLoc> regs;
|
|
|
|
std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception);
|
|
|
|
ABI_PushRegistersAndAdjustStack(code, 0, regs);
|
|
|
|
}
|
|
|
|
|
2018-09-28 21:12:17 +01:00
|
|
|
void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, HostLoc exception) {
|
2018-02-12 18:17:39 +00:00
|
|
|
std::vector<HostLoc> regs;
|
|
|
|
std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception);
|
|
|
|
ABI_PopRegistersAndAdjustStack(code, 0, regs);
|
|
|
|
}
|
|
|
|
|
2020-04-08 11:46:36 +01:00
|
|
|
} // namespace Dynarmic::Backend::X64
|