backend/x64: Move spill from JitState onto the stack
This commit is contained in:
parent
f8d8ea0deb
commit
ddbc50cee0
11 changed files with 52 additions and 40 deletions
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
22
src/backend/x64/stack_layout.h
Normal file
22
src/backend/x64/stack_layout.h
Normal 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
|
Loading…
Reference in a new issue