mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2026-05-16 16:15:19 -05:00
recompilation: extend tolerant emit to print_branch fall-through path
Found a third emit-non-compilable-code path during Pokemon Stadium runner build: print_branch lambda (line 371) checks for tail-call candidates when the branch target is outside the function, prints a warning if not found — then falls through to emit `goto L_<branch_target>` to a label that doesn't exist in the generated function. Linker compiles fail with "use of undeclared label L_XXXXXXXX". Fixed by emitting the same recomp_unhandled_branch runtime call as the other tolerant-emit paths, plus an early return so the fall- through to emit_goto doesn't run. Also exposes recomp_unhandled_* declarations in include/recomp.h (after the existing recomp_context definition + recomp_syscall_handler decl) so generated C compiles cleanly without consumer-side header patches. 171 → ~600+ tolerant-emit warnings on Pokemon Stadium pass; full build pipeline now produces a linked PokemonStadiumRecomp.exe that loads librecomp/ultramodern and runs cleanly to a "link-only entry" message. Real boot still needs runtime wiring (renderer, scheduler, init). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3fe70f94a3
commit
5c0f771c59
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef __RECOMP_H__
|
||||
#define __RECOMP_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
|
@ -468,6 +470,24 @@ void recomp_syscall_handler(uint8_t* rdram, recomp_context* ctx, int32_t instruc
|
|||
|
||||
void pause_self(uint8_t *rdram);
|
||||
|
||||
/* Tolerant-emit runtime entry points. The engine emits calls to these
|
||||
* for instructions/branches/calls it can't translate at compile time;
|
||||
* consumers implement them in a runtime hook file (e.g. extras.c).
|
||||
* See src/recompilation.cpp for the emit sites and PRINCIPLES.md #12
|
||||
* for why these exist (loud runtime aborts, NOT stubs). */
|
||||
void recomp_unhandled_branch(uint8_t *rdram, recomp_context *ctx,
|
||||
uint32_t instr_vram, uint32_t branch_target);
|
||||
void recomp_unhandled_call(uint8_t *rdram, recomp_context *ctx,
|
||||
uint32_t instr_vram, uint32_t target);
|
||||
void recomp_unhandled_jalr(uint8_t *rdram, recomp_context *ctx,
|
||||
uint32_t instr_vram, uint64_t target_value, int rd);
|
||||
uint64_t recomp_unhandled_cop0_read(uint8_t *rdram, recomp_context *ctx,
|
||||
uint32_t instr_vram, int cop0_reg);
|
||||
void recomp_unhandled_cop0_write(uint8_t *rdram, recomp_context *ctx,
|
||||
uint32_t instr_vram, int cop0_reg, uint64_t value);
|
||||
void recomp_unhandled_instruction(uint8_t *rdram, recomp_context *ctx,
|
||||
uint32_t instr_vram, const char *opcode_name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -387,7 +387,21 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con
|
|||
return true;
|
||||
}
|
||||
|
||||
fmt::print(stderr, "[Warn] Function {} is branching outside of the function (to 0x{:08X})\n", func.name, branch_target);
|
||||
// Branch out of function with no symbol at target. Emit a
|
||||
// runtime abort instead of `goto L_<vram>` to a label that
|
||||
// never exists. Per project principles: no stub, an
|
||||
// unimplementable hole surfaced loudly at runtime.
|
||||
fmt::print(stderr, "[Warn] Function {} is branching outside of the function (to 0x{:08X}) — emitting runtime abort\n", func.name, branch_target);
|
||||
if (!process_delay_slot(true)) {
|
||||
return false;
|
||||
}
|
||||
print_indent();
|
||||
print_indent();
|
||||
fmt::print(output_file, "recomp_unhandled_branch(rdram, ctx, 0x{:08X}u, 0x{:08X}u);\n", instr_vram, branch_target);
|
||||
print_indent();
|
||||
print_indent();
|
||||
generator.emit_return(context, func_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!process_delay_slot(true)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user