Repair the faithful-adopt-caner merge: 3 dropped lifter fixes + 6 dangling runtime refs - #90
Open
sp00nznet wants to merge 4 commits into
Open
Conversation
The faithful-adopt-caner merge took sagemono's ppu_lifter.py wholesale (`git diff sagemono/spu/faithful-adopt-caner HEAD -- tools/ppu_lifter.py` is 28 lines), discarding ~835 lines of the ydkj side. Three of the losses are silent miscompiles, all caught relifting flOw: - Direct `bl` no longer set ctx->lr. PPC `bl` writes LR = next insn; without it every mflr reads stale state and every stack-saved LR is garbage. In a run log EVERY lr= field printed 0x00000000. ctx->lr writes: 140k -> 29k. - The ELFv1 `ld r2,N(r1)` TOC-restore lowering was gone. The recomp has no glink stub writing that save slot, so the reload pulls uninitialised stack into r2 -> garbage TOC -> OPD/table loads read code-as-data. flOw's lift had 14146 such sites. Guarded on a single TOC candidate, as before; multi-TOC titles keep the stack read. - D-form loads/stores lost the rA=0-means-literal-0 rule (PowerISA V2.03 3.3.2/3.3.3). _mem_base() restored alongside the existing _xea() that already implements the X-form twin. Verified on flOw: 14146 TOCFIX / 0 stack-TOC reads / 120101 ctx->lr writes / 0 gpr[0] D-form bases, and the runtime's lr= diagnostics now match the known-good ps3-draw lift exactly. Still dropped by the same merge, NOT restored here (flOw's EBOOT does not use them, so they are unverified): VRSAVE mfspr/mtspr, stvlx/stvrx(l), vrfin/vrfiz/vrfip/vrfim, vexptefp, vlogefp. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…efs) The static lib archives fine -- undefined symbols in a .lib are only diagnosed when a title links it -- so these went unnoticed. flOw could not link at all against this branch. The SPU interpreter was not "consolidated into spu_channels.c" as 6dd8524 claims; it was deleted, while both of its call sites in lv2_register.c stayed. Restored spu_interp.{c,h} + spu_interp_tables.inc from 6dd8524^ and the spu_run_interp_job static-inline into spu_lifted_job.h. The FUNCTION REGISTRY genuinely was consolidated (spu_register_function / spu_lookup / spu_begin_image now live in spu_channels.c), so restoring spu_fn_registry.c wholesale duplicates them -- only its spu_lifted_lookup was missing, added here as the 3-line wrapper over spu_lookup it always was. spu_spurs_taskset_syscall goes back to non-static: the pure interpreter calls it too. lbp_hle_complete_pending, g_taskset_policy_bytes/size and g_vm_page_bitmap are title-provided symbols referenced from shared runtime code. Each gets a default definition in its own one-symbol TU, following the existing spu_tsp_weak.c pattern: a port that supplies the real one resolves the reference from its own object and never pulls the archive member, so no duplicate symbol. They must stay SEPARATE files -- a port can supply one without the others. g_vm_page_bitmap storage moves out of lbp/main.cpp (which is why every non-LBP port failed) into runtime/spu/spu_vm_pagemap.c; LBP's fault handler keeps seeding it through the extern. spurs_policy.c bails out of the taskset-policy path on a zero-size blob rather than executing an empty local store. NB: the runtime CMakeLists globs runtime/*.c without CONFIGURE_DEPENDS, so a new TU needs `cmake -S . -B build` re-run or it is silently not compiled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ps3-draw returned CELL_OK when funcStat sets CELL_SAVEDATA_CBRESULT_ERR_NODATA (-4), with the comment "an ERROR return leaves the title parked in MODE_AUTO_LOAD". The merge took the spec-correct CELL_SAVEDATA_ERROR_NODATA (0x8002B40B) instead and flOw parked exactly as that comment predicted: no app loop, 0 flips, never reaching m_InitEntityHierarchy. Applied to BOTH entry points. flOw calls the old non-_2 cellSaveDataAutoLoad, which 9db188d added as a separate function -- patching only AutoLoad2 (as I first did) changes nothing. Per the SDK the error return is correct and a real title handles it; that flOw does not is an unexplained bug in its own MODE_AUTO_LOAD state machine. The comment says so, so the next person does not "fix" this back and lose another boot. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
main() calls SetThreadStackGuarantee(256KB) so the STACK_OVERFLOW handler has room to report; guest threads got nothing. Deep recompiled call chains do overflow even a 256 MB stack (a lifter bug that turns a tail call into recursion is unbounded), and without the guarantee the handler itself faults while reporting -- the process dies with a bare access violation INSIDE the handler and the backtrace naming the recursing function is lost. Found while chasing what looked like a plain segfault in flOw: the Windows Application event log gave fault offset 0x2839, which llvm-symbolizer resolved to boot_main.cpp:488 -- the stack-overflow VEH itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sp00nznet
added a commit
that referenced
this pull request
Aug 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes for regressions introduced by the
faithful-adopt-canermerge itself. Targets #82's branch so that PR isn't rewritten — merge or cherry-pick, whichever suits.The merge resolution for
tools/ppu_lifter.pywas not a supersetIt took sagemono's file wholesale and discarded ~835 lines of the ydkj side. Three of the losses are silent miscompiles:
ctx->lr = <ret>on directbllr=field in the runtime logs printed0x00000000;ctx->lrwrites 140k → 29kld r2,N(r1)→ literal module TOC_mem_base()rA=0 D-form literal-zero basectx->gpr[0](the_xea()X-form twin survived)After relifting: 14146 TOCFIX / 0 stack-TOC reads / 120101
ctx->lrwrites / 0gpr[0]D-form bases, and thelr=diagnostics match the known-good ps3-draw lift exactly.Still dropped, not restored here (flOw's EBOOT doesn't use them, so I can't verify them): VRSAVE
mfspr/mtspr,stvlx/stvrx(l),vrfin/vrfiz/vrfip/vrfim,vexptefp,vlogefp. Worth a follow-up.The runtime didn't link for any title
Undefined symbols in a
.libare only diagnosed when a title links it, so the archive built clean and this went unnoticed.The SPU interpreter was not "consolidated into
spu_channels.c" as 6dd8524 says — it was deleted, while both call sites inlv2_register.cstayed. Restored, along withspu_run_interp_job.The function registry genuinely was consolidated, so restoring
spu_fn_registry.cwholesale duplicatesspu_register_function/spu_lookup/spu_begin_image; onlyspu_lifted_lookupwas missing and it's re-added as the 3-line wrapper it always was.lbp_hle_complete_pending,g_taskset_policy_bytes/sizeandg_vm_page_bitmapare title symbols referenced from shared runtime code. Each gets a default definition in its own one-symbol TU, per the existingspu_tsp_weak.cpattern — a port supplying the real one never pulls the archive member. They must stay separate files; a port can supply one without the others.g_vm_page_bitmapstorage moves out oflbp/main.cpp, which is precisely why every non-LBP port failed.Two more dropped/missing behaviours
cellSaveData: ps3-draw returnedCELL_OKonCBRESULT_ERR_NODATAwith the comment "an ERROR return leaves the title parked in MODE_AUTO_LOAD". The merge restored the spec-correctCELL_SAVEDATA_ERROR_NODATAand flOw parked exactly as predicted — 0 flips, never reachingm_InitEntityHierarchy. Applied to both entry points: flOw calls the old non-_2cellSaveDataAutoLoad, which 9db188d added as a separate function, so patching onlyAutoLoad2does nothing. Per the SDK the error return is correct; that flOw can't handle it is an unexplained bug in its own state machine, and the code now says so.sys_ppu_thread: guest threads never gotSetThreadStackGuarantee, so on a stack overflow the handler faults while reporting and the process dies with a bare AV inside the handler, losing the backtrace.main()already did this for the main thread.Status
flOw builds and boots substantially further against this branch (209 → 306 log lines: savedata clears,
thr_auto_load()completes), then hits a stack overflow before the app loop.FLOW_NO_SPU_WL=1reproduces it, so it's the PPU lift. Lead for the follow-up: this lifter emits 7,915g_trampoline_fnsites vs ps3-draw's 19,171, and 16 mid-function tail-entry wrappers vs 1,141, at near-identical function counts (38,287 vs 38,421) — so it's the branch routing, not the function list. The trampoline exists specifically to stop backward branches re-entering a prologue and growing the stack.🤖 Generated with Claude Code