[A64] Add v8-v15 to allocatable VEC pool
Expands the vector register allocator from 20 to 28 registers by including v8-v15. The HostToGuestThunk now saves/restores full Q8-Q15 (128-bit) instead of just D8-D15, and the GuestToHostThunk adds Q8-Q15 to its save/restore set since AAPCS64 only preserves their lower 64 bits across C calls. Reduces register pressure for VMX-heavy guest code at the cost of slightly larger thunk stack frames.
This commit is contained in:
@@ -112,11 +112,11 @@ HostToGuestThunk A64HelperEmitter::EmitHostToGuestThunk() {
|
|||||||
stp(x27, x28, ptr(sp, 0x40));
|
stp(x27, x28, ptr(sp, 0x40));
|
||||||
stp(x29, x30, ptr(sp, 0x50));
|
stp(x29, x30, ptr(sp, 0x50));
|
||||||
|
|
||||||
// Save callee-saved NEON regs: d8-d15
|
// Save callee-saved NEON regs: full q8-q15 (JIT uses all 128 bits).
|
||||||
stp(d8, d9, ptr(sp, 0x60));
|
stp(Xbyak_aarch64::QReg(8), Xbyak_aarch64::QReg(9), ptr(sp, 0x60));
|
||||||
stp(d10, d11, ptr(sp, 0x70));
|
stp(Xbyak_aarch64::QReg(10), Xbyak_aarch64::QReg(11), ptr(sp, 0x80));
|
||||||
stp(d12, d13, ptr(sp, 0x80));
|
stp(Xbyak_aarch64::QReg(12), Xbyak_aarch64::QReg(13), ptr(sp, 0xA0));
|
||||||
stp(d14, d15, ptr(sp, 0x90));
|
stp(Xbyak_aarch64::QReg(14), Xbyak_aarch64::QReg(15), ptr(sp, 0xC0));
|
||||||
|
|
||||||
code_offsets.body = getSize();
|
code_offsets.body = getSize();
|
||||||
|
|
||||||
@@ -146,11 +146,11 @@ HostToGuestThunk A64HelperEmitter::EmitHostToGuestThunk() {
|
|||||||
|
|
||||||
code_offsets.epilog = getSize();
|
code_offsets.epilog = getSize();
|
||||||
|
|
||||||
// Restore callee-saved NEON regs.
|
// Restore callee-saved NEON regs (full q8-q15).
|
||||||
ldp(d14, d15, ptr(sp, 0x90));
|
ldp(Xbyak_aarch64::QReg(14), Xbyak_aarch64::QReg(15), ptr(sp, 0xC0));
|
||||||
ldp(d12, d13, ptr(sp, 0x80));
|
ldp(Xbyak_aarch64::QReg(12), Xbyak_aarch64::QReg(13), ptr(sp, 0xA0));
|
||||||
ldp(d10, d11, ptr(sp, 0x70));
|
ldp(Xbyak_aarch64::QReg(10), Xbyak_aarch64::QReg(11), ptr(sp, 0x80));
|
||||||
ldp(d8, d9, ptr(sp, 0x60));
|
ldp(Xbyak_aarch64::QReg(8), Xbyak_aarch64::QReg(9), ptr(sp, 0x60));
|
||||||
|
|
||||||
// Restore callee-saved GPRs.
|
// Restore callee-saved GPRs.
|
||||||
ldp(x29, x30, ptr(sp, 0x50));
|
ldp(x29, x30, ptr(sp, 0x50));
|
||||||
@@ -201,41 +201,50 @@ GuestToHostThunk A64HelperEmitter::EmitGuestToHostThunk() {
|
|||||||
|
|
||||||
code_offsets.prolog = getSize();
|
code_offsets.prolog = getSize();
|
||||||
|
|
||||||
// The guest JIT uses v4-v7 and v16-v31 as allocatable VEC regs.
|
// The guest JIT uses v4-v15, v16-v31 as allocatable VEC regs.
|
||||||
// These are caller-saved in AAPCS64, so the host C function WILL clobber
|
// v0-v7, v16-v31 are caller-saved in AAPCS64 (fully clobbered by C).
|
||||||
// them. We must save all guest-allocated VEC regs (full 128-bit Q regs).
|
// v8-v15 lower 64 bits are callee-saved, but upper 64 bits are not.
|
||||||
|
// We must save all guest-allocated VEC regs (full 128-bit Q regs).
|
||||||
// GPRs x19-x28 are callee-saved in AAPCS64, so the C function preserves them.
|
// GPRs x19-x28 are callee-saved in AAPCS64, so the C function preserves them.
|
||||||
//
|
//
|
||||||
// Stack layout:
|
// Stack layout:
|
||||||
// q4, q5 sp + 0x000 (32 bytes)
|
// q4, q5 sp + 0x000 (32 bytes)
|
||||||
// q6, q7 sp + 0x020
|
// q6, q7 sp + 0x020
|
||||||
// q16, q17 sp + 0x040
|
// q8, q9 sp + 0x040
|
||||||
// q18, q19 sp + 0x060
|
// q10, q11 sp + 0x060
|
||||||
// q20, q21 sp + 0x080
|
// q12, q13 sp + 0x080
|
||||||
// q22, q23 sp + 0x0A0
|
// q14, q15 sp + 0x0A0
|
||||||
// q24, q25 sp + 0x0C0
|
// q16, q17 sp + 0x0C0
|
||||||
// q26, q27 sp + 0x0E0
|
// q18, q19 sp + 0x0E0
|
||||||
// q28, q29 sp + 0x100
|
// q20, q21 sp + 0x100
|
||||||
// q30, q31 sp + 0x120
|
// q22, q23 sp + 0x120
|
||||||
// x29, x30 sp + 0x140
|
// q24, q25 sp + 0x140
|
||||||
// Total: 0x150 = 336 bytes (16-byte aligned)
|
// q26, q27 sp + 0x160
|
||||||
const size_t g2h_stack = 336;
|
// q28, q29 sp + 0x180
|
||||||
|
// q30, q31 sp + 0x1A0
|
||||||
|
// x29, x30 sp + 0x1C0
|
||||||
|
// Total: 0x1D0 = 464 bytes (16-byte aligned)
|
||||||
|
const size_t g2h_stack = 464;
|
||||||
sub(sp, sp, static_cast<uint32_t>(g2h_stack));
|
sub(sp, sp, static_cast<uint32_t>(g2h_stack));
|
||||||
code_offsets.prolog_stack_alloc = getSize();
|
code_offsets.prolog_stack_alloc = getSize();
|
||||||
|
|
||||||
// Save guest-allocated VEC regs (full Q = 128-bit).
|
// Save guest-allocated VEC regs (full Q = 128-bit).
|
||||||
stp(Xbyak_aarch64::QReg(4), Xbyak_aarch64::QReg(5), ptr(sp, 0x000));
|
stp(Xbyak_aarch64::QReg(4), Xbyak_aarch64::QReg(5), ptr(sp, 0x000));
|
||||||
stp(Xbyak_aarch64::QReg(6), Xbyak_aarch64::QReg(7), ptr(sp, 0x020));
|
stp(Xbyak_aarch64::QReg(6), Xbyak_aarch64::QReg(7), ptr(sp, 0x020));
|
||||||
stp(Xbyak_aarch64::QReg(16), Xbyak_aarch64::QReg(17), ptr(sp, 0x040));
|
stp(Xbyak_aarch64::QReg(8), Xbyak_aarch64::QReg(9), ptr(sp, 0x040));
|
||||||
stp(Xbyak_aarch64::QReg(18), Xbyak_aarch64::QReg(19), ptr(sp, 0x060));
|
stp(Xbyak_aarch64::QReg(10), Xbyak_aarch64::QReg(11), ptr(sp, 0x060));
|
||||||
stp(Xbyak_aarch64::QReg(20), Xbyak_aarch64::QReg(21), ptr(sp, 0x080));
|
stp(Xbyak_aarch64::QReg(12), Xbyak_aarch64::QReg(13), ptr(sp, 0x080));
|
||||||
stp(Xbyak_aarch64::QReg(22), Xbyak_aarch64::QReg(23), ptr(sp, 0x0A0));
|
stp(Xbyak_aarch64::QReg(14), Xbyak_aarch64::QReg(15), ptr(sp, 0x0A0));
|
||||||
stp(Xbyak_aarch64::QReg(24), Xbyak_aarch64::QReg(25), ptr(sp, 0x0C0));
|
stp(Xbyak_aarch64::QReg(16), Xbyak_aarch64::QReg(17), ptr(sp, 0x0C0));
|
||||||
stp(Xbyak_aarch64::QReg(26), Xbyak_aarch64::QReg(27), ptr(sp, 0x0E0));
|
stp(Xbyak_aarch64::QReg(18), Xbyak_aarch64::QReg(19), ptr(sp, 0x0E0));
|
||||||
stp(Xbyak_aarch64::QReg(28), Xbyak_aarch64::QReg(29), ptr(sp, 0x100));
|
stp(Xbyak_aarch64::QReg(20), Xbyak_aarch64::QReg(21), ptr(sp, 0x100));
|
||||||
stp(Xbyak_aarch64::QReg(30), Xbyak_aarch64::QReg(31), ptr(sp, 0x120));
|
stp(Xbyak_aarch64::QReg(22), Xbyak_aarch64::QReg(23), ptr(sp, 0x120));
|
||||||
|
stp(Xbyak_aarch64::QReg(24), Xbyak_aarch64::QReg(25), ptr(sp, 0x140));
|
||||||
|
stp(Xbyak_aarch64::QReg(26), Xbyak_aarch64::QReg(27), ptr(sp, 0x160));
|
||||||
|
stp(Xbyak_aarch64::QReg(28), Xbyak_aarch64::QReg(29), ptr(sp, 0x180));
|
||||||
|
stp(Xbyak_aarch64::QReg(30), Xbyak_aarch64::QReg(31), ptr(sp, 0x1A0));
|
||||||
// Save x29/x30 (FP/LR).
|
// Save x29/x30 (FP/LR).
|
||||||
stp(x29, x30, ptr(sp, 0x140));
|
stp(x29, x30, ptr(sp, 0x1C0));
|
||||||
|
|
||||||
code_offsets.body = getSize();
|
code_offsets.body = getSize();
|
||||||
|
|
||||||
@@ -256,15 +265,19 @@ GuestToHostThunk A64HelperEmitter::EmitGuestToHostThunk() {
|
|||||||
code_offsets.epilog = getSize();
|
code_offsets.epilog = getSize();
|
||||||
|
|
||||||
// Restore.
|
// Restore.
|
||||||
ldp(x29, x30, ptr(sp, 0x140));
|
ldp(x29, x30, ptr(sp, 0x1C0));
|
||||||
ldp(Xbyak_aarch64::QReg(30), Xbyak_aarch64::QReg(31), ptr(sp, 0x120));
|
ldp(Xbyak_aarch64::QReg(30), Xbyak_aarch64::QReg(31), ptr(sp, 0x1A0));
|
||||||
ldp(Xbyak_aarch64::QReg(28), Xbyak_aarch64::QReg(29), ptr(sp, 0x100));
|
ldp(Xbyak_aarch64::QReg(28), Xbyak_aarch64::QReg(29), ptr(sp, 0x180));
|
||||||
ldp(Xbyak_aarch64::QReg(26), Xbyak_aarch64::QReg(27), ptr(sp, 0x0E0));
|
ldp(Xbyak_aarch64::QReg(26), Xbyak_aarch64::QReg(27), ptr(sp, 0x160));
|
||||||
ldp(Xbyak_aarch64::QReg(24), Xbyak_aarch64::QReg(25), ptr(sp, 0x0C0));
|
ldp(Xbyak_aarch64::QReg(24), Xbyak_aarch64::QReg(25), ptr(sp, 0x140));
|
||||||
ldp(Xbyak_aarch64::QReg(22), Xbyak_aarch64::QReg(23), ptr(sp, 0x0A0));
|
ldp(Xbyak_aarch64::QReg(22), Xbyak_aarch64::QReg(23), ptr(sp, 0x120));
|
||||||
ldp(Xbyak_aarch64::QReg(20), Xbyak_aarch64::QReg(21), ptr(sp, 0x080));
|
ldp(Xbyak_aarch64::QReg(20), Xbyak_aarch64::QReg(21), ptr(sp, 0x100));
|
||||||
ldp(Xbyak_aarch64::QReg(18), Xbyak_aarch64::QReg(19), ptr(sp, 0x060));
|
ldp(Xbyak_aarch64::QReg(18), Xbyak_aarch64::QReg(19), ptr(sp, 0x0E0));
|
||||||
ldp(Xbyak_aarch64::QReg(16), Xbyak_aarch64::QReg(17), ptr(sp, 0x040));
|
ldp(Xbyak_aarch64::QReg(16), Xbyak_aarch64::QReg(17), ptr(sp, 0x0C0));
|
||||||
|
ldp(Xbyak_aarch64::QReg(14), Xbyak_aarch64::QReg(15), ptr(sp, 0x0A0));
|
||||||
|
ldp(Xbyak_aarch64::QReg(12), Xbyak_aarch64::QReg(13), ptr(sp, 0x080));
|
||||||
|
ldp(Xbyak_aarch64::QReg(10), Xbyak_aarch64::QReg(11), ptr(sp, 0x060));
|
||||||
|
ldp(Xbyak_aarch64::QReg(8), Xbyak_aarch64::QReg(9), ptr(sp, 0x040));
|
||||||
ldp(Xbyak_aarch64::QReg(6), Xbyak_aarch64::QReg(7), ptr(sp, 0x020));
|
ldp(Xbyak_aarch64::QReg(6), Xbyak_aarch64::QReg(7), ptr(sp, 0x020));
|
||||||
ldp(Xbyak_aarch64::QReg(4), Xbyak_aarch64::QReg(5), ptr(sp, 0x000));
|
ldp(Xbyak_aarch64::QReg(4), Xbyak_aarch64::QReg(5), ptr(sp, 0x000));
|
||||||
|
|
||||||
@@ -592,7 +605,7 @@ bool A64Backend::Initialize(Processor* processor) {
|
|||||||
std::strcpy(gpr_set.name, "gpr");
|
std::strcpy(gpr_set.name, "gpr");
|
||||||
gpr_set.types = MachineInfo::RegisterSet::INT_TYPES;
|
gpr_set.types = MachineInfo::RegisterSet::INT_TYPES;
|
||||||
gpr_set.count = A64Emitter::GPR_COUNT;
|
gpr_set.count = A64Emitter::GPR_COUNT;
|
||||||
// VEC set: v4-v7, v16-v31 (20 registers, v0-v3 scratch)
|
// VEC set: v4-v15, v16-v31 (28 registers, v0-v3 scratch)
|
||||||
auto& vec_set = machine_info_.register_sets[1];
|
auto& vec_set = machine_info_.register_sets[1];
|
||||||
vec_set.id = 1;
|
vec_set.id = 1;
|
||||||
std::strcpy(vec_set.name, "vec");
|
std::strcpy(vec_set.name, "vec");
|
||||||
|
|||||||
@@ -63,10 +63,11 @@ const uint32_t A64Emitter::gpr_reg_map_[GPR_COUNT] = {
|
|||||||
22, 23, 24, 25, 26, 27, 28,
|
22, 23, 24, 25, 26, 27, 28,
|
||||||
};
|
};
|
||||||
|
|
||||||
// VEC allocatable registers: v4-v7, v16-v31
|
// VEC allocatable registers: v4-v15, v16-v31
|
||||||
// (v0-v3 are scratch)
|
// (v0-v3 are scratch)
|
||||||
const uint32_t A64Emitter::vec_reg_map_[VEC_COUNT] = {
|
const uint32_t A64Emitter::vec_reg_map_[VEC_COUNT] = {
|
||||||
4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||||
|
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||||
};
|
};
|
||||||
|
|
||||||
A64Emitter::A64Emitter(A64Backend* backend, XbyakA64Allocator* allocator)
|
A64Emitter::A64Emitter(A64Backend* backend, XbyakA64Allocator* allocator)
|
||||||
|
|||||||
@@ -75,8 +75,8 @@ class A64Emitter : public Xbyak_aarch64::CodeGenerator {
|
|||||||
// Scratch: x0-x18 (caller-saved), v0-v3
|
// Scratch: x0-x18 (caller-saved), v0-v3
|
||||||
// Available GPRs for register allocator: x22-x28
|
// Available GPRs for register allocator: x22-x28
|
||||||
static constexpr int GPR_COUNT = 7;
|
static constexpr int GPR_COUNT = 7;
|
||||||
// Available VEC regs: v4-v7, v16-v31
|
// Available VEC regs: v4-v15, v16-v31
|
||||||
static constexpr int VEC_COUNT = 20;
|
static constexpr int VEC_COUNT = 28;
|
||||||
static constexpr size_t kStashOffset = 32;
|
static constexpr size_t kStashOffset = 32;
|
||||||
|
|
||||||
static void SetupReg(const hir::Value* v, Xbyak_aarch64::WReg& r) {
|
static void SetupReg(const hir::Value* v, Xbyak_aarch64::WReg& r) {
|
||||||
|
|||||||
@@ -20,35 +20,24 @@ namespace a64 {
|
|||||||
class StackLayout {
|
class StackLayout {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* ARM64 Thunk Stack Layout
|
* ARM64 Thunk Stack Layout (HostToGuest)
|
||||||
* NOTE: stack must always be 16-byte aligned.
|
* NOTE: stack must always be 16-byte aligned.
|
||||||
*
|
*
|
||||||
* Thunk (HostToGuest/GuestToHost):
|
|
||||||
* +------------------+
|
* +------------------+
|
||||||
* | x19 | sp + 0x000
|
* | x19, x20 | sp + 0x000
|
||||||
* | x20 (context) | sp + 0x008
|
* | x21, x22 | sp + 0x010
|
||||||
* | x21 (membase) | sp + 0x010
|
* | x23, x24 | sp + 0x020
|
||||||
* | x22 | sp + 0x018
|
* | x25, x26 | sp + 0x030
|
||||||
* | x23 | sp + 0x020
|
* | x27, x28 | sp + 0x040
|
||||||
* | x24 | sp + 0x028
|
* | x29 (fp), x30 | sp + 0x050
|
||||||
* | x25 | sp + 0x030
|
* | q8, q9 | sp + 0x060 (full 128-bit, used by JIT)
|
||||||
* | x26 | sp + 0x038
|
* | q10, q11 | sp + 0x080
|
||||||
* | x27 | sp + 0x040
|
* | q12, q13 | sp + 0x0A0
|
||||||
* | x28 | sp + 0x048
|
* | q14, q15 | sp + 0x0C0
|
||||||
* | x29 (fp) | sp + 0x050
|
|
||||||
* | x30 (lr) | sp + 0x058
|
|
||||||
* | d8 | sp + 0x060
|
|
||||||
* | d9 | sp + 0x068
|
|
||||||
* | d10 | sp + 0x070
|
|
||||||
* | d11 | sp + 0x078
|
|
||||||
* | d12 | sp + 0x080
|
|
||||||
* | d13 | sp + 0x088
|
|
||||||
* | d14 | sp + 0x090
|
|
||||||
* | d15 | sp + 0x098
|
|
||||||
* +------------------+
|
* +------------------+
|
||||||
* Total: 0xA0 = 160 bytes (already 16-byte aligned)
|
* Total: 0xE0 = 224 bytes (16-byte aligned)
|
||||||
*/
|
*/
|
||||||
static constexpr size_t THUNK_STACK_SIZE = 160;
|
static constexpr size_t THUNK_STACK_SIZE = 224;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ARM64 Guest Stack Layout
|
* ARM64 Guest Stack Layout
|
||||||
|
|||||||
Reference in New Issue
Block a user