diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp index f037919eb0..137e958e12 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp @@ -117,28 +117,49 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) { const u8* const entrypoint = code.getCurr(); EmitCondPrelude(ctx); - - for (auto iter = block.instructions.begin(); iter != block.instructions.end(); ++iter) [[likely]] { - auto* inst = &*iter; - // Call the relevant Emit* member function. - switch (inst->GetOpcode()) { -#define OPCODE(name, type, ...) \ - case IR::Opcode::name: \ - A32EmitX64::Emit##name(ctx, inst); \ - break; -#define A32OPC(name, type, ...) \ - case IR::Opcode::A32##name: \ - A32EmitX64::EmitA32##name(ctx, inst);\ - break; + typedef void (EmitX64::*EmitHandlerFn)(EmitContext& context, IR::Inst* inst); + constexpr EmitHandlerFn opcode_handlers[] = { +#define OPCODE(name, type, ...) &EmitX64::Emit##name, +#define A32OPC(name, type, ...) +#define A64OPC(name, type, ...) +#include "dynarmic/ir/opcodes.inc" +#undef OPCODE +#undef A32OPC +#undef A64OPC + }; + typedef void (A32EmitX64::*A32EmitHandlerFn)(A32EmitContext& context, IR::Inst* inst); + constexpr A32EmitHandlerFn a32_handlers[] = { +#define OPCODE(...) +#define A32OPC(name, type, ...) &A32EmitX64::EmitA32##name, #define A64OPC(...) #include "dynarmic/ir/opcodes.inc" #undef OPCODE #undef A32OPC +#undef A64OPC + }; + + for (auto& inst : block.instructions) { + auto const opcode = inst.GetOpcode(); + // Call the relevant Emit* member function. + switch (opcode) { +#define OPCODE(name, type, ...) case IR::Opcode::name: goto opcode_branch; +#define A32OPC(name, type, ...) case IR::Opcode::A32##name: goto a32_branch; +#define A64OPC(name, type, ...) +#include "dynarmic/ir/opcodes.inc" +#undef OPCODE +#undef A32OPC #undef A64OPC default: UNREACHABLE(); } - reg_alloc.EndOfAllocScope(); +opcode_branch: + (this->*opcode_handlers[size_t(opcode)])(ctx, &inst); + goto finish_this_inst; +a32_branch: + // Update with FIRST A32 instruction + (this->*a32_handlers[size_t(opcode) - size_t(IR::Opcode::A32SetCheckBit)])(ctx, &inst); +finish_this_inst: + ctx.reg_alloc.EndOfAllocScope(); #ifndef NDEBUG if (conf.very_verbose_debugging_output) EmitVerboseDebuggingOutput(reg_alloc); diff --git a/src/dynarmic/src/dynarmic/ir/opcodes.inc b/src/dynarmic/src/dynarmic/ir/opcodes.inc index b05220834d..ea94a8a4c9 100644 --- a/src/dynarmic/src/dynarmic/ir/opcodes.inc +++ b/src/dynarmic/src/dynarmic/ir/opcodes.inc @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // First we list common shared opcodes // Since we give priority to A64 performance, we include them first, this is so we // can discard all A32 opcodes instead of having a "hole" in our checks @@ -709,6 +712,8 @@ A64OPC(ExclusiveWriteMemory32, U32, U64, A64OPC(ExclusiveWriteMemory64, U32, U64, U64, U64, AccType ) A64OPC(ExclusiveWriteMemory128, U32, U64, U64, U128, AccType ) +// Remember to update: +// - a32_emit_x64.cpp // A32 Context getters/setters A32OPC(SetCheckBit, Void, U1 )