mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-28 10:59:16 -04:00
00b1b02a07
Restores entry-scoped overlay analysis (analyze_exact_entries + split_mid_function_targets=false) as the MANDATORY mode for overlay inputs, renamed --overlay-exact -> --overlay: the ingester's contract, set unconditionally by compile_overlays.py for every overlay, never a human toggle. Evidence-scoped discovery compiles only proven seeds + reachable code and keeps branch/jump-table targets as in-parent labels — no whole-byte sweep, so it no longer decodes embedded data tables as code. Effect on the captured Tomba overlay: the data-as-code explosion collapses from thousands of UNSUPPORTED to 122 clean functions with 42 residual unsupported opcodes + 8 bad targets. Those residuals are now a per-function-audit concern (Inc1-B), not a wholesale region failure. Main-EXE codegen is unchanged (Tomba still regenerates 2854 functions; split pre-pass still runs in non-overlay mode). Also adds docs/overlay-recompilation-design.md — the converged design of record (precision-over-recall; compiled!=registered!=callable; write-invalidation over CRC; internal-labels-in-parent; the RAM-write-path audit result; the three implementation increments). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
74 lines
2.5 KiB
C++
74 lines
2.5 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <vector>
|
|
#include <string>
|
|
#include "ps1_exe_parser.h"
|
|
|
|
namespace PSXRecomp {
|
|
|
|
struct Function {
|
|
uint32_t start_addr;
|
|
uint32_t end_addr;
|
|
uint32_t size;
|
|
bool has_prologue;
|
|
bool has_epilogue;
|
|
int32_t stack_frame_size; // Size of stack frame (if has prologue)
|
|
std::string name; // Optional name (for now, just "func_<addr>")
|
|
bool is_data_section = false; // True if this "function" is actually a data section
|
|
};
|
|
|
|
struct FunctionAnalysisResult {
|
|
std::vector<Function> functions;
|
|
int total_instructions;
|
|
int jr_ra_count;
|
|
int prologue_count;
|
|
int call_discovered_count = 0; // Functions found via JAL call-target following
|
|
int strong_prologue_count = 0; // Functions found from prologues with saved $ra
|
|
int state_continuation_count = 0; // Split entries after calls to SaveState-style helpers
|
|
};
|
|
|
|
class FunctionAnalyzer {
|
|
public:
|
|
explicit FunctionAnalyzer(const PS1Executable& exe);
|
|
|
|
// Scan entire executable for function boundaries
|
|
FunctionAnalysisResult analyze();
|
|
|
|
// Analyze only explicit entry points and direct JAL targets reachable from
|
|
// them. This is for runtime-loaded overlays where scanning the whole blob
|
|
// treats data and basic-block targets as standalone functions.
|
|
FunctionAnalysisResult analyze_exact_entries(const std::vector<uint32_t>& entries);
|
|
|
|
// Add a forced entry point address that is treated as a function start
|
|
// even if it has no standard ADDIU $sp prologue. The function will be
|
|
// included in the analysis result with has_prologue = false.
|
|
void add_forced_entry(uint32_t addr);
|
|
|
|
// Check if instruction is jr $ra (return)
|
|
static bool is_jr_ra(uint32_t instr);
|
|
|
|
// Check if instruction is function prologue (addiu $sp, $sp, -N)
|
|
static bool is_prologue(uint32_t instr, int32_t& stack_size);
|
|
|
|
// Check if instruction is epilogue (addiu $sp, $sp, +N)
|
|
static bool is_epilogue(uint32_t instr, int32_t& stack_size);
|
|
|
|
// Check if instruction is a branch or jump (has a delay slot)
|
|
static bool is_branch_or_jump(uint32_t instr);
|
|
|
|
private:
|
|
const PS1Executable& exe_;
|
|
|
|
// Forced entry points (from add_forced_entry())
|
|
std::vector<uint32_t> forced_entry_points_;
|
|
|
|
// Find function start by scanning backward from jr $ra
|
|
uint32_t find_function_start(uint32_t return_addr);
|
|
|
|
// Detect if a region is likely a data section masquerading as code
|
|
bool is_likely_data_section(uint32_t start_addr, uint32_t end_addr) const;
|
|
};
|
|
|
|
} // namespace PSXRecomp
|