Refactor runtime for move speed and better code style (#140)

* feat: added guestBranchKind enum to categorize branch types
feat: added missingFunctionPolicy enum to define behaviors for missing function scenarios
refactor: added handle guest branches and report missing functions
feat lookupFunction to utilize new dispatch logic and improve error handling for unregistered functions

* fix: fix test conflict

* feat: added debug sound driver logs

* feat: emmiter for return

* feat: added recompiler reporter
feat: added strict diagnostics flag for heavy debug calls

* feat: staticc table insted of hashmap for runtime

* feat: back file to ignore

* feat: explode code across helpers and classes

* feat: update codegen test
feat: better guest nop check

* feat: fix link problem on linux

* feat: fix Segmentation fault
This commit is contained in:
Ranieri
2026-07-04 00:43:22 -03:00
committed by GitHub
parent 3a2e0d69fd
commit 5196a6672a
53 changed files with 5879 additions and 4353 deletions
+184
View File
@@ -0,0 +1,184 @@
#include "ps2recomp/Emitters/function_emitter.h"
#include "ps2recomp/code_generator.h"
#include "ps2recomp/instructions.h"
#include "ps2recomp/r5900_decoder.h"
#include "ps2recomp/recompiler_reporter.h"
#include "ps2recomp/types.h"
#include <algorithm>
#include <sstream>
#include <stdexcept>
#include <unordered_set>
namespace ps2recomp
{
namespace
{
Instruction makeSyntheticDelaySlot(uint32_t address)
{
Instruction inst{};
inst.address = address;
inst.raw = 0;
inst.opcode = OPCODE_SPECIAL;
inst.function = SPECIAL_SLL;
return inst;
}
}
FunctionEmitter::FunctionEmitter(CodeGenerator &codeGenerator)
: m_codeGenerator(codeGenerator)
{
}
std::string FunctionEmitter::emit(
const Function &function,
const std::vector<Instruction> &instructions,
bool useHeaders)
{
CodeGenerator &cg = m_codeGenerator;
std::stringstream ss;
cg.m_currentFunctionName = function.name;
if (useHeaders)
{
ss << "#include <stdexcept>\n";
ss << "#include \"ps2_runtime_macros.h\"\n";
ss << "#include \"ps2_runtime.h\"\n";
ss << "#include \"ps2_recompiled_functions.h\"\n";
ss << "#include \"ps2_recompiled_stubs.h\"\n\n";
ss << "#include \"ps2_syscalls.h\"\n";
ss << "#include \"ps2_stubs.h\"\n\n";
ss << "#ifdef PS2_FUNCTION_LOG_TRACKER\n";
ss << "#include \"ps2_log.h\"\n";
ss << "#endif\n\n";
}
CodeGenerator::AnalysisResult analysisResult = cg.collectInternalBranchTargets(function, instructions);
std::vector<uint32_t> resumeTargets(analysisResult.resumeEntryPoints.begin(),
analysisResult.resumeEntryPoints.end());
auto resumeIt = cg.m_resumeEntryTargetsByOwner.find(function.start);
if (resumeIt != cg.m_resumeEntryTargetsByOwner.end())
{
resumeTargets.insert(resumeTargets.end(), resumeIt->second.begin(), resumeIt->second.end());
}
std::sort(resumeTargets.begin(), resumeTargets.end());
resumeTargets.erase(std::unique(resumeTargets.begin(), resumeTargets.end()), resumeTargets.end());
for (uint32_t target : resumeTargets)
{
analysisResult.entryPoints.insert(target);
}
const std::unordered_set<uint32_t> &internalTargets = analysisResult.entryPoints;
ss << "// Function: " << function.name << "\n";
ss << "// Address: 0x" << std::hex << function.start << " - 0x" << function.end << std::dec << "\n";
std::string sanitizedName = cg.getFunctionName(function.start);
if (sanitizedName.empty())
{
std::stringstream nameBuilder;
nameBuilder << "Errorfunc_" << std::hex << function.start;
sanitizedName = nameBuilder.str();
}
ss << "void " << sanitizedName << "(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime) {\n";
ss << "#ifdef PS2_FUNCTION_LOG_TRACKER\n";
ss << " PS_LOG_ENTRY(\"" << sanitizedName << "\");\n";
ss << "#endif\n";
ss << "\n";
if (!resumeTargets.empty())
{
ss << " switch (ctx->pc) {\n";
for (uint32_t target : resumeTargets)
{
ss << " case 0x" << std::hex << target << "u: goto label_" << target << ";\n"
<< std::dec;
}
ss << " default: break;\n";
ss << " }\n\n";
}
ss << " ctx->pc = 0x" << std::hex << function.start << "u;\n"
<< std::dec;
ss << "\n";
for (size_t i = 0; i < instructions.size(); ++i)
{
const Instruction &inst = instructions[i];
if (internalTargets.contains(inst.address))
{
ss << "label_" << std::hex << inst.address << std::dec << ":\n";
}
if (cg.m_emitInstructionComments)
{
ss << " // 0x" << std::hex << inst.address << ": 0x" << inst.raw << std::dec;
std::string disassembly = R5900Decoder::disassembleInstruction(inst);
if (!disassembly.empty())
{
ss << " " << disassembly;
}
ss << "\n";
}
try
{
if (inst.hasDelaySlot)
{
const bool hasDecodedDelaySlot =
i + 1 < instructions.size() &&
instructions[i + 1].address == inst.address + 4u;
Instruction syntheticDelaySlot{};
const Instruction *delaySlot = nullptr;
if (hasDecodedDelaySlot)
{
delaySlot = &instructions[i + 1];
}
else
{
syntheticDelaySlot = makeSyntheticDelaySlot(inst.address + 4u);
delaySlot = &syntheticDelaySlot;
}
if (hasDecodedDelaySlot && internalTargets.contains(delaySlot->address))
{
ss << "label_" << std::hex << delaySlot->address << std::dec << ":\n";
}
ss << cg.handleBranchDelaySlots(inst, *delaySlot, function, analysisResult);
if (hasDecodedDelaySlot)
{
++i; // Skip delay slot instruction (handled inside branch logic)
}
}
else
{
ss << " ctx->pc = 0x" << std::hex << inst.address << "u;\n"
<< std::dec;
ss << " " << cg.translateInstruction(inst);
if (inst.isMmio)
{
ss << " // MMIO: 0x" << std::hex << inst.mmioAddress << std::dec;
}
ss << "\n";
}
}
catch (const std::exception &e)
{
if (cg.m_reporter)
{
std::ostringstream msg;
msg << "translation failed: " << e.what() << " raw=0x" << std::hex << inst.raw;
cg.m_reporter->errorAt("codegen", function.name, inst.address, msg.str());
}
throw;
}
}
ss << "}\n";
return ss.str();
}
}