backend/x64: Move spill from JitState onto the stack

This commit is contained in:
MerryMage 2021-05-04 14:15:35 +01:00
parent f8d8ea0deb
commit ddbc50cee0
11 changed files with 52 additions and 40 deletions

View file

@ -293,6 +293,7 @@ if (ARCHITECTURE STREQUAL "x86_64")
backend/x64/perf_map.h backend/x64/perf_map.h
backend/x64/reg_alloc.cpp backend/x64/reg_alloc.cpp
backend/x64/reg_alloc.h backend/x64/reg_alloc.h
backend/x64/stack_layout.h
) )
if ("A32" IN_LIST DYNARMIC_FRONTENDS) if ("A32" IN_LIST DYNARMIC_FRONTENDS)

View file

@ -109,7 +109,7 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
return gprs; return gprs;
}(); }();
RegAlloc reg_alloc{code, A32JitState::SpillCount, SpillToOpArg<A32JitState>, gpr_order, any_xmm}; RegAlloc reg_alloc{code, gpr_order, any_xmm};
A32EmitContext ctx{conf, reg_alloc, block}; A32EmitContext ctx{conf, reg_alloc, block};
// Start emitting. // Start emitting.

View file

@ -39,13 +39,6 @@ struct A32JitState {
alignas(16) std::array<u32, 64> ExtReg{}; // Extension registers. alignas(16) std::array<u32, 64> ExtReg{}; // Extension registers.
static constexpr size_t SpillCount = 64;
alignas(16) std::array<std::array<u64, 2>, SpillCount> spill{}; // Spill.
static Xbyak::Address GetSpillLocationFromIndex(size_t i) {
using namespace Xbyak::util;
return xword[r15 + offsetof(A32JitState, spill) + i * sizeof(u64) * 2];
}
// For internal use (See: BlockOfCode::RunCode) // For internal use (See: BlockOfCode::RunCode)
u32 guest_MXCSR = 0x00001f80; u32 guest_MXCSR = 0x00001f80;
u32 asimd_MXCSR = 0x00009fc0; u32 asimd_MXCSR = 0x00009fc0;

View file

@ -75,7 +75,7 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) {
return gprs; return gprs;
}(); }();
RegAlloc reg_alloc{code, A64JitState::SpillCount, SpillToOpArg<A64JitState>, gpr_order, any_xmm}; RegAlloc reg_alloc{code, gpr_order, any_xmm};
A64EmitContext ctx{conf, reg_alloc, block}; A64EmitContext ctx{conf, reg_alloc, block};
// Start emitting. // Start emitting.

View file

@ -42,13 +42,6 @@ struct A64JitState {
alignas(16) std::array<u64, 64> vec{}; // Extension registers. alignas(16) std::array<u64, 64> vec{}; // Extension registers.
static constexpr size_t SpillCount = 64;
alignas(16) std::array<std::array<u64, 2>, SpillCount> spill{}; // Spill.
static Xbyak::Address GetSpillLocationFromIndex(size_t i) {
using namespace Xbyak::util;
return xword[r15 + offsetof(A64JitState, spill) + i * sizeof(u64) * 2];
}
// For internal use (See: BlockOfCode::RunCode) // For internal use (See: BlockOfCode::RunCode)
u32 guest_MXCSR = 0x00001f80; u32 guest_MXCSR = 0x00001f80;
u32 asimd_MXCSR = 0x00009fc0; u32 asimd_MXCSR = 0x00009fc0;

View file

@ -13,6 +13,7 @@
#include "backend/x64/block_of_code.h" #include "backend/x64/block_of_code.h"
#include "backend/x64/hostloc.h" #include "backend/x64/hostloc.h"
#include "backend/x64/perf_map.h" #include "backend/x64/perf_map.h"
#include "backend/x64/stack_layout.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/bit_util.h" #include "common/bit_util.h"
@ -155,7 +156,7 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
// 1. It saves all the registers we as a callee need to save. // 1. It saves all the registers we as a callee need to save.
// 2. It aligns the stack so that the code the JIT emits can assume // 2. It aligns the stack so that the code the JIT emits can assume
// that the stack is appropriately aligned for CALLs. // that the stack is appropriately aligned for CALLs.
ABI_PushCalleeSaveRegistersAndAdjustStack(*this); ABI_PushCalleeSaveRegistersAndAdjustStack(*this, sizeof(StackLayout));
mov(r15, ABI_PARAM1); mov(r15, ABI_PARAM1);
mov(rbx, ABI_PARAM2); // save temporarily in non-volatile register mov(rbx, ABI_PARAM2); // save temporarily in non-volatile register
@ -172,7 +173,7 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
align(); align();
step_code = getCurr<RunCodeFuncType>(); step_code = getCurr<RunCodeFuncType>();
ABI_PushCalleeSaveRegistersAndAdjustStack(*this); ABI_PushCalleeSaveRegistersAndAdjustStack(*this, sizeof(StackLayout));
mov(r15, ABI_PARAM1); mov(r15, ABI_PARAM1);
@ -222,7 +223,7 @@ void BlockOfCode::GenRunCode(std::function<void(BlockOfCode&)> rcp) {
sub(param[0], qword[r15 + jsi.offsetof_cycles_remaining]); sub(param[0], qword[r15 + jsi.offsetof_cycles_remaining]);
}); });
ABI_PopCalleeSaveRegistersAndAdjustStack(*this); ABI_PopCalleeSaveRegistersAndAdjustStack(*this, sizeof(StackLayout));
ret(); ret();
PerfMapRegister(run_code, getCurr(), "dynarmic_dispatcher"); PerfMapRegister(run_code, getCurr(), "dynarmic_dispatcher");

View file

@ -5,7 +5,9 @@
#include <xbyak.h> #include <xbyak.h>
#include "backend/x64/abi.h"
#include "backend/x64/hostloc.h" #include "backend/x64/hostloc.h"
#include "backend/x64/stack_layout.h"
namespace Dynarmic::Backend::X64 { namespace Dynarmic::Backend::X64 {
@ -19,4 +21,14 @@ Xbyak::Xmm HostLocToXmm(HostLoc loc) {
return Xbyak::Xmm(static_cast<int>(loc) - static_cast<int>(HostLoc::XMM0)); return Xbyak::Xmm(static_cast<int>(loc) - static_cast<int>(HostLoc::XMM0));
} }
Xbyak::Address SpillToOpArg(HostLoc loc) {
ASSERT(HostLocIsSpill(loc));
size_t i = static_cast<size_t>(loc) - static_cast<size_t>(HostLoc::FirstSpill);
ASSERT_MSG(i < SpillCount, "Spill index greater than number of available spill locations");
using namespace Xbyak::util;
return xword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, spill) + i * sizeof(u64) * 2];
}
} // namespace Dynarmic::Backend::X64 } // namespace Dynarmic::Backend::X64

View file

@ -110,15 +110,6 @@ const HostLocList any_xmm = {
Xbyak::Reg64 HostLocToReg64(HostLoc loc); Xbyak::Reg64 HostLocToReg64(HostLoc loc);
Xbyak::Xmm HostLocToXmm(HostLoc loc); Xbyak::Xmm HostLocToXmm(HostLoc loc);
Xbyak::Address SpillToOpArg(HostLoc loc);
template <typename JitStateType>
Xbyak::Address SpillToOpArg(HostLoc loc) {
ASSERT(HostLocIsSpill(loc));
size_t i = static_cast<size_t>(loc) - static_cast<size_t>(HostLoc::FirstSpill);
ASSERT_MSG(i < JitStateType::SpillCount, "Spill index greater than number of available spill locations");
return JitStateType::GetSpillLocationFromIndex(i);
}
} // namespace Dynarmic::Backend::X64 } // namespace Dynarmic::Backend::X64

View file

@ -12,6 +12,7 @@
#include "backend/x64/abi.h" #include "backend/x64/abi.h"
#include "backend/x64/reg_alloc.h" #include "backend/x64/reg_alloc.h"
#include "backend/x64/stack_layout.h"
#include "common/assert.h" #include "common/assert.h"
namespace Dynarmic::Backend::X64 { namespace Dynarmic::Backend::X64 {
@ -223,12 +224,11 @@ bool Argument::IsInMemory() const {
return HostLocIsSpill(*reg_alloc.ValueLocation(value.GetInst())); return HostLocIsSpill(*reg_alloc.ValueLocation(value.GetInst()));
} }
RegAlloc::RegAlloc(BlockOfCode& code, size_t num_spills, std::function<Xbyak::Address(HostLoc)> spill_to_addr, std::vector<HostLoc> gpr_order, std::vector<HostLoc> xmm_order) RegAlloc::RegAlloc(BlockOfCode& code, std::vector<HostLoc> gpr_order, std::vector<HostLoc> xmm_order)
: gpr_order(gpr_order) : gpr_order(gpr_order)
, xmm_order(xmm_order) , xmm_order(xmm_order)
, hostloc_info(NonSpillHostLocCount + num_spills) , hostloc_info(NonSpillHostLocCount + SpillCount)
, code(code) , code(code)
, spill_to_addr(std::move(spill_to_addr))
{} {}
RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) { RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) {
@ -629,7 +629,7 @@ void RegAlloc::EmitMove(size_t bit_width, HostLoc to, HostLoc from) {
MAYBE_AVX(movd, HostLocToReg64(to).cvt32(), HostLocToXmm(from)); MAYBE_AVX(movd, HostLocToReg64(to).cvt32(), HostLocToXmm(from));
} }
} else if (HostLocIsXMM(to) && HostLocIsSpill(from)) { } else if (HostLocIsXMM(to) && HostLocIsSpill(from)) {
const Xbyak::Address spill_addr = spill_to_addr(from); const Xbyak::Address spill_addr = SpillToOpArg(from);
ASSERT(spill_addr.getBit() >= bit_width); ASSERT(spill_addr.getBit() >= bit_width);
switch (bit_width) { switch (bit_width) {
case 128: case 128:
@ -647,7 +647,7 @@ void RegAlloc::EmitMove(size_t bit_width, HostLoc to, HostLoc from) {
UNREACHABLE(); UNREACHABLE();
} }
} else if (HostLocIsSpill(to) && HostLocIsXMM(from)) { } else if (HostLocIsSpill(to) && HostLocIsXMM(from)) {
const Xbyak::Address spill_addr = spill_to_addr(to); const Xbyak::Address spill_addr = SpillToOpArg(to);
ASSERT(spill_addr.getBit() >= bit_width); ASSERT(spill_addr.getBit() >= bit_width);
switch (bit_width) { switch (bit_width) {
case 128: case 128:
@ -667,16 +667,16 @@ void RegAlloc::EmitMove(size_t bit_width, HostLoc to, HostLoc from) {
} else if (HostLocIsGPR(to) && HostLocIsSpill(from)) { } else if (HostLocIsGPR(to) && HostLocIsSpill(from)) {
ASSERT(bit_width != 128); ASSERT(bit_width != 128);
if (bit_width == 64) { if (bit_width == 64) {
code.mov(HostLocToReg64(to), spill_to_addr(from)); code.mov(HostLocToReg64(to), SpillToOpArg(from));
} else { } else {
code.mov(HostLocToReg64(to).cvt32(), spill_to_addr(from)); code.mov(HostLocToReg64(to).cvt32(), SpillToOpArg(from));
} }
} else if (HostLocIsSpill(to) && HostLocIsGPR(from)) { } else if (HostLocIsSpill(to) && HostLocIsGPR(from)) {
ASSERT(bit_width != 128); ASSERT(bit_width != 128);
if (bit_width == 64) { if (bit_width == 64) {
code.mov(spill_to_addr(to), HostLocToReg64(from)); code.mov(SpillToOpArg(to), HostLocToReg64(from));
} else { } else {
code.mov(spill_to_addr(to), HostLocToReg64(from).cvt32()); code.mov(SpillToOpArg(to), HostLocToReg64(from).cvt32());
} }
} else { } else {
ASSERT_FALSE("Invalid RegAlloc::EmitMove"); ASSERT_FALSE("Invalid RegAlloc::EmitMove");

View file

@ -96,7 +96,7 @@ class RegAlloc final {
public: public:
using ArgumentInfo = std::array<Argument, IR::max_arg_count>; using ArgumentInfo = std::array<Argument, IR::max_arg_count>;
explicit RegAlloc(BlockOfCode& code, size_t num_spills, std::function<Xbyak::Address(HostLoc)> spill_to_addr, std::vector<HostLoc> gpr_order, std::vector<HostLoc> xmm_order); explicit RegAlloc(BlockOfCode& code, std::vector<HostLoc> gpr_order, std::vector<HostLoc> xmm_order);
ArgumentInfo GetArgumentInfo(IR::Inst* inst); ArgumentInfo GetArgumentInfo(IR::Inst* inst);
@ -160,7 +160,6 @@ private:
const HostLocInfo& LocInfo(HostLoc loc) const; const HostLocInfo& LocInfo(HostLoc loc) const;
BlockOfCode& code; BlockOfCode& code;
std::function<Xbyak::Address(HostLoc)> spill_to_addr;
void EmitMove(size_t bit_width, HostLoc to, HostLoc from); void EmitMove(size_t bit_width, HostLoc to, HostLoc from);
void EmitExchange(HostLoc a, HostLoc b); void EmitExchange(HostLoc a, HostLoc b);
}; };

View file

@ -0,0 +1,22 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <array>
#include "common/common_types.h"
namespace Dynarmic::Backend::X64 {
constexpr size_t SpillCount = 64;
struct alignas(16) StackLayout {
std::array<std::array<u64, 2>, SpillCount> spill;
};
static_assert(sizeof(StackLayout) % 16 == 0);
} // namespace Dynarmic::Backend::X64