emit_arm64_a32: Implement barriers

This commit is contained in:
Merry 2022-07-26 09:30:35 +01:00 committed by merry
parent a7f675864b
commit 8a0359ec52
6 changed files with 24 additions and 20 deletions

View file

@ -111,6 +111,7 @@ void A32AddressSpace::EmitPrelude() {
prelude_info.write_memory_16 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite16>(code, conf.callbacks);
prelude_info.write_memory_32 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite32>(code, conf.callbacks);
prelude_info.write_memory_64 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite64>(code, conf.callbacks);
prelude_info.isb_raised = EmitCallTrampoline<&A32::UserCallbacks::InstructionSynchronizationBarrierRaised>(code, conf.callbacks);
prelude_info.end_of_prelude = code.ptr<u32*>();
@ -129,6 +130,7 @@ EmittedBlockInfo A32AddressSpace::Emit(IR::Block block) {
mem.unprotect();
EmittedBlockInfo block_info = EmitArm64(code, std::move(block), {
.hook_isb = conf.hook_isb,
.enable_cycle_counting = conf.enable_cycle_counting,
.always_little_endian = conf.always_little_endian,
});
@ -176,6 +178,9 @@ void A32AddressSpace::Link(EmittedBlockInfo& block_info) {
case LinkTarget::WriteMemory64:
c.BL(prelude_info.write_memory_64);
break;
case LinkTarget::InstructionSynchronizationBarrierRaised:
c.BL(prelude_info.isb_raised);
break;
default:
ASSERT_FALSE("Invalid relocation target");
}

View file

@ -64,6 +64,7 @@ private:
void* write_memory_16;
void* write_memory_32;
void* write_memory_64;
void* isb_raised;
} prelude_info;
};

View file

@ -117,11 +117,11 @@ void EmitIR<IR::Opcode::NZCVFromPackedFlags>(oaknut::CodeGenerator&, EmitContext
ctx.reg_alloc.DefineAsExisting(inst, args[0]);
}
EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& emit_conf) {
EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& conf) {
EmittedBlockInfo ebi;
RegAlloc reg_alloc{code, GPR_ORDER, FPR_ORDER};
EmitContext ctx{block, reg_alloc, emit_conf, ebi, {}};
EmitContext ctx{block, reg_alloc, conf, ebi, {}};
ebi.entry_point = code.ptr<CodePtr>();
@ -155,7 +155,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E
reg_alloc.AssertNoMoreUses();
if (emit_conf.enable_cycle_counting) {
if (ctx.conf.enable_cycle_counting) {
const size_t cycles_to_add = block.CycleCount();
code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_remaining));
if (oaknut::AddSubImm::is_valid(cycles_to_add)) {

View file

@ -39,6 +39,7 @@ enum class LinkTarget {
WriteMemory16,
WriteMemory32,
WriteMemory64,
InstructionSynchronizationBarrierRaised,
};
struct Relocation {
@ -53,6 +54,7 @@ struct EmittedBlockInfo {
};
struct EmitConfig {
bool hook_isb;
bool enable_cycle_counting;
bool always_little_endian;
};

View file

@ -47,7 +47,7 @@ void EmitSetUpperLocationDescriptor(oaknut::CodeGenerator& code, EmitContext& ct
const u32 old_upper = get_upper(old_location);
const u32 new_upper = [&] {
const u32 mask = ~u32(ctx.emit_conf.always_little_endian ? 0x2 : 0);
const u32 mask = ~u32(ctx.conf.always_little_endian ? 0x2 : 0);
return get_upper(new_location) & mask;
}();
@ -396,27 +396,23 @@ void EmitIR<IR::Opcode::A32ExceptionRaised>(oaknut::CodeGenerator& code, EmitCon
}
template<>
void EmitIR<IR::Opcode::A32DataSynchronizationBarrier>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
void EmitIR<IR::Opcode::A32DataSynchronizationBarrier>(oaknut::CodeGenerator& code, EmitContext&, IR::Inst*) {
code.DSB(oaknut::BarrierOp::SY);
}
template<>
void EmitIR<IR::Opcode::A32DataMemoryBarrier>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
void EmitIR<IR::Opcode::A32DataMemoryBarrier>(oaknut::CodeGenerator& code, EmitContext&, IR::Inst*) {
code.DMB(oaknut::BarrierOp::SY);
}
template<>
void EmitIR<IR::Opcode::A32InstructionSynchronizationBarrier>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
(void)code;
(void)ctx;
(void)inst;
ASSERT_FALSE("Unimplemented");
void EmitIR<IR::Opcode::A32InstructionSynchronizationBarrier>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst*) {
if (!ctx.conf.hook_isb) {
return;
}
ctx.reg_alloc.PrepareForCall(nullptr);
EmitRelocation(code, ctx, LinkTarget::InstructionSynchronizationBarrierRaised);
}
template<>

View file

@ -24,7 +24,7 @@ struct FpsrManager {
struct EmitContext {
IR::Block& block;
RegAlloc& reg_alloc;
const EmitConfig& emit_conf;
const EmitConfig& conf;
EmittedBlockInfo& ebi;
FpsrManager fpsr;
};