Fix overlay autocompile: missing cull-widen ABI symbols; PGXP hooks swallowed by #endif

Two bugs that together kept every mod-patched text page interpreted forever
(the WipEout 3 framerate mod's 74 divergent pages -> ~0.5M interpreted block
dispatches/sec in play):

- The [[widescreen.cull.widen]] emitter writes psx_ws_cull_slt_widen /
  psx_ws_cull_slti_lower at configured sites, including in overlay-resident
  code, but the overlay dispatch preamble never defined them: every shard
  containing a widen site failed to link (undefined reference) and the
  autocompile pipeline reported compile-error for the whole region. Mirror
  both helpers into the preamble following the documented self-contained,
  byte-identical convention.

- append_pgxp_hooks joins the hook onto the translated statement with a
  space; the block-cycles MULT/DIV/MFLO/MFHI translations end in `#endif`,
  and the preprocessor discards tokens after #endif (the "extra tokens"
  warning class) - so those hooks silently never ran. Give the hook its own
  line when the translation ends in a directive.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
tetrisgm
2026-08-19 00:30:29 -07:00
parent 249057f93f
commit d31953fe6b
2 changed files with 24 additions and 0 deletions
+7
View File
@@ -30,6 +30,13 @@ inline int16_t get_imm16(uint32_t i) { return (int16_t)(i & 0xFFFF); }
* return early above translate_instruction's main dispatch and are likewise
* unhooked (they are cull compares, not vertex moves; validation covers). */
void append_pgxp_hooks(uint32_t instr, std::string& code) {
/* A translation ending in a preprocessor directive (the block-cycles
* muldiv wrappers end in `#endif`) would swallow an appended hook: the
* preprocessor discards tokens after #endif (the "extra tokens at end of
* #endif" warning class), so the MULT/DIV/MFLO/MFHI hooks silently never
* ran. Give the hook its own line. */
if (code.size() >= 6 && code.compare(code.size() - 6, 6, "#endif") == 0)
code += "\n ";
const uint32_t opcode = (instr >> 26) & 0x3F;
const uint32_t rs = get_rs(instr);
const uint32_t rt = get_rt(instr);
@@ -211,6 +211,23 @@ int psx_ws_cull_vxrange(uint32_t x, uint32_t imm) {
return (((x + (uint32_t)margin) & 0xFFFFu) <
(bound + 2u * (uint32_t)margin)) ? 1 : 0;
}
/* [[widescreen.cull.widen]] SLT-family helpers. The emitter writes these at
* explicitly configured cull sites, INCLUDING in overlay-resident code, so
* the DLL must define them or the shard fails to link (undefined reference ->
* no native shard -> that mod-patched page runs interpreted forever). Same
* contract as the funnel helpers above: self-contained on psx_ws_x_margin(),
* identity at margin 0 (4:3), MUST stay byte-for-byte identical to the gpu.c
* implementations. */
int psx_ws_cull_slti_lower(uint32_t sx, uint32_t imm) {
int32_t bound = (int32_t)(int16_t)(uint16_t)imm;
return ((int32_t)sx < bound - psx_ws_x_margin()) ? 1 : 0;
}
int psx_ws_cull_slt_widen(uint32_t rs, uint32_t rt, int bound_is_rt) {
const int32_t m = psx_ws_x_margin();
const int32_t a = (int32_t)rs, b = (int32_t)rt;
return bound_is_rt ? ((a < b + m) ? 1 : 0)
: ((a + m < b) ? 1 : 0);
}
void psx_ws_sprite_tag(CPUState *cpu) {
if (g_cbs.ws_sprite_tag) g_cbs.ws_sprite_tag(cpu);
}