From f3f60cd1790b0336087b23d06a96aed97a8e3168 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 17 Aug 2018 20:20:42 -0400 Subject: [PATCH] A64: Implement ISB Given we want to ensure that all instructions are fetched again, we can treat an ISB instruction as a code cache flush. --- src/backend_x64/a64_emit_x64.cpp | 13 +++++++++-- src/backend_x64/a64_emit_x64.h | 4 +++- src/backend_x64/a64_interface.cpp | 6 ++--- src/frontend/A64/decoder/a64.inc | 2 +- src/frontend/A64/ir_emitter.cpp | 4 ++++ src/frontend/A64/ir_emitter.h | 1 + src/frontend/A64/translate/impl/system.cpp | 7 ++++++ src/frontend/ir/microinstruction.cpp | 27 +++++++++++----------- src/frontend/ir/opcodes.inc | 1 + 9 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/backend_x64/a64_emit_x64.cpp b/src/backend_x64/a64_emit_x64.cpp index 7c59a3f1..086e64b1 100644 --- a/src/backend_x64/a64_emit_x64.cpp +++ b/src/backend_x64/a64_emit_x64.cpp @@ -60,8 +60,8 @@ bool A64EmitContext::AccurateNaN() const { return conf.floating_point_nan_accuracy == A64::UserConfig::NaNAccuracy::Accurate; } -A64EmitX64::A64EmitX64(BlockOfCode& code, A64::UserConfig conf) - : EmitX64(code), conf(conf) +A64EmitX64::A64EmitX64(BlockOfCode& code, A64::UserConfig conf, A64::Jit* jit_interface) + : EmitX64(code), conf(conf), jit_interface{jit_interface} { GenMemory128Accessors(); GenFastmemFallbacks(); @@ -538,6 +538,15 @@ void A64EmitX64::EmitA64DataMemoryBarrier(A64EmitContext&, IR::Inst*) { code.lfence(); } +void A64EmitX64::EmitA64InstructionSynchronizationBarrier(A64EmitContext& ctx, IR::Inst* ) { + ctx.reg_alloc.HostCall(nullptr); + + code.mov(code.ABI_PARAM1, reinterpret_cast(jit_interface)); + code.CallFunction(static_cast([](A64::Jit* jit) { + jit->ClearCache(); + })); +} + void A64EmitX64::EmitA64GetCNTFRQ(A64EmitContext& ctx, IR::Inst* inst) { Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); code.mov(result, conf.cntfrq_el0); diff --git a/src/backend_x64/a64_emit_x64.h b/src/backend_x64/a64_emit_x64.h index e6e51c31..0958defc 100644 --- a/src/backend_x64/a64_emit_x64.h +++ b/src/backend_x64/a64_emit_x64.h @@ -12,6 +12,7 @@ #include "backend_x64/a64_jitstate.h" #include "backend_x64/block_range_information.h" #include "backend_x64/emit_x64.h" +#include "dynarmic/A64/a64.h" #include "dynarmic/A64/config.h" #include "frontend/A64/location_descriptor.h" #include "frontend/ir/terminal.h" @@ -34,7 +35,7 @@ struct A64EmitContext final : public EmitContext { class A64EmitX64 final : public EmitX64 { public: - A64EmitX64(BlockOfCode& code, A64::UserConfig conf); + A64EmitX64(BlockOfCode& code, A64::UserConfig conf, A64::Jit* jit_interface); ~A64EmitX64() override; /** @@ -49,6 +50,7 @@ public: protected: const A64::UserConfig conf; + A64::Jit* jit_interface; BlockRangeInformation block_ranges; void (*memory_read_128)(); diff --git a/src/backend_x64/a64_interface.cpp b/src/backend_x64/a64_interface.cpp index 397f6f32..62538bcd 100644 --- a/src/backend_x64/a64_interface.cpp +++ b/src/backend_x64/a64_interface.cpp @@ -36,10 +36,10 @@ static RunCodeCallbacks GenRunCodeCallbacks(A64::UserCallbacks* cb, CodePtr (*Lo struct Jit::Impl final { public: - explicit Impl(UserConfig conf) + Impl(Jit* jit, UserConfig conf) : conf(conf) , block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this), JitStateInfo{jit_state}) - , emitter(block_of_code, conf) + , emitter(block_of_code, conf, jit) { ASSERT(conf.page_table_address_space_bits >= 12 && conf.page_table_address_space_bits <= 64); } @@ -247,7 +247,7 @@ private: }; Jit::Jit(UserConfig conf) - : impl(std::make_unique(conf)) {} + : impl(std::make_unique(this, conf)) {} Jit::~Jit() = default; diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index bf32a974..5f9cd343 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -64,7 +64,7 @@ INST(SEVL, "SEVL", "11010 INST(CLREX, "CLREX", "11010101000000110011MMMM01011111") INST(DSB, "DSB", "11010101000000110011MMMM10011111") INST(DMB, "DMB", "11010101000000110011MMMM10111111") -//INST(ISB, "ISB", "11010101000000110011MMMM11011111") +INST(ISB, "ISB", "11010101000000110011MMMM11011111") //INST(SYS, "SYS", "1101010100001oooNNNNMMMMooottttt") INST(MSR_reg, "MSR (register)", "110101010001poooNNNNMMMMooottttt") //INST(SYSL, "SYSL", "1101010100101oooNNNNMMMMooottttt") diff --git a/src/frontend/A64/ir_emitter.cpp b/src/frontend/A64/ir_emitter.cpp index 2b6f287d..e01fa988 100644 --- a/src/frontend/A64/ir_emitter.cpp +++ b/src/frontend/A64/ir_emitter.cpp @@ -57,6 +57,10 @@ void IREmitter::DataMemoryBarrier() { Inst(Opcode::A64DataMemoryBarrier); } +void IREmitter::InstructionSynchronizationBarrier() { + Inst(Opcode::A64InstructionSynchronizationBarrier); +} + IR::U32 IREmitter::GetCNTFRQ() { return Inst(Opcode::A64GetCNTFRQ); } diff --git a/src/frontend/A64/ir_emitter.h b/src/frontend/A64/ir_emitter.h index a97d8e1a..53a9296d 100644 --- a/src/frontend/A64/ir_emitter.h +++ b/src/frontend/A64/ir_emitter.h @@ -45,6 +45,7 @@ public: void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value); void DataSynchronizationBarrier(); void DataMemoryBarrier(); + void InstructionSynchronizationBarrier(); IR::U32 GetCNTFRQ(); IR::U64 GetCNTPCT(); // TODO: Ensure sub-basic-block cycle counts are updated before this. IR::U32 GetCTR(); diff --git a/src/frontend/A64/translate/impl/system.cpp b/src/frontend/A64/translate/impl/system.cpp index e670eb75..fe7ca3cb 100644 --- a/src/frontend/A64/translate/impl/system.cpp +++ b/src/frontend/A64/translate/impl/system.cpp @@ -71,6 +71,13 @@ bool TranslatorVisitor::DMB(Imm<4> /*CRm*/) { return true; } +bool TranslatorVisitor::ISB(Imm<4> /*CRm*/) { + ir.InstructionSynchronizationBarrier(); + ir.SetPC(ir.Imm64(ir.current_location->PC() + 4)); + ir.SetTerm(IR::Term::ReturnToDispatch{}); + return false; +} + bool TranslatorVisitor::MSR_reg(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) { const auto sys_reg = concatenate(Imm<1>{1}, o0, op1, CRn, CRm, op2).ZeroExtend(); switch (sys_reg) { diff --git a/src/frontend/ir/microinstruction.cpp b/src/frontend/ir/microinstruction.cpp index 906dc20c..4fbce11d 100644 --- a/src/frontend/ir/microinstruction.cpp +++ b/src/frontend/ir/microinstruction.cpp @@ -395,19 +395,20 @@ bool Inst::IsCoprocessorInstruction() const { } bool Inst::MayHaveSideEffects() const { - return op == Opcode::PushRSB || - op == Opcode::A64SetCheckBit || - op == Opcode::A64DataCacheOperationRaised || - op == Opcode::A64DataSynchronizationBarrier || - op == Opcode::A64DataMemoryBarrier || - CausesCPUException() || - WritesToCoreRegister() || - WritesToSystemRegister() || - WritesToCPSR() || - WritesToFPCR() || - WritesToFPSR() || - AltersExclusiveState() || - IsMemoryWrite() || + return op == Opcode::PushRSB || + op == Opcode::A64SetCheckBit || + op == Opcode::A64DataCacheOperationRaised || + op == Opcode::A64DataSynchronizationBarrier || + op == Opcode::A64DataMemoryBarrier || + op == Opcode::A64InstructionSynchronizationBarrier || + CausesCPUException() || + WritesToCoreRegister() || + WritesToSystemRegister() || + WritesToCPSR() || + WritesToFPCR() || + WritesToFPSR() || + AltersExclusiveState() || + IsMemoryWrite() || IsCoprocessorInstruction(); } diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index 69030b32..d4f012c2 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -66,6 +66,7 @@ A64OPC(ExceptionRaised, T::Void, T::U64, A64OPC(DataCacheOperationRaised, T::Void, T::U64, T::U64 ) A64OPC(DataSynchronizationBarrier, T::Void, ) A64OPC(DataMemoryBarrier, T::Void, ) +A64OPC(InstructionSynchronizationBarrier, T::Void, ) A64OPC(GetCNTFRQ, T::U32, ) A64OPC(GetCNTPCT, T::U64, ) A64OPC(GetCTR, T::U32, )