From 94e90aba685c549ada10e5b48de16f039dd45fc7 Mon Sep 17 00:00:00 2001 From: SachinVin Date: Sun, 17 May 2020 20:39:50 +0530 Subject: [PATCH] backend/A64:port single stepping fix --- src/backend/A64/a32_emit_a64.cpp | 83 ++++++++++++++++++++++--------- src/backend/A64/a32_emit_a64.h | 21 ++++---- src/backend/A64/a32_interface.cpp | 14 +++--- src/backend/A64/emit_a64.cpp | 20 ++------ src/backend/A64/emit_a64.h | 21 ++++---- 5 files changed, 92 insertions(+), 67 deletions(-) diff --git a/src/backend/A64/a32_emit_a64.cpp b/src/backend/A64/a32_emit_a64.cpp index 0284066c..1c2a4234 100644 --- a/src/backend/A64/a32_emit_a64.cpp +++ b/src/backend/A64/a32_emit_a64.cpp @@ -61,6 +61,10 @@ A32::LocationDescriptor A32EmitContext::Location() const { return A32::LocationDescriptor{block.Location()}; } +bool A32EmitContext::IsSingleStep() const { + return A32::LocationDescriptor{block.Location()}.SingleStepping(); +} + FP::RoundingMode A32EmitContext::FPSCR_RMode() const { return Location().FPSCR().RMode(); } @@ -99,14 +103,13 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) { code.DisableWriting(); }; - code.AlignCode16(); - const u8* entrypoint = code.GetCodePtr(); + RegAlloc reg_alloc{code, A32JitState::SpillCount, SpillToOpArg}; + A32EmitContext ctx{reg_alloc, block}; + + const u8* entrypoint = code.AlignCode16(); // Start emitting. - EmitCondPrelude(block); - - RegAlloc reg_alloc{code, A32JitState::SpillCount, SpillToOpArg}; - A32EmitContext ctx{reg_alloc, block}; + EmitCondPrelude(ctx); for (auto iter = block.begin(); iter != block.end(); ++iter) { IR::Inst* inst = &*iter; @@ -139,7 +142,7 @@ A32EmitA64::BlockDescriptor A32EmitA64::Emit(IR::Block& block) { reg_alloc.AssertNoMoreUses(); EmitAddCycles(block.CycleCount()); - EmitA64::EmitTerminal(block.GetTerminal(), block.Location()); + EmitA64::EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); code.BRK(0); code.PatchConstPool(); code.FlushIcacheSection(entrypoint, code.GetCodePtr()); @@ -166,6 +169,20 @@ void A32EmitA64::InvalidateCacheRanges(const boost::icl::interval_set& rang InvalidateBasicBlocks(block_ranges.InvalidateRanges(ranges)); } +void A32EmitA64::EmitCondPrelude(const A32EmitContext& ctx) { + if (ctx.block.GetCondition() == IR::Cond::AL) { + ASSERT(!ctx.block.HasConditionFailedLocation()); + return; + } + + ASSERT(ctx.block.HasConditionFailedLocation()); + + FixupBranch pass = EmitCond(ctx.block.GetCondition()); + EmitAddCycles(ctx.block.ConditionFailedCycleCount()); + EmitTerminal(IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, ctx.block.Location(), ctx.IsSingleStep()); + code.SetJumpTarget(pass); +} + void A32EmitA64::ClearFastDispatchTable() { if (config.enable_fast_dispatch) { fast_dispatch_table.fill({}); @@ -664,7 +681,7 @@ void A32EmitA64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto& arg = args[0]; - const u32 upper_without_t = (ctx.Location().UniqueHash() >> 32) & 0xFFFFFFFE; + const u32 upper_without_t = (ctx.Location().SetSingleStepping(false).UniqueHash() >> 32) & 0xFFFFFFFE; // Pseudocode: // if (new_pc & 1) { @@ -1397,7 +1414,7 @@ void A32EmitA64::FastmemCallback(CodePtr PC) { fastmem_patch_info.erase(iter); } -void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) { +void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool) { ASSERT_MSG(A32::LocationDescriptor{terminal.next}.TFlag() == A32::LocationDescriptor{initial_location}.TFlag(), "Unimplemented"); ASSERT_MSG(A32::LocationDescriptor{terminal.next}.EFlag() == A32::LocationDescriptor{initial_location}.EFlag(), "Unimplemented"); @@ -1409,13 +1426,13 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDesc code.ReturnFromRunCode(true); // TODO: Check cycles } -void A32EmitA64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescriptor) { +void A32EmitA64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) { code.ReturnFromRunCode(); } void A32EmitA64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_location, IR::LocationDescriptor old_location) { auto get_upper = [](const IR::LocationDescriptor &desc) -> u32 { - return static_cast(desc.Value() >> 32); + return static_cast(A32::LocationDescriptor{desc}.SetSingleStepping(false).UniqueHash() >> 32); }; const u32 old_upper = get_upper(old_location); @@ -1430,9 +1447,16 @@ void A32EmitA64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_locat } } -void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) { +void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool is_single_step) { EmitSetUpperLocationDescriptor(terminal.next, initial_location); + if (!config.enable_optimizations || is_single_step) { + code.MOVI2R(DecodeReg(code.ABI_SCRATCH1), A32::LocationDescriptor{terminal.next}.PC()); + code.STR(INDEX_UNSIGNED, DecodeReg(code.ABI_SCRATCH1), X28, MJitStateReg(A32::Reg::PC)); + code.ReturnFromRunCode(); + return; + } + code.CMP(X26, ZR); patch_information[terminal.next].jg.emplace_back(code.GetCodePtr()); @@ -1457,8 +1481,15 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDesc code.SwitchToNearCode(); } -void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) { +void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) { EmitSetUpperLocationDescriptor(terminal.next, initial_location); + + if (!config.enable_optimizations || is_single_step) { + code.MOVI2R(DecodeReg(code.ABI_SCRATCH1), A32::LocationDescriptor{terminal.next}.PC()); + code.STR(INDEX_UNSIGNED, DecodeReg(code.ABI_SCRATCH1), X28, MJitStateReg(A32::Reg::PC)); + code.ReturnFromRunCode(); + return; + } patch_information[terminal.next].jmp.emplace_back(code.GetCodePtr()); if (auto next_bb = GetBasicBlock(terminal.next)) { @@ -1468,41 +1499,45 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::Location } } -void A32EmitA64::EmitTerminalImpl(IR::Term::PopRSBHint, IR::LocationDescriptor) { +void A32EmitA64::EmitTerminalImpl(IR::Term::PopRSBHint, IR::LocationDescriptor, bool is_single_step) { + if (!config.enable_optimizations || is_single_step) { + code.ReturnFromRunCode(); + return; + } code.B(terminal_handler_pop_rsb_hint); } -void A32EmitA64::EmitTerminalImpl(IR::Term::FastDispatchHint, IR::LocationDescriptor) { - if (config.enable_fast_dispatch) { +void A32EmitA64::EmitTerminalImpl(IR::Term::FastDispatchHint, IR::LocationDescriptor, bool is_single_step) { + if (config.enable_fast_dispatch && !is_single_step) { code.B(terminal_handler_fast_dispatch_hint); } else { code.ReturnFromRunCode(); } } -void A32EmitA64::EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location) { +void A32EmitA64::EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) { FixupBranch pass = EmitCond(terminal.if_); - EmitTerminal(terminal.else_, initial_location); + EmitTerminal(terminal.else_, initial_location, is_single_step); code.SetJumpTarget(pass); - EmitTerminal(terminal.then_, initial_location); + EmitTerminal(terminal.then_, initial_location, is_single_step); } -void A32EmitA64::EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location) { +void A32EmitA64::EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) { FixupBranch fail; code.LDRB(INDEX_UNSIGNED, DecodeReg(code.ABI_SCRATCH1), X28, offsetof(A32JitState, check_bit)); fail = code.CBZ(DecodeReg(code.ABI_SCRATCH1)); - EmitTerminal(terminal.then_, initial_location); + EmitTerminal(terminal.then_, initial_location, is_single_step); code.SetJumpTarget(fail); - EmitTerminal(terminal.else_, initial_location); + EmitTerminal(terminal.else_, initial_location, is_single_step); } -void A32EmitA64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location) { +void A32EmitA64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) { code.LDRB(INDEX_UNSIGNED, DecodeReg(code.ABI_SCRATCH1), X28, offsetof(A32JitState, halt_requested)); // Conditional branch only gives +/- 1MB of branch distance FixupBranch zero = code.CBZ(DecodeReg(code.ABI_SCRATCH1)); code.B(code.GetForceReturnFromRunCodeAddress()); code.SetJumpTarget(zero); - EmitTerminal(terminal.else_, initial_location); + EmitTerminal(terminal.else_, initial_location, is_single_step); } void A32EmitA64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr) { diff --git a/src/backend/A64/a32_emit_a64.h b/src/backend/A64/a32_emit_a64.h index 320cb3d1..4989cccb 100644 --- a/src/backend/A64/a32_emit_a64.h +++ b/src/backend/A64/a32_emit_a64.h @@ -30,6 +30,7 @@ class RegAlloc; struct A32EmitContext final : public EmitContext { A32EmitContext(RegAlloc& reg_alloc, IR::Block& block); A32::LocationDescriptor Location() const; + bool IsSingleStep() const; FP::RoundingMode FPSCR_RMode() const override; u32 FPCR() const override; bool FPSCR_FTZ() const override; @@ -60,6 +61,8 @@ protected: BlockRangeInformation block_ranges; ExceptionHandler exception_handler; + void EmitCondPrelude(const A32EmitContext& ctx); + struct FastDispatchEntry { u64 location_descriptor = 0xFFFF'FFFF'FFFF'FFFFull; const void* code_ptr = nullptr; @@ -115,15 +118,15 @@ protected: // Terminal instruction emitters void EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_location, IR::LocationDescriptor old_location); - void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) override; - void EmitTerminalImpl(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location) override; - void EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) override; - void EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) override; - void EmitTerminalImpl(IR::Term::PopRSBHint terminal, IR::LocationDescriptor initial_location) override; - void EmitTerminalImpl(IR::Term::FastDispatchHint terminal, IR::LocationDescriptor initial_location) override; - void EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location) override; - void EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location) override; - void EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location) override; + void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool is_single_step) override; + void EmitTerminalImpl(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location, bool is_single_step) override; + void EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool is_single_step) override; + void EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) override; + void EmitTerminalImpl(IR::Term::PopRSBHint terminal, IR::LocationDescriptor initial_location, bool is_single_step) override; + void EmitTerminalImpl(IR::Term::FastDispatchHint terminal, IR::LocationDescriptor initial_location, bool is_single_step) override; + void EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) override; + void EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) override; + void EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) override; // Patching void Unpatch(const IR::LocationDescriptor& target_desc) override; diff --git a/src/backend/A64/a32_interface.cpp b/src/backend/A64/a32_interface.cpp index 531bd7b8..22eddb6b 100644 --- a/src/backend/A64/a32_interface.cpp +++ b/src/backend/A64/a32_interface.cpp @@ -155,12 +155,14 @@ private: } IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, [this](u32 vaddr) { return config.callbacks->MemoryReadCode(vaddr); }, {config.define_unpredictable_behaviour, config.hook_hint_instructions}); - Optimization::A32GetSetElimination(ir_block); - Optimization::DeadCodeElimination(ir_block); - Optimization::A32ConstantMemoryReads(ir_block, config.callbacks); - Optimization::ConstantPropagation(ir_block); - Optimization::DeadCodeElimination(ir_block); - Optimization::A32MergeInterpretBlocksPass(ir_block, config.callbacks); + if (config.enable_optimizations) { + Optimization::A32GetSetElimination(ir_block); + Optimization::DeadCodeElimination(ir_block); + Optimization::A32ConstantMemoryReads(ir_block, config.callbacks); + Optimization::ConstantPropagation(ir_block); + Optimization::DeadCodeElimination(ir_block); + Optimization::A32MergeInterpretBlocksPass(ir_block, config.callbacks); + } Optimization::VerificationPass(ir_block); return emitter.Emit(ir_block); } diff --git a/src/backend/A64/emit_a64.cpp b/src/backend/A64/emit_a64.cpp index 96da14f0..c1a3070f 100644 --- a/src/backend/A64/emit_a64.cpp +++ b/src/backend/A64/emit_a64.cpp @@ -210,20 +210,6 @@ FixupBranch EmitA64::EmitCond(IR::Cond cond) { return label; } -void EmitA64::EmitCondPrelude(const IR::Block& block) { - if (block.GetCondition() == IR::Cond::AL) { - ASSERT(!block.HasConditionFailedLocation()); - return; - } - - ASSERT(block.HasConditionFailedLocation()); - - FixupBranch pass = EmitCond(block.GetCondition()); - EmitAddCycles(block.ConditionFailedCycleCount()); - EmitTerminal(IR::Term::LinkBlock{block.ConditionFailedLocation()}, block.Location()); - code.SetJumpTarget(pass); -} - EmitA64::BlockDescriptor EmitA64::RegisterBlock(const IR::LocationDescriptor& descriptor, CodePtr entrypoint, size_t size) { PerfMapRegister(entrypoint, code.GetCodePtr(), LocationDescriptorToFriendlyName(descriptor)); Patch(descriptor, entrypoint); @@ -233,11 +219,11 @@ EmitA64::BlockDescriptor EmitA64::RegisterBlock(const IR::LocationDescriptor& de return block_desc; } -void EmitA64::EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location) { - Common::VisitVariant(terminal, [this, &initial_location](auto x) { +void EmitA64::EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) { + Common::VisitVariant(terminal, [this, initial_location, is_single_step](auto x) { using T = std::decay_t; if constexpr (!std::is_same_v) { - this->EmitTerminalImpl(x, initial_location); + this->EmitTerminalImpl(x, initial_location, is_single_step); } else { ASSERT_MSG(false, "Invalid terminal"); } diff --git a/src/backend/A64/emit_a64.h b/src/backend/A64/emit_a64.h index d67e6967..1716af6d 100644 --- a/src/backend/A64/emit_a64.h +++ b/src/backend/A64/emit_a64.h @@ -88,21 +88,20 @@ protected: virtual std::string LocationDescriptorToFriendlyName(const IR::LocationDescriptor&) const = 0; void EmitAddCycles(size_t cycles); FixupBranch EmitCond(IR::Cond cond); - void EmitCondPrelude(const IR::Block& block); BlockDescriptor RegisterBlock(const IR::LocationDescriptor& location_descriptor, CodePtr entrypoint, size_t size); void PushRSBHelper(Arm64Gen::ARM64Reg loc_desc_reg, Arm64Gen::ARM64Reg index_reg, IR::LocationDescriptor target); // Terminal instruction emitters - void EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location); - virtual void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) = 0; - virtual void EmitTerminalImpl(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location) = 0; - virtual void EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) = 0; - virtual void EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) = 0; - virtual void EmitTerminalImpl(IR::Term::PopRSBHint terminal, IR::LocationDescriptor initial_location) = 0; - virtual void EmitTerminalImpl(IR::Term::FastDispatchHint terminal, IR::LocationDescriptor initial_location) = 0; - virtual void EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location) = 0; - virtual void EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location) = 0; - virtual void EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location) = 0; + void EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step); + virtual void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0; + virtual void EmitTerminalImpl(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0; + virtual void EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0; + virtual void EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0; + virtual void EmitTerminalImpl(IR::Term::PopRSBHint terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0; + virtual void EmitTerminalImpl(IR::Term::FastDispatchHint terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0; + virtual void EmitTerminalImpl(IR::Term::If terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0; + virtual void EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0; + virtual void EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) = 0; // Patching struct PatchInformation {