[A64] Lift code-size and cond-branch range limits in JIT emitter

This commit is contained in:
Herman S.
2026-04-27 00:57:10 +09:00
parent d8a0f832a8
commit 89b81da8df
2 changed files with 103 additions and 4 deletions
+78 -4
View File
@@ -71,7 +71,7 @@ const uint32_t A64Emitter::vec_reg_map_[VEC_COUNT] = {
};
A64Emitter::A64Emitter(A64Backend* backend, XbyakA64Allocator* allocator)
: CodeGenerator(kMaxCodeSize, Xbyak_aarch64::DontSetProtectRWE, allocator),
: CodeGenerator(kMaxCodeSize, Xbyak_aarch64::AutoGrow, allocator),
processor_(backend->processor()),
backend_(backend),
code_cache_(backend->code_cache()),
@@ -324,6 +324,78 @@ void A64Emitter::DebugBreak() { brk(0xF000); }
void A64Emitter::Trap(uint16_t trap_type) { brk(trap_type); }
void A64Emitter::b(const Xbyak_aarch64::Cond cond,
const Xbyak_aarch64::Label& label) {
Xbyak_aarch64::Label skip;
CodeGenerator::b(static_cast<Xbyak_aarch64::Cond>(cond ^ 1), skip);
CodeGenerator::b(label);
L(skip);
}
void A64Emitter::cbz(const Xbyak_aarch64::WReg& rt,
const Xbyak_aarch64::Label& label) {
Xbyak_aarch64::Label skip;
CodeGenerator::cbnz(rt, skip);
CodeGenerator::b(label);
L(skip);
}
void A64Emitter::cbz(const Xbyak_aarch64::XReg& rt,
const Xbyak_aarch64::Label& label) {
Xbyak_aarch64::Label skip;
CodeGenerator::cbnz(rt, skip);
CodeGenerator::b(label);
L(skip);
}
void A64Emitter::cbnz(const Xbyak_aarch64::WReg& rt,
const Xbyak_aarch64::Label& label) {
Xbyak_aarch64::Label skip;
CodeGenerator::cbz(rt, skip);
CodeGenerator::b(label);
L(skip);
}
void A64Emitter::cbnz(const Xbyak_aarch64::XReg& rt,
const Xbyak_aarch64::Label& label) {
Xbyak_aarch64::Label skip;
CodeGenerator::cbz(rt, skip);
CodeGenerator::b(label);
L(skip);
}
void A64Emitter::tbz(const Xbyak_aarch64::WReg& rt, uint32_t imm,
const Xbyak_aarch64::Label& label) {
Xbyak_aarch64::Label skip;
CodeGenerator::tbnz(rt, imm, skip);
CodeGenerator::b(label);
L(skip);
}
void A64Emitter::tbz(const Xbyak_aarch64::XReg& rt, uint32_t imm,
const Xbyak_aarch64::Label& label) {
Xbyak_aarch64::Label skip;
CodeGenerator::tbnz(rt, imm, skip);
CodeGenerator::b(label);
L(skip);
}
void A64Emitter::tbnz(const Xbyak_aarch64::WReg& rt, uint32_t imm,
const Xbyak_aarch64::Label& label) {
Xbyak_aarch64::Label skip;
CodeGenerator::tbz(rt, imm, skip);
CodeGenerator::b(label);
L(skip);
}
void A64Emitter::tbnz(const Xbyak_aarch64::XReg& rt, uint32_t imm,
const Xbyak_aarch64::Label& label) {
Xbyak_aarch64::Label skip;
CodeGenerator::tbz(rt, imm, skip);
CodeGenerator::b(label);
L(skip);
}
void A64Emitter::UnimplementedInstr(const hir::Instr* i) {
XELOGE("A64: Unimplemented HIR instruction: {}",
hir::GetOpcodeName(i->GetOpcodeInfo()));
@@ -674,16 +746,18 @@ void A64Emitter::EnsureSynchronizedGuestAndHostStack() {
StackLayout::GUEST_SAVED_STACKPOINT_DEPTH)));
cmp(w17, w16);
auto& sync_label = AddToTail([&return_from_sync](A64Emitter& e, Label& lbl) {
// Set up arguments for the sync helper:
auto& sync_label = AddToTail([](A64Emitter& e, Label& lbl) {
// x8 was set up in the body to point at return_from_sync; do that there
// instead of here because adr's ±1 MiB range can't span body+tail in
// large functions.
// x8 = return address (where to resume after fixup)
// x9 = this function's stack size
e.adr(e.x8, return_from_sync);
e.mov(e.x9, static_cast<uint64_t>(e.stack_size()));
e.mov(e.x10, reinterpret_cast<uint64_t>(
e.backend()->synchronize_guest_and_host_stack_helper()));
e.br(e.x10);
});
adr(x8, return_from_sync);
b(NE, sync_label);
L(return_from_sync);
+25
View File
@@ -153,6 +153,31 @@ class A64Emitter : public Xbyak_aarch64::CodeGenerator {
uint32_t alignment = 0);
Xbyak_aarch64::Label& NewCachedLabel();
// ARM64 conditional branches (cbz/cbnz: ±1 MiB, tbz/tbnz: ±32 KiB,
// b.cond: ±1 MiB) can fall short of their target in large guest functions.
// These shadows emit the safe pattern `<inverse> skip; b target; skip:`,
// routing the long branch through unconditional b (±128 MiB). The
// int64_t-immediate overloads remain available via the using-declarations
// for hand-tuned thunks that pass literal byte offsets.
using Xbyak_aarch64::CodeGenerator::b;
using Xbyak_aarch64::CodeGenerator::cbnz;
using Xbyak_aarch64::CodeGenerator::cbz;
using Xbyak_aarch64::CodeGenerator::tbnz;
using Xbyak_aarch64::CodeGenerator::tbz;
void b(const Xbyak_aarch64::Cond cond, const Xbyak_aarch64::Label& label);
void cbz(const Xbyak_aarch64::WReg& rt, const Xbyak_aarch64::Label& label);
void cbz(const Xbyak_aarch64::XReg& rt, const Xbyak_aarch64::Label& label);
void cbnz(const Xbyak_aarch64::WReg& rt, const Xbyak_aarch64::Label& label);
void cbnz(const Xbyak_aarch64::XReg& rt, const Xbyak_aarch64::Label& label);
void tbz(const Xbyak_aarch64::WReg& rt, uint32_t imm,
const Xbyak_aarch64::Label& label);
void tbz(const Xbyak_aarch64::XReg& rt, uint32_t imm,
const Xbyak_aarch64::Label& label);
void tbnz(const Xbyak_aarch64::WReg& rt, uint32_t imm,
const Xbyak_aarch64::Label& label);
void tbnz(const Xbyak_aarch64::XReg& rt, uint32_t imm,
const Xbyak_aarch64::Label& label);
// Get or create a xbyak_aarch64 label for a HIR label ID.
Xbyak_aarch64::Label& GetLabel(uint32_t label_id);