a64/fastmem: Only generate abort handler if needed.

If fastmem fails, we call the callback from the signal handler. So this callback proxy in slowmem won't be used ever.
This commit is contained in:
Markus Wick 2021-05-27 21:49:08 +02:00 committed by merry
parent b4ee976a6f
commit ff01b1c6f9

View file

@ -880,7 +880,7 @@ Xbyak::RegExp EmitVAddrLookup(BlockOfCode& code, A64EmitContext& ctx, size_t bit
return page + tmp; return page + tmp;
} }
Xbyak::RegExp EmitFastmemVAddr(BlockOfCode& code, A64EmitContext& ctx, Xbyak::Label& abort, Xbyak::Reg64 vaddr) { Xbyak::RegExp EmitFastmemVAddr(BlockOfCode& code, A64EmitContext& ctx, Xbyak::Label& abort, Xbyak::Reg64 vaddr, bool& require_abort_handling) {
const size_t unused_top_bits = 64 - ctx.conf.page_table_address_space_bits; const size_t unused_top_bits = 64 - ctx.conf.page_table_address_space_bits;
if (unused_top_bits == 0) { if (unused_top_bits == 0) {
@ -902,12 +902,14 @@ Xbyak::RegExp EmitFastmemVAddr(BlockOfCode& code, A64EmitContext& ctx, Xbyak::La
if (ctx.conf.page_table_address_space_bits < 32) { if (ctx.conf.page_table_address_space_bits < 32) {
code.test(vaddr, u32(-(1 << ctx.conf.page_table_address_space_bits))); code.test(vaddr, u32(-(1 << ctx.conf.page_table_address_space_bits)));
code.jnz(abort, code.T_NEAR); code.jnz(abort, code.T_NEAR);
require_abort_handling = true;
} else { } else {
// TODO: Consider having TEST as above but coalesce 64-bit constant in register allocator // TODO: Consider having TEST as above but coalesce 64-bit constant in register allocator
Xbyak::Reg64 tmp = ctx.reg_alloc.ScratchGpr(); Xbyak::Reg64 tmp = ctx.reg_alloc.ScratchGpr();
code.mov(tmp, vaddr); code.mov(tmp, vaddr);
code.shr(tmp, int(ctx.conf.page_table_address_space_bits)); code.shr(tmp, int(ctx.conf.page_table_address_space_bits));
code.jnz(abort, code.T_NEAR); code.jnz(abort, code.T_NEAR);
require_abort_handling = true;
} }
return r13 + vaddr; return r13 + vaddr;
} }
@ -973,10 +975,11 @@ void A64EmitX64::EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst) {
const auto wrapped_fn = read_fallbacks[std::make_tuple(bitsize, vaddr.getIdx(), value.getIdx())]; const auto wrapped_fn = read_fallbacks[std::make_tuple(bitsize, vaddr.getIdx(), value.getIdx())];
Xbyak::Label abort, end; Xbyak::Label abort, end;
bool require_abort_handling = false;
if (fastmem_marker) { if (fastmem_marker) {
// Use fastmem // Use fastmem
const auto src_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr); const auto src_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling);
const auto location = code.getCurr(); const auto location = code.getCurr();
EmitReadMemoryMov<bitsize>(code, value, src_ptr); EmitReadMemoryMov<bitsize>(code, value, src_ptr);
@ -993,15 +996,18 @@ void A64EmitX64::EmitMemoryRead(A64EmitContext& ctx, IR::Inst* inst) {
// Use page table // Use page table
ASSERT(conf.page_table); ASSERT(conf.page_table);
const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr); const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr);
require_abort_handling = true;
EmitReadMemoryMov<bitsize>(code, value, src_ptr); EmitReadMemoryMov<bitsize>(code, value, src_ptr);
} }
code.L(end); code.L(end);
if (require_abort_handling) {
code.SwitchToFarCode(); code.SwitchToFarCode();
code.L(abort); code.L(abort);
code.call(wrapped_fn); code.call(wrapped_fn);
code.jmp(end, code.T_NEAR); code.jmp(end, code.T_NEAR);
code.SwitchToNearCode(); code.SwitchToNearCode();
}
ctx.reg_alloc.DefineValue(inst, value); ctx.reg_alloc.DefineValue(inst, value);
} }
@ -1024,10 +1030,11 @@ void A64EmitX64::EmitMemoryWrite(A64EmitContext& ctx, IR::Inst* inst) {
const auto wrapped_fn = write_fallbacks[std::make_tuple(bitsize, vaddr.getIdx(), value.getIdx())]; const auto wrapped_fn = write_fallbacks[std::make_tuple(bitsize, vaddr.getIdx(), value.getIdx())];
Xbyak::Label abort, end; Xbyak::Label abort, end;
bool require_abort_handling = false;
if (fastmem_marker) { if (fastmem_marker) {
// Use fastmem // Use fastmem
const auto dest_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr); const auto dest_ptr = EmitFastmemVAddr(code, ctx, abort, vaddr, require_abort_handling);
const auto location = code.getCurr(); const auto location = code.getCurr();
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value); EmitWriteMemoryMov<bitsize>(code, dest_ptr, value);
@ -1044,16 +1051,19 @@ void A64EmitX64::EmitMemoryWrite(A64EmitContext& ctx, IR::Inst* inst) {
// Use page table // Use page table
ASSERT(conf.page_table); ASSERT(conf.page_table);
const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr); const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, abort, vaddr);
require_abort_handling = true;
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value); EmitWriteMemoryMov<bitsize>(code, dest_ptr, value);
} }
code.L(end); code.L(end);
if (require_abort_handling) {
code.SwitchToFarCode(); code.SwitchToFarCode();
code.L(abort); code.L(abort);
code.call(wrapped_fn); code.call(wrapped_fn);
code.jmp(end, code.T_NEAR); code.jmp(end, code.T_NEAR);
code.SwitchToNearCode(); code.SwitchToNearCode();
} }
}
void A64EmitX64::EmitA64ReadMemory8(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64ReadMemory8(A64EmitContext& ctx, IR::Inst* inst) {
EmitMemoryRead<8, &A64::UserCallbacks::MemoryRead8>(ctx, inst); EmitMemoryRead<8, &A64::UserCallbacks::MemoryRead8>(ctx, inst);