diff --git a/src/dynarmic/backend/arm64/a32_address_space.cpp b/src/dynarmic/backend/arm64/a32_address_space.cpp index 208a033e..a7a8a7a8 100644 --- a/src/dynarmic/backend/arm64/a32_address_space.cpp +++ b/src/dynarmic/backend/arm64/a32_address_space.cpp @@ -303,21 +303,30 @@ EmittedBlockInfo A32AddressSpace::Emit(IR::Block block) { mem.unprotect(); const EmitConfig emit_conf{ - .tpidr_el0{}, - .tpidrro_el0{}, - .cntfreq_el0{}, - .dczid_el0{}, - .ctr_el0{}, - .is_a64 = false, + .optimizations = conf.unsafe_optimizations ? conf.optimizations : conf.optimizations & all_safe_optimizations, + .hook_isb = conf.hook_isb, - .enable_cycle_counting = conf.enable_cycle_counting, + + .cntfreq_el0{}, + .ctr_el0{}, + .dczid_el0{}, + .tpidrro_el0{}, + .tpidr_el0{}, + .wall_clock_cntpct = conf.wall_clock_cntpct, + .enable_cycle_counting = conf.enable_cycle_counting, + .always_little_endian = conf.always_little_endian, + .descriptor_to_fpcr = [](const IR::LocationDescriptor& location) { return FP::FPCR{A32::LocationDescriptor{location}.FPSCR().Value()}; }, + .emit_cond = EmitA32Cond, + .emit_condition_failed_terminal = EmitA32ConditionFailedTerminal, + .emit_terminal = EmitA32Terminal, + .state_nzcv_offset = offsetof(A32JitState, cpsr_nzcv), .state_fpsr_offset = offsetof(A32JitState, fpsr), + .coprocessors = conf.coprocessors, - .optimizations = conf.unsafe_optimizations ? conf.optimizations : conf.optimizations & all_safe_optimizations, }; EmittedBlockInfo block_info = EmitArm64(code, std::move(block), emit_conf); diff --git a/src/dynarmic/backend/arm64/a64_address_space.cpp b/src/dynarmic/backend/arm64/a64_address_space.cpp index 72b12b6d..3bb2b7cf 100644 --- a/src/dynarmic/backend/arm64/a64_address_space.cpp +++ b/src/dynarmic/backend/arm64/a64_address_space.cpp @@ -433,21 +433,30 @@ EmittedBlockInfo A64AddressSpace::Emit(IR::Block block) { mem.unprotect(); const EmitConfig emit_conf{ + .optimizations = conf.unsafe_optimizations ? conf.optimizations : conf.optimizations & all_safe_optimizations, + + .hook_isb = conf.hook_isb, + .tpidr_el0 = conf.tpidr_el0, .tpidrro_el0 = conf.tpidrro_el0, .cntfreq_el0 = conf.cntfrq_el0, .dczid_el0 = conf.dczid_el0, .ctr_el0 = conf.ctr_el0, - .is_a64 = true, - .hook_isb = conf.hook_isb, - .enable_cycle_counting = conf.enable_cycle_counting, + .wall_clock_cntpct = conf.wall_clock_cntpct, + .enable_cycle_counting = conf.enable_cycle_counting, + .always_little_endian = true, + .descriptor_to_fpcr = [](const IR::LocationDescriptor& location) { return A64::LocationDescriptor{location}.FPCR(); }, + .emit_cond = EmitA64Cond, + .emit_condition_failed_terminal = EmitA64ConditionFailedTerminal, + .emit_terminal = EmitA64Terminal, + .state_nzcv_offset = offsetof(A64JitState, cpsr_nzcv), .state_fpsr_offset = offsetof(A64JitState, fpsr), + .coprocessors{}, - .optimizations = conf.unsafe_optimizations ? conf.optimizations : conf.optimizations & all_safe_optimizations, }; EmittedBlockInfo block_info = EmitArm64(code, std::move(block), emit_conf); diff --git a/src/dynarmic/backend/arm64/emit_arm64.cpp b/src/dynarmic/backend/arm64/emit_arm64.cpp index 625bb379..ef553f2b 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64.cpp @@ -8,7 +8,6 @@ #include #include -#include "dynarmic/backend/arm64/a32_jitstate.h" #include "dynarmic/backend/arm64/abi.h" #include "dynarmic/backend/arm64/emit_context.h" #include "dynarmic/backend/arm64/fpsr_manager.h" @@ -191,15 +190,9 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E ASSERT(ctx.block.HasConditionFailedLocation()); oaknut::Label pass; - if (conf.is_a64) { - pass = EmitA64Cond(code, ctx, ctx.block.GetCondition()); - EmitAddCycles(code, ctx, ctx.block.ConditionFailedCycleCount()); - EmitA64ConditionFailedTerminal(code, ctx); - } else { - pass = EmitA32Cond(code, ctx, ctx.block.GetCondition()); - EmitAddCycles(code, ctx, ctx.block.ConditionFailedCycleCount()); - EmitA32ConditionFailedTerminal(code, ctx); - } + pass = conf.emit_cond(code, ctx, ctx.block.GetCondition()); + EmitAddCycles(code, ctx, ctx.block.ConditionFailedCycleCount()); + conf.emit_condition_failed_terminal(code, ctx); code.l(pass); } @@ -238,11 +231,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E reg_alloc.AssertNoMoreUses(); EmitAddCycles(code, ctx, block.CycleCount()); - if (conf.is_a64) { - EmitA64Terminal(code, ctx); - } else { - EmitA32Terminal(code, ctx); - } + conf.emit_terminal(code, ctx); ebi.size = code.ptr() - ebi.entry_point; return ebi; diff --git a/src/dynarmic/backend/arm64/emit_arm64.h b/src/dynarmic/backend/arm64/emit_arm64.h index ee3fc03a..20d10f92 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.h +++ b/src/dynarmic/backend/arm64/emit_arm64.h @@ -38,6 +38,8 @@ enum class Opcode; namespace Dynarmic::Backend::Arm64 { +struct EmitContext; + using CodePtr = std::byte*; enum class LinkTarget { @@ -90,31 +92,39 @@ struct EmittedBlockInfo { }; struct EmitConfig { - u64* tpidr_el0; - const u64* tpidrro_el0; - u64 cntfreq_el0; - u32 dczid_el0; - u32 ctr_el0; - bool is_a64; + OptimizationFlag optimizations; + bool HasOptimization(OptimizationFlag f) const { return (f & optimizations) != no_optimizations; } + bool hook_isb; - bool enable_cycle_counting; + + // System registers + u64 cntfreq_el0; + u32 ctr_el0; + u32 dczid_el0; + const u64* tpidrro_el0; + u64* tpidr_el0; + + // Timing bool wall_clock_cntpct; + bool enable_cycle_counting; + + // Endianness bool always_little_endian; + // Frontend specific callbacks FP::FPCR (*descriptor_to_fpcr)(const IR::LocationDescriptor& descriptor); + oaknut::Label (*emit_cond)(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Cond cond); + void (*emit_condition_failed_terminal)(oaknut::CodeGenerator& code, EmitContext& ctx); + void (*emit_terminal)(oaknut::CodeGenerator& code, EmitContext& ctx); + // State offsets size_t state_nzcv_offset; size_t state_fpsr_offset; + // A32 specific std::array, 16> coprocessors{}; - - OptimizationFlag optimizations; - - bool HasOptimization(OptimizationFlag f) const { return (f & optimizations) != no_optimizations; } }; -struct EmitContext; - EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const EmitConfig& emit_conf); template diff --git a/src/dynarmic/backend/arm64/emit_arm64_a64.cpp b/src/dynarmic/backend/arm64/emit_arm64_a64.cpp index 44c39096..a0f2fac9 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_a64.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_a64.cpp @@ -19,8 +19,6 @@ namespace Dynarmic::Backend::Arm64 { using namespace oaknut::util; -static constexpr int nzcv_c_flag_shift = 29; - oaknut::Label EmitA64Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond cond) { oaknut::Label pass; // TODO: Flags in host flags @@ -145,7 +143,7 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& c auto Wflag = ctx.reg_alloc.WriteW(inst); RegAlloc::Realize(Wflag); code.LDR(Wflag, Xstate, offsetof(A64JitState, cpsr_nzcv)); - code.AND(Wflag, Wflag, 1 << nzcv_c_flag_shift); + code.AND(Wflag, Wflag, 1 << 29); } template<> diff --git a/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp b/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp index ce9bab2f..d534c8b8 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp @@ -258,7 +258,7 @@ void EmitToFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) }); } -template +template static void EmitTwoOpFallbackWithoutRegAlloc(oaknut::CodeGenerator& code, EmitContext& ctx, oaknut::QReg Qresult, oaknut::QReg Qarg1, Lambda lambda, bool fpcr_controlled) { const auto fn = static_cast*>(lambda); @@ -274,7 +274,7 @@ static void EmitTwoOpFallbackWithoutRegAlloc(oaknut::CodeGenerator& code, EmitCo code.ADD(X0, Xscratch0, 0 * 16); code.ADD(X1, Xscratch0, 1 * 16); code.MOV(X2, fpcr); - code.ADD(X3, Xstate, offsetof(JitState, fpsr)); + code.ADD(X3, Xstate, ctx.conf.state_fpsr_offset); code.STR(Qarg1, X1); code.BLR(Xscratch1); @@ -289,7 +289,7 @@ static void EmitTwoOpFallbackWithoutRegAlloc(oaknut::CodeGenerator& code, EmitCo code.l(end); } -template +template static void EmitTwoOpFallback(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, Lambda lambda) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto Qarg1 = ctx.reg_alloc.ReadQ(args[0]); @@ -300,7 +300,7 @@ static void EmitTwoOpFallback(oaknut::CodeGenerator& code, EmitContext& ctx, IR: ctx.fpsr.Spill(); const bool fpcr_controlled = args[fpcr_controlled_arg_index].GetImmediateU1(); - EmitTwoOpFallbackWithoutRegAlloc(code, ctx, Qresult, Qarg1, lambda, fpcr_controlled); + EmitTwoOpFallbackWithoutRegAlloc(code, ctx, Qresult, Qarg1, lambda, fpcr_controlled); } template<> @@ -592,11 +592,7 @@ void EmitIR(oaknut::CodeGenerator& code, EmitCon }, mp::cartesian_product{}); - if (ctx.conf.is_a64) { - EmitTwoOpFallback<3, A64JitState>(code, ctx, inst, lut.at(std::make_tuple(rounding, exact))); - } else { - EmitTwoOpFallback<3, A32JitState>(code, ctx, inst, lut.at(std::make_tuple(rounding, exact))); - } + EmitTwoOpFallback<3>(code, ctx, inst, lut.at(std::make_tuple(rounding, exact))); } template<>