mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
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:
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user