[dynarmic] remove dead-code interpreter (#3547)

interpreter was never called in practice and doesn't do anything other than just crash

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3547
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2026-02-21 01:53:34 +01:00 committed by crueter
parent 732b7eb560
commit f76dc401c3
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
36 changed files with 41 additions and 231 deletions

View file

@ -286,15 +286,6 @@ Exclusive OR (i.e.: XOR)
Memory access. Memory access.
### Terminal: Interpret
```c++
SetTerm(IR::Term::Interpret{next})
```
This terminal instruction calls the interpreter, starting at `next`.
The interpreter must interpret exactly one instruction.
### Terminal: ReturnToDispatch ### Terminal: ReturnToDispatch
```c++ ```c++

View file

@ -117,11 +117,6 @@ public:
MemoryWrite32(vaddr + 4, u32(value >> 32)); MemoryWrite32(vaddr + 4, u32(value >> 32));
} }
void InterpreterFallback(u32 pc, size_t num_instructions) override {
// This is never called in practice.
std::terminate();
}
void CallSVC(u32 swi) override { void CallSVC(u32 swi) override {
// Do something. // Do something.
} }

View file

@ -88,13 +88,6 @@ bool DynarmicCallbacks32::MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expec
m_memory.WriteExclusive64(vaddr, value, expected); m_memory.WriteExclusive64(vaddr, value, expected);
} }
void DynarmicCallbacks32::InterpreterFallback(u32 pc, std::size_t num_instructions) {
m_parent.LogBacktrace(m_process);
LOG_ERROR(Core_ARM,
"Unimplemented instruction @ {:#X} for {} instructions (instr = {:08X})", pc,
num_instructions, m_memory.Read32(pc));
}
void DynarmicCallbacks32::ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) { void DynarmicCallbacks32::ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) {
switch (exception) { switch (exception) {
case Dynarmic::A32::Exception::NoExecuteFault: case Dynarmic::A32::Exception::NoExecuteFault:

View file

@ -43,7 +43,6 @@ public:
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override; bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override;
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override; bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override;
bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override; bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override;
void InterpreterFallback(u32 pc, std::size_t num_instructions) override;
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override; void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override;
void CallSVC(u32 swi) override; void CallSVC(u32 swi) override;
void AddTicks(u64 ticks) override; void AddTicks(u64 ticks) override;

View file

@ -102,13 +102,6 @@ bool DynarmicCallbacks64::MemoryWriteExclusive128(u64 vaddr, Dynarmic::A64::Vect
m_memory.WriteExclusive128(vaddr, value, expected); m_memory.WriteExclusive128(vaddr, value, expected);
} }
void DynarmicCallbacks64::InterpreterFallback(u64 pc, std::size_t num_instructions) {
m_parent.LogBacktrace(m_process);
LOG_ERROR(Core_ARM, "Unimplemented instruction @ {:#X} for {} instructions (instr = {:08X})", pc,
num_instructions, m_memory.Read32(pc));
ReturnException(pc, PrefetchAbort);
}
void DynarmicCallbacks64::InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, u64 value) { void DynarmicCallbacks64::InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, u64 value) {
switch (op) { switch (op) {
case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: { case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: {

View file

@ -52,7 +52,6 @@ public:
bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override; bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override;
bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override; bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override;
bool MemoryWriteExclusive128(u64 vaddr, Dynarmic::A64::Vector value, Dynarmic::A64::Vector expected) override; bool MemoryWriteExclusive128(u64 vaddr, Dynarmic::A64::Vector value, Dynarmic::A64::Vector expected) override;
void InterpreterFallback(u64 pc, std::size_t num_instructions) override;
void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, u64 value) override; void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, u64 value) override;
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override; void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override;
void CallSVC(u32 svc) override; void CallSVC(u32 svc) override;

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@ -772,12 +772,8 @@ std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, m
u32 instruction = memory.Read32(pc); u32 instruction = memory.Read32(pc);
bool was_executed = false; bool was_executed = false;
if (auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction)) { auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction);
was_executed = decoder->get().call(visitor, instruction); was_executed = decoder.get().call(visitor, instruction);
} else {
LOG_ERROR(Core_ARM, "Unallocated encoding: {:#x}", instruction);
}
return was_executed ? std::optional<u64>(pc + 4) : std::nullopt; return was_executed ? std::optional<u64>(pc + 4) : std::nullopt;
} }

View file

@ -116,7 +116,6 @@ public:
void CallSVC(u32 swi) override; void CallSVC(u32 swi) override;
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override; void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override;
void InterpreterFallback(u64 pc, size_t num_instructions) override;
void AddTicks(u64 ticks) override {} void AddTicks(u64 ticks) override {}
u64 GetTicksRemaining() override { u64 GetTicksRemaining() override {
@ -432,11 +431,6 @@ void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception excep
parent.jit->HaltExecution(); parent.jit->HaltExecution();
} }
void DynarmicCallbacks64::InterpreterFallback(u64 pc, size_t num_instructions) {
LOG_CRITICAL(Service_JIT, "Unimplemented instruction PC @ {:08x}", pc);
parent.jit->HaltExecution();
}
JITContext::JITContext(Core::Memory::Memory& memory) JITContext::JITContext(Core::Memory::Memory& memory)
: impl{std::make_unique<JITContextImpl>(memory)} {} : impl{std::make_unique<JITContextImpl>(memory)} {}

View file

@ -36,10 +36,6 @@ oaknut::Label EmitA32Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step); void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA32Terminal(oaknut::CodeGenerator&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
UNREACHABLE();
}
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) { void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher); EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher);
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -35,10 +35,6 @@ oaknut::Label EmitA64Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step); void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA64Terminal(oaknut::CodeGenerator&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
UNREACHABLE();
}
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) { void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher); EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher);
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -114,10 +114,6 @@ void EmitA32Cond(biscuit::Assembler& as, EmitContext&, IR::Cond cond, biscuit::L
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step); void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
void EmitA32Terminal(biscuit::Assembler&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
UNREACHABLE();
}
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) { void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
EmitRelocation(as, ctx, LinkTarget::ReturnFromRunCode); EmitRelocation(as, ctx, LinkTarget::ReturnFromRunCode);
} }

View file

@ -1135,19 +1135,6 @@ void A32EmitX64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_locat
} }
namespace { namespace {
void EmitTerminalImpl(A32EmitX64& e, IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool) {
ASSERT(A32::LocationDescriptor{terminal.next}.TFlag() == A32::LocationDescriptor{initial_location}.TFlag() && "Unimplemented");
ASSERT(A32::LocationDescriptor{terminal.next}.EFlag() == A32::LocationDescriptor{initial_location}.EFlag() && "Unimplemented");
ASSERT(terminal.num_instructions == 1 && "Unimplemented");
e.code.mov(e.code.ABI_PARAM2.cvt32(), A32::LocationDescriptor{terminal.next}.PC());
e.code.mov(e.code.ABI_PARAM3.cvt32(), 1);
e.code.mov(MJitStateReg(A32::Reg::PC), e.code.ABI_PARAM2.cvt32());
e.code.SwitchMxcsrOnExit();
Devirtualize<&A32::UserCallbacks::InterpreterFallback>(e.conf.callbacks).EmitCall(e.code);
e.code.ReturnFromRunCode(true); // TODO: Check cycles
}
void EmitTerminalImpl(A32EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) { void EmitTerminalImpl(A32EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
e.code.ReturnFromRunCode(); e.code.ReturnFromRunCode();
} }

View file

@ -619,16 +619,6 @@ std::string A64EmitX64::LocationDescriptorToFriendlyName(const IR::LocationDescr
} }
namespace { namespace {
void EmitTerminalImpl(A64EmitX64& e, IR::Term::Interpret terminal, IR::LocationDescriptor, bool) {
e.code.SwitchMxcsrOnExit();
Devirtualize<&A64::UserCallbacks::InterpreterFallback>(e.conf.callbacks).EmitCall(e.code, [&](RegList param) {
e.code.mov(param[0], A64::LocationDescriptor{terminal.next}.PC());
e.code.mov(qword[e.code.ABI_JIT_PTR + offsetof(A64JitState, pc)], param[0]);
e.code.mov(param[1].cvt32(), terminal.num_instructions);
});
e.code.ReturnFromRunCode(true); // TODO: Check cycles
}
void EmitTerminalImpl(A64EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) { void EmitTerminalImpl(A64EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
e.code.ReturnFromRunCode(); e.code.ReturnFromRunCode();
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -35,11 +35,6 @@ bool TranslatorVisitor::VFPConditionPassed(Cond cond) {
return ArmConditionPassed(cond); return ArmConditionPassed(cond);
} }
bool TranslatorVisitor::InterpretThisInstruction() {
ir.SetTerm(IR::Term::Interpret(ir.current_location));
return false;
}
bool TranslatorVisitor::UnpredictableInstruction() { bool TranslatorVisitor::UnpredictableInstruction() {
return RaiseException(Exception::UnpredictableInstruction); return RaiseException(Exception::UnpredictableInstruction);
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -39,7 +39,6 @@ struct TranslatorVisitor final {
bool ThumbConditionPassed(); bool ThumbConditionPassed();
bool VFPConditionPassed(Cond cond); bool VFPConditionPassed(Cond cond);
bool InterpretThisInstruction();
bool UnpredictableInstruction(); bool UnpredictableInstruction();
bool UndefinedInstruction(); bool UndefinedInstruction();
bool DecodeError(); bool DecodeError();

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -871,11 +871,11 @@ bool TranslatorVisitor::arm_LDMIB(Cond cond, bool W, Reg n, RegList list) {
} }
bool TranslatorVisitor::arm_LDM_usr() { bool TranslatorVisitor::arm_LDM_usr() {
return InterpretThisInstruction(); UNREACHABLE();
} }
bool TranslatorVisitor::arm_LDM_eret() { bool TranslatorVisitor::arm_LDM_eret() {
return InterpretThisInstruction(); UNREACHABLE();
} }
static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) { static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
@ -956,7 +956,7 @@ bool TranslatorVisitor::arm_STMIB(Cond cond, bool W, Reg n, RegList list) {
} }
bool TranslatorVisitor::arm_STM_usr() { bool TranslatorVisitor::arm_STM_usr() {
return InterpretThisInstruction(); UNREACHABLE();
} }
} // namespace Dynarmic::A32 } // namespace Dynarmic::A32

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -15,7 +15,7 @@ namespace Dynarmic::A32 {
// CPS<effect> <iflags>{, #<mode>} // CPS<effect> <iflags>{, #<mode>}
// CPS #<mode> // CPS #<mode>
bool TranslatorVisitor::arm_CPS() { bool TranslatorVisitor::arm_CPS() {
return InterpretThisInstruction(); UNREACHABLE();
} }
// MRS<c> <Rd>, <spec_reg> // MRS<c> <Rd>, <spec_reg>
@ -107,7 +107,7 @@ bool TranslatorVisitor::arm_MSR_reg(Cond cond, unsigned mask, Reg n) {
// RFE{<amode>} <Rn>{!} // RFE{<amode>} <Rn>{!}
bool TranslatorVisitor::arm_RFE() { bool TranslatorVisitor::arm_RFE() {
return InterpretThisInstruction(); UNREACHABLE();
} }
// SETEND <endian_specifier> // SETEND <endian_specifier>
@ -118,7 +118,7 @@ bool TranslatorVisitor::arm_SETEND(bool E) {
// SRS{<amode>} SP{!}, #<mode> // SRS{<amode>} SP{!}, #<mode>
bool TranslatorVisitor::arm_SRS() { bool TranslatorVisitor::arm_SRS() {
return InterpretThisInstruction(); UNREACHABLE();
} }
} // namespace Dynarmic::A32 } // namespace Dynarmic::A32

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -68,14 +68,16 @@ constexpr DecodeTable<V> GetDecodeTable() {
return table; return table;
} }
/// In practice it must always suceed, otherwise something else unrelated would have gone awry
template<typename V> template<typename V>
std::optional<std::reference_wrapper<const Matcher<V>>> Decode(u32 instruction) { std::reference_wrapper<const Matcher<V>> Decode(u32 instruction) {
alignas(64) static const auto table = GetDecodeTable<V>(); alignas(64) static const auto table = GetDecodeTable<V>();
const auto& subtable = table[detail::ToFastLookupIndex(instruction)]; const auto& subtable = table[detail::ToFastLookupIndex(instruction)];
auto iter = std::find_if(subtable.begin(), subtable.end(), [instruction](const auto& matcher) { auto iter = std::find_if(subtable.begin(), subtable.end(), [instruction](const auto& matcher) {
return matcher.Matches(instruction); return matcher.Matches(instruction);
}); });
return iter != subtable.end() ? std::optional<std::reference_wrapper<const Matcher<V>>>(*iter) : std::nullopt; DEBUG_ASSERT(iter != subtable.end());
return std::reference_wrapper<const Matcher<V>>(*iter);
} }
template<typename V> template<typename V>

View file

@ -23,17 +23,12 @@ void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFu
bool should_continue = true; bool should_continue = true;
do { do {
const u64 pc = visitor.ir.current_location->PC(); const u64 pc = visitor.ir.current_location->PC();
if (const auto instruction = memory_read_code(pc)) { if (const auto instruction = memory_read_code(pc)) {
if (auto decoder = Decode<TranslatorVisitor>(*instruction)) { auto decoder = Decode<TranslatorVisitor>(*instruction);
should_continue = decoder->get().call(visitor, *instruction); should_continue = decoder.get().call(visitor, *instruction);
} else {
should_continue = visitor.InterpretThisInstruction();
}
} else { } else {
should_continue = visitor.RaiseException(Exception::NoExecuteFault); should_continue = visitor.RaiseException(Exception::NoExecuteFault);
} }
visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4); visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4);
block.CycleCount()++; block.CycleCount()++;
} while (should_continue && !single_step); } while (should_continue && !single_step);
@ -49,11 +44,8 @@ bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor,
TranslatorVisitor visitor{block, descriptor, {}}; TranslatorVisitor visitor{block, descriptor, {}};
bool should_continue = true; bool should_continue = true;
if (auto decoder = Decode<TranslatorVisitor>(instruction)) { auto const decoder = Decode<TranslatorVisitor>(instruction);
should_continue = decoder->get().call(visitor, instruction); should_continue = decoder.get().call(visitor, instruction);
} else {
should_continue = visitor.InterpretThisInstruction();
}
visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4); visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4);
block.CycleCount()++; block.CycleCount()++;

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -16,11 +16,6 @@
namespace Dynarmic::A64 { namespace Dynarmic::A64 {
bool TranslatorVisitor::InterpretThisInstruction() {
ir.SetTerm(IR::Term::Interpret(*ir.current_location));
return false;
}
bool TranslatorVisitor::UnpredictableInstruction() { bool TranslatorVisitor::UnpredictableInstruction() {
return RaiseException(Exception::UnpredictableInstruction); return RaiseException(Exception::UnpredictableInstruction);
} }

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage * Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
@ -24,7 +27,6 @@ struct TranslatorVisitor final {
A64::IREmitter ir; A64::IREmitter ir;
TranslationOptions options; TranslationOptions options;
bool InterpretThisInstruction();
bool UnpredictableInstruction(); bool UnpredictableInstruction();
bool DecodeError(); bool DecodeError();
bool ReservedValue(); bool ReservedValue();

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage * Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
@ -63,9 +66,7 @@ bool TranslatorVisitor::FCMLA_vec(bool Q, Imm<2> size, Vec Vm, Imm<2> rot, Vec V
const size_t esize = 8U << size.ZeroExtend(); const size_t esize = 8U << size.ZeroExtend();
// TODO: Currently we don't support half-precision floating point // TODO: Currently we don't support half-precision floating point
if (esize == 16) { ASSERT(esize != 16);
return InterpretThisInstruction();
}
const size_t datasize = Q ? 128 : 64; const size_t datasize = Q ? 128 : 64;
const size_t num_elements = datasize / esize; const size_t num_elements = datasize / esize;
@ -134,9 +135,7 @@ bool TranslatorVisitor::FCADD_vec(bool Q, Imm<2> size, Vec Vm, Imm<1> rot, Vec V
const size_t esize = 8U << size.ZeroExtend(); const size_t esize = 8U << size.ZeroExtend();
// TODO: Currently we don't support half-precision floating point // TODO: Currently we don't support half-precision floating point
if (esize == 16) { ASSERT(esize != 16);
return InterpretThisInstruction();
}
const size_t datasize = Q ? 128 : 64; const size_t datasize = Q ? 128 : 64;
const size_t num_elements = datasize / esize; const size_t num_elements = datasize / esize;

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -223,9 +223,7 @@ bool TranslatorVisitor::FCMLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4
const size_t esize = 8U << size.ZeroExtend(); const size_t esize = 8U << size.ZeroExtend();
// TODO: We don't support the half-precision floating point variant yet. // TODO: We don't support the half-precision floating point variant yet.
if (esize == 16) { ASSERT(esize != 16);
return InterpretThisInstruction();
}
const size_t index = [=] { const size_t index = [=] {
if (size == 0b01) { if (size == 0b01) {

View file

@ -118,7 +118,7 @@ bool TranslatorVisitor::MSR_reg(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, I
default: default:
break; break;
} }
return InterpretThisInstruction(); UNREACHABLE();
} }
bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) { bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) {
@ -158,7 +158,7 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3
X(64, Rt, ir.GetTPIDRRO()); X(64, Rt, ir.GetTPIDRRO());
return true; return true;
} }
return InterpretThisInstruction(); UNREACHABLE();
} }
} // namespace Dynarmic::A64 } // namespace Dynarmic::A64

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -103,9 +103,6 @@ struct UserCallbacks : public TranslateCallbacks {
// A conservative implementation that always returns false is safe. // A conservative implementation that always returns false is safe.
virtual bool IsReadOnlyMemory(VAddr /*vaddr*/) { return false; } virtual bool IsReadOnlyMemory(VAddr /*vaddr*/) { return false; }
/// The interpreter must execute exactly num_instructions starting from PC.
virtual void InterpreterFallback(VAddr pc, size_t num_instructions) = 0;
// This callback is called whenever a SVC instruction is executed. // This callback is called whenever a SVC instruction is executed.
virtual void CallSVC(std::uint32_t swi) = 0; virtual void CallSVC(std::uint32_t swi) = 0;

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -118,9 +118,6 @@ struct UserCallbacks {
// A conservative implementation that always returns false is safe. // A conservative implementation that always returns false is safe.
virtual bool IsReadOnlyMemory(VAddr /*vaddr*/) { return false; } virtual bool IsReadOnlyMemory(VAddr /*vaddr*/) { return false; }
/// The interpreter must execute exactly num_instructions starting from PC.
virtual void InterpreterFallback(VAddr pc, size_t num_instructions) = 0;
// This callback is called whenever a SVC instruction is executed. // This callback is called whenever a SVC instruction is executed.
virtual void CallSVC(std::uint32_t swi) = 0; virtual void CallSVC(std::uint32_t swi) = 0;

View file

@ -77,9 +77,6 @@ static std::string TerminalToString(const Terminal& terminal_variant) noexcept {
std::string operator()(const Term::Invalid&) const { std::string operator()(const Term::Invalid&) const {
return "<invalid terminal>"; return "<invalid terminal>";
} }
std::string operator()(const Term::Interpret& terminal) const {
return fmt::format("Interpret{{{}}}", terminal.next);
}
std::string operator()(const Term::ReturnToDispatch&) const { std::string operator()(const Term::ReturnToDispatch&) const {
return "ReturnToDispatch{}"; return "ReturnToDispatch{}";
} }

View file

@ -638,43 +638,6 @@ static void A64GetSetElimination(IR::Block& block) {
} }
} }
static void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb) {
const auto is_interpret_instruction = [cb](A64::LocationDescriptor location) {
const auto instruction = cb->MemoryReadCode(location.PC());
if (!instruction)
return false;
IR::Block new_block{location};
A64::TranslateSingleInstruction(new_block, location, *instruction);
if (!new_block.Instructions().empty())
return false;
const IR::Terminal terminal = new_block.GetTerminal();
if (auto term = boost::get<IR::Term::Interpret>(&terminal)) {
return term->next == location;
}
return false;
};
IR::Terminal terminal = block.GetTerminal();
auto term = boost::get<IR::Term::Interpret>(&terminal);
if (!term)
return;
A64::LocationDescriptor location{term->next};
size_t num_instructions = 1;
while (is_interpret_instruction(location.AdvancePC(static_cast<int>(num_instructions * 4)))) {
num_instructions++;
}
term->num_instructions = num_instructions;
block.ReplaceTerminal(terminal);
block.CycleCount() += num_instructions - 1;
}
using Op = Dynarmic::IR::Opcode; using Op = Dynarmic::IR::Opcode;
static IR::Value Value(bool is_32_bit, u64 value) { static IR::Value Value(bool is_32_bit, u64 value) {
@ -1504,9 +1467,6 @@ void Optimize(IR::Block& block, const A64::UserConfig& conf, const Optimization:
Optimization::ConstantPropagation(block); Optimization::ConstantPropagation(block);
Optimization::DeadCodeElimination(block); Optimization::DeadCodeElimination(block);
} }
if (conf.HasOptimization(OptimizationFlag::MiscIROpt)) {
Optimization::A64MergeInterpretBlocksPass(block, conf.callbacks);
}
Optimization::IdentityRemovalPass(block); Optimization::IdentityRemovalPass(block);
if (!conf.HasOptimization(OptimizationFlag::DisableVerification)) { if (!conf.HasOptimization(OptimizationFlag::DisableVerification)) {
Optimization::VerificationPass(block); Optimization::VerificationPass(block);

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -19,17 +19,6 @@ namespace Term {
struct Invalid {}; struct Invalid {};
/**
* This terminal instruction calls the interpreter, starting at `next`.
* The interpreter must interpret exactly `num_instructions` instructions.
*/
struct Interpret {
explicit Interpret(const LocationDescriptor& next_)
: next(next_) {}
LocationDescriptor next; ///< Location at which interpretation starts.
size_t num_instructions = 1;
};
/** /**
* This terminal instruction returns control to the dispatcher. * This terminal instruction returns control to the dispatcher.
* The dispatcher will use the current cpu state to determine what comes next. * The dispatcher will use the current cpu state to determine what comes next.
@ -83,7 +72,6 @@ struct CheckHalt;
/// A Terminal is the terminal instruction in a MicroBlock. /// A Terminal is the terminal instruction in a MicroBlock.
using Terminal = boost::variant< using Terminal = boost::variant<
Invalid, Invalid,
Interpret,
ReturnToDispatch, ReturnToDispatch,
LinkBlock, LinkBlock,
LinkBlockFast, LinkBlockFast,

View file

@ -59,8 +59,6 @@ bool AnyLocationDescriptorForTerminalHas(IR::Terminal terminal, Fn fn) {
return fn(t.next); return fn(t.next);
} else if constexpr (std::is_same_v<T, IR::Term::PopRSBHint>) { } else if constexpr (std::is_same_v<T, IR::Term::PopRSBHint>) {
return false; return false;
} else if constexpr (std::is_same_v<T, IR::Term::Interpret>) {
return fn(t.next);
} else if constexpr (std::is_same_v<T, IR::Term::FastDispatchHint>) { } else if constexpr (std::is_same_v<T, IR::Term::FastDispatchHint>) {
return false; return false;
} else if constexpr (std::is_same_v<T, IR::Term::If>) { } else if constexpr (std::is_same_v<T, IR::Term::If>) {
@ -85,10 +83,6 @@ bool ShouldTestInst(u32 instruction, u32 pc, bool is_thumb, bool is_last_inst, A
return false; return false;
} }
if (auto terminal = block.GetTerminal(); boost::get<IR::Term::Interpret>(&terminal)) {
return false;
}
if (AnyLocationDescriptorForTerminalHas(block.GetTerminal(), [&](IR::LocationDescriptor ld) { return A32::LocationDescriptor{ld}.PC() <= pc; })) { if (AnyLocationDescriptorForTerminalHas(block.GetTerminal(), [&](IR::LocationDescriptor ld) { return A32::LocationDescriptor{ld}.PC() <= pc; })) {
return false; return false;
} }

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project. /* This file is part of the dynarmic project.
@ -97,10 +97,6 @@ public:
MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32)); MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32));
} }
void InterpreterFallback(u32 pc, size_t num_instructions) override {
UNREACHABLE(); //ASSERT(false && "InterpreterFallback({:08x} && {}) code = {:08x}", pc, num_instructions, *MemoryReadCode(pc));
}
void CallSVC(std::uint32_t swi) override { void CallSVC(std::uint32_t swi) override {
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi); UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
} }
@ -190,10 +186,6 @@ public:
return true; return true;
} }
void InterpreterFallback(std::uint32_t pc, size_t num_instructions) override {
UNREACHABLE(); //ASSERT(false && "InterpreterFallback({:016x} && {})", pc, num_instructions);
}
void CallSVC(std::uint32_t swi) override { void CallSVC(std::uint32_t swi) override {
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi); UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
} }

View file

@ -69,11 +69,6 @@ public:
MemoryWrite64(vaddr + 8, value[1]); MemoryWrite64(vaddr + 8, value[1]);
} }
void InterpreterFallback(u64, size_t) override {
// This is never called in practice.
std::terminate();
}
void CallSVC(u32) override { void CallSVC(u32) override {
// Do something. // Do something.
} }

View file

@ -43,8 +43,6 @@ static bool ShouldTestInst(u32 instruction, u64 pc, bool is_last_inst) {
bool should_continue = A64::TranslateSingleInstruction(block, location, instruction); bool should_continue = A64::TranslateSingleInstruction(block, location, instruction);
if (!should_continue && !is_last_inst) if (!should_continue && !is_last_inst)
return false; return false;
if (auto terminal = block.GetTerminal(); boost::get<IR::Term::Interpret>(&terminal))
return false;
for (const auto& ir_inst : block.instructions) { for (const auto& ir_inst : block.instructions) {
switch (ir_inst.GetOpcode()) { switch (ir_inst.GetOpcode()) {
case IR::Opcode::A64ExceptionRaised: case IR::Opcode::A64ExceptionRaised:

View file

@ -105,10 +105,6 @@ public:
return true; return true;
} }
void InterpreterFallback(u64 pc, size_t num_instructions) override {
UNREACHABLE(); // ASSERT(false&& "InterpreterFallback({:016x} && {})", pc, num_instructions);
}
void CallSVC(std::uint32_t swi) override { void CallSVC(std::uint32_t swi) override {
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi); UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
} }
@ -208,10 +204,6 @@ public:
return true; return true;
} }
void InterpreterFallback(u64 pc, size_t num_instructions) override {
ASSERT(ignore_invalid_insn && "InterpreterFallback");
}
void CallSVC(std::uint32_t swi) override { void CallSVC(std::uint32_t swi) override {
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi); UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
} }

View file

@ -152,9 +152,6 @@ public:
MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32)); MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32));
} }
void InterpreterFallback(u32 pc, size_t num_instructions) override {
fmt::print("> InterpreterFallback({:08x}, {}) code = {:08x}\n", pc, num_instructions, *MemoryReadCode(pc));
}
void CallSVC(std::uint32_t swi) override { void CallSVC(std::uint32_t swi) override {
fmt::print("> CallSVC({})\n", swi); fmt::print("> CallSVC({})\n", swi);
} }

View file

@ -50,10 +50,6 @@ namespace {
using namespace Dynarmic; using namespace Dynarmic;
bool ShouldTestInst(IR::Block& block) { bool ShouldTestInst(IR::Block& block) {
if (auto terminal = block.GetTerminal(); boost::get<IR::Term::Interpret>(&terminal)) {
return false;
}
for (const auto& ir_inst : block.instructions) { for (const auto& ir_inst : block.instructions) {
switch (ir_inst.GetOpcode()) { switch (ir_inst.GetOpcode()) {
// A32 // A32