emit_arm64_a32: Implement barriers
This commit is contained in:
parent
a7f675864b
commit
8a0359ec52
6 changed files with 24 additions and 20 deletions
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ private:
|
|||
void* write_memory_16;
|
||||
void* write_memory_32;
|
||||
void* write_memory_64;
|
||||
void* isb_raised;
|
||||
} prelude_info;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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<>
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue