From 39558b299118fae48f0c5fa18577d2f8b2a13401 Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Sat, 1 Aug 2026 17:28:06 -0600 Subject: [PATCH] =?UTF-8?q?fix(phase-30=20S6b):=20MULTI-LINE=20BLINDNESS?= =?UTF-8?q?=20in=20family=5Fremap=20=E2=80=94=204=20faces,=203=20fixed;=20?= =?UTF-8?q?+740=20members=20(R22=20140/140)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ONE root cause, four faces (cookbook §134): extract_unit's preamble scanner reads C one line at a time, so every construct that WRAPS was misread. D1 the {-guard fired on a documentation comment mentioning a brace -> carry truncated mid-comment -> `parse error before 'the'`. D2 _def_head_at's "param list continues -> ANSI definition" fallback accepted a WRAPPED DECLARATION as a definition head -> a 16-line fragment with no body, closed by a brace pair inside a comment -> a silent 0/137 that reads exactly like a compiler wall. D5 the backscan met a multi-line typedef's CLOSING line `} T;` first and stopped -> the type never travelled -> `T undeclared` across 17 families / 24,332 templatable ins. (The code comment claimed they "route through the engine_types.h lift"; measured, they routed nowhere.) D4 wrapped __asm__("func_...") alias invisible to a single-line regex — MEASURED (1 exemplar, 3,288 ins, second blocker behind it) and deliberately NOT fixed; it now returns None so the sweep reports a VISIBLE skip instead of 137 silent failures (R32). - Fixes: _def_head_at(ln, idx, more=()) lookahead (no-lookahead keeps the historical answer); {-guard exempts comment-only lines + an R32 dangling-comment backstop; forward brace scan counts over cdecl._mask (R33, one masking oracle); _typedef_block_start carries whole blocks. - BLAST RADIUS (R14): extract_unit diffed vs the pre-fix tool over all 181 zero-crack exemplars -> 157 byte-IDENTICAL, 24 changed, all in the intended direction. - PAYOFF: D1+D2 +323 members from families that banked ZERO; D5 +417 incl. func_8012B77C 139/139 (8,062 ins) and func_80128C98 137/275. S6 total 1,582 members (pre-fix tool scored 842). - R22 clean-fleet 140/140. Fleet 94.43->94.88% fn-count, 91.4->91.9% instr, 84.0->84.6% distinct. - TELL worth keeping (§134): bimodal bank rates (57 all / 52 zero / 8 partial) are a TOOLING signature, not codegen. Probe one member and read one compiler error before writing a family off. --- docs/backlog.md | 2426 ++++++++++----------- docs/cookbook-index.md | 9 +- docs/matching-cookbook.md | 54 + docs/progress.fleet.md | 288 +-- phase-ends/CURRENT_PHASE.md | 35 + src/ov_SC01_000/ov_SC01_000.c | 22 +- src/ov_SC01_000/ov_SC01_000_after.c | 79 +- src/ov_SC01_000/ov_SC01_000_jr_8012ACE0.c | 50 +- src/ov_SC01_000/ov_SC01_000_jr_801734BC.c | 75 +- src/ov_SC01_000/ov_SC01_000_jr_8017BEBC.c | 28 +- src/ov_SC01_001/ov_SC01_001.c | 22 +- src/ov_SC01_001/ov_SC01_001_after.c | 79 +- src/ov_SC01_001/ov_SC01_001_jr_8012ACE0.c | 50 +- src/ov_SC01_001/ov_SC01_001_jr_801734BC.c | 75 +- src/ov_SC01_001/ov_SC01_001_jr_8017BEBC.c | 28 +- src/ov_SC01_004/ov_SC01_004.c | 22 +- src/ov_SC01_004/ov_SC01_004_after.c | 79 +- src/ov_SC01_004/ov_SC01_004_jr_8012ACE0.c | 50 +- src/ov_SC01_004/ov_SC01_004_jr_801734BC.c | 75 +- src/ov_SC01_005/ov_SC01_005.c | 22 +- src/ov_SC01_005/ov_SC01_005_after.c | 79 +- src/ov_SC01_005/ov_SC01_005_jr_8012ACE0.c | 50 +- src/ov_SC01_005/ov_SC01_005_jr_801734BC.c | 75 +- src/ov_SC01_006/ov_SC01_006.c | 22 +- src/ov_SC01_006/ov_SC01_006_after.c | 79 +- src/ov_SC01_006/ov_SC01_006_jr_8012ACE0.c | 50 +- src/ov_SC01_006/ov_SC01_006_jr_801734BC.c | 75 +- src/ov_SC01_008/ov_SC01_008.c | 22 +- src/ov_SC01_008/ov_SC01_008_after.c | 79 +- src/ov_SC01_008/ov_SC01_008_jr_8012ACE0.c | 50 +- src/ov_SC01_008/ov_SC01_008_jr_801734BC.c | 75 +- src/ov_SC01_009/ov_SC01_009.c | 22 +- src/ov_SC01_009/ov_SC01_009_after.c | 79 +- src/ov_SC01_009/ov_SC01_009_jr_8012ACE0.c | 50 +- src/ov_SC01_009/ov_SC01_009_jr_801734BC.c | 75 +- src/ov_SC01_074/ov_SC01_074.c | 22 +- src/ov_SC01_074/ov_SC01_074_after.c | 79 +- src/ov_SC01_074/ov_SC01_074_jr_8012ACE0.c | 50 +- src/ov_SC01_074/ov_SC01_074_jr_801734BC.c | 75 +- src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c | 50 +- src/ov_SC01_080/ov_SC01_080.c | 22 +- src/ov_SC01_080/ov_SC01_080_after.c | 79 +- src/ov_SC01_080/ov_SC01_080_jr_8012ACE0.c | 50 +- src/ov_SC01_080/ov_SC01_080_jr_801734BC.c | 75 +- src/ov_SC01_084/ov_SC01_084.c | 22 +- src/ov_SC01_084/ov_SC01_084_after.c | 79 +- src/ov_SC01_084/ov_SC01_084_jr_8012ACE0.c | 50 +- src/ov_SC01_084/ov_SC01_084_jr_801734BC.c | 75 +- src/ov_SC02_000/ov_SC02_000.c | 22 +- src/ov_SC02_000/ov_SC02_000_after.c | 79 +- src/ov_SC02_000/ov_SC02_000_jr_8012ACE0.c | 50 +- src/ov_SC02_000/ov_SC02_000_jr_801734BC.c | 75 +- src/ov_SC02_000/ov_SC02_000_jr_8017AE2C.c | 109 +- src/ov_SC02_003/ov_SC02_003.c | 22 +- src/ov_SC02_003/ov_SC02_003_after.c | 79 +- src/ov_SC02_003/ov_SC02_003_jr_8012ACE0.c | 50 +- src/ov_SC02_003/ov_SC02_003_jr_801734BC.c | 75 +- src/ov_SC02_003/ov_SC02_003_jr_8017AE2C.c | 109 +- src/ov_SC02_003/ov_SC02_003_jr_8017FCB0.c | 62 +- src/ov_SC02_004/ov_SC02_004.c | 22 +- src/ov_SC02_004/ov_SC02_004_after.c | 79 +- src/ov_SC02_004/ov_SC02_004_jr_8012ACE0.c | 50 +- src/ov_SC02_004/ov_SC02_004_jr_801734BC.c | 75 +- src/ov_SC02_005/ov_SC02_005.c | 22 +- src/ov_SC02_005/ov_SC02_005_after.c | 79 +- src/ov_SC02_005/ov_SC02_005_jr_8012ACE0.c | 50 +- src/ov_SC02_005/ov_SC02_005_jr_801734BC.c | 75 +- src/ov_SC02_011/ov_SC02_011.c | 22 +- src/ov_SC02_011/ov_SC02_011_after.c | 79 +- src/ov_SC02_011/ov_SC02_011_jr_8012ACE0.c | 50 +- src/ov_SC02_011/ov_SC02_011_jr_801734BC.c | 75 +- src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c | 271 ++- src/ov_SC02_015/ov_SC02_015.c | 22 +- src/ov_SC02_015/ov_SC02_015_after.c | 79 +- src/ov_SC02_015/ov_SC02_015_jr_8012ACE0.c | 50 +- src/ov_SC02_015/ov_SC02_015_jr_801734BC.c | 75 +- src/ov_SC02_016/ov_SC02_016.c | 22 +- src/ov_SC02_016/ov_SC02_016_after.c | 79 +- src/ov_SC02_016/ov_SC02_016_jr_8012ACE0.c | 50 +- src/ov_SC02_016/ov_SC02_016_jr_801734BC.c | 75 +- src/ov_SC02_016/ov_SC02_016_jr_8017AE2C.c | 109 +- src/ov_SC02_017/ov_SC02_017.c | 22 +- src/ov_SC02_017/ov_SC02_017_after.c | 79 +- src/ov_SC02_017/ov_SC02_017_jr_8012ACE0.c | 50 +- src/ov_SC02_017/ov_SC02_017_jr_801734BC.c | 75 +- src/ov_SC02_017/ov_SC02_017_jr_8017AE2C.c | 109 +- src/ov_SC02_021/ov_SC02_021.c | 22 +- src/ov_SC02_021/ov_SC02_021_after.c | 79 +- src/ov_SC02_021/ov_SC02_021_jr_8012ACE0.c | 50 +- src/ov_SC02_021/ov_SC02_021_jr_801734BC.c | 75 +- src/ov_SC02_026/ov_SC02_026.c | 22 +- src/ov_SC02_026/ov_SC02_026_after.c | 79 +- src/ov_SC02_026/ov_SC02_026_jr_8012ACE0.c | 50 +- src/ov_SC02_026/ov_SC02_026_jr_801734BC.c | 75 +- src/ov_SC02_027/ov_SC02_027.c | 22 +- src/ov_SC02_027/ov_SC02_027_after.c | 79 +- src/ov_SC02_027/ov_SC02_027_jr_8012ACE0.c | 50 +- src/ov_SC02_027/ov_SC02_027_jr_801734BC.c | 75 +- src/ov_SC02_027/ov_SC02_027_jr_8017AE2C.c | 109 +- src/ov_SC02_028/ov_SC02_028.c | 22 +- src/ov_SC02_028/ov_SC02_028_after.c | 79 +- src/ov_SC02_028/ov_SC02_028_jr_8012ACE0.c | 50 +- src/ov_SC02_028/ov_SC02_028_jr_801734BC.c | 75 +- src/ov_SC02_028/ov_SC02_028_jr_8017AE2C.c | 109 +- src/ov_SC02_028/ov_SC02_028_jr_8017D898.c | 100 +- src/ov_SC02_031/ov_SC02_031.c | 22 +- src/ov_SC02_031/ov_SC02_031_after.c | 79 +- src/ov_SC02_031/ov_SC02_031_jr_8012ACE0.c | 50 +- src/ov_SC02_031/ov_SC02_031_jr_801734BC.c | 75 +- src/ov_SC02_031/ov_SC02_031_jr_8017AE2C.c | 109 +- src/ov_SC02_035/ov_SC02_035.c | 22 +- src/ov_SC02_035/ov_SC02_035_after.c | 79 +- src/ov_SC02_035/ov_SC02_035_jr_8012ACE0.c | 50 +- src/ov_SC02_035/ov_SC02_035_jr_801734BC.c | 75 +- src/ov_SC02_039/ov_SC02_039.c | 22 +- src/ov_SC02_039/ov_SC02_039_after.c | 79 +- src/ov_SC02_039/ov_SC02_039_jr_8012ACE0.c | 50 +- src/ov_SC02_039/ov_SC02_039_jr_801734BC.c | 75 +- src/ov_SC02_041/ov_SC02_041.c | 22 +- src/ov_SC02_041/ov_SC02_041_after.c | 79 +- src/ov_SC02_041/ov_SC02_041_jr_8012ACE0.c | 50 +- src/ov_SC02_041/ov_SC02_041_jr_801734BC.c | 75 +- src/ov_SC02_041/ov_SC02_041_jr_8017BEBC.c | 26 +- src/ov_SC03_001/ov_SC03_001.c | 22 +- src/ov_SC03_001/ov_SC03_001_after.c | 79 +- src/ov_SC03_001/ov_SC03_001_jr_8012ACE0.c | 50 +- src/ov_SC03_001/ov_SC03_001_jr_801734BC.c | 75 +- src/ov_SC03_002/ov_SC03_002.c | 22 +- src/ov_SC03_002/ov_SC03_002_after.c | 79 +- src/ov_SC03_002/ov_SC03_002_jr_8012ACE0.c | 50 +- src/ov_SC03_002/ov_SC03_002_jr_801734BC.c | 75 +- src/ov_SC03_003/ov_SC03_003.c | 22 +- src/ov_SC03_003/ov_SC03_003_after.c | 79 +- src/ov_SC03_003/ov_SC03_003_jr_8012ACE0.c | 50 +- src/ov_SC03_003/ov_SC03_003_jr_801734BC.c | 75 +- src/ov_SC03_006/ov_SC03_006.c | 22 +- src/ov_SC03_006/ov_SC03_006_after.c | 79 +- src/ov_SC03_006/ov_SC03_006_jr_8012ACE0.c | 50 +- src/ov_SC03_006/ov_SC03_006_jr_801734BC.c | 75 +- src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c | 109 +- src/ov_SC03_007/ov_SC03_007.c | 22 +- src/ov_SC03_007/ov_SC03_007_after.c | 79 +- src/ov_SC03_007/ov_SC03_007_jr_8012ACE0.c | 50 +- src/ov_SC03_007/ov_SC03_007_jr_801734BC.c | 75 +- src/ov_SC03_010/ov_SC03_010.c | 22 +- src/ov_SC03_010/ov_SC03_010_after.c | 79 +- src/ov_SC03_010/ov_SC03_010_jr_8012ACE0.c | 50 +- src/ov_SC03_010/ov_SC03_010_jr_801734BC.c | 75 +- src/ov_SC03_011/ov_SC03_011.c | 22 +- src/ov_SC03_011/ov_SC03_011_after.c | 79 +- src/ov_SC03_011/ov_SC03_011_jr_8012ACE0.c | 50 +- src/ov_SC03_011/ov_SC03_011_jr_801734BC.c | 75 +- src/ov_SC03_012/ov_SC03_012.c | 22 +- src/ov_SC03_012/ov_SC03_012_after.c | 79 +- src/ov_SC03_012/ov_SC03_012_jr_8012ACE0.c | 50 +- src/ov_SC03_012/ov_SC03_012_jr_801734BC.c | 75 +- src/ov_SC03_013/ov_SC03_013.c | 22 +- src/ov_SC03_013/ov_SC03_013_after.c | 79 +- src/ov_SC03_013/ov_SC03_013_jr_8012ACE0.c | 50 +- src/ov_SC03_013/ov_SC03_013_jr_801734BC.c | 75 +- src/ov_SC03_014/ov_SC03_014.c | 22 +- src/ov_SC03_014/ov_SC03_014_after.c | 79 +- src/ov_SC03_014/ov_SC03_014_jr_8012ACE0.c | 50 +- src/ov_SC03_014/ov_SC03_014_jr_801734BC.c | 75 +- src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c | 109 +- src/ov_SC03_015/ov_SC03_015.c | 22 +- src/ov_SC03_015/ov_SC03_015_after.c | 79 +- src/ov_SC03_015/ov_SC03_015_jr_8012ACE0.c | 50 +- src/ov_SC03_015/ov_SC03_015_jr_801734BC.c | 75 +- src/ov_SC03_015/ov_SC03_015_jr_8017AE2C.c | 62 +- src/ov_SC03_015/ov_SC03_015_jr_8017EB7C.c | 109 +- src/ov_SC03_015/ov_SC03_015_jr_801848E4.c | 100 +- src/ov_SC03_015/ov_SC03_015_o0c.c | 131 +- src/ov_SC03_015/ov_SC03_015_o0d.c | 37 +- src/ov_SC03_023/ov_SC03_023.c | 22 +- src/ov_SC03_023/ov_SC03_023_after.c | 79 +- src/ov_SC03_023/ov_SC03_023_jr_8012ACE0.c | 50 +- src/ov_SC03_023/ov_SC03_023_jr_801734BC.c | 75 +- src/ov_SC03_024/ov_SC03_024.c | 22 +- src/ov_SC03_024/ov_SC03_024_after.c | 79 +- src/ov_SC03_024/ov_SC03_024_jr_8012ACE0.c | 50 +- src/ov_SC03_024/ov_SC03_024_jr_801734BC.c | 75 +- src/ov_SC03_024/ov_SC03_024_jr_8017AE2C.c | 62 +- src/ov_SC03_024/ov_SC03_024_jr_8017DF84.c | 147 +- src/ov_SC03_028/ov_SC03_028.c | 22 +- src/ov_SC03_028/ov_SC03_028_after.c | 79 +- src/ov_SC03_028/ov_SC03_028_jr_8012ACE0.c | 50 +- src/ov_SC03_028/ov_SC03_028_jr_801734BC.c | 75 +- src/ov_SC03_029/ov_SC03_029.c | 22 +- src/ov_SC03_029/ov_SC03_029_after.c | 79 +- src/ov_SC03_029/ov_SC03_029_jr_8012ACE0.c | 50 +- src/ov_SC03_029/ov_SC03_029_jr_801734BC.c | 75 +- src/ov_SC03_029/ov_SC03_029_jr_8017AE2C.c | 109 +- src/ov_SC03_030/ov_SC03_030.c | 22 +- src/ov_SC03_030/ov_SC03_030_after.c | 79 +- src/ov_SC03_030/ov_SC03_030_jr_8012ACE0.c | 50 +- src/ov_SC03_030/ov_SC03_030_jr_801734BC.c | 75 +- src/ov_SC03_031/ov_SC03_031.c | 22 +- src/ov_SC03_031/ov_SC03_031_after.c | 79 +- src/ov_SC03_031/ov_SC03_031_jr_8012ACE0.c | 50 +- src/ov_SC03_031/ov_SC03_031_jr_801734BC.c | 75 +- src/ov_SC03_031/ov_SC03_031_jr_8017AE2C.c | 109 +- src/ov_SC03_089/ov_SC03_089.c | 22 +- src/ov_SC03_089/ov_SC03_089_after.c | 79 +- src/ov_SC03_089/ov_SC03_089_jr_8012ACE0.c | 50 +- src/ov_SC03_089/ov_SC03_089_jr_801734BC.c | 75 +- src/ov_SC03_089/ov_SC03_089_jr_8017AE2C.c | 109 +- src/ov_SC03_090/ov_SC03_090.c | 22 +- src/ov_SC03_090/ov_SC03_090_after.c | 79 +- src/ov_SC03_090/ov_SC03_090_jr_8012ACE0.c | 50 +- src/ov_SC03_090/ov_SC03_090_jr_801734BC.c | 75 +- src/ov_SC03_090/ov_SC03_090_jr_8017AE2C.c | 109 +- src/ov_SC03_091/ov_SC03_091.c | 22 +- src/ov_SC03_091/ov_SC03_091_after.c | 79 +- src/ov_SC03_091/ov_SC03_091_jr_8012ACE0.c | 50 +- src/ov_SC03_091/ov_SC03_091_jr_801734BC.c | 75 +- src/ov_SC03_091/ov_SC03_091_jr_8017AE2C.c | 109 +- src/ov_SC03_092/ov_SC03_092.c | 22 +- src/ov_SC03_092/ov_SC03_092_after.c | 79 +- src/ov_SC03_092/ov_SC03_092_jr_8012ACE0.c | 50 +- src/ov_SC03_092/ov_SC03_092_jr_801734BC.c | 75 +- src/ov_SC03_092/ov_SC03_092_jr_8017AE2C.c | 109 +- src/ov_SC03_093/ov_SC03_093.c | 22 +- src/ov_SC03_093/ov_SC03_093_after.c | 79 +- src/ov_SC03_093/ov_SC03_093_jr_8012ACE0.c | 50 +- src/ov_SC03_093/ov_SC03_093_jr_801734BC.c | 75 +- src/ov_SC03_093/ov_SC03_093_jr_8017AE2C.c | 109 +- src/ov_SC03_093/ov_SC03_093_jr_8017D898.c | 55 +- src/ov_SC03_094/ov_SC03_094.c | 22 +- src/ov_SC03_094/ov_SC03_094_after.c | 79 +- src/ov_SC03_094/ov_SC03_094_jr_8012ACE0.c | 50 +- src/ov_SC03_094/ov_SC03_094_jr_801734BC.c | 75 +- src/ov_SC03_094/ov_SC03_094_jr_8017BEBC.c | 88 +- src/ov_SC03_095/ov_SC03_095.c | 22 +- src/ov_SC03_095/ov_SC03_095_after.c | 79 +- src/ov_SC03_095/ov_SC03_095_jr_8012ACE0.c | 50 +- src/ov_SC03_095/ov_SC03_095_jr_801734BC.c | 75 +- src/ov_SC03_095/ov_SC03_095_jr_8017BEBC.c | 28 +- src/ov_SC03_096/ov_SC03_096.c | 22 +- src/ov_SC03_096/ov_SC03_096_after.c | 79 +- src/ov_SC03_096/ov_SC03_096_jr_8012ACE0.c | 50 +- src/ov_SC03_096/ov_SC03_096_jr_801734BC.c | 75 +- src/ov_SC03_097/ov_SC03_097.c | 22 +- src/ov_SC03_097/ov_SC03_097_after.c | 79 +- src/ov_SC03_097/ov_SC03_097_jr_8012ACE0.c | 50 +- src/ov_SC03_097/ov_SC03_097_jr_801734BC.c | 75 +- src/ov_SC03_097/ov_SC03_097_jr_8017AE2C.c | 109 +- src/ov_SC03_097/ov_SC03_097_jr_8017D898.c | 100 +- src/ov_SC03_098/ov_SC03_098.c | 22 +- src/ov_SC03_098/ov_SC03_098_after.c | 79 +- src/ov_SC03_098/ov_SC03_098_jr_8012ACE0.c | 50 +- src/ov_SC03_098/ov_SC03_098_jr_801734BC.c | 75 +- src/ov_SC03_098/ov_SC03_098_jr_8017AE2C.c | 109 +- src/ov_SC03_098/ov_SC03_098_jr_8017D898.c | 55 +- src/ov_SC03_099/ov_SC03_099.c | 22 +- src/ov_SC03_099/ov_SC03_099_after.c | 79 +- src/ov_SC03_099/ov_SC03_099_jr_8012ACE0.c | 50 +- src/ov_SC03_099/ov_SC03_099_jr_801734BC.c | 75 +- src/ov_SC03_099/ov_SC03_099_jr_8017BEBC.c | 61 +- src/ov_SC03_100/ov_SC03_100.c | 22 +- src/ov_SC03_100/ov_SC03_100_after.c | 79 +- src/ov_SC03_100/ov_SC03_100_jr_8012ACE0.c | 50 +- src/ov_SC03_100/ov_SC03_100_jr_801734BC.c | 75 +- src/ov_SC03_100/ov_SC03_100_jr_8017AE2C.c | 109 +- src/ov_SC03_100/ov_SC03_100_jr_8017D898.c | 26 +- src/ov_SC03_101/ov_SC03_101.c | 22 +- src/ov_SC03_101/ov_SC03_101_after.c | 79 +- src/ov_SC03_101/ov_SC03_101_jr_8012ACE0.c | 50 +- src/ov_SC03_101/ov_SC03_101_jr_801734BC.c | 75 +- src/ov_SC03_101/ov_SC03_101_jr_8017AE2C.c | 109 +- src/ov_SC03_101/ov_SC03_101_jr_8017CA80.c | 128 +- src/ov_SC03_102/ov_SC03_102.c | 22 +- src/ov_SC03_102/ov_SC03_102_after.c | 79 +- src/ov_SC03_102/ov_SC03_102_jr_8012ACE0.c | 50 +- src/ov_SC03_102/ov_SC03_102_jr_801734BC.c | 75 +- src/ov_SC03_103/ov_SC03_103.c | 22 +- src/ov_SC03_103/ov_SC03_103_after.c | 79 +- src/ov_SC03_103/ov_SC03_103_jr_8012ACE0.c | 50 +- src/ov_SC03_103/ov_SC03_103_jr_801734BC.c | 75 +- src/ov_SC03_103/ov_SC03_103_jr_8017C294.c | 88 +- src/ov_SC03_104/ov_SC03_104.c | 22 +- src/ov_SC03_104/ov_SC03_104_after.c | 79 +- src/ov_SC03_104/ov_SC03_104_jr_8012ACE0.c | 50 +- src/ov_SC03_104/ov_SC03_104_jr_801734BC.c | 75 +- src/ov_SC03_104/ov_SC03_104_jr_8017AE2C.c | 109 +- src/ov_SC03_104/ov_SC03_104_jr_8017CA80.c | 100 +- src/ov_SC03_105/ov_SC03_105.c | 22 +- src/ov_SC03_105/ov_SC03_105_after.c | 79 +- src/ov_SC03_105/ov_SC03_105_jr_8012ACE0.c | 50 +- src/ov_SC03_105/ov_SC03_105_jr_801734BC.c | 75 +- src/ov_SC03_108/ov_SC03_108.c | 22 +- src/ov_SC03_108/ov_SC03_108_after.c | 79 +- src/ov_SC03_108/ov_SC03_108_jr_8012ACE0.c | 50 +- src/ov_SC03_108/ov_SC03_108_jr_801734BC.c | 75 +- src/ov_SC03_109/ov_SC03_109.c | 22 +- src/ov_SC03_109/ov_SC03_109_after.c | 79 +- src/ov_SC03_109/ov_SC03_109_jr_8012ACE0.c | 50 +- src/ov_SC03_109/ov_SC03_109_jr_801734BC.c | 75 +- src/ov_SC03_110/ov_SC03_110.c | 22 +- src/ov_SC03_110/ov_SC03_110_after.c | 79 +- src/ov_SC03_110/ov_SC03_110_jr_8012ACE0.c | 50 +- src/ov_SC03_110/ov_SC03_110_jr_801734BC.c | 75 +- src/ov_SC03_110/ov_SC03_110_jr_8017AE2C.c | 109 +- src/ov_SC03_111/ov_SC03_111.c | 22 +- src/ov_SC03_111/ov_SC03_111_after.c | 79 +- src/ov_SC03_111/ov_SC03_111_jr_8012ACE0.c | 50 +- src/ov_SC03_111/ov_SC03_111_jr_801734BC.c | 75 +- src/ov_SC03_111/ov_SC03_111_jr_8017AE2C.c | 109 +- src/ov_SC03_112/ov_SC03_112.c | 22 +- src/ov_SC03_112/ov_SC03_112_after.c | 79 +- src/ov_SC03_112/ov_SC03_112_jr_8012ACE0.c | 50 +- src/ov_SC03_112/ov_SC03_112_jr_801734BC.c | 75 +- src/ov_SC03_113/ov_SC03_113.c | 22 +- src/ov_SC03_113/ov_SC03_113_after.c | 79 +- src/ov_SC03_113/ov_SC03_113_jr_8012ACE0.c | 50 +- src/ov_SC03_113/ov_SC03_113_jr_801734BC.c | 75 +- src/ov_SC03_113/ov_SC03_113_jr_8017C294.c | 28 +- src/ov_SC03_114/ov_SC03_114.c | 22 +- src/ov_SC03_114/ov_SC03_114_after.c | 79 +- src/ov_SC03_114/ov_SC03_114_jr_8012ACE0.c | 50 +- src/ov_SC03_114/ov_SC03_114_jr_801734BC.c | 75 +- src/ov_SC03_114/ov_SC03_114_jr_8017BEBC.c | 28 +- src/ov_SC03_115/ov_SC03_115.c | 22 +- src/ov_SC03_115/ov_SC03_115_after.c | 79 +- src/ov_SC03_115/ov_SC03_115_jr_8012ACE0.c | 50 +- src/ov_SC03_115/ov_SC03_115_jr_801734BC.c | 75 +- src/ov_SC03_116/ov_SC03_116.c | 22 +- src/ov_SC03_116/ov_SC03_116_after.c | 79 +- src/ov_SC03_116/ov_SC03_116_jr_8012ACE0.c | 50 +- src/ov_SC03_116/ov_SC03_116_jr_801734BC.c | 75 +- src/ov_SC03_116/ov_SC03_116_jr_8017AE2C.c | 28 +- src/ov_SC03_117/ov_SC03_117.c | 22 +- src/ov_SC03_117/ov_SC03_117_after.c | 79 +- src/ov_SC03_117/ov_SC03_117_jr_8012ACE0.c | 50 +- src/ov_SC03_117/ov_SC03_117_jr_801734BC.c | 75 +- src/ov_SC03_118/ov_SC03_118.c | 22 +- src/ov_SC03_118/ov_SC03_118_after.c | 79 +- src/ov_SC03_118/ov_SC03_118_jr_8012ACE0.c | 50 +- src/ov_SC03_118/ov_SC03_118_jr_801734BC.c | 75 +- src/ov_SC03_118/ov_SC03_118_jr_8017AE2C.c | 62 +- src/ov_SC03_118/ov_SC03_118_jr_8017FB84.c | 100 +- src/ov_SC03_119/ov_SC03_119.c | 22 +- src/ov_SC03_119/ov_SC03_119_after.c | 79 +- src/ov_SC03_119/ov_SC03_119_jr_8012ACE0.c | 50 +- src/ov_SC03_119/ov_SC03_119_jr_801734BC.c | 75 +- src/ov_SC03_119/ov_SC03_119_jr_8017AE2C.c | 62 +- src/ov_SC03_119/ov_SC03_119_jr_8017FB84.c | 100 +- src/ov_SC03_121/ov_SC03_121.c | 22 +- src/ov_SC03_121/ov_SC03_121_after.c | 79 +- src/ov_SC03_121/ov_SC03_121_jr_8012ACE0.c | 50 +- src/ov_SC03_121/ov_SC03_121_jr_801734BC.c | 75 +- src/ov_SC03_124/ov_SC03_124.c | 22 +- src/ov_SC03_124/ov_SC03_124_after.c | 79 +- src/ov_SC03_124/ov_SC03_124_jr_8012ACE0.c | 50 +- src/ov_SC03_124/ov_SC03_124_jr_801734BC.c | 75 +- src/ov_SC03_125/ov_SC03_125.c | 22 +- src/ov_SC03_125/ov_SC03_125_after.c | 79 +- src/ov_SC03_125/ov_SC03_125_jr_8012ACE0.c | 50 +- src/ov_SC03_125/ov_SC03_125_jr_801734BC.c | 75 +- src/ov_SC03_126/ov_SC03_126.c | 22 +- src/ov_SC03_126/ov_SC03_126_after.c | 79 +- src/ov_SC03_126/ov_SC03_126_jr_8012ACE0.c | 50 +- src/ov_SC03_126/ov_SC03_126_jr_801734BC.c | 75 +- src/ov_SC04_000/ov_SC04_000.c | 22 +- src/ov_SC04_000/ov_SC04_000_after.c | 79 +- src/ov_SC04_000/ov_SC04_000_jr_8012ACE0.c | 50 +- src/ov_SC04_000/ov_SC04_000_jr_801734BC.c | 75 +- src/ov_SC04_000/ov_SC04_000_jr_8017BEBC.c | 176 +- src/ov_SC04_002/ov_SC04_002.c | 22 +- src/ov_SC04_002/ov_SC04_002_after.c | 79 +- src/ov_SC04_002/ov_SC04_002_jr_8012ACE0.c | 50 +- src/ov_SC04_002/ov_SC04_002_jr_801734BC.c | 75 +- src/ov_SC04_002/ov_SC04_002_jr_8017BEBC.c | 231 +- src/ov_SC04_003/ov_SC04_003.c | 22 +- src/ov_SC04_003/ov_SC04_003_after.c | 79 +- src/ov_SC04_003/ov_SC04_003_jr_8012ACE0.c | 50 +- src/ov_SC04_003/ov_SC04_003_jr_801734BC.c | 75 +- src/ov_SC04_003/ov_SC04_003_jr_8017BEBC.c | 119 +- src/ov_SC04_004/ov_SC04_004.c | 22 +- src/ov_SC04_004/ov_SC04_004_after.c | 79 +- src/ov_SC04_004/ov_SC04_004_jr_8012ACE0.c | 50 +- src/ov_SC04_004/ov_SC04_004_jr_801734BC.c | 75 +- src/ov_SC04_004/ov_SC04_004_jr_8017AE2C.c | 230 +- src/ov_SC04_005/ov_SC04_005.c | 22 +- src/ov_SC04_005/ov_SC04_005_after.c | 79 +- src/ov_SC04_005/ov_SC04_005_jr_8012ACE0.c | 50 +- src/ov_SC04_005/ov_SC04_005_jr_801734BC.c | 75 +- src/ov_SC04_005/ov_SC04_005_jr_8017BEBC.c | 249 ++- src/ov_SC04_006/ov_SC04_006.c | 22 +- src/ov_SC04_006/ov_SC04_006_after.c | 79 +- src/ov_SC04_006/ov_SC04_006_jr_8012ACE0.c | 50 +- src/ov_SC04_006/ov_SC04_006_jr_801734BC.c | 75 +- src/ov_SC04_006/ov_SC04_006_jr_8017BEBC.c | 93 +- src/ov_SC04_007/ov_SC04_007.c | 22 +- src/ov_SC04_007/ov_SC04_007_after.c | 79 +- src/ov_SC04_007/ov_SC04_007_jr_8012ACE0.c | 50 +- src/ov_SC04_007/ov_SC04_007_jr_801734BC.c | 75 +- src/ov_SC04_007/ov_SC04_007_jr_8017BEBC.c | 249 ++- src/ov_SC04_008/ov_SC04_008.c | 22 +- src/ov_SC04_008/ov_SC04_008_after.c | 79 +- src/ov_SC04_008/ov_SC04_008_jr_8012ACE0.c | 50 +- src/ov_SC04_008/ov_SC04_008_jr_801734BC.c | 75 +- src/ov_SC04_008/ov_SC04_008_jr_8017AE2C.c | 67 +- src/ov_SC04_009/ov_SC04_009.c | 22 +- src/ov_SC04_009/ov_SC04_009_after.c | 79 +- src/ov_SC04_009/ov_SC04_009_jr_8012ACE0.c | 50 +- src/ov_SC04_009/ov_SC04_009_jr_801734BC.c | 75 +- src/ov_SC04_009/ov_SC04_009_jr_8017BEBC.c | 67 +- src/ov_SC04_010/ov_SC04_010.c | 22 +- src/ov_SC04_010/ov_SC04_010_after.c | 79 +- src/ov_SC04_010/ov_SC04_010_jr_8012ACE0.c | 50 +- src/ov_SC04_010/ov_SC04_010_jr_801734BC.c | 75 +- src/ov_SC04_010/ov_SC04_010_jr_8017BEBC.c | 67 +- src/ov_SC04_011/ov_SC04_011.c | 22 +- src/ov_SC04_011/ov_SC04_011_after.c | 79 +- src/ov_SC04_011/ov_SC04_011_jr_8012ACE0.c | 50 +- src/ov_SC04_011/ov_SC04_011_jr_801734BC.c | 75 +- src/ov_SC04_011/ov_SC04_011_jr_8017AE2C.c | 109 +- src/ov_SC04_011/ov_SC04_011_jr_8017D494.c | 167 +- src/ov_SC04_012/ov_SC04_012.c | 22 +- src/ov_SC04_012/ov_SC04_012_after.c | 79 +- src/ov_SC04_012/ov_SC04_012_jr_8012ACE0.c | 50 +- src/ov_SC04_012/ov_SC04_012_jr_801734BC.c | 75 +- src/ov_SC04_012/ov_SC04_012_jr_8017AE2C.c | 67 +- src/ov_SC04_015/ov_SC04_015.c | 22 +- src/ov_SC04_015/ov_SC04_015_after.c | 79 +- src/ov_SC04_015/ov_SC04_015_jr_8012ACE0.c | 50 +- src/ov_SC04_015/ov_SC04_015_jr_801734BC.c | 75 +- src/ov_SC04_016/ov_SC04_016.c | 22 +- src/ov_SC04_016/ov_SC04_016_after.c | 79 +- src/ov_SC04_016/ov_SC04_016_jr_8012ACE0.c | 50 +- src/ov_SC04_016/ov_SC04_016_jr_801734BC.c | 75 +- src/ov_SC04_016/ov_SC04_016_jr_8017BEBC.c | 28 +- src/ov_SC04_018/ov_SC04_018.c | 22 +- src/ov_SC04_018/ov_SC04_018_after.c | 79 +- src/ov_SC04_018/ov_SC04_018_jr_8012ACE0.c | 50 +- src/ov_SC04_018/ov_SC04_018_jr_801734BC.c | 75 +- src/ov_SC04_019/ov_SC04_019.c | 22 +- src/ov_SC04_019/ov_SC04_019_after.c | 79 +- src/ov_SC04_019/ov_SC04_019_jr_8012ACE0.c | 50 +- src/ov_SC04_019/ov_SC04_019_jr_801734BC.c | 75 +- src/ov_SC04_020/ov_SC04_020.c | 22 +- src/ov_SC04_020/ov_SC04_020_after.c | 79 +- src/ov_SC04_020/ov_SC04_020_jr_8012ACE0.c | 50 +- src/ov_SC04_020/ov_SC04_020_jr_801734BC.c | 75 +- src/ov_SC04_021/ov_SC04_021.c | 22 +- src/ov_SC04_021/ov_SC04_021_after.c | 79 +- src/ov_SC04_021/ov_SC04_021_jr_8012ACE0.c | 50 +- src/ov_SC04_021/ov_SC04_021_jr_801734BC.c | 75 +- src/ov_SC05_000/ov_SC05_000.c | 22 +- src/ov_SC05_000/ov_SC05_000_after.c | 79 +- src/ov_SC05_000/ov_SC05_000_jr_8012ACE0.c | 50 +- src/ov_SC05_000/ov_SC05_000_jr_801734BC.c | 75 +- src/ov_SC05_001/ov_SC05_001.c | 22 +- src/ov_SC05_001/ov_SC05_001_after.c | 79 +- src/ov_SC05_001/ov_SC05_001_jr_8012ACE0.c | 50 +- src/ov_SC05_001/ov_SC05_001_jr_801734BC.c | 75 +- src/ov_SC05_001/ov_SC05_001_jr_8017BEBC.c | 109 +- src/ov_SC05_002/ov_SC05_002.c | 22 +- src/ov_SC05_002/ov_SC05_002_after.c | 79 +- src/ov_SC05_002/ov_SC05_002_jr_8012ACE0.c | 50 +- src/ov_SC05_002/ov_SC05_002_jr_801734BC.c | 75 +- src/ov_SC05_002/ov_SC05_002_jr_8017BEBC.c | 26 +- src/ov_SC05_003/ov_SC05_003.c | 22 +- src/ov_SC05_003/ov_SC05_003_after.c | 79 +- src/ov_SC05_003/ov_SC05_003_jr_8012ACE0.c | 50 +- src/ov_SC05_003/ov_SC05_003_jr_801734BC.c | 75 +- src/ov_SC05_004/ov_SC05_004.c | 22 +- src/ov_SC05_004/ov_SC05_004_after.c | 79 +- src/ov_SC05_004/ov_SC05_004_jr_8012ACE0.c | 50 +- src/ov_SC05_004/ov_SC05_004_jr_801734BC.c | 75 +- src/ov_SC05_005/ov_SC05_005.c | 22 +- src/ov_SC05_005/ov_SC05_005_after.c | 79 +- src/ov_SC05_005/ov_SC05_005_jr_8012ACE0.c | 50 +- src/ov_SC05_005/ov_SC05_005_jr_801734BC.c | 75 +- src/ov_SC05_005/ov_SC05_005_jr_8017AE2C.c | 109 +- src/ov_SC05_006/ov_SC05_006.c | 22 +- src/ov_SC05_006/ov_SC05_006_after.c | 79 +- src/ov_SC05_006/ov_SC05_006_jr_8012ACE0.c | 50 +- src/ov_SC05_006/ov_SC05_006_jr_801734BC.c | 75 +- src/ov_SC05_006/ov_SC05_006_jr_8017BEBC.c | 109 +- src/ov_SC05_007/ov_SC05_007.c | 22 +- src/ov_SC05_007/ov_SC05_007_after.c | 79 +- src/ov_SC05_007/ov_SC05_007_jr_8012ACE0.c | 50 +- src/ov_SC05_007/ov_SC05_007_jr_801734BC.c | 75 +- src/ov_SC05_008/ov_SC05_008.c | 22 +- src/ov_SC05_008/ov_SC05_008_after.c | 79 +- src/ov_SC05_008/ov_SC05_008_jr_8012ACE0.c | 50 +- src/ov_SC05_008/ov_SC05_008_jr_801734BC.c | 75 +- src/ov_SC05_009/ov_SC05_009.c | 22 +- src/ov_SC05_009/ov_SC05_009_after.c | 79 +- src/ov_SC05_009/ov_SC05_009_jr_8012ACE0.c | 50 +- src/ov_SC05_009/ov_SC05_009_jr_801734BC.c | 75 +- src/ov_SC05_009/ov_SC05_009_jr_8017BEBC.c | 64 +- src/ov_SC05_010/ov_SC05_010.c | 22 +- src/ov_SC05_010/ov_SC05_010_after.c | 79 +- src/ov_SC05_010/ov_SC05_010_jr_8012ACE0.c | 50 +- src/ov_SC05_010/ov_SC05_010_jr_801734BC.c | 75 +- src/ov_SC05_010/ov_SC05_010_jr_8017C8D0.c | 28 +- src/ov_SC05_011/ov_SC05_011.c | 22 +- src/ov_SC05_011/ov_SC05_011_after.c | 79 +- src/ov_SC05_011/ov_SC05_011_jr_8012ACE0.c | 50 +- src/ov_SC05_011/ov_SC05_011_jr_801734BC.c | 75 +- src/ov_SC05_011/ov_SC05_011_jr_8017BEBC.c | 28 +- src/ov_SC05_017/ov_SC05_017.c | 22 +- src/ov_SC05_017/ov_SC05_017_after.c | 79 +- src/ov_SC05_017/ov_SC05_017_jr_8012ACE0.c | 50 +- src/ov_SC05_017/ov_SC05_017_jr_801734BC.c | 75 +- src/ov_SC05_018/ov_SC05_018.c | 22 +- src/ov_SC05_018/ov_SC05_018_after.c | 79 +- src/ov_SC05_018/ov_SC05_018_jr_8012ACE0.c | 50 +- src/ov_SC05_018/ov_SC05_018_jr_801734BC.c | 75 +- src/ov_SC05_019/ov_SC05_019.c | 22 +- src/ov_SC05_019/ov_SC05_019_after.c | 79 +- src/ov_SC05_019/ov_SC05_019_jr_8012ACE0.c | 50 +- src/ov_SC05_019/ov_SC05_019_jr_801734BC.c | 75 +- src/ov_SC06_000/ov_SC06_000.c | 22 +- src/ov_SC06_000/ov_SC06_000_after.c | 79 +- src/ov_SC06_000/ov_SC06_000_jr_8012ACE0.c | 50 +- src/ov_SC06_000/ov_SC06_000_jr_801734BC.c | 75 +- src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c | 333 ++- src/ov_SC06_006/ov_SC06_006.c | 22 +- src/ov_SC06_006/ov_SC06_006_after.c | 79 +- src/ov_SC06_006/ov_SC06_006_jr_8012ACE0.c | 50 +- src/ov_SC06_006/ov_SC06_006_jr_801734BC.c | 75 +- src/ov_SC06_006/ov_SC06_006_jr_8017BEBC.c | 27 +- src/ov_SC06_008/ov_SC06_008.c | 22 +- src/ov_SC06_008/ov_SC06_008_after.c | 79 +- src/ov_SC06_008/ov_SC06_008_jr_8012ACE0.c | 50 +- src/ov_SC06_008/ov_SC06_008_jr_801734BC.c | 75 +- src/ov_SC06_010/ov_SC06_010.c | 22 +- src/ov_SC06_010/ov_SC06_010_after.c | 79 +- src/ov_SC06_010/ov_SC06_010_jr_8012ACE0.c | 50 +- src/ov_SC06_010/ov_SC06_010_jr_801734BC.c | 75 +- src/ov_SC06_011/ov_SC06_011.c | 22 +- src/ov_SC06_011/ov_SC06_011_after.c | 79 +- src/ov_SC06_011/ov_SC06_011_jr_8012ACE0.c | 50 +- src/ov_SC06_011/ov_SC06_011_jr_801734BC.c | 75 +- src/ov_SC06_011/ov_SC06_011_jr_8017BEBC.c | 136 +- src/ov_SC06_013/ov_SC06_013.c | 22 +- src/ov_SC06_013/ov_SC06_013_after.c | 79 +- src/ov_SC06_013/ov_SC06_013_jr_8012ACE0.c | 50 +- src/ov_SC06_013/ov_SC06_013_jr_801734BC.c | 75 +- src/ov_SC06_013/ov_SC06_013_jr_8017BEBC.c | 55 +- src/ov_SC06_014/ov_SC06_014.c | 22 +- src/ov_SC06_014/ov_SC06_014_after.c | 79 +- src/ov_SC06_014/ov_SC06_014_jr_8012ACE0.c | 50 +- src/ov_SC06_014/ov_SC06_014_jr_801734BC.c | 75 +- src/ov_SC06_014/ov_SC06_014_jr_8017BEBC.c | 55 +- src/ov_SC06_015/ov_SC06_015.c | 22 +- src/ov_SC06_015/ov_SC06_015_after.c | 79 +- src/ov_SC06_015/ov_SC06_015_jr_8012ACE0.c | 50 +- src/ov_SC06_015/ov_SC06_015_jr_801734BC.c | 75 +- src/ov_SC06_015/ov_SC06_015_jr_8017BEBC.c | 28 +- src/ov_SC06_016/ov_SC06_016.c | 22 +- src/ov_SC06_016/ov_SC06_016_after.c | 79 +- src/ov_SC06_016/ov_SC06_016_jr_8012ACE0.c | 50 +- src/ov_SC06_016/ov_SC06_016_jr_801734BC.c | 75 +- src/ov_SC06_016/ov_SC06_016_jr_8017C8D0.c | 147 +- src/ov_SC06_018/ov_SC06_018.c | 22 +- src/ov_SC06_018/ov_SC06_018_after.c | 79 +- src/ov_SC06_018/ov_SC06_018_jr_8012ACE0.c | 50 +- src/ov_SC06_018/ov_SC06_018_jr_801734BC.c | 75 +- src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c | 50 +- src/ov_SC06_020/ov_SC06_020.c | 22 +- src/ov_SC06_020/ov_SC06_020_after.c | 79 +- src/ov_SC06_020/ov_SC06_020_jr_8012ACE0.c | 50 +- src/ov_SC06_020/ov_SC06_020_jr_801734BC.c | 75 +- src/ov_SC06_020/ov_SC06_020_jr_8017C24C.c | 105 +- src/ov_SC06_022/ov_SC06_022.c | 22 +- src/ov_SC06_022/ov_SC06_022_after.c | 79 +- src/ov_SC06_022/ov_SC06_022_jr_8012ACE0.c | 50 +- src/ov_SC06_022/ov_SC06_022_jr_801734BC.c | 75 +- src/ov_SC06_022/ov_SC06_022_jr_8017BEBC.c | 107 +- src/ov_SC06_024/ov_SC06_024.c | 22 +- src/ov_SC06_024/ov_SC06_024_after.c | 79 +- src/ov_SC06_024/ov_SC06_024_jr_8012ACE0.c | 50 +- src/ov_SC06_024/ov_SC06_024_jr_801734BC.c | 75 +- src/ov_SC06_024/ov_SC06_024_jr_8017BEBC.c | 105 +- src/ov_SC06_025/ov_SC06_025.c | 22 +- src/ov_SC06_025/ov_SC06_025_after.c | 79 +- src/ov_SC06_025/ov_SC06_025_jr_8012ACE0.c | 50 +- src/ov_SC06_025/ov_SC06_025_jr_801734BC.c | 75 +- src/ov_SC06_027/ov_SC06_027.c | 22 +- src/ov_SC06_027/ov_SC06_027_after.c | 79 +- src/ov_SC06_027/ov_SC06_027_jr_8012ACE0.c | 50 +- src/ov_SC06_027/ov_SC06_027_jr_801734BC.c | 75 +- src/ov_SC06_029/ov_SC06_029.c | 22 +- src/ov_SC06_029/ov_SC06_029_after.c | 79 +- src/ov_SC06_029/ov_SC06_029_jr_8012ACE0.c | 50 +- src/ov_SC06_029/ov_SC06_029_jr_801734BC.c | 75 +- src/ov_SC06_030/ov_SC06_030.c | 22 +- src/ov_SC06_030/ov_SC06_030_after.c | 79 +- src/ov_SC06_030/ov_SC06_030_jr_8012ACE0.c | 50 +- src/ov_SC06_030/ov_SC06_030_jr_801734BC.c | 75 +- src/ov_SC06_032/ov_SC06_032.c | 22 +- src/ov_SC06_032/ov_SC06_032_after.c | 79 +- src/ov_SC06_032/ov_SC06_032_jr_8012ACE0.c | 50 +- src/ov_SC06_032/ov_SC06_032_jr_801734BC.c | 75 +- src/ov_SC06_032/ov_SC06_032_jr_8017C24C.c | 155 +- src/ov_SC06_033/ov_SC06_033.c | 22 +- src/ov_SC06_033/ov_SC06_033_after.c | 79 +- src/ov_SC06_033/ov_SC06_033_jr_8012ACE0.c | 50 +- src/ov_SC06_033/ov_SC06_033_jr_801734BC.c | 75 +- src/ov_SC06_033/ov_SC06_033_jr_8017C24C.c | 105 +- src/ov_SC07_000/ov_SC07_000.c | 22 +- src/ov_SC07_000/ov_SC07_000_after.c | 79 +- src/ov_SC07_000/ov_SC07_000_jr_8012ACE0.c | 50 +- src/ov_SC07_000/ov_SC07_000_jr_801734BC.c | 75 +- src/ov_SC07_000/ov_SC07_000_jr_8017BEBC.c | 100 +- src/ov_SC07_001/ov_SC07_001.c | 22 +- src/ov_SC07_001/ov_SC07_001_after.c | 79 +- src/ov_SC07_001/ov_SC07_001_jr_8012ACE0.c | 50 +- src/ov_SC07_001/ov_SC07_001_jr_801734BC.c | 75 +- src/ov_SC07_002/ov_SC07_002.c | 22 +- src/ov_SC07_002/ov_SC07_002_after.c | 79 +- src/ov_SC07_002/ov_SC07_002_jr_8012ACE0.c | 50 +- src/ov_SC07_002/ov_SC07_002_jr_801734BC.c | 75 +- src/ov_SC07_002/ov_SC07_002_jr_8017C8D0.c | 100 +- src/ov_SC07_006/ov_SC07_006.c | 23 +- src/ov_SC07_006/ov_SC07_006_jr_80140608.c | 79 +- src/ov_SC07_006/ov_SC07_006_jr_8016AE5C.c | 56 +- src/ov_SC07_006/ov_SC07_006_jr_8017BEBC.c | 29 +- src/ov_SC07_007/ov_SC07_007.c | 73 +- src/ov_SC07_007/ov_SC07_007_jr_80140608.c | 79 +- src/ov_SC07_007/ov_SC07_007_jr_8016AE5C.c | 56 +- src/ov_SC07_007/ov_SC07_007_jr_80171B4C.c | 75 +- src/ov_SC07_008/ov_SC07_008.c | 22 +- src/ov_SC07_008/ov_SC07_008_after.c | 79 +- src/ov_SC07_008/ov_SC07_008_jr_8012ACE0.c | 50 +- src/ov_SC07_008/ov_SC07_008_jr_801734BC.c | 75 +- src/ov_SC07_008/ov_SC07_008_jr_8017BEBC.c | 28 +- src/ov_SC07_009/ov_SC07_009.c | 22 +- src/ov_SC07_009/ov_SC07_009_after.c | 79 +- src/ov_SC07_009/ov_SC07_009_jr_8012ACE0.c | 50 +- src/ov_SC07_009/ov_SC07_009_jr_801734BC.c | 75 +- src/ov_SC07_010/ov_SC07_010.c | 73 +- src/ov_SC07_010/ov_SC07_010_jr_80140608.c | 79 +- src/ov_SC07_010/ov_SC07_010_jr_8016AE5C.c | 56 +- src/ov_SC07_010/ov_SC07_010_jr_80171B4C.c | 75 +- src/ov_SC07_010/ov_SC07_010_jr_8017AE2C.c | 19 +- src/ov_SC07_011/ov_SC07_011.c | 73 +- src/ov_SC07_011/ov_SC07_011_jr_80140608.c | 79 +- src/ov_SC07_011/ov_SC07_011_jr_8016AE5C.c | 56 +- src/ov_SC07_011/ov_SC07_011_jr_80171B4C.c | 75 +- src/ov_SC07_011/ov_SC07_011_jr_8017BEBC.c | 20 +- tools/family_remap.py | 144 +- 647 files changed, 40805 insertions(+), 2169 deletions(-) diff --git a/docs/backlog.md b/docs/backlog.md index 3ac5af60cd..f19d9ddca5 100644 --- a/docs/backlog.md +++ b/docs/backlog.md @@ -2,7 +2,7 @@ > Generated by `tools/backlog.py render` from `.run/backlog.jsonl`. These are functions the Phase-21 automation got **close** on but did NOT byte-match. The whole-binary byte-gate is the sole arbiter (G3/P9): **byte-matches bank and are NOT listed here** — only genuine near-misses/blockers are. Ranked by hand-session priority: **reach** (×N propagation leverage) → **closeness** (match_one mismatch count, lower = closer) → **size**. Each row's `best_draft` is the closest C the machine reached — resume from there. -**Open near-misses:** 1224 · by status {'near': 1173, 'failed': 51} · by class {'schedule': 5, 'struct': 13, 'plumbing': 6, 'STUB': 1, 'remat': 1, 'regalloc-order': 13, None: 1179, 'other': 1, 'WAVE': 3, 'STRUCT': 1, 'loose-typing': 1} +**Open near-misses:** 1216 · by status {'near': 1165, 'failed': 51} · by class {'schedule': 4, 'struct': 13, 'plumbing': 6, 'STUB': 1, 'remat': 1, 'regalloc-order': 13, None: 1172, 'other': 1, 'WAVE': 3, 'STRUCT': 1, 'loose-typing': 1} | # | addr | reach | class | nins | status | closeness | where it stuck | best draft | |--:|------|------:|-------|-----:|--------|----------:|----------------|------------| @@ -14,1219 +14,1211 @@ | 6 | func_8016BA68 | 134 | STUB | 29 | near | 1 | STUB: 1 mismatch | `.run/backlog_drafts/func_8016BA68.c` | | 7 | func_80147364 | 134 | remat | 30 | near | 4 | none — MATCH (30 ins). Lever: hoist &D_80126B58 into a local ptr `u8 *p=&D_80126B58;` so gcc | `.run/backlog_drafts/func_80147364.c` | | 8 | func_80146A6C | 134 | struct | 18 | near | 5 | none — MATCH | `.run/backlog_drafts/func_80146A6C.c` | -| 9 | func_8012B77C | 134 | schedule | 58 | near | 33 | gcc instruction-scheduler load-ordering + 1st-ratan2 delay-slot fill differ (s2 subtraction lands early instead of in the delay slot; `lh s1,2(a2)` hoisted ahead of the iVar8 loads). All regs/ops correct (result pinned $s4 reads uninit then RMW-builds the u32; iVar8 unpinned so both halves load to temps -> `subu s5,v1,v0`). Residual is the §20 store-vs-load/delay-slot scheduler tie-break (source reorder/barrier/precompute all tried, do not move it); ~3-4 real slots, count inflated by offset cascade. move==addu rd,rs,zero byte-identical. | `.run/backlog_drafts/func_8012B77C.c` | -| 10 | func_80178004 | 134 | regalloc-order | 165 | near | 91 | [Phase-27 T8 corrected] close=91 pure local-alloc regalloc wall (§52 flagship; the 'MATCH' claim was a retracted myth — never a real match) | `.run/backlog_drafts/func_80178004.c` | -| 11 | func_801412A8 | 134 | regalloc-order | 198 | near | 110 | 110 mismatch (count-exact 198/198). S11 LUID(x)alloc: register-assignment permutation + prim2 store-schedule. §31 permuter seed (was mis-logged 164). | `.run/backlog_drafts/func_801412A8.c` | -| 12 | func_8017C294 | 2 | regalloc-order | 246 | near | 230 | structurally matched (246 ins, param_3 in $fp, spurious psVar7[1] giv killed via | `.run/backlog_drafts/func_8017C294.c` | -| 13 | func_80182988 | 1 | plumbing | 22 | near | 0 | none — MATCH (u16 store of 0xAA10 forces ori, not sign-extended addiu) | `.run/backlog_drafts/func_80182988.c` | -| 14 | func_8017E224 | 1 | struct | 29 | near | 0 | none — MATCH (unaligned 8-byte memcpy of global onto stack + cond byte incr) | `.run/backlog_drafts/func_8017E224.c` | -| 15 | func_80183BAC | 1 | struct | 41 | near | 0 | switch jump-table dispatch (jtbl_801D9420); verifying case grouping 0,1,2,5,6/3,7/4 emits the target table + tail | `.run/backlog_drafts/func_80183BAC.c` | -| 16 | func_80183C50 | 1 | struct | 41 | near | 0 | none — MATCH (cross-jump exploit §cookbook L1543: dup func_8012C218 into case3/7 + case4 → merged jal;nop) | `.run/backlog_drafts/func_80183C50.c` | -| 17 | func_80183AF0 | 1 | regalloc-order | 47 | near | 0 | none — MATCH (mask pinned $a1/$5 + p pinned $v0/$2; switch w/ distributed func_8012C218 tail via dup calls + cross-jump merge) | `.run/backlog_drafts/func_80183AF0.c` | -| 18 | func_8017EC7C | 1 | struct | 52 | near | 0 | none — MATCH (52 ins, relocation-masked) | `.run/backlog_drafts/func_8017EC7C.c` | -| 19 | func_80183CF4 | 1 | struct | 57 | near | 0 | none — MATCH (clean switch + jtbl; orchestrator owns jtbl/rodata migration) | `.run/backlog_drafts/func_80183CF4.c` | -| 20 | func_801842C8 | 1 | plumbing | 62 | near | 0 | none — MATCH | `.run/backlog_drafts/func_801842C8.c` | -| 21 | func_8018281C | 1 | struct | 76 | near | 0 | none — MATCH (76 ins). jtbl forced via explicit case 4/6 (count>=5 over MIPS tablejump threshold); case-5 block placed between if-block and default via goto so the if-block emits j default w/ e2=0 in the delay slot | `.run/backlog_drafts/func_8018281C.c` | -| 22 | func_80182E7C | 1 | struct | 85 | near | 0 | none — MATCH (85 ins, relocation-masked). Two switch-codegen levers: | `.run/backlog_drafts/func_80182E7C.c` | -| 23 | func_801820DC | 1 | struct | 94 | near | 0 | none — MATCH (switch on entity state at 0x34, inner jtbl on (s8)(u70>>8)) | `.run/backlog_drafts/func_801820DC.c` | -| 24 | func_80184D50 | 1 | schedule | 98 | near | 0 | none — MATCH (98 ins, relocation-masked) | `.run/backlog_drafts/func_80184D50.c` | -| 25 | func_8017F1C8 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017F1C8.c` | -| 26 | func_80182B9C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80182B9C.c` | -| 27 | func_8017C150 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017C150.c` | -| 28 | func_8017C078 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017C078.c` | -| 29 | func_801803A0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_801803A0.c` | -| 30 | func_80185D6C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80185D6C.c` | -| 31 | func_801832D0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_801832D0.c` | -| 32 | func_80180EF4 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180EF4.c` | -| 33 | func_8017D880 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D880.c` | -| 34 | func_80180EE0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180EE0.c` | -| 35 | func_8017D9FC | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D9FC.c` | -| 36 | func_8017E2A0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017E2A0.c` | -| 37 | func_8017D798 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D798.c` | -| 38 | func_8017D770 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D770.c` | -| 39 | func_8017DE84 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DE84.c` | -| 40 | func_8017D7C0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D7C0.c` | -| 41 | func_8017DE6C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DE6C.c` | -| 42 | func_8017DF1C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DF1C.c` | -| 43 | func_8017E1C0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017E1C0.c` | -| 44 | func_8017DF54 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DF54.c` | -| 45 | func_8017F060 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017F060.c` | -| 46 | func_8018234C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018234C.c` | -| 47 | func_80180FF8 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180FF8.c` | -| 48 | func_8017DB78 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DB78.c` | -| 49 | func_8017DD30 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DD30.c` | -| 50 | func_80184674 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80184674.c` | -| 51 | func_80184C90 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80184C90.c` | -| 52 | func_80184884 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80184884.c` | -| 53 | func_80185D00 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80185D00.c` | -| 54 | func_8017F54C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017F54C.c` | -| 55 | func_8017E58C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017E58C.c` | -| 56 | func_8017DDE0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DDE0.c` | -| 57 | func_8017FD88 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017FD88.c` | -| 58 | func_8017F630 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017F630.c` | -| 59 | func_80182148 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80182148.c` | -| 60 | func_80186BD8 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80186BD8.c` | -| 61 | func_80182A18 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80182A18.c` | -| 62 | func_80186C1C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80186C1C.c` | -| 63 | func_80180264 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180264.c` | -| 64 | func_8017D700 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D700.c` | -| 65 | func_80186BF8 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80186BF8.c` | -| 66 | func_8017D4C0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D4C0.c` | -| 67 | func_8017D5A0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D5A0.c` | -| 68 | func_80183554 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80183554.c` | -| 69 | func_8017D5D0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D5D0.c` | -| 70 | func_8017D944 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D944.c` | -| 71 | func_8018540C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018540C.c` | -| 72 | func_80183DF8 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80183DF8.c` | -| 73 | func_80180534 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180534.c` | -| 74 | func_80183100 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80183100.c` | -| 75 | func_8017D9AC | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D9AC.c` | -| 76 | func_8018C118 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018C118.c` | -| 77 | func_80188720 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80188720.c` | -| 78 | func_8018C3EC | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018C3EC.c` | -| 79 | func_80180944 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180944.c` | -| 80 | func_8018603C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018603C.c` | -| 81 | func_80181D30 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80181D30.c` | -| 82 | func_8018C2CC | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018C2CC.c` | -| 83 | func_8017E464 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017E464.c` | -| 84 | func_800CFE60 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_800CFE60.c` | -| 85 | func_800D0214 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_800D0214.c` | -| 86 | func_80187DD0 | None | regalloc-order | None | near | 0 | none — MATCH (174 ins). Levers: obj = *(*(b+0x20)+0x20) reads via b not a (store side uses a); | `.run/backlog_drafts/func_80187DD0.c` | -| 87 | func_801886B0 | None | struct | None | near | 0 | none — MATCH (276 ins, relocation-masked) | `.run/backlog_drafts/func_801886B0.c` | -| 88 | func_8017F714 | 1 | plumbing | 27 | near | 1 | none — MATCH (27/27 ins, match_one verified) | `.run/backlog_drafts/func_8017F714.c` | -| 89 | func_80184C0C | 1 | struct | 48 | near | 1 | none — MATCH (array-of-struct %lo-fold for &D_8018AEB8[idx], stride 0x34) | `.run/backlog_drafts/func_80184C0C.c` | -| 90 | func_801803B0 | 1 | other | 51 | near | 1 | none — MATCH expected; simple if/else, no call-crossing locals beyond param in $s0 | `.run/backlog_drafts/func_801803B0.c` | -| 91 | func_8017F114 | 1 | regalloc-order | 75 | near | 1 | none — MATCH | `.run/backlog_drafts/func_8017F114.c` | -| 92 | func_801807D8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801807D8.c` | -| 93 | func_80180AD0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80180AD0.c` | -| 94 | func_8017FDB0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017FDB0.c` | -| 95 | func_80180720 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80180720.c` | -| 96 | func_80184A28 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184A28.c` | -| 97 | func_80183AFC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80183AFC.c` | -| 98 | func_8017EE50 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017EE50.c` | -| 99 | func_80181FF8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80181FF8.c` | -| 100 | func_801832F4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801832F4.c` | -| 101 | func_8017FE4C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017FE4C.c` | -| 102 | func_801827C4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801827C4.c` | -| 103 | func_80182B68 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182B68.c` | -| 104 | func_80185E38 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80185E38.c` | -| 105 | func_8017FD70 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017FD70.c` | -| 106 | func_801811D4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801811D4.c` | -| 107 | func_801819DC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801819DC.c` | -| 108 | func_8018ADF8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018ADF8.c` | -| 109 | func_80186554 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80186554.c` | -| 110 | func_801873FC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801873FC.c` | -| 111 | func_80180E7C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80180E7C.c` | -| 112 | func_801835FC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801835FC.c` | -| 113 | func_80184970 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184970.c` | -| 114 | func_801863D4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801863D4.c` | -| 115 | func_80181540 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80181540.c` | -| 116 | func_801809D4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801809D4.c` | -| 117 | func_801802A4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801802A4.c` | -| 118 | func_801830A8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801830A8.c` | -| 119 | func_8017E858 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017E858.c` | -| 120 | func_80186BD4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80186BD4.c` | -| 121 | func_8017FB98 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017FB98.c` | -| 122 | func_8017EE14 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017EE14.c` | -| 123 | func_80181DA0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80181DA0.c` | -| 124 | func_80187840 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80187840.c` | -| 125 | func_80184E58 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184E58.c` | -| 126 | func_80184354 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184354.c` | -| 127 | func_8018011C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018011C.c` | -| 128 | func_8017E29C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017E29C.c` | -| 129 | func_8017D930 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017D930.c` | -| 130 | func_80182A8C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182A8C.c` | -| 131 | func_80181FCC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80181FCC.c` | -| 132 | func_801893E0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801893E0.c` | -| 133 | func_80186908 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80186908.c` | -| 134 | func_80189DC4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80189DC4.c` | -| 135 | func_80182AB0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182AB0.c` | -| 136 | func_80183EA4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80183EA4.c` | -| 137 | func_8018B344 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018B344.c` | -| 138 | func_80188858 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80188858.c` | -| 139 | func_8018773C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018773C.c` | -| 140 | func_80182E9C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182E9C.c` | -| 141 | func_8017F378 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017F378.c` | -| 142 | func_80184BAC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184BAC.c` | -| 143 | func_801852D4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801852D4.c` | -| 144 | func_80189B60 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80189B60.c` | -| 145 | func_8018445C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018445C.c` | -| 146 | func_8018AA08 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018AA08.c` | -| 147 | func_80182CEC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182CEC.c` | -| 148 | func_8018944C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018944C.c` | -| 149 | func_8018A598 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018A598.c` | -| 150 | func_8017EA40 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017EA40.c` | -| 151 | func_801826C8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801826C8.c` | -| 152 | func_801854C0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801854C0.c` | -| 153 | func_8017EC64 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017EC64.c` | -| 154 | func_80184C94 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184C94.c` | -| 155 | func_80185CE4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80185CE4.c` | -| 156 | func_8017EA68 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017EA68.c` | -| 157 | func_80180074 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80180074.c` | -| 158 | func_801847E4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801847E4.c` | -| 159 | func_80182470 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182470.c` | -| 160 | func_8017E3D8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017E3D8.c` | -| 161 | func_8018386C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018386C.c` | -| 162 | func_80187A0C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80187A0C.c` | -| 163 | func_8018893C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018893C.c` | -| 164 | func_80185BEC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80185BEC.c` | -| 165 | func_801900B0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801900B0.c` | -| 166 | func_8017BFC8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017BFC8.c` | -| 167 | func_8017F6B0 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017F6B0.c` | -| 168 | func_8017DDFC | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017DDFC.c` | -| 169 | func_801817DC | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_801817DC.c` | -| 170 | func_80182264 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80182264.c` | -| 171 | func_80181834 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80181834.c` | -| 172 | func_8018558C | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8018558C.c` | -| 173 | func_801843CC | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_801843CC.c` | -| 174 | func_8017FC8C | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017FC8C.c` | -| 175 | func_80183228 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80183228.c` | -| 176 | func_80183118 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80183118.c` | -| 177 | func_8017E404 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017E404.c` | -| 178 | func_80183B4C | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80183B4C.c` | -| 179 | func_801879B0 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_801879B0.c` | -| 180 | func_801828C8 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_801828C8.c` | -| 181 | func_8017FA80 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017FA80.c` | -| 182 | func_8017E874 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017E874.c` | -| 183 | func_80185000 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80185000.c` | -| 184 | func_80180F18 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80180F18.c` | -| 185 | func_8018C658 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8018C658.c` | -| 186 | func_80183F48 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80183F48.c` | -| 187 | func_80180834 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80180834.c` | -| 188 | func_8018BA9C | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8018BA9C.c` | -| 189 | func_80186DAC | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80186DAC.c` | -| 190 | func_8017EE78 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017EE78.c` | -| 191 | func_801804C8 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_801804C8.c` | -| 192 | func_8017D468 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017D468.c` | -| 193 | func_801816FC | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801816FC.c` | -| 194 | func_8017DE90 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017DE90.c` | -| 195 | func_80190480 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80190480.c` | -| 196 | func_8018AFDC | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018AFDC.c` | -| 197 | func_80180D34 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80180D34.c` | -| 198 | func_8017F38C | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017F38C.c` | -| 199 | func_8018AE6C | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018AE6C.c` | -| 200 | func_80181720 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80181720.c` | -| 201 | func_80183BC8 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80183BC8.c` | -| 202 | func_8017F0C0 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017F0C0.c` | -| 203 | func_8018D4B4 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018D4B4.c` | -| 204 | func_801874E8 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801874E8.c` | -| 205 | func_80183320 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80183320.c` | -| 206 | func_801857D4 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801857D4.c` | -| 207 | func_8018A184 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018A184.c` | -| 208 | func_8018B234 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018B234.c` | -| 209 | func_8017F534 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017F534.c` | -| 210 | func_801861DC | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801861DC.c` | -| 211 | func_801896EC | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801896EC.c` | -| 212 | func_8018C7C8 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018C7C8.c` | -| 213 | func_80187B80 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80187B80.c` | -| 214 | func_801806C8 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801806C8.c` | -| 215 | func_8018672C | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018672C.c` | -| 216 | func_801894B0 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801894B0.c` | -| 217 | func_8018B1E0 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018B1E0.c` | -| 218 | func_80184870 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80184870.c` | -| 219 | func_8017E6B0 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017E6B0.c` | -| 220 | func_8017F8E4 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8017F8E4.c` | -| 221 | func_80187074 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80187074.c` | -| 222 | func_8017FF90 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8017FF90.c` | -| 223 | func_8017FAE0 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8017FAE0.c` | -| 224 | func_8017E918 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8017E918.c` | -| 225 | func_80180ED4 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80180ED4.c` | -| 226 | func_80186700 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80186700.c` | -| 227 | func_80184880 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80184880.c` | -| 228 | func_8018CC04 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8018CC04.c` | -| 229 | func_8017DED8 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8017DED8.c` | -| 230 | func_8018455C | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8018455C.c` | -| 231 | func_80181B08 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80181B08.c` | -| 232 | func_801823F0 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_801823F0.c` | -| 233 | func_80188510 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80188510.c` | -| 234 | func_80181A44 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80181A44.c` | -| 235 | func_80182CD4 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80182CD4.c` | -| 236 | func_8018119C | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8018119C.c` | -| 237 | func_8018C394 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8018C394.c` | -| 238 | func_801803F0 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_801803F0.c` | -| 239 | func_8017F7D8 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017F7D8.c` | -| 240 | func_80181B8C | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80181B8C.c` | -| 241 | func_80180564 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80180564.c` | -| 242 | func_801809F4 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_801809F4.c` | -| 243 | func_8017F250 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017F250.c` | -| 244 | func_8017F66C | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017F66C.c` | -| 245 | func_80181E18 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80181E18.c` | -| 246 | func_801852C8 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_801852C8.c` | -| 247 | func_80180100 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80180100.c` | -| 248 | func_80181EF0 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80181EF0.c` | -| 249 | func_801821B8 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_801821B8.c` | -| 250 | func_8018312C | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8018312C.c` | -| 251 | func_8017F11C | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017F11C.c` | -| 252 | func_80182810 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80182810.c` | -| 253 | func_8017FDA8 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017FDA8.c` | -| 254 | func_80182938 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80182938.c` | -| 255 | func_8018517C | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8018517C.c` | -| 256 | func_80182B18 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80182B18.c` | -| 257 | func_8017DA90 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017DA90.c` | -| 258 | func_80181BB4 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80181BB4.c` | -| 259 | func_80185338 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80185338.c` | -| 260 | func_80185978 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80185978.c` | -| 261 | func_80185E54 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80185E54.c` | -| 262 | func_80187DAC | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80187DAC.c` | -| 263 | func_80183DB8 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80183DB8.c` | -| 264 | func_80180AE8 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80180AE8.c` | -| 265 | func_8017D398 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017D398.c` | -| 266 | func_80184A58 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80184A58.c` | -| 267 | func_80182280 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80182280.c` | -| 268 | func_80181C78 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80181C78.c` | -| 269 | func_801855DC | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_801855DC.c` | -| 270 | func_8017FCD4 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017FCD4.c` | -| 271 | func_80183158 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80183158.c` | -| 272 | func_80182E2C | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80182E2C.c` | -| 273 | func_8017F704 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017F704.c` | -| 274 | func_8017E06C | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017E06C.c` | -| 275 | func_80187AD4 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80187AD4.c` | -| 276 | func_8018595C | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8018595C.c` | -| 277 | func_80185B20 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80185B20.c` | -| 278 | func_801802CC | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_801802CC.c` | -| 279 | func_8017E2C4 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017E2C4.c` | -| 280 | func_8017F0EC | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017F0EC.c` | -| 281 | func_80180FFC | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80180FFC.c` | -| 282 | func_80188F80 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80188F80.c` | -| 283 | func_80181FF4 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80181FF4.c` | -| 284 | func_80189240 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80189240.c` | -| 285 | func_80184618 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80184618.c` | -| 286 | func_8018413C | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8018413C.c` | -| 287 | func_801819A0 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_801819A0.c` | -| 288 | func_801855F0 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_801855F0.c` | -| 289 | func_80186A28 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80186A28.c` | -| 290 | func_80186A88 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80186A88.c` | -| 291 | func_80180F4C | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80180F4C.c` | -| 292 | func_80186C88 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80186C88.c` | -| 293 | func_801815D8 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_801815D8.c` | -| 294 | func_80189898 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80189898.c` | -| 295 | func_8017CF40 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_8017CF40.c` | -| 296 | func_80180458 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80180458.c` | -| 297 | func_80185C6C | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80185C6C.c` | -| 298 | func_8018146C | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_8018146C.c` | -| 299 | func_8017C104 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_8017C104.c` | -| 300 | func_80180410 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80180410.c` | -| 301 | func_80180754 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80180754.c` | -| 302 | func_80186720 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80186720.c` | -| 303 | func_8017EA60 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_8017EA60.c` | -| 304 | func_8017F710 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_8017F710.c` | -| 305 | func_80184990 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80184990.c` | -| 306 | func_80185344 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80185344.c` | -| 307 | func_80182230 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80182230.c` | -| 308 | func_80185F24 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80185F24.c` | -| 309 | func_80189858 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80189858.c` | -| 310 | func_8017FFF0 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017FFF0.c` | -| 311 | func_8017E908 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017E908.c` | -| 312 | func_8017CF9C | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017CF9C.c` | -| 313 | func_801832B0 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801832B0.c` | -| 314 | func_801813B8 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801813B8.c` | -| 315 | func_80184734 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80184734.c` | -| 316 | func_801825C8 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801825C8.c` | -| 317 | func_80183430 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80183430.c` | -| 318 | func_80186120 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80186120.c` | -| 319 | func_80188508 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80188508.c` | -| 320 | func_8018D330 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8018D330.c` | -| 321 | func_80186A70 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80186A70.c` | -| 322 | func_8017F474 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017F474.c` | -| 323 | func_8017E804 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017E804.c` | -| 324 | func_80182D50 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80182D50.c` | -| 325 | func_801843B8 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801843B8.c` | -| 326 | func_80181C84 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80181C84.c` | -| 327 | func_801842D4 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801842D4.c` | -| 328 | func_80185EB4 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80185EB4.c` | -| 329 | func_80188690 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80188690.c` | -| 330 | func_80185F20 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80185F20.c` | -| 331 | func_8018F658 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8018F658.c` | -| 332 | func_8017F228 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017F228.c` | -| 333 | func_801801F4 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801801F4.c` | -| 334 | func_8017F358 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017F358.c` | -| 335 | func_80180E9C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80180E9C.c` | -| 336 | func_8017BEBC | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017BEBC.c` | -| 337 | func_80180854 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80180854.c` | -| 338 | func_80180E54 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80180E54.c` | -| 339 | func_8017F7F4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017F7F4.c` | -| 340 | func_8017EF28 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017EF28.c` | -| 341 | func_801816E4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801816E4.c` | -| 342 | func_8017D400 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017D400.c` | -| 343 | func_8017D6E8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017D6E8.c` | -| 344 | func_8017E4F8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017E4F8.c` | -| 345 | func_801829F4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801829F4.c` | -| 346 | func_801822A8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801822A8.c` | -| 347 | func_8017E954 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017E954.c` | -| 348 | func_80181F84 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80181F84.c` | -| 349 | func_801827FC | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801827FC.c` | -| 350 | func_8017FE88 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017FE88.c` | -| 351 | func_80180EC0 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80180EC0.c` | -| 352 | func_80181C4C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80181C4C.c` | -| 353 | func_801817A4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801817A4.c` | -| 354 | func_8017E52C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017E52C.c` | -| 355 | func_801805B0 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801805B0.c` | -| 356 | func_8018897C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8018897C.c` | -| 357 | func_8018AA88 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8018AA88.c` | -| 358 | func_8017FED4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017FED4.c` | -| 359 | func_8017CCD4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017CCD4.c` | -| 360 | func_801858C4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801858C4.c` | -| 361 | func_8018C310 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8018C310.c` | -| 362 | func_80182AD4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80182AD4.c` | -| 363 | func_8018868C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8018868C.c` | -| 364 | func_8017F624 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017F624.c` | -| 365 | func_8017FEB4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017FEB4.c` | -| 366 | func_80182298 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80182298.c` | -| 367 | func_80187114 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80187114.c` | -| 368 | func_80184590 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80184590.c` | -| 369 | func_80181B34 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80181B34.c` | -| 370 | func_801860F8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801860F8.c` | -| 371 | func_8017FFD8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017FFD8.c` | -| 372 | func_80188BF8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80188BF8.c` | -| 373 | func_80183BD0 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80183BD0.c` | -| 374 | func_801860F4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801860F4.c` | -| 375 | func_80183628 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80183628.c` | -| 376 | func_8018964C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8018964C.c` | -| 377 | func_801854C8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801854C8.c` | -| 378 | func_80184664 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80184664.c` | -| 379 | func_80185528 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80185528.c` | -| 380 | func_80187454 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80187454.c` | -| 381 | func_8017F7BC | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017F7BC.c` | -| 382 | func_801830C8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801830C8.c` | -| 383 | func_8017D4F0 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017D4F0.c` | -| 384 | func_801825E8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801825E8.c` | -| 385 | func_80183C1C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80183C1C.c` | -| 386 | func_80185A00 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80185A00.c` | -| 387 | func_8017FCC0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017FCC0.c` | -| 388 | func_801833C8 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801833C8.c` | -| 389 | func_8017FFD0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017FFD0.c` | -| 390 | func_80180E34 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80180E34.c` | -| 391 | func_801844C4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801844C4.c` | -| 392 | func_8018AB24 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018AB24.c` | -| 393 | func_80188C84 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80188C84.c` | -| 394 | func_8017E184 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017E184.c` | -| 395 | func_80181434 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80181434.c` | -| 396 | func_80181A70 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80181A70.c` | -| 397 | func_8017DF88 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017DF88.c` | -| 398 | func_801841D0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801841D0.c` | -| 399 | func_80184204 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80184204.c` | -| 400 | func_8018534C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018534C.c` | -| 401 | func_80184940 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80184940.c` | -| 402 | func_80180B60 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80180B60.c` | -| 403 | func_8017FB0C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017FB0C.c` | -| 404 | func_8017E72C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017E72C.c` | -| 405 | func_80189C4C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80189C4C.c` | -| 406 | func_8017E670 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017E670.c` | -| 407 | func_80180014 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80180014.c` | -| 408 | func_80180B90 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80180B90.c` | -| 409 | func_801848E8 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801848E8.c` | -| 410 | func_8017E094 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017E094.c` | -| 411 | func_8018082C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018082C.c` | -| 412 | func_8018373C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018373C.c` | -| 413 | func_8017DF48 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017DF48.c` | -| 414 | func_80182724 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80182724.c` | -| 415 | func_80182EC0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80182EC0.c` | -| 416 | func_80188E8C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80188E8C.c` | -| 417 | func_801806E0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801806E0.c` | -| 418 | func_8018A5A4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018A5A4.c` | -| 419 | func_80181AC0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80181AC0.c` | -| 420 | func_801841A0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801841A0.c` | -| 421 | func_80183744 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80183744.c` | -| 422 | func_8018924C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018924C.c` | -| 423 | func_80185778 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80185778.c` | -| 424 | func_801870B4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801870B4.c` | -| 425 | func_80185E3C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80185E3C.c` | -| 426 | func_8017F5E8 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017F5E8.c` | -| 427 | func_801823D4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801823D4.c` | -| 428 | func_80186EE4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80186EE4.c` | -| 429 | func_80180AF4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80180AF4.c` | -| 430 | func_801831FC | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801831FC.c` | -| 431 | func_801862D4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801862D4.c` | -| 432 | func_80184578 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80184578.c` | -| 433 | func_8017F804 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017F804.c` | -| 434 | func_80183888 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80183888.c` | -| 435 | func_80187224 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80187224.c` | -| 436 | func_801850F8 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801850F8.c` | -| 437 | func_80183F7C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80183F7C.c` | -| 438 | func_801800DC | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801800DC.c` | -| 439 | func_80182190 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80182190.c` | -| 440 | func_80182380 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80182380.c` | -| 441 | func_8018EDB8 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018EDB8.c` | -| 442 | func_80190298 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80190298.c` | -| 443 | func_8018311C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018311C.c` | -| 444 | func_8018A594 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018A594.c` | -| 445 | func_8017DED0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017DED0.c` | -| 446 | func_8018228C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018228C.c` | -| 447 | func_801889E0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801889E0.c` | -| 448 | func_8017DEEC | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017DEEC.c` | -| 449 | func_8017F300 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017F300.c` | -| 450 | func_80184794 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80184794.c` | -| 451 | func_80185648 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80185648.c` | -| 452 | func_80186D64 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80186D64.c` | -| 453 | func_8018151C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018151C.c` | -| 454 | func_8017F7E8 | 1 | WAVE | 177 | near | 11 | WAVE: 11 mismatch | `.run/backlog_drafts/func_8017F7E8.c` | -| 455 | func_801824D0 | 1 | WAVE | 181 | near | 11 | WAVE: 11 mismatch | `.run/backlog_drafts/func_801824D0.c` | -| 456 | func_80182F4C | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80182F4C.c` | -| 457 | func_801835C8 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_801835C8.c` | -| 458 | func_8017D6C4 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017D6C4.c` | -| 459 | func_80181960 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80181960.c` | -| 460 | func_8017D7C8 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017D7C8.c` | -| 461 | func_8017F67C | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017F67C.c` | -| 462 | func_80181724 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80181724.c` | -| 463 | func_8017F128 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017F128.c` | -| 464 | func_80180154 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80180154.c` | -| 465 | func_80180240 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80180240.c` | -| 466 | func_80185274 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80185274.c` | -| 467 | func_801833D4 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_801833D4.c` | -| 468 | func_80180EA8 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80180EA8.c` | -| 469 | func_8018F91C | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8018F91C.c` | -| 470 | func_801835F4 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_801835F4.c` | -| 471 | func_801848B4 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_801848B4.c` | -| 472 | func_8017E5D4 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017E5D4.c` | -| 473 | func_80182118 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80182118.c` | -| 474 | func_8017E2C0 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017E2C0.c` | -| 475 | func_80181744 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80181744.c` | -| 476 | func_8017EECC | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017EECC.c` | -| 477 | func_80182F78 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80182F78.c` | -| 478 | func_8017F154 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017F154.c` | -| 479 | func_8018150C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018150C.c` | -| 480 | func_801803A4 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801803A4.c` | -| 481 | func_8017D7F8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017D7F8.c` | -| 482 | func_8017FFFC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017FFFC.c` | -| 483 | func_8018766C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018766C.c` | -| 484 | func_8017DFF8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017DFF8.c` | -| 485 | func_8017D08C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017D08C.c` | -| 486 | func_8017DBD8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017DBD8.c` | -| 487 | func_8017F574 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017F574.c` | -| 488 | func_80183AC8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80183AC8.c` | -| 489 | func_80181C08 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80181C08.c` | -| 490 | func_801822C8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801822C8.c` | -| 491 | func_80181388 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80181388.c` | -| 492 | func_80185C2C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80185C2C.c` | -| 493 | func_80183BEC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80183BEC.c` | -| 494 | func_80184DB4 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80184DB4.c` | -| 495 | func_8018AE08 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018AE08.c` | -| 496 | func_80184698 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80184698.c` | -| 497 | func_80184718 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80184718.c` | -| 498 | func_8018134C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018134C.c` | -| 499 | func_8017F4BC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017F4BC.c` | -| 500 | func_80181070 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80181070.c` | -| 501 | func_801810A4 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801810A4.c` | -| 502 | func_801810D8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801810D8.c` | -| 503 | func_801819CC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801819CC.c` | -| 504 | func_80180554 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80180554.c` | -| 505 | func_80181E5C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80181E5C.c` | -| 506 | func_80189DDC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80189DDC.c` | -| 507 | func_8018ABE0 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018ABE0.c` | -| 508 | func_80189A60 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80189A60.c` | -| 509 | func_8018278C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018278C.c` | -| 510 | func_801827C0 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801827C0.c` | -| 511 | func_80186A58 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80186A58.c` | -| 512 | func_8017F2BC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017F2BC.c` | -| 513 | func_8017F184 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017F184.c` | -| 514 | func_80185F58 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80185F58.c` | -| 515 | func_8018A3C8 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8018A3C8.c` | -| 516 | func_8017EA20 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017EA20.c` | -| 517 | func_80180528 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80180528.c` | -| 518 | func_80180BCC | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80180BCC.c` | -| 519 | func_801818EC | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801818EC.c` | -| 520 | func_8017DA3C | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017DA3C.c` | -| 521 | func_8017EDA8 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017EDA8.c` | -| 522 | func_801816CC | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801816CC.c` | -| 523 | func_8017D914 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017D914.c` | -| 524 | func_801828A8 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801828A8.c` | -| 525 | func_8017FD58 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017FD58.c` | -| 526 | func_8017F830 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017F830.c` | -| 527 | func_8018276C | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8018276C.c` | -| 528 | func_80183AF8 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80183AF8.c` | -| 529 | func_801858D0 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801858D0.c` | -| 530 | func_80180C34 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80180C34.c` | -| 531 | func_8018BDA4 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8018BDA4.c` | -| 532 | func_8017C8E4 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017C8E4.c` | -| 533 | func_80186D30 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80186D30.c` | -| 534 | func_8017F0D8 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017F0D8.c` | -| 535 | func_8017E358 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017E358.c` | -| 536 | func_80180420 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80180420.c` | -| 537 | func_8017E35C | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017E35C.c` | -| 538 | func_801834E4 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801834E4.c` | -| 539 | func_801811B4 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801811B4.c` | -| 540 | func_8017CDBC | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017CDBC.c` | -| 541 | func_80180D10 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80180D10.c` | -| 542 | func_8018316C | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8018316C.c` | -| 543 | func_8017E808 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017E808.c` | -| 544 | func_8017EDC4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017EDC4.c` | -| 545 | func_80180654 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80180654.c` | -| 546 | func_8017C6F4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017C6F4.c` | -| 547 | func_8017E4F0 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017E4F0.c` | -| 548 | func_8018B2DC | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8018B2DC.c` | -| 549 | func_80183398 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80183398.c` | -| 550 | func_80181468 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80181468.c` | -| 551 | func_80184384 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80184384.c` | -| 552 | func_8018A934 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8018A934.c` | -| 553 | func_8018B50C | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8018B50C.c` | -| 554 | func_80182844 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80182844.c` | -| 555 | func_80181B90 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80181B90.c` | -| 556 | func_80185F98 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80185F98.c` | -| 557 | func_80185EEC | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80185EEC.c` | -| 558 | func_80186DE8 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80186DE8.c` | -| 559 | func_801838EC | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_801838EC.c` | -| 560 | func_80182348 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80182348.c` | -| 561 | func_80185CD4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80185CD4.c` | -| 562 | func_801892C0 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_801892C0.c` | -| 563 | func_801859E4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_801859E4.c` | -| 564 | func_80184B70 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80184B70.c` | -| 565 | func_801871C4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_801871C4.c` | -| 566 | func_80189504 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80189504.c` | -| 567 | func_8017C918 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017C918.c` | -| 568 | func_801813F0 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_801813F0.c` | -| 569 | func_80181F6C | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80181F6C.c` | -| 570 | func_8017EA04 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017EA04.c` | -| 571 | func_8017EF68 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017EF68.c` | -| 572 | func_8017EBA8 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017EBA8.c` | -| 573 | func_80185404 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80185404.c` | -| 574 | func_8017D7C4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017D7C4.c` | -| 575 | func_8017D974 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017D974.c` | -| 576 | func_80180950 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80180950.c` | -| 577 | func_80181784 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181784.c` | -| 578 | func_8017FFE8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017FFE8.c` | -| 579 | func_801820F0 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_801820F0.c` | -| 580 | func_8018B0EC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8018B0EC.c` | -| 581 | func_801803F4 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_801803F4.c` | -| 582 | func_8017E818 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E818.c` | -| 583 | func_80181B0C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181B0C.c` | -| 584 | func_80184010 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80184010.c` | -| 585 | func_8018648C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8018648C.c` | -| 586 | func_8017F138 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017F138.c` | -| 587 | func_8017D9B8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D9B8.c` | -| 588 | func_80180DB0 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80180DB0.c` | -| 589 | func_8017E290 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E290.c` | -| 590 | func_8017EDC8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017EDC8.c` | -| 591 | func_80181A94 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181A94.c` | -| 592 | func_8017E318 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E318.c` | -| 593 | func_80181B44 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181B44.c` | -| 594 | func_8017D1B4 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D1B4.c` | -| 595 | func_8017E778 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E778.c` | -| 596 | func_80180D5C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80180D5C.c` | -| 597 | func_8017CDB8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CDB8.c` | -| 598 | func_8017CE20 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CE20.c` | -| 599 | func_8017CE40 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CE40.c` | -| 600 | func_8017D220 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D220.c` | -| 601 | func_80183718 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80183718.c` | -| 602 | func_8017EB1C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017EB1C.c` | -| 603 | func_80181028 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181028.c` | -| 604 | func_8017DACC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017DACC.c` | -| 605 | func_8018533C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8018533C.c` | -| 606 | func_8017D104 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D104.c` | -| 607 | func_8017F268 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017F268.c` | -| 608 | func_8017F120 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017F120.c` | -| 609 | func_80185A68 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80185A68.c` | -| 610 | func_8017CE48 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CE48.c` | -| 611 | func_8017CEB0 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CEB0.c` | -| 612 | func_801801C4 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_801801C4.c` | -| 613 | func_8017CEEC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CEEC.c` | -| 614 | func_8017DDD8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017DDD8.c` | -| 615 | func_8017DD9C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017DD9C.c` | -| 616 | func_8017DF80 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017DF80.c` | -| 617 | func_8017D49C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D49C.c` | -| 618 | func_8017F5E0 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017F5E0.c` | -| 619 | func_8017DFCC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017DFCC.c` | -| 620 | func_80181C1C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181C1C.c` | -| 621 | func_8017D22C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D22C.c` | -| 622 | func_8018338C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8018338C.c` | -| 623 | func_8017EEB8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017EEB8.c` | -| 624 | func_8017E9F4 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E9F4.c` | -| 625 | func_8017E6CC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E6CC.c` | -| 626 | func_8017F3A8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017F3A8.c` | -| 627 | func_8017D040 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D040.c` | -| 628 | func_8017E7AC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E7AC.c` | -| 629 | func_8017E304 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E304.c` | -| 630 | func_8017D084 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D084.c` | -| 631 | func_8017D19C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D19C.c` | -| 632 | func_8017E700 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E700.c` | -| 633 | func_8017E0F0 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017E0F0.c` | -| 634 | func_8017E7D8 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017E7D8.c` | -| 635 | func_80183988 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80183988.c` | -| 636 | func_80184154 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80184154.c` | -| 637 | func_80182D78 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80182D78.c` | -| 638 | func_80183074 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80183074.c` | -| 639 | func_80184EA4 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80184EA4.c` | -| 640 | func_8017F920 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017F920.c` | -| 641 | func_80180EDC | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80180EDC.c` | -| 642 | func_80187A8C | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80187A8C.c` | -| 643 | func_8017F1F8 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017F1F8.c` | -| 644 | func_8017EC84 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017EC84.c` | -| 645 | func_8017E9CC | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017E9CC.c` | -| 646 | func_8017EAE0 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017EAE0.c` | -| 647 | func_80186984 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80186984.c` | -| 648 | func_8017F414 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017F414.c` | -| 649 | func_8017E090 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017E090.c` | -| 650 | func_801853F8 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_801853F8.c` | -| 651 | func_8017F20C | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017F20C.c` | -| 652 | func_80182654 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80182654.c` | -| 653 | func_8017CDE4 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017CDE4.c` | -| 654 | func_8017DFAC | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017DFAC.c` | -| 655 | func_8017EF1C | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017EF1C.c` | -| 656 | func_8017EEF4 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017EEF4.c` | -| 657 | func_8017E814 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017E814.c` | -| 658 | func_80184EE0 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80184EE0.c` | -| 659 | func_8017FA44 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017FA44.c` | -| 660 | func_80182D1C | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80182D1C.c` | -| 661 | func_8018384C | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8018384C.c` | -| 662 | func_8017E950 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017E950.c` | -| 663 | func_8017CDD8 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017CDD8.c` | -| 664 | func_80180890 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80180890.c` | -| 665 | func_8017D5F8 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017D5F8.c` | -| 666 | func_80180D74 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80180D74.c` | -| 667 | func_8017F568 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017F568.c` | -| 668 | func_80180D14 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80180D14.c` | -| 669 | func_80183C58 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80183C58.c` | -| 670 | func_8018208C | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8018208C.c` | -| 671 | func_8017FD6C | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017FD6C.c` | -| 672 | func_801877DC | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_801877DC.c` | -| 673 | func_8017DA10 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017DA10.c` | -| 674 | func_80189630 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80189630.c` | -| 675 | func_80184630 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80184630.c` | -| 676 | func_80185334 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80185334.c` | -| 677 | func_8017E850 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017E850.c` | -| 678 | func_8017DCF4 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017DCF4.c` | -| 679 | func_8017D988 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017D988.c` | -| 680 | func_80182E38 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80182E38.c` | -| 681 | func_80183138 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80183138.c` | -| 682 | func_80180B54 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80180B54.c` | -| 683 | func_8017D600 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017D600.c` | -| 684 | func_8017F6C4 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017F6C4.c` | -| 685 | func_8017E9E4 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017E9E4.c` | -| 686 | func_801827D4 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_801827D4.c` | -| 687 | func_80185888 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80185888.c` | -| 688 | func_80180574 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80180574.c` | -| 689 | func_80183F1C | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80183F1C.c` | -| 690 | func_8017FFCC | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017FFCC.c` | -| 691 | func_80182344 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80182344.c` | -| 692 | func_801811F4 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_801811F4.c` | -| 693 | func_80180DB8 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80180DB8.c` | -| 694 | func_8017D184 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017D184.c` | -| 695 | func_8017F160 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017F160.c` | -| 696 | func_8017F4D0 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017F4D0.c` | -| 697 | func_8018033C | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8018033C.c` | -| 698 | func_80181138 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80181138.c` | -| 699 | func_8017E048 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017E048.c` | -| 700 | func_8017F3BC | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017F3BC.c` | -| 701 | func_80180DEC | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80180DEC.c` | -| 702 | func_801845B4 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_801845B4.c` | -| 703 | func_80181C74 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80181C74.c` | -| 704 | func_80182234 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80182234.c` | -| 705 | func_8017FF30 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017FF30.c` | -| 706 | func_80185288 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80185288.c` | -| 707 | func_8017E890 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017E890.c` | -| 708 | func_8018555C | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8018555C.c` | -| 709 | func_801826EC | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_801826EC.c` | -| 710 | func_8017DB00 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017DB00.c` | -| 711 | func_80181054 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_80181054.c` | -| 712 | func_8017F87C | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017F87C.c` | -| 713 | func_8017D704 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017D704.c` | -| 714 | func_80180AD8 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_80180AD8.c` | -| 715 | func_8018774C | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8018774C.c` | -| 716 | func_8017DE7C | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017DE7C.c` | -| 717 | func_8017FA00 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017FA00.c` | -| 718 | func_8018B6F4 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8018B6F4.c` | -| 719 | func_8017EEC8 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017EEC8.c` | -| 720 | func_8017E134 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017E134.c` | -| 721 | func_8017C6B8 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017C6B8.c` | -| 722 | func_801871E8 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_801871E8.c` | -| 723 | func_80188668 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_80188668.c` | -| 724 | func_8017DB44 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017DB44.c` | -| 725 | func_80187050 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_80187050.c` | -| 726 | func_8017DD18 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017DD18.c` | -| 727 | func_8018288C | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8018288C.c` | -| 728 | func_8017E1C8 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017E1C8.c` | -| 729 | func_8017D308 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017D308.c` | -| 730 | func_8017EAC8 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017EAC8.c` | -| 731 | func_8017D8B0 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017D8B0.c` | -| 732 | func_8017F080 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017F080.c` | -| 733 | func_8017CD14 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017CD14.c` | -| 734 | func_80180548 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_80180548.c` | -| 735 | func_8017DE78 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017DE78.c` | -| 736 | func_80185A18 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_80185A18.c` | -| 737 | func_8017FF2C | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017FF2C.c` | -| 738 | func_801803E0 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_801803E0.c` | -| 739 | func_8017D828 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017D828.c` | -| 740 | func_8017DC08 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017DC08.c` | -| 741 | func_80184388 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_80184388.c` | -| 742 | func_80187C64 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_80187C64.c` | -| 743 | func_8018A030 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8018A030.c` | -| 744 | func_8017D688 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017D688.c` | -| 745 | func_8017FA90 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017FA90.c` | -| 746 | func_8017F320 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017F320.c` | -| 747 | func_801813AC | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_801813AC.c` | -| 748 | func_80181478 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_80181478.c` | -| 749 | func_801868E0 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_801868E0.c` | -| 750 | func_8018AB74 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8018AB74.c` | -| 751 | func_8017DE70 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017DE70.c` | -| 752 | func_8018A640 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8018A640.c` | -| 753 | func_8017DC54 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017DC54.c` | -| 754 | func_8017F480 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017F480.c` | -| 755 | func_8017EF7C | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017EF7C.c` | -| 756 | func_80182FF0 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_80182FF0.c` | -| 757 | func_80182EE8 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_80182EE8.c` | -| 758 | func_8017E240 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017E240.c` | -| 759 | func_8017CE94 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017CE94.c` | -| 760 | func_8017D2A4 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017D2A4.c` | -| 761 | func_8017FAC8 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017FAC8.c` | -| 762 | func_80181E1C | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_80181E1C.c` | -| 763 | func_80181F60 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_80181F60.c` | -| 764 | func_8018381C | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8018381C.c` | -| 765 | func_80182488 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_80182488.c` | -| 766 | func_8017F500 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017F500.c` | -| 767 | func_8017D1E0 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017D1E0.c` | -| 768 | func_8017DDBC | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017DDBC.c` | -| 769 | func_8017F1BC | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017F1BC.c` | -| 770 | func_8017D384 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017D384.c` | -| 771 | func_8017EFB0 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017EFB0.c` | -| 772 | func_80182708 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_80182708.c` | -| 773 | func_8017F8A8 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017F8A8.c` | -| 774 | func_8017EBEC | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017EBEC.c` | -| 775 | func_80184DE8 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_80184DE8.c` | -| 776 | func_801834B4 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_801834B4.c` | -| 777 | func_8018333C | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8018333C.c` | -| 778 | func_8018056C | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8018056C.c` | -| 779 | func_80182C68 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_80182C68.c` | -| 780 | func_8017EA18 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017EA18.c` | -| 781 | func_80180EB8 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_80180EB8.c` | -| 782 | func_801856F0 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_801856F0.c` | -| 783 | func_8018DFDC | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8018DFDC.c` | -| 784 | func_801827A8 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_801827A8.c` | -| 785 | func_8017CFC4 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8017CFC4.c` | -| 786 | func_8017D7A4 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8017D7A4.c` | -| 787 | func_80182514 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_80182514.c` | -| 788 | func_8018545C | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8018545C.c` | -| 789 | func_80189FCC | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_80189FCC.c` | -| 790 | func_80181134 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_80181134.c` | -| 791 | func_8017FE10 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8017FE10.c` | -| 792 | func_80185AF8 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_80185AF8.c` | -| 793 | func_80182E34 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_80182E34.c` | -| 794 | func_8017D864 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8017D864.c` | -| 795 | func_8017DB70 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8017DB70.c` | -| 796 | func_8017FB68 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8017FB68.c` | -| 797 | func_8018ACB4 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8018ACB4.c` | -| 798 | func_8017EBF4 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8017EBF4.c` | -| 799 | func_80180A5C | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_80180A5C.c` | -| 800 | func_801830EC | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_801830EC.c` | -| 801 | func_801804F4 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_801804F4.c` | -| 802 | func_8017E6C0 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8017E6C0.c` | -| 803 | func_8017DD64 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8017DD64.c` | -| 804 | func_8017F024 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8017F024.c` | -| 805 | func_80181254 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_80181254.c` | -| 806 | func_80181020 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_80181020.c` | -| 807 | func_80184A1C | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_80184A1C.c` | -| 808 | func_80184430 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_80184430.c` | -| 809 | func_80185934 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_80185934.c` | -| 810 | func_801841B0 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_801841B0.c` | -| 811 | func_80180D28 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_80180D28.c` | -| 812 | func_8017E1F4 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_8017E1F4.c` | -| 813 | func_80182C24 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80182C24.c` | -| 814 | func_8017DAD0 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017DAD0.c` | -| 815 | func_8017EE08 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017EE08.c` | -| 816 | func_80183C4C | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80183C4C.c` | -| 817 | func_80181300 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80181300.c` | -| 818 | func_8017E218 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017E218.c` | -| 819 | func_8017F8AC | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017F8AC.c` | -| 820 | func_80180E98 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80180E98.c` | -| 821 | func_8017D21C | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017D21C.c` | -| 822 | func_80188650 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80188650.c` | -| 823 | func_801810C0 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_801810C0.c` | -| 824 | func_8017D004 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017D004.c` | -| 825 | func_80183A18 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80183A18.c` | -| 826 | func_80182324 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80182324.c` | -| 827 | func_80183A24 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80183A24.c` | -| 828 | func_8017D404 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017D404.c` | -| 829 | func_80182544 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_80182544.c` | -| 830 | func_80180CA0 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_80180CA0.c` | -| 831 | func_8017ED0C | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_8017ED0C.c` | -| 832 | func_8017FB4C | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_8017FB4C.c` | -| 833 | func_801840C0 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_801840C0.c` | -| 834 | func_8017F344 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_8017F344.c` | -| 835 | func_80180214 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_80180214.c` | -| 836 | func_801803DC | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_801803DC.c` | -| 837 | func_80181304 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_80181304.c` | -| 838 | func_8018B9DC | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_8018B9DC.c` | -| 839 | func_80180840 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_80180840.c` | -| 840 | func_80182E08 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_80182E08.c` | -| 841 | func_8018AF0C | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8018AF0C.c` | -| 842 | func_8017F750 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8017F750.c` | -| 843 | func_8018133C | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8018133C.c` | -| 844 | func_80183C10 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_80183C10.c` | -| 845 | func_80180B2C | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_80180B2C.c` | -| 846 | func_8017D894 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8017D894.c` | -| 847 | func_8017D1DC | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8017D1DC.c` | -| 848 | func_8017D9A8 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8017D9A8.c` | -| 849 | func_801845E8 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_801845E8.c` | -| 850 | func_8017CE0C | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8017CE0C.c` | -| 851 | func_80182268 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_80182268.c` | -| 852 | func_8018337C | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8018337C.c` | -| 853 | func_801800F4 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_801800F4.c` | -| 854 | func_80181990 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_80181990.c` | -| 855 | func_8017D8C8 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8017D8C8.c` | -| 856 | func_80184AA8 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_80184AA8.c` | -| 857 | func_8017E9EC | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8017E9EC.c` | -| 858 | func_80182D18 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_80182D18.c` | -| 859 | func_8017D524 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8017D524.c` | -| 860 | func_8017D784 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8017D784.c` | -| 861 | func_801856E4 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_801856E4.c` | -| 862 | func_8017D1D0 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017D1D0.c` | -| 863 | func_8017EEFC | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017EEFC.c` | -| 864 | func_8017FC50 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017FC50.c` | -| 865 | func_8017D554 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017D554.c` | -| 866 | func_80183018 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_80183018.c` | -| 867 | func_8017F370 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017F370.c` | -| 868 | func_8018739C | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8018739C.c` | -| 869 | func_8017DBC0 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017DBC0.c` | -| 870 | func_80182000 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_80182000.c` | -| 871 | func_8017E55C | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017E55C.c` | -| 872 | func_80182600 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_80182600.c` | -| 873 | func_8017FCE8 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017FCE8.c` | -| 874 | func_8017FEC8 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017FEC8.c` | -| 875 | func_8017D874 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017D874.c` | -| 876 | func_8017FACC | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017FACC.c` | -| 877 | func_8017F7F8 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017F7F8.c` | -| 878 | func_8017FB78 | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_8017FB78.c` | -| 879 | func_80181A40 | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_80181A40.c` | -| 880 | func_801800D4 | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_801800D4.c` | -| 881 | func_80182E1C | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_80182E1C.c` | -| 882 | func_80181F4C | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_80181F4C.c` | -| 883 | func_8017EEB0 | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_8017EEB0.c` | -| 884 | func_8017BF14 | None | | None | near | 34 | residual: 34 mismatch | `.run/backlog_drafts/func_8017BF14.c` | -| 885 | func_801859A0 | None | | None | near | 34 | residual: 34 mismatch | `.run/backlog_drafts/func_801859A0.c` | -| 886 | func_8017F8E0 | None | | None | near | 34 | residual: 34 mismatch | `.run/backlog_drafts/func_8017F8E0.c` | -| 887 | func_8017E740 | None | | None | near | 34 | residual: 34 mismatch | `.run/backlog_drafts/func_8017E740.c` | -| 888 | func_8017D804 | None | | None | near | 35 | residual: 35 mismatch | `.run/backlog_drafts/func_8017D804.c` | -| 889 | func_8017DA0C | None | | None | near | 35 | residual: 35 mismatch | `.run/backlog_drafts/func_8017DA0C.c` | -| 890 | func_80180030 | None | | None | near | 35 | residual: 35 mismatch | `.run/backlog_drafts/func_80180030.c` | -| 891 | func_8017E038 | None | | None | near | 35 | residual: 35 mismatch | `.run/backlog_drafts/func_8017E038.c` | -| 892 | func_8017E32C | None | | None | near | 35 | residual: 35 mismatch | `.run/backlog_drafts/func_8017E32C.c` | -| 893 | func_80181090 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_80181090.c` | -| 894 | func_8017EC78 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_8017EC78.c` | -| 895 | func_8017E79C | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_8017E79C.c` | -| 896 | func_80182A08 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_80182A08.c` | -| 897 | func_8017F0E8 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_8017F0E8.c` | -| 898 | func_8017D294 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_8017D294.c` | -| 899 | func_80189B38 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_80189B38.c` | -| 900 | func_80180F08 | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_80180F08.c` | -| 901 | func_8017D024 | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017D024.c` | -| 902 | func_8017EB5C | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017EB5C.c` | -| 903 | func_8017EB4C | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017EB4C.c` | -| 904 | func_8017EAD8 | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017EAD8.c` | -| 905 | func_8017D29C | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017D29C.c` | -| 906 | func_8017D450 | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017D450.c` | -| 907 | func_8017E230 | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017E230.c` | -| 908 | func_8017DA00 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017DA00.c` | -| 909 | func_8017E6FC | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017E6FC.c` | -| 910 | func_8017FE08 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017FE08.c` | -| 911 | func_8017D80C | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017D80C.c` | -| 912 | func_8018263C | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8018263C.c` | -| 913 | func_80186FA8 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_80186FA8.c` | -| 914 | func_80180A38 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_80180A38.c` | -| 915 | func_8017D740 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017D740.c` | -| 916 | func_8017DD44 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017DD44.c` | -| 917 | func_8017E840 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017E840.c` | -| 918 | func_8017D1F0 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017D1F0.c` | -| 919 | func_8017E014 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017E014.c` | -| 920 | func_8017D09C | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017D09C.c` | -| 921 | func_8017EC70 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017EC70.c` | -| 922 | func_80180C2C | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_80180C2C.c` | -| 923 | func_8017ECC0 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017ECC0.c` | -| 924 | func_8017F724 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017F724.c` | -| 925 | func_8017E36C | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017E36C.c` | -| 926 | func_8018ACD4 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8018ACD4.c` | -| 927 | func_8017ED80 | None | | None | near | 40 | residual: 40 mismatch | `.run/backlog_drafts/func_8017ED80.c` | -| 928 | func_80180850 | None | | None | near | 40 | residual: 40 mismatch | `.run/backlog_drafts/func_80180850.c` | -| 929 | func_80181438 | None | | None | near | 40 | residual: 40 mismatch | `.run/backlog_drafts/func_80181438.c` | -| 930 | func_8017D0BC | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8017D0BC.c` | -| 931 | func_8017E94C | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8017E94C.c` | -| 932 | func_8017E170 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8017E170.c` | -| 933 | func_8018043C | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8018043C.c` | -| 934 | func_8018A3F0 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8018A3F0.c` | -| 935 | func_80183364 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_80183364.c` | -| 936 | func_801824F0 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_801824F0.c` | -| 937 | func_8017F4A0 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8017F4A0.c` | -| 938 | func_801877E4 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_801877E4.c` | -| 939 | func_80183F4C | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_80183F4C.c` | -| 940 | func_80186044 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_80186044.c` | -| 941 | func_80180010 | None | | None | near | 42 | residual: 42 mismatch | `.run/backlog_drafts/func_80180010.c` | -| 942 | func_8017E824 | None | | None | near | 42 | residual: 42 mismatch | `.run/backlog_drafts/func_8017E824.c` | -| 943 | func_80183598 | None | | None | near | 42 | residual: 42 mismatch | `.run/backlog_drafts/func_80183598.c` | -| 944 | func_8017ECF4 | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8017ECF4.c` | -| 945 | func_8018118C | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8018118C.c` | -| 946 | func_8018FB8C | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8018FB8C.c` | -| 947 | func_8017D6D0 | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8017D6D0.c` | -| 948 | func_8017D96C | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8017D96C.c` | -| 949 | func_8017DF44 | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8017DF44.c` | -| 950 | func_801812FC | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_801812FC.c` | -| 951 | func_80186B08 | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_80186B08.c` | -| 952 | func_8017E578 | None | | None | near | 44 | residual: 44 mismatch | `.run/backlog_drafts/func_8017E578.c` | -| 953 | func_8017D6FC | None | | None | near | 44 | residual: 44 mismatch | `.run/backlog_drafts/func_8017D6FC.c` | -| 954 | func_8017E7D0 | None | | None | near | 45 | residual: 45 mismatch | `.run/backlog_drafts/func_8017E7D0.c` | -| 955 | func_8017D01C | None | | None | near | 45 | residual: 45 mismatch | `.run/backlog_drafts/func_8017D01C.c` | -| 956 | func_8017E380 | None | | None | near | 45 | residual: 45 mismatch | `.run/backlog_drafts/func_8017E380.c` | -| 957 | func_80180A88 | None | | None | near | 45 | residual: 45 mismatch | `.run/backlog_drafts/func_80180A88.c` | -| 958 | func_8017E9D8 | None | | None | near | 45 | residual: 45 mismatch | `.run/backlog_drafts/func_8017E9D8.c` | -| 959 | func_80189DB4 | None | | None | near | 45 | residual: 45 mismatch | `.run/backlog_drafts/func_80189DB4.c` | -| 960 | func_8018001C | None | | None | near | 46 | residual: 46 mismatch | `.run/backlog_drafts/func_8018001C.c` | -| 961 | func_8017F2A0 | None | | None | near | 46 | residual: 46 mismatch | `.run/backlog_drafts/func_8017F2A0.c` | -| 962 | func_80185EA8 | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_80185EA8.c` | -| 963 | func_8018912C | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_8018912C.c` | -| 964 | func_80188BEC | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_80188BEC.c` | -| 965 | func_801804DC | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_801804DC.c` | -| 966 | func_801808D8 | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_801808D8.c` | -| 967 | func_8017E8D0 | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_8017E8D0.c` | -| 968 | func_801846AC | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_801846AC.c` | -| 969 | func_801805DC | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_801805DC.c` | -| 970 | func_80184D0C | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_80184D0C.c` | -| 971 | func_8017F84C | None | | None | near | 48 | residual: 48 mismatch | `.run/backlog_drafts/func_8017F84C.c` | -| 972 | func_8017EF54 | None | | None | near | 48 | residual: 48 mismatch | `.run/backlog_drafts/func_8017EF54.c` | -| 973 | func_80181CE0 | None | | None | near | 48 | residual: 48 mismatch | `.run/backlog_drafts/func_80181CE0.c` | -| 974 | func_8017FCF0 | None | | None | near | 48 | residual: 48 mismatch | `.run/backlog_drafts/func_8017FCF0.c` | -| 975 | func_8017D6F0 | None | | None | near | 49 | residual: 49 mismatch | `.run/backlog_drafts/func_8017D6F0.c` | -| 976 | func_8017DF40 | None | | None | near | 49 | residual: 49 mismatch | `.run/backlog_drafts/func_8017DF40.c` | -| 977 | func_801845EC | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_801845EC.c` | -| 978 | func_8017F4C4 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_8017F4C4.c` | -| 979 | func_80188BB0 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_80188BB0.c` | -| 980 | func_80181B78 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_80181B78.c` | -| 981 | func_8017DE74 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_8017DE74.c` | -| 982 | func_80183D48 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_80183D48.c` | -| 983 | func_80184130 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_80184130.c` | -| 984 | func_80181124 | None | | None | near | 52 | residual: 52 mismatch | `.run/backlog_drafts/func_80181124.c` | -| 985 | func_8017FB48 | None | | None | near | 52 | residual: 52 mismatch | `.run/backlog_drafts/func_8017FB48.c` | -| 986 | func_80186A0C | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_80186A0C.c` | -| 987 | func_8017F050 | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_8017F050.c` | -| 988 | func_8018592C | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_8018592C.c` | -| 989 | func_8018CFF4 | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_8018CFF4.c` | -| 990 | func_8017DB6C | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_8017DB6C.c` | -| 991 | func_8018048C | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_8018048C.c` | -| 992 | func_8018465C | None | | None | near | 54 | residual: 54 mismatch | `.run/backlog_drafts/func_8018465C.c` | -| 993 | func_80183C54 | None | | None | near | 54 | residual: 54 mismatch | `.run/backlog_drafts/func_80183C54.c` | -| 994 | func_80180B7C | None | | None | near | 54 | residual: 54 mismatch | `.run/backlog_drafts/func_80180B7C.c` | -| 995 | func_8017FE54 | None | | None | near | 55 | residual: 55 mismatch | `.run/backlog_drafts/func_8017FE54.c` | -| 996 | func_8017ED60 | None | | None | near | 55 | residual: 55 mismatch | `.run/backlog_drafts/func_8017ED60.c` | -| 997 | func_801802BC | None | | None | near | 55 | residual: 55 mismatch | `.run/backlog_drafts/func_801802BC.c` | -| 998 | func_80182030 | None | | None | near | 55 | residual: 55 mismatch | `.run/backlog_drafts/func_80182030.c` | -| 999 | func_80180204 | None | | None | near | 55 | residual: 55 mismatch | `.run/backlog_drafts/func_80180204.c` | -| 1000 | func_80181DEC | None | | None | near | 57 | residual: 57 mismatch | `.run/backlog_drafts/func_80181DEC.c` | -| 1001 | func_8017E524 | None | | None | near | 57 | residual: 57 mismatch | `.run/backlog_drafts/func_8017E524.c` | -| 1002 | func_8018A538 | None | | None | near | 57 | residual: 57 mismatch | `.run/backlog_drafts/func_8018A538.c` | -| 1003 | func_8017ECB0 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_8017ECB0.c` | -| 1004 | func_801898C8 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_801898C8.c` | -| 1005 | func_80184920 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_80184920.c` | -| 1006 | func_80182EA0 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_80182EA0.c` | -| 1007 | func_8017F1C4 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_8017F1C4.c` | -| 1008 | func_80181A5C | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_80181A5C.c` | -| 1009 | func_8017D544 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_8017D544.c` | -| 1010 | func_8017EA2C | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_8017EA2C.c` | -| 1011 | func_80182BF4 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_80182BF4.c` | -| 1012 | func_8017F24C | None | | None | near | 59 | residual: 59 mismatch | `.run/backlog_drafts/func_8017F24C.c` | -| 1013 | func_8017D4CC | None | | None | near | 59 | residual: 59 mismatch | `.run/backlog_drafts/func_8017D4CC.c` | -| 1014 | func_80183624 | None | | None | near | 59 | residual: 59 mismatch | `.run/backlog_drafts/func_80183624.c` | -| 1015 | func_80180B50 | None | | None | near | 59 | residual: 59 mismatch | `.run/backlog_drafts/func_80180B50.c` | -| 1016 | func_8018567C | None | | None | near | 59 | residual: 59 mismatch | `.run/backlog_drafts/func_8018567C.c` | -| 1017 | func_8017E75C | None | | None | near | 61 | residual: 61 mismatch | `.run/backlog_drafts/func_8017E75C.c` | -| 1018 | func_80184778 | None | | None | near | 61 | residual: 61 mismatch | `.run/backlog_drafts/func_80184778.c` | -| 1019 | func_8017EEE0 | None | | None | near | 62 | residual: 62 mismatch | `.run/backlog_drafts/func_8017EEE0.c` | -| 1020 | func_80188204 | None | | None | near | 62 | residual: 62 mismatch | `.run/backlog_drafts/func_80188204.c` | -| 1021 | func_8017F25C | None | | None | near | 62 | residual: 62 mismatch | `.run/backlog_drafts/func_8017F25C.c` | -| 1022 | func_8017EB74 | None | | None | near | 63 | residual: 63 mismatch | `.run/backlog_drafts/func_8017EB74.c` | -| 1023 | func_8017E798 | None | | None | near | 64 | residual: 64 mismatch | `.run/backlog_drafts/func_8017E798.c` | -| 1024 | func_8017D610 | None | | None | near | 64 | residual: 64 mismatch | `.run/backlog_drafts/func_8017D610.c` | -| 1025 | func_8017CD10 | None | | None | near | 64 | residual: 64 mismatch | `.run/backlog_drafts/func_8017CD10.c` | -| 1026 | func_8017F1A0 | None | | None | near | 64 | residual: 64 mismatch | `.run/backlog_drafts/func_8017F1A0.c` | -| 1027 | func_8017D928 | None | | None | near | 64 | residual: 64 mismatch | `.run/backlog_drafts/func_8017D928.c` | -| 1028 | func_8018656C | None | | None | near | 65 | residual: 65 mismatch | `.run/backlog_drafts/func_8018656C.c` | -| 1029 | func_80184854 | None | | None | near | 66 | residual: 66 mismatch | `.run/backlog_drafts/func_80184854.c` | -| 1030 | func_80185B5C | None | | None | near | 67 | residual: 67 mismatch | `.run/backlog_drafts/func_80185B5C.c` | -| 1031 | func_8017E910 | None | | None | near | 68 | residual: 68 mismatch | `.run/backlog_drafts/func_8017E910.c` | -| 1032 | func_80182378 | None | | None | near | 69 | residual: 69 mismatch | `.run/backlog_drafts/func_80182378.c` | -| 1033 | func_80183544 | None | | None | near | 69 | residual: 69 mismatch | `.run/backlog_drafts/func_80183544.c` | -| 1034 | func_8018434C | None | | None | near | 69 | residual: 69 mismatch | `.run/backlog_drafts/func_8018434C.c` | -| 1035 | func_80180224 | None | | None | near | 71 | residual: 71 mismatch | `.run/backlog_drafts/func_80180224.c` | -| 1036 | func_80184238 | None | | None | near | 72 | residual: 72 mismatch | `.run/backlog_drafts/func_80184238.c` | -| 1037 | func_801866B0 | None | | None | near | 72 | residual: 72 mismatch | `.run/backlog_drafts/func_801866B0.c` | -| 1038 | func_8017D9E4 | None | | None | near | 73 | residual: 73 mismatch | `.run/backlog_drafts/func_8017D9E4.c` | -| 1039 | func_80181344 | None | | None | near | 73 | residual: 73 mismatch | `.run/backlog_drafts/func_80181344.c` | -| 1040 | func_80189B3C | None | | None | near | 74 | residual: 74 mismatch | `.run/backlog_drafts/func_80189B3C.c` | -| 1041 | func_80182B90 | None | | None | near | 74 | residual: 74 mismatch | `.run/backlog_drafts/func_80182B90.c` | -| 1042 | func_8018165C | None | | None | near | 74 | residual: 74 mismatch | `.run/backlog_drafts/func_8018165C.c` | -| 1043 | func_8017F468 | None | | None | near | 74 | residual: 74 mismatch | `.run/backlog_drafts/func_8017F468.c` | -| 1044 | func_8017DAB4 | None | | None | near | 75 | residual: 75 mismatch | `.run/backlog_drafts/func_8017DAB4.c` | -| 1045 | func_80181500 | None | | None | near | 75 | residual: 75 mismatch | `.run/backlog_drafts/func_80181500.c` | -| 1046 | func_801814A8 | None | | None | near | 76 | residual: 76 mismatch | `.run/backlog_drafts/func_801814A8.c` | -| 1047 | func_8017E81C | None | | None | near | 76 | residual: 76 mismatch | `.run/backlog_drafts/func_8017E81C.c` | -| 1048 | func_8018474C | None | | None | near | 76 | residual: 76 mismatch | `.run/backlog_drafts/func_8018474C.c` | -| 1049 | func_80184DDC | None | | None | near | 77 | residual: 77 mismatch | `.run/backlog_drafts/func_80184DDC.c` | -| 1050 | func_8017E2F4 | None | | None | near | 77 | residual: 77 mismatch | `.run/backlog_drafts/func_8017E2F4.c` | -| 1051 | func_8017EDBC | None | | None | near | 78 | residual: 78 mismatch | `.run/backlog_drafts/func_8017EDBC.c` | -| 1052 | func_8017E5F0 | None | | None | near | 79 | residual: 79 mismatch | `.run/backlog_drafts/func_8017E5F0.c` | -| 1053 | func_801815AC | None | | None | near | 79 | residual: 79 mismatch | `.run/backlog_drafts/func_801815AC.c` | -| 1054 | func_8017D54C | None | | None | near | 79 | residual: 79 mismatch | `.run/backlog_drafts/func_8017D54C.c` | -| 1055 | func_80181260 | None | | None | near | 79 | residual: 79 mismatch | `.run/backlog_drafts/func_80181260.c` | -| 1056 | func_801805D0 | None | | None | near | 79 | residual: 79 mismatch | `.run/backlog_drafts/func_801805D0.c` | -| 1057 | func_8017F290 | 1 | regalloc-order | 86 | near | 81 | none — MATCH. Two levers: (1) hold &D_801270CC in a `int *state` local so its | `.run/backlog_drafts/func_8017F290.c` | -| 1058 | func_80181068 | None | | None | near | 81 | residual: 81 mismatch | `.run/backlog_drafts/func_80181068.c` | -| 1059 | func_80184E00 | None | | None | near | 82 | residual: 82 mismatch | `.run/backlog_drafts/func_80184E00.c` | -| 1060 | func_8017EB88 | None | | None | near | 82 | residual: 82 mismatch | `.run/backlog_drafts/func_8017EB88.c` | -| 1061 | func_8017FB3C | None | | None | near | 82 | residual: 82 mismatch | `.run/backlog_drafts/func_8017FB3C.c` | -| 1062 | func_8017F840 | None | | None | near | 82 | residual: 82 mismatch | `.run/backlog_drafts/func_8017F840.c` | -| 1063 | func_8017DA9C | None | | None | near | 83 | residual: 83 mismatch | `.run/backlog_drafts/func_8017DA9C.c` | -| 1064 | func_801829F0 | None | | None | near | 83 | residual: 83 mismatch | `.run/backlog_drafts/func_801829F0.c` | -| 1065 | func_8017FBA4 | None | | None | near | 83 | residual: 83 mismatch | `.run/backlog_drafts/func_8017FBA4.c` | -| 1066 | func_801848AC | None | | None | near | 84 | residual: 84 mismatch | `.run/backlog_drafts/func_801848AC.c` | -| 1067 | func_8017DC9C | None | | None | near | 84 | residual: 84 mismatch | `.run/backlog_drafts/func_8017DC9C.c` | -| 1068 | func_801840FC | None | | None | near | 85 | residual: 85 mismatch | `.run/backlog_drafts/func_801840FC.c` | -| 1069 | func_80186094 | None | | None | near | 85 | residual: 85 mismatch | `.run/backlog_drafts/func_80186094.c` | -| 1070 | func_801847FC | None | | None | near | 86 | residual: 86 mismatch | `.run/backlog_drafts/func_801847FC.c` | -| 1071 | func_8018006C | None | | None | near | 86 | residual: 86 mismatch | `.run/backlog_drafts/func_8018006C.c` | -| 1072 | func_8017DFD8 | None | | None | near | 87 | residual: 87 mismatch | `.run/backlog_drafts/func_8017DFD8.c` | -| 1073 | func_8017D1F8 | None | | None | near | 87 | residual: 87 mismatch | `.run/backlog_drafts/func_8017D1F8.c` | -| 1074 | func_8017CE68 | None | | None | near | 87 | residual: 87 mismatch | `.run/backlog_drafts/func_8017CE68.c` | -| 1075 | func_8017D7D0 | None | | None | near | 88 | residual: 88 mismatch | `.run/backlog_drafts/func_8017D7D0.c` | -| 1076 | func_80181838 | None | | None | near | 88 | residual: 88 mismatch | `.run/backlog_drafts/func_80181838.c` | -| 1077 | func_801821D4 | None | | None | near | 90 | residual: 90 mismatch | `.run/backlog_drafts/func_801821D4.c` | -| 1078 | func_8017F0A8 | None | | None | near | 90 | residual: 90 mismatch | `.run/backlog_drafts/func_8017F0A8.c` | -| 1079 | func_8018AD3C | None | | None | near | 90 | residual: 90 mismatch | `.run/backlog_drafts/func_8018AD3C.c` | -| 1080 | func_8017DD5C | None | | None | near | 90 | residual: 90 mismatch | `.run/backlog_drafts/func_8017DD5C.c` | -| 1081 | func_8017EDC0 | None | | None | near | 91 | residual: 91 mismatch | `.run/backlog_drafts/func_8017EDC0.c` | -| 1082 | func_801807DC | None | | None | near | 92 | residual: 92 mismatch | `.run/backlog_drafts/func_801807DC.c` | -| 1083 | func_80180170 | None | | None | near | 92 | residual: 92 mismatch | `.run/backlog_drafts/func_80180170.c` | -| 1084 | func_8017D98C | 1 | plumbing | 31 | near | 93 | none — MATCH (expected): straight global stores + tail call; const 0x140 reused for two halves | `.run/backlog_drafts/func_8017D98C.c` | -| 1085 | func_8017EFFC | None | | None | near | 93 | residual: 93 mismatch | `.run/backlog_drafts/func_8017EFFC.c` | -| 1086 | func_8017D940 | None | | None | near | 94 | residual: 94 mismatch | `.run/backlog_drafts/func_8017D940.c` | -| 1087 | func_8017D934 | None | | None | near | 95 | residual: 95 mismatch | `.run/backlog_drafts/func_8017D934.c` | -| 1088 | func_8017DAB8 | None | | None | near | 97 | residual: 97 mismatch | `.run/backlog_drafts/func_8017DAB8.c` | -| 1089 | func_80180040 | None | | None | near | 97 | residual: 97 mismatch | `.run/backlog_drafts/func_80180040.c` | -| 1090 | func_8017FBE0 | None | | None | near | 97 | residual: 97 mismatch | `.run/backlog_drafts/func_8017FBE0.c` | -| 1091 | func_8017F240 | 1 | regalloc-order | 20 | near | 98 | none — MATCH (base &D_801270D0 pinned to $s0 holds across call; one lui/addiu reused for load+store) | `.run/backlog_drafts/func_8017F240.c` | -| 1092 | func_801863B0 | None | | None | near | 98 | residual: 98 mismatch | `.run/backlog_drafts/func_801863B0.c` | -| 1093 | func_80182728 | None | | None | near | 98 | residual: 98 mismatch | `.run/backlog_drafts/func_80182728.c` | -| 1094 | func_8018038C | None | | None | near | 100 | residual: 100 mismatch | `.run/backlog_drafts/func_8018038C.c` | -| 1095 | func_8017D808 | None | | None | near | 102 | residual: 102 mismatch | `.run/backlog_drafts/func_8017D808.c` | -| 1096 | func_80182D10 | None | | None | near | 102 | residual: 102 mismatch | `.run/backlog_drafts/func_80182D10.c` | -| 1097 | func_8017DC40 | None | | None | near | 104 | residual: 104 mismatch | `.run/backlog_drafts/func_8017DC40.c` | -| 1098 | func_80180F34 | None | | None | near | 105 | residual: 105 mismatch | `.run/backlog_drafts/func_80180F34.c` | -| 1099 | func_80181C44 | None | | None | near | 105 | residual: 105 mismatch | `.run/backlog_drafts/func_80181C44.c` | -| 1100 | func_8017F96C | None | | None | near | 106 | residual: 106 mismatch | `.run/backlog_drafts/func_8017F96C.c` | -| 1101 | func_8017EFEC | None | | None | near | 107 | residual: 107 mismatch | `.run/backlog_drafts/func_8017EFEC.c` | -| 1102 | func_80182BC8 | None | | None | near | 107 | residual: 107 mismatch | `.run/backlog_drafts/func_80182BC8.c` | -| 1103 | func_8017F69C | None | | None | near | 107 | residual: 107 mismatch | `.run/backlog_drafts/func_8017F69C.c` | -| 1104 | func_80184828 | None | | None | near | 109 | residual: 109 mismatch | `.run/backlog_drafts/func_80184828.c` | -| 1105 | func_8017F3E4 | None | | None | near | 110 | residual: 110 mismatch | `.run/backlog_drafts/func_8017F3E4.c` | -| 1106 | func_8017DAF4 | None | | None | near | 111 | residual: 111 mismatch | `.run/backlog_drafts/func_8017DAF4.c` | -| 1107 | func_8017FE9C | None | | None | near | 111 | residual: 111 mismatch | `.run/backlog_drafts/func_8017FE9C.c` | -| 1108 | func_8017F768 | None | | None | near | 112 | residual: 112 mismatch | `.run/backlog_drafts/func_8017F768.c` | -| 1109 | func_8017F3B8 | None | | None | near | 112 | residual: 112 mismatch | `.run/backlog_drafts/func_8017F3B8.c` | -| 1110 | func_8017D508 | None | | None | near | 113 | residual: 113 mismatch | `.run/backlog_drafts/func_8017D508.c` | -| 1111 | func_8018788C | None | | None | near | 113 | residual: 113 mismatch | `.run/backlog_drafts/func_8018788C.c` | -| 1112 | func_8017E978 | None | | None | near | 115 | residual: 115 mismatch | `.run/backlog_drafts/func_8017E978.c` | -| 1113 | func_80181858 | None | | None | near | 117 | residual: 117 mismatch | `.run/backlog_drafts/func_80181858.c` | -| 1114 | func_80184CD0 | None | | None | near | 118 | residual: 118 mismatch | `.run/backlog_drafts/func_80184CD0.c` | -| 1115 | func_8017E8F8 | None | | None | near | 120 | residual: 120 mismatch | `.run/backlog_drafts/func_8017E8F8.c` | -| 1116 | func_80184358 | None | | None | near | 121 | residual: 121 mismatch | `.run/backlog_drafts/func_80184358.c` | -| 1117 | func_8017F074 | None | | None | near | 121 | residual: 121 mismatch | `.run/backlog_drafts/func_8017F074.c` | -| 1118 | func_8017D890 | None | | None | near | 124 | residual: 124 mismatch | `.run/backlog_drafts/func_8017D890.c` | -| 1119 | func_8017DECC | None | | None | near | 125 | residual: 125 mismatch | `.run/backlog_drafts/func_8017DECC.c` | -| 1120 | func_80185020 | None | | None | near | 125 | residual: 125 mismatch | `.run/backlog_drafts/func_80185020.c` | -| 1121 | func_8017DD2C | None | | None | near | 125 | residual: 125 mismatch | `.run/backlog_drafts/func_8017DD2C.c` | -| 1122 | func_801884BC | None | | None | near | 125 | residual: 125 mismatch | `.run/backlog_drafts/func_801884BC.c` | -| 1123 | func_801892CC | None | | None | near | 127 | residual: 127 mismatch | `.run/backlog_drafts/func_801892CC.c` | -| 1124 | func_8017EB00 | None | | None | near | 127 | residual: 127 mismatch | `.run/backlog_drafts/func_8017EB00.c` | -| 1125 | func_8017E538 | None | | None | near | 128 | residual: 128 mismatch | `.run/backlog_drafts/func_8017E538.c` | -| 1126 | func_8017D50C | None | | None | near | 128 | residual: 128 mismatch | `.run/backlog_drafts/func_8017D50C.c` | -| 1127 | func_801803F8 | None | | None | near | 129 | residual: 129 mismatch | `.run/backlog_drafts/func_801803F8.c` | -| 1128 | func_80185E68 | 1 | STRUCT | 132 | near | 131 | STRUCT: 131 mismatch | `.run/backlog_drafts/func_80185E68.c` | -| 1129 | func_8017E378 | None | | None | near | 134 | residual: 134 mismatch | `.run/backlog_drafts/func_8017E378.c` | -| 1130 | func_80185730 | None | | None | near | 136 | residual: 136 mismatch | `.run/backlog_drafts/func_80185730.c` | -| 1131 | func_8018523C | None | | None | near | 136 | residual: 136 mismatch | `.run/backlog_drafts/func_8018523C.c` | -| 1132 | func_80186530 | None | | None | near | 139 | residual: 139 mismatch | `.run/backlog_drafts/func_80186530.c` | -| 1133 | func_80184F08 | None | regalloc-order | None | near | 141 | none — MATCH (145/145 ins, match_one confirmed) | `.run/backlog_drafts/func_80184F08.c` | -| 1134 | func_80185668 | None | | None | near | 142 | residual: 142 mismatch | `.run/backlog_drafts/func_80185668.c` | -| 1135 | func_8017DB0C | None | | None | near | 142 | residual: 142 mismatch | `.run/backlog_drafts/func_8017DB0C.c` | -| 1136 | func_801814B0 | None | | None | near | 144 | residual: 144 mismatch | `.run/backlog_drafts/func_801814B0.c` | -| 1137 | func_801801A4 | None | | None | near | 148 | residual: 148 mismatch | `.run/backlog_drafts/func_801801A4.c` | -| 1138 | func_80180868 | None | | None | near | 148 | residual: 148 mismatch | `.run/backlog_drafts/func_80180868.c` | -| 1139 | func_801829BC | None | | None | near | 150 | residual: 150 mismatch | `.run/backlog_drafts/func_801829BC.c` | -| 1140 | func_8017FBE8 | None | | None | near | 151 | residual: 151 mismatch | `.run/backlog_drafts/func_8017FBE8.c` | -| 1141 | func_8018200C | None | | None | near | 152 | residual: 152 mismatch | `.run/backlog_drafts/func_8018200C.c` | -| 1142 | func_80181984 | None | | None | near | 153 | residual: 153 mismatch | `.run/backlog_drafts/func_80181984.c` | -| 1143 | func_80183280 | None | | None | near | 154 | residual: 154 mismatch | `.run/backlog_drafts/func_80183280.c` | -| 1144 | func_80184CA0 | None | | None | near | 162 | residual: 162 mismatch | `.run/backlog_drafts/func_80184CA0.c` | -| 1145 | func_8017FA54 | None | | None | near | 166 | residual: 166 mismatch | `.run/backlog_drafts/func_8017FA54.c` | -| 1146 | func_8017D708 | None | | None | near | 166 | residual: 166 mismatch | `.run/backlog_drafts/func_8017D708.c` | -| 1147 | func_8017E6EC | None | | None | near | 172 | residual: 172 mismatch | `.run/backlog_drafts/func_8017E6EC.c` | -| 1148 | func_8017D5DC | None | | None | near | 173 | residual: 173 mismatch | `.run/backlog_drafts/func_8017D5DC.c` | -| 1149 | func_8017D47C | None | | None | near | 173 | residual: 173 mismatch | `.run/backlog_drafts/func_8017D47C.c` | -| 1150 | func_8017F40C | None | | None | near | 174 | residual: 174 mismatch | `.run/backlog_drafts/func_8017F40C.c` | -| 1151 | func_80184210 | None | | None | near | 176 | residual: 176 mismatch | `.run/backlog_drafts/func_80184210.c` | -| 1152 | func_80185E34 | None | | None | near | 185 | residual: 185 mismatch | `.run/backlog_drafts/func_80185E34.c` | -| 1153 | func_80180568 | None | | None | near | 185 | residual: 185 mismatch | `.run/backlog_drafts/func_80180568.c` | -| 1154 | func_801809C4 | None | | None | near | 190 | residual: 190 mismatch | `.run/backlog_drafts/func_801809C4.c` | -| 1155 | func_80183D84 | None | | None | near | 192 | residual: 192 mismatch | `.run/backlog_drafts/func_80183D84.c` | -| 1156 | func_80183FEC | None | | None | near | 198 | residual: 198 mismatch | `.run/backlog_drafts/func_80183FEC.c` | -| 1157 | func_801823B8 | None | | None | near | 204 | residual: 204 mismatch | `.run/backlog_drafts/func_801823B8.c` | -| 1158 | func_801826C4 | None | | None | near | 207 | residual: 207 mismatch | `.run/backlog_drafts/func_801826C4.c` | -| 1159 | func_8017E374 | None | | None | near | 234 | residual: 234 mismatch | `.run/backlog_drafts/func_8017E374.c` | -| 1160 | func_8018C3F8 | None | | None | near | 236 | residual: 236 mismatch | `.run/backlog_drafts/func_8018C3F8.c` | -| 1161 | func_80183438 | None | | None | near | 237 | residual: 237 mismatch | `.run/backlog_drafts/func_80183438.c` | -| 1162 | func_8017E7D4 | None | | None | near | 241 | residual: 241 mismatch | `.run/backlog_drafts/func_8017E7D4.c` | -| 1163 | func_80183BF8 | None | | None | near | 258 | residual: 258 mismatch | `.run/backlog_drafts/func_80183BF8.c` | -| 1164 | func_8017EB30 | None | | None | near | 278 | residual: 278 mismatch | `.run/backlog_drafts/func_8017EB30.c` | -| 1165 | func_801804A0 | None | | None | near | 280 | residual: 280 mismatch | `.run/backlog_drafts/func_801804A0.c` | -| 1166 | func_80187EDC | None | | None | near | 296 | residual: 296 mismatch | `.run/backlog_drafts/func_80187EDC.c` | -| 1167 | func_8017F554 | None | | None | near | 299 | residual: 299 mismatch | `.run/backlog_drafts/func_8017F554.c` | -| 1168 | func_8017FEF0 | None | | None | near | 304 | residual: 304 mismatch | `.run/backlog_drafts/func_8017FEF0.c` | -| 1169 | func_80181670 | None | | None | near | 311 | residual: 311 mismatch | `.run/backlog_drafts/func_80181670.c` | -| 1170 | func_801833F0 | None | | None | near | 328 | residual: 328 mismatch | `.run/backlog_drafts/func_801833F0.c` | -| 1171 | func_80181128 | None | | None | near | 385 | residual: 385 mismatch | `.run/backlog_drafts/func_80181128.c` | -| 1172 | func_8017EA84 | None | | None | near | 578 | residual: 578 mismatch | `.run/backlog_drafts/func_8017EA84.c` | -| 1173 | func_8018057C | None | | None | near | 897 | residual: 897 mismatch | `.run/backlog_drafts/func_8018057C.c` | -| 1174 | func_80184A68 | 1 | regalloc-order | 33 | failed | | none — MATCH | `.run/backlog_drafts/func_80184A68.c` | -| 1175 | func_80180B64 | 1 | struct | 75 | failed | | none — MATCH (75 ins, relocation-masked) | `.run/backlog_drafts/func_80180B64.c` | -| 1176 | func_80183DE0 | 1 | regalloc-order | 91 | failed | | testing if(!=1) layout + counter-before-pointer init order | `.run/backlog_drafts/func_80183DE0.c` | -| 1177 | func_80182C9C | 1 | schedule | 101 | failed | | none — MATCH (101 ins). Inner-switch break-to-shared-tail must be written as | `.run/backlog_drafts/func_80182C9C.c` | -| 1178 | func_80183FB8 | 1 | loose-typing | 101 | failed | | none — MATCH (relocation-masked match_one, 101/101 ins) | `.run/backlog_drafts/func_80183FB8.c` | -| 1179 | func_80185BA4 | 1 | WAVE | 177 | failed | | won't compile standalone (loose-typing / missing decl) | | -| 1180 | func_8017D8DC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017D8DC.c` | -| 1181 | func_80187750 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80187750.c` | -| 1182 | func_8017FFEC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFEC.c` | -| 1183 | func_80184018 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80184018.c` | -| 1184 | func_8017DC18 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017DC18.c` | -| 1185 | func_801853CC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801853CC.c` | -| 1186 | func_80181894 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181894.c` | -| 1187 | func_8018BFBC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8018BFBC.c` | -| 1188 | func_801807F4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801807F4.c` | -| 1189 | func_8017FFC8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFC8.c` | -| 1190 | func_8017E99C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E99C.c` | -| 1191 | func_80180294 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80180294.c` | -| 1192 | func_8017E76C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E76C.c` | -| 1193 | func_8017F29C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F29C.c` | -| 1194 | func_8018253C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8018253C.c` | -| 1195 | func_8017F00C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F00C.c` | -| 1196 | func_801802B0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801802B0.c` | -| 1197 | func_80181FDC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181FDC.c` | -| 1198 | func_8017DA1C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017DA1C.c` | -| 1199 | func_8017FFC4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFC4.c` | -| 1200 | func_8017E2F0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E2F0.c` | -| 1201 | func_801841E4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801841E4.c` | -| 1202 | func_80181738 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181738.c` | -| 1203 | func_801873D8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801873D8.c` | -| 1204 | func_80181E90 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181E90.c` | -| 1205 | func_80185628 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80185628.c` | -| 1206 | func_80182384 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80182384.c` | -| 1207 | func_801829D8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801829D8.c` | -| 1208 | func_80181A78 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181A78.c` | -| 1209 | func_80186E58 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80186E58.c` | -| 1210 | func_801805D4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801805D4.c` | -| 1211 | func_8017EA1C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017EA1C.c` | -| 1212 | func_8017F098 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F098.c` | -| 1213 | func_801822CC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801822CC.c` | -| 1214 | func_80185BA8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80185BA8.c` | -| 1215 | func_8018E710 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8018E710.c` | -| 1216 | func_801852D0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801852D0.c` | -| 1217 | func_8017E3F4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E3F4.c` | -| 1218 | func_800D1658 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D1658.c` | -| 1219 | func_800D1984 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D1984.c` | -| 1220 | func_800D24A0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D24A0.c` | -| 1221 | func_8018457C | None | regalloc-order | None | failed | | none — MATCH (160 ins). case1-tail needed a $a0 pin on the state temp | `.run/backlog_drafts/func_8018457C.c` | -| 1222 | func_8018D870 | None | regalloc-order | None | failed | | none — MATCH (match_one 380/380, relocation-masked). Levers: &&-DeMorgan for the mult block layout; lhu-corrected reads; split temps (t=func_8012C658 ret->v1, d8p=d8 load-temp->a0, s60/amt pinned $v1/$a1 for the mult chain); accumulate-in-place for the 0xe add; unsigned-short store for ori 0x8800; d8-load-via-temp to force the addu s3,a0 copy (fixes -1 length drift). | `.run/backlog_drafts/func_8018D870.c` | -| 1223 | func_80144B9C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80144B9C.c` | -| 1224 | func_8013DD68 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8013DD68.c` | +| 9 | func_80178004 | 134 | regalloc-order | 165 | near | 91 | [Phase-27 T8 corrected] close=91 pure local-alloc regalloc wall (§52 flagship; the 'MATCH' claim was a retracted myth — never a real match) | `.run/backlog_drafts/func_80178004.c` | +| 10 | func_801412A8 | 134 | regalloc-order | 198 | near | 110 | 110 mismatch (count-exact 198/198). S11 LUID(x)alloc: register-assignment permutation + prim2 store-schedule. §31 permuter seed (was mis-logged 164). | `.run/backlog_drafts/func_801412A8.c` | +| 11 | func_8017C294 | 2 | regalloc-order | 246 | near | 230 | structurally matched (246 ins, param_3 in $fp, spurious psVar7[1] giv killed via | `.run/backlog_drafts/func_8017C294.c` | +| 12 | func_80182988 | 1 | plumbing | 22 | near | 0 | none — MATCH (u16 store of 0xAA10 forces ori, not sign-extended addiu) | `.run/backlog_drafts/func_80182988.c` | +| 13 | func_8017E224 | 1 | struct | 29 | near | 0 | none — MATCH (unaligned 8-byte memcpy of global onto stack + cond byte incr) | `.run/backlog_drafts/func_8017E224.c` | +| 14 | func_80183BAC | 1 | struct | 41 | near | 0 | switch jump-table dispatch (jtbl_801D9420); verifying case grouping 0,1,2,5,6/3,7/4 emits the target table + tail | `.run/backlog_drafts/func_80183BAC.c` | +| 15 | func_80183C50 | 1 | struct | 41 | near | 0 | none — MATCH (cross-jump exploit §cookbook L1543: dup func_8012C218 into case3/7 + case4 → merged jal;nop) | `.run/backlog_drafts/func_80183C50.c` | +| 16 | func_80183AF0 | 1 | regalloc-order | 47 | near | 0 | none — MATCH (mask pinned $a1/$5 + p pinned $v0/$2; switch w/ distributed func_8012C218 tail via dup calls + cross-jump merge) | `.run/backlog_drafts/func_80183AF0.c` | +| 17 | func_8017EC7C | 1 | struct | 52 | near | 0 | none — MATCH (52 ins, relocation-masked) | `.run/backlog_drafts/func_8017EC7C.c` | +| 18 | func_80183CF4 | 1 | struct | 57 | near | 0 | none — MATCH (clean switch + jtbl; orchestrator owns jtbl/rodata migration) | `.run/backlog_drafts/func_80183CF4.c` | +| 19 | func_801842C8 | 1 | plumbing | 62 | near | 0 | none — MATCH | `.run/backlog_drafts/func_801842C8.c` | +| 20 | func_8018281C | 1 | struct | 76 | near | 0 | none — MATCH (76 ins). jtbl forced via explicit case 4/6 (count>=5 over MIPS tablejump threshold); case-5 block placed between if-block and default via goto so the if-block emits j default w/ e2=0 in the delay slot | `.run/backlog_drafts/func_8018281C.c` | +| 21 | func_80182E7C | 1 | struct | 85 | near | 0 | none — MATCH (85 ins, relocation-masked). Two switch-codegen levers: | `.run/backlog_drafts/func_80182E7C.c` | +| 22 | func_801820DC | 1 | struct | 94 | near | 0 | none — MATCH (switch on entity state at 0x34, inner jtbl on (s8)(u70>>8)) | `.run/backlog_drafts/func_801820DC.c` | +| 23 | func_80184D50 | 1 | schedule | 98 | near | 0 | none — MATCH (98 ins, relocation-masked) | `.run/backlog_drafts/func_80184D50.c` | +| 24 | func_8017F1C8 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017F1C8.c` | +| 25 | func_80182B9C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80182B9C.c` | +| 26 | func_8017C150 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017C150.c` | +| 27 | func_8017C078 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017C078.c` | +| 28 | func_801803A0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_801803A0.c` | +| 29 | func_80185D6C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80185D6C.c` | +| 30 | func_801832D0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_801832D0.c` | +| 31 | func_80180EF4 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180EF4.c` | +| 32 | func_8017D880 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D880.c` | +| 33 | func_80180EE0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180EE0.c` | +| 34 | func_8017D9FC | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D9FC.c` | +| 35 | func_8017E2A0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017E2A0.c` | +| 36 | func_8017D798 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D798.c` | +| 37 | func_8017D770 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D770.c` | +| 38 | func_8017DE84 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DE84.c` | +| 39 | func_8017D7C0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D7C0.c` | +| 40 | func_8017DE6C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DE6C.c` | +| 41 | func_8017DF1C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DF1C.c` | +| 42 | func_8017E1C0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017E1C0.c` | +| 43 | func_8017DF54 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DF54.c` | +| 44 | func_8017F060 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017F060.c` | +| 45 | func_8018234C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018234C.c` | +| 46 | func_80180FF8 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180FF8.c` | +| 47 | func_8017DB78 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DB78.c` | +| 48 | func_8017DD30 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DD30.c` | +| 49 | func_80184674 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80184674.c` | +| 50 | func_80184C90 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80184C90.c` | +| 51 | func_80184884 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80184884.c` | +| 52 | func_80185D00 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80185D00.c` | +| 53 | func_8017F54C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017F54C.c` | +| 54 | func_8017E58C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017E58C.c` | +| 55 | func_8017DDE0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017DDE0.c` | +| 56 | func_8017FD88 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017FD88.c` | +| 57 | func_8017F630 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017F630.c` | +| 58 | func_80182148 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80182148.c` | +| 59 | func_80186BD8 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80186BD8.c` | +| 60 | func_80182A18 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80182A18.c` | +| 61 | func_80186C1C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80186C1C.c` | +| 62 | func_80180264 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180264.c` | +| 63 | func_8017D700 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D700.c` | +| 64 | func_80186BF8 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80186BF8.c` | +| 65 | func_8017D4C0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D4C0.c` | +| 66 | func_8017D5A0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D5A0.c` | +| 67 | func_80183554 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80183554.c` | +| 68 | func_8017D5D0 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D5D0.c` | +| 69 | func_8017D944 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D944.c` | +| 70 | func_8018540C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018540C.c` | +| 71 | func_80183DF8 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80183DF8.c` | +| 72 | func_80180534 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180534.c` | +| 73 | func_80183100 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80183100.c` | +| 74 | func_8017D9AC | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017D9AC.c` | +| 75 | func_8018C118 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018C118.c` | +| 76 | func_80188720 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80188720.c` | +| 77 | func_8018C3EC | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018C3EC.c` | +| 78 | func_80180944 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80180944.c` | +| 79 | func_8018603C | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018603C.c` | +| 80 | func_80181D30 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_80181D30.c` | +| 81 | func_8018C2CC | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8018C2CC.c` | +| 82 | func_8017E464 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_8017E464.c` | +| 83 | func_800CFE60 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_800CFE60.c` | +| 84 | func_800D0214 | None | | None | near | 0 | match_one MATCH but gate rejected (declaration/TU plumbing) | `.run/backlog_drafts/func_800D0214.c` | +| 85 | func_80187DD0 | None | regalloc-order | None | near | 0 | none — MATCH (174 ins). Levers: obj = *(*(b+0x20)+0x20) reads via b not a (store side uses a); | `.run/backlog_drafts/func_80187DD0.c` | +| 86 | func_801886B0 | None | struct | None | near | 0 | none — MATCH (276 ins, relocation-masked) | `.run/backlog_drafts/func_801886B0.c` | +| 87 | func_8017F714 | 1 | plumbing | 27 | near | 1 | none — MATCH (27/27 ins, match_one verified) | `.run/backlog_drafts/func_8017F714.c` | +| 88 | func_80184C0C | 1 | struct | 48 | near | 1 | none — MATCH (array-of-struct %lo-fold for &D_8018AEB8[idx], stride 0x34) | `.run/backlog_drafts/func_80184C0C.c` | +| 89 | func_801803B0 | 1 | other | 51 | near | 1 | none — MATCH expected; simple if/else, no call-crossing locals beyond param in $s0 | `.run/backlog_drafts/func_801803B0.c` | +| 90 | func_8017F114 | 1 | regalloc-order | 75 | near | 1 | none — MATCH | `.run/backlog_drafts/func_8017F114.c` | +| 91 | func_801807D8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801807D8.c` | +| 92 | func_80180AD0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80180AD0.c` | +| 93 | func_8017FDB0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017FDB0.c` | +| 94 | func_80180720 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80180720.c` | +| 95 | func_80184A28 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184A28.c` | +| 96 | func_80183AFC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80183AFC.c` | +| 97 | func_8017EE50 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017EE50.c` | +| 98 | func_80181FF8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80181FF8.c` | +| 99 | func_801832F4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801832F4.c` | +| 100 | func_8017FE4C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017FE4C.c` | +| 101 | func_801827C4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801827C4.c` | +| 102 | func_80182B68 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182B68.c` | +| 103 | func_80185E38 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80185E38.c` | +| 104 | func_8017FD70 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017FD70.c` | +| 105 | func_801811D4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801811D4.c` | +| 106 | func_801819DC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801819DC.c` | +| 107 | func_8018ADF8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018ADF8.c` | +| 108 | func_80186554 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80186554.c` | +| 109 | func_801873FC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801873FC.c` | +| 110 | func_80180E7C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80180E7C.c` | +| 111 | func_801835FC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801835FC.c` | +| 112 | func_80184970 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184970.c` | +| 113 | func_801863D4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801863D4.c` | +| 114 | func_80181540 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80181540.c` | +| 115 | func_801809D4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801809D4.c` | +| 116 | func_801802A4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801802A4.c` | +| 117 | func_801830A8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801830A8.c` | +| 118 | func_8017E858 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017E858.c` | +| 119 | func_80186BD4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80186BD4.c` | +| 120 | func_8017FB98 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017FB98.c` | +| 121 | func_8017EE14 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017EE14.c` | +| 122 | func_80181DA0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80181DA0.c` | +| 123 | func_80187840 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80187840.c` | +| 124 | func_80184E58 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184E58.c` | +| 125 | func_80184354 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184354.c` | +| 126 | func_8018011C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018011C.c` | +| 127 | func_8017E29C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017E29C.c` | +| 128 | func_8017D930 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017D930.c` | +| 129 | func_80182A8C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182A8C.c` | +| 130 | func_80181FCC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80181FCC.c` | +| 131 | func_801893E0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801893E0.c` | +| 132 | func_80186908 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80186908.c` | +| 133 | func_80189DC4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80189DC4.c` | +| 134 | func_80182AB0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182AB0.c` | +| 135 | func_80183EA4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80183EA4.c` | +| 136 | func_8018B344 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018B344.c` | +| 137 | func_80188858 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80188858.c` | +| 138 | func_8018773C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018773C.c` | +| 139 | func_80182E9C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182E9C.c` | +| 140 | func_8017F378 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017F378.c` | +| 141 | func_80184BAC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184BAC.c` | +| 142 | func_801852D4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801852D4.c` | +| 143 | func_80189B60 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80189B60.c` | +| 144 | func_8018445C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018445C.c` | +| 145 | func_8018AA08 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018AA08.c` | +| 146 | func_80182CEC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182CEC.c` | +| 147 | func_8018944C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018944C.c` | +| 148 | func_8018A598 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018A598.c` | +| 149 | func_8017EA40 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017EA40.c` | +| 150 | func_801826C8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801826C8.c` | +| 151 | func_801854C0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801854C0.c` | +| 152 | func_8017EC64 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017EC64.c` | +| 153 | func_80184C94 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80184C94.c` | +| 154 | func_80185CE4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80185CE4.c` | +| 155 | func_8017EA68 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017EA68.c` | +| 156 | func_80180074 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80180074.c` | +| 157 | func_801847E4 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801847E4.c` | +| 158 | func_80182470 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80182470.c` | +| 159 | func_8017E3D8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017E3D8.c` | +| 160 | func_8018386C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018386C.c` | +| 161 | func_80187A0C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80187A0C.c` | +| 162 | func_8018893C | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8018893C.c` | +| 163 | func_80185BEC | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_80185BEC.c` | +| 164 | func_801900B0 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_801900B0.c` | +| 165 | func_8017BFC8 | None | | None | near | 1 | residual: 1 mismatch | `.run/backlog_drafts/func_8017BFC8.c` | +| 166 | func_8017F6B0 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017F6B0.c` | +| 167 | func_8017DDFC | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017DDFC.c` | +| 168 | func_801817DC | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_801817DC.c` | +| 169 | func_80182264 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80182264.c` | +| 170 | func_80181834 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80181834.c` | +| 171 | func_8018558C | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8018558C.c` | +| 172 | func_801843CC | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_801843CC.c` | +| 173 | func_8017FC8C | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017FC8C.c` | +| 174 | func_80183228 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80183228.c` | +| 175 | func_80183118 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80183118.c` | +| 176 | func_8017E404 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017E404.c` | +| 177 | func_80183B4C | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80183B4C.c` | +| 178 | func_801879B0 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_801879B0.c` | +| 179 | func_801828C8 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_801828C8.c` | +| 180 | func_8017FA80 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017FA80.c` | +| 181 | func_8017E874 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017E874.c` | +| 182 | func_80185000 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80185000.c` | +| 183 | func_80180F18 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80180F18.c` | +| 184 | func_8018C658 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8018C658.c` | +| 185 | func_80183F48 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80183F48.c` | +| 186 | func_80180834 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80180834.c` | +| 187 | func_8018BA9C | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8018BA9C.c` | +| 188 | func_80186DAC | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_80186DAC.c` | +| 189 | func_8017EE78 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_8017EE78.c` | +| 190 | func_801804C8 | None | | None | near | 2 | residual: 2 mismatch | `.run/backlog_drafts/func_801804C8.c` | +| 191 | func_8017D468 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017D468.c` | +| 192 | func_801816FC | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801816FC.c` | +| 193 | func_8017DE90 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017DE90.c` | +| 194 | func_80190480 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80190480.c` | +| 195 | func_8018AFDC | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018AFDC.c` | +| 196 | func_80180D34 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80180D34.c` | +| 197 | func_8017F38C | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017F38C.c` | +| 198 | func_8018AE6C | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018AE6C.c` | +| 199 | func_80181720 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80181720.c` | +| 200 | func_80183BC8 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80183BC8.c` | +| 201 | func_8017F0C0 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017F0C0.c` | +| 202 | func_8018D4B4 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018D4B4.c` | +| 203 | func_801874E8 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801874E8.c` | +| 204 | func_80183320 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80183320.c` | +| 205 | func_801857D4 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801857D4.c` | +| 206 | func_8018A184 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018A184.c` | +| 207 | func_8018B234 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018B234.c` | +| 208 | func_8017F534 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017F534.c` | +| 209 | func_801861DC | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801861DC.c` | +| 210 | func_801896EC | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801896EC.c` | +| 211 | func_8018C7C8 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018C7C8.c` | +| 212 | func_80187B80 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80187B80.c` | +| 213 | func_801806C8 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801806C8.c` | +| 214 | func_8018672C | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018672C.c` | +| 215 | func_801894B0 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_801894B0.c` | +| 216 | func_8018B1E0 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8018B1E0.c` | +| 217 | func_80184870 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_80184870.c` | +| 218 | func_8017E6B0 | None | | None | near | 3 | residual: 3 mismatch | `.run/backlog_drafts/func_8017E6B0.c` | +| 219 | func_8017F8E4 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8017F8E4.c` | +| 220 | func_80187074 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80187074.c` | +| 221 | func_8017FF90 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8017FF90.c` | +| 222 | func_8017FAE0 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8017FAE0.c` | +| 223 | func_8017E918 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8017E918.c` | +| 224 | func_80180ED4 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80180ED4.c` | +| 225 | func_80186700 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80186700.c` | +| 226 | func_80184880 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80184880.c` | +| 227 | func_8018CC04 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8018CC04.c` | +| 228 | func_8017DED8 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8017DED8.c` | +| 229 | func_8018455C | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8018455C.c` | +| 230 | func_80181B08 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80181B08.c` | +| 231 | func_801823F0 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_801823F0.c` | +| 232 | func_80188510 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80188510.c` | +| 233 | func_80181A44 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80181A44.c` | +| 234 | func_80182CD4 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_80182CD4.c` | +| 235 | func_8018119C | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8018119C.c` | +| 236 | func_8018C394 | None | | None | near | 4 | residual: 4 mismatch | `.run/backlog_drafts/func_8018C394.c` | +| 237 | func_801803F0 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_801803F0.c` | +| 238 | func_8017F7D8 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017F7D8.c` | +| 239 | func_80181B8C | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80181B8C.c` | +| 240 | func_80180564 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80180564.c` | +| 241 | func_801809F4 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_801809F4.c` | +| 242 | func_8017F250 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017F250.c` | +| 243 | func_8017F66C | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017F66C.c` | +| 244 | func_80181E18 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80181E18.c` | +| 245 | func_801852C8 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_801852C8.c` | +| 246 | func_80180100 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80180100.c` | +| 247 | func_80181EF0 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80181EF0.c` | +| 248 | func_801821B8 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_801821B8.c` | +| 249 | func_8018312C | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8018312C.c` | +| 250 | func_8017F11C | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017F11C.c` | +| 251 | func_80182810 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80182810.c` | +| 252 | func_8017FDA8 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017FDA8.c` | +| 253 | func_80182938 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80182938.c` | +| 254 | func_8018517C | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8018517C.c` | +| 255 | func_80182B18 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80182B18.c` | +| 256 | func_8017DA90 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_8017DA90.c` | +| 257 | func_80181BB4 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80181BB4.c` | +| 258 | func_80185338 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80185338.c` | +| 259 | func_80185978 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80185978.c` | +| 260 | func_80185E54 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80185E54.c` | +| 261 | func_80187DAC | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80187DAC.c` | +| 262 | func_80183DB8 | None | | None | near | 5 | residual: 5 mismatch | `.run/backlog_drafts/func_80183DB8.c` | +| 263 | func_80180AE8 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80180AE8.c` | +| 264 | func_8017D398 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017D398.c` | +| 265 | func_80184A58 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80184A58.c` | +| 266 | func_80182280 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80182280.c` | +| 267 | func_80181C78 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80181C78.c` | +| 268 | func_801855DC | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_801855DC.c` | +| 269 | func_8017FCD4 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017FCD4.c` | +| 270 | func_80183158 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80183158.c` | +| 271 | func_80182E2C | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80182E2C.c` | +| 272 | func_8017F704 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017F704.c` | +| 273 | func_8017E06C | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017E06C.c` | +| 274 | func_80187AD4 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80187AD4.c` | +| 275 | func_8018595C | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8018595C.c` | +| 276 | func_80185B20 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80185B20.c` | +| 277 | func_801802CC | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_801802CC.c` | +| 278 | func_8017E2C4 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017E2C4.c` | +| 279 | func_8017F0EC | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8017F0EC.c` | +| 280 | func_80180FFC | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80180FFC.c` | +| 281 | func_80188F80 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80188F80.c` | +| 282 | func_80181FF4 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80181FF4.c` | +| 283 | func_80189240 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80189240.c` | +| 284 | func_80184618 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80184618.c` | +| 285 | func_8018413C | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_8018413C.c` | +| 286 | func_801819A0 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_801819A0.c` | +| 287 | func_801855F0 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_801855F0.c` | +| 288 | func_80186A28 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80186A28.c` | +| 289 | func_80186A88 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80186A88.c` | +| 290 | func_80180F4C | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80180F4C.c` | +| 291 | func_80186C88 | None | | None | near | 6 | residual: 6 mismatch | `.run/backlog_drafts/func_80186C88.c` | +| 292 | func_801815D8 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_801815D8.c` | +| 293 | func_80189898 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80189898.c` | +| 294 | func_8017CF40 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_8017CF40.c` | +| 295 | func_80180458 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80180458.c` | +| 296 | func_80185C6C | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80185C6C.c` | +| 297 | func_8018146C | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_8018146C.c` | +| 298 | func_8017C104 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_8017C104.c` | +| 299 | func_80180410 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80180410.c` | +| 300 | func_80180754 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80180754.c` | +| 301 | func_80186720 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80186720.c` | +| 302 | func_8017EA60 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_8017EA60.c` | +| 303 | func_8017F710 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_8017F710.c` | +| 304 | func_80184990 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80184990.c` | +| 305 | func_80185344 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80185344.c` | +| 306 | func_80182230 | None | | None | near | 7 | residual: 7 mismatch | `.run/backlog_drafts/func_80182230.c` | +| 307 | func_80185F24 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80185F24.c` | +| 308 | func_80189858 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80189858.c` | +| 309 | func_8017FFF0 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017FFF0.c` | +| 310 | func_8017E908 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017E908.c` | +| 311 | func_8017CF9C | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017CF9C.c` | +| 312 | func_801832B0 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801832B0.c` | +| 313 | func_801813B8 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801813B8.c` | +| 314 | func_80184734 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80184734.c` | +| 315 | func_801825C8 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801825C8.c` | +| 316 | func_80183430 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80183430.c` | +| 317 | func_80186120 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80186120.c` | +| 318 | func_80188508 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80188508.c` | +| 319 | func_8018D330 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8018D330.c` | +| 320 | func_80186A70 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80186A70.c` | +| 321 | func_8017F474 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017F474.c` | +| 322 | func_8017E804 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017E804.c` | +| 323 | func_80182D50 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80182D50.c` | +| 324 | func_801843B8 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801843B8.c` | +| 325 | func_80181C84 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80181C84.c` | +| 326 | func_801842D4 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801842D4.c` | +| 327 | func_80185EB4 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80185EB4.c` | +| 328 | func_80188690 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80188690.c` | +| 329 | func_80185F20 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_80185F20.c` | +| 330 | func_8018F658 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8018F658.c` | +| 331 | func_8017F228 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_8017F228.c` | +| 332 | func_801801F4 | None | | None | near | 8 | residual: 8 mismatch | `.run/backlog_drafts/func_801801F4.c` | +| 333 | func_8017F358 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017F358.c` | +| 334 | func_80180E9C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80180E9C.c` | +| 335 | func_8017BEBC | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017BEBC.c` | +| 336 | func_80180854 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80180854.c` | +| 337 | func_80180E54 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80180E54.c` | +| 338 | func_8017F7F4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017F7F4.c` | +| 339 | func_8017EF28 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017EF28.c` | +| 340 | func_801816E4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801816E4.c` | +| 341 | func_8017D400 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017D400.c` | +| 342 | func_8017D6E8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017D6E8.c` | +| 343 | func_8017E4F8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017E4F8.c` | +| 344 | func_801829F4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801829F4.c` | +| 345 | func_801822A8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801822A8.c` | +| 346 | func_8017E954 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017E954.c` | +| 347 | func_80181F84 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80181F84.c` | +| 348 | func_801827FC | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801827FC.c` | +| 349 | func_8017FE88 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017FE88.c` | +| 350 | func_80180EC0 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80180EC0.c` | +| 351 | func_80181C4C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80181C4C.c` | +| 352 | func_801817A4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801817A4.c` | +| 353 | func_8017E52C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017E52C.c` | +| 354 | func_801805B0 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801805B0.c` | +| 355 | func_8018897C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8018897C.c` | +| 356 | func_8018AA88 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8018AA88.c` | +| 357 | func_8017FED4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017FED4.c` | +| 358 | func_8017CCD4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017CCD4.c` | +| 359 | func_801858C4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801858C4.c` | +| 360 | func_8018C310 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8018C310.c` | +| 361 | func_80182AD4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80182AD4.c` | +| 362 | func_8018868C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8018868C.c` | +| 363 | func_8017F624 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017F624.c` | +| 364 | func_8017FEB4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017FEB4.c` | +| 365 | func_80182298 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80182298.c` | +| 366 | func_80187114 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80187114.c` | +| 367 | func_80184590 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80184590.c` | +| 368 | func_80181B34 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80181B34.c` | +| 369 | func_801860F8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801860F8.c` | +| 370 | func_8017FFD8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017FFD8.c` | +| 371 | func_80188BF8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80188BF8.c` | +| 372 | func_80183BD0 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80183BD0.c` | +| 373 | func_801860F4 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801860F4.c` | +| 374 | func_80183628 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80183628.c` | +| 375 | func_8018964C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8018964C.c` | +| 376 | func_801854C8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801854C8.c` | +| 377 | func_80184664 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80184664.c` | +| 378 | func_80185528 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80185528.c` | +| 379 | func_80187454 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80187454.c` | +| 380 | func_8017F7BC | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017F7BC.c` | +| 381 | func_801830C8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801830C8.c` | +| 382 | func_8017D4F0 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_8017D4F0.c` | +| 383 | func_801825E8 | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_801825E8.c` | +| 384 | func_80183C1C | None | | None | near | 9 | residual: 9 mismatch | `.run/backlog_drafts/func_80183C1C.c` | +| 385 | func_80185A00 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80185A00.c` | +| 386 | func_8017FCC0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017FCC0.c` | +| 387 | func_801833C8 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801833C8.c` | +| 388 | func_8017FFD0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017FFD0.c` | +| 389 | func_80180E34 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80180E34.c` | +| 390 | func_801844C4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801844C4.c` | +| 391 | func_8018AB24 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018AB24.c` | +| 392 | func_80188C84 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80188C84.c` | +| 393 | func_8017E184 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017E184.c` | +| 394 | func_80181434 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80181434.c` | +| 395 | func_80181A70 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80181A70.c` | +| 396 | func_8017DF88 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017DF88.c` | +| 397 | func_801841D0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801841D0.c` | +| 398 | func_80184204 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80184204.c` | +| 399 | func_8018534C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018534C.c` | +| 400 | func_80184940 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80184940.c` | +| 401 | func_80180B60 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80180B60.c` | +| 402 | func_8017FB0C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017FB0C.c` | +| 403 | func_8017E72C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017E72C.c` | +| 404 | func_80189C4C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80189C4C.c` | +| 405 | func_8017E670 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017E670.c` | +| 406 | func_80180014 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80180014.c` | +| 407 | func_80180B90 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80180B90.c` | +| 408 | func_801848E8 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801848E8.c` | +| 409 | func_8017E094 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017E094.c` | +| 410 | func_8018082C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018082C.c` | +| 411 | func_8018373C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018373C.c` | +| 412 | func_8017DF48 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017DF48.c` | +| 413 | func_80182724 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80182724.c` | +| 414 | func_80182EC0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80182EC0.c` | +| 415 | func_80188E8C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80188E8C.c` | +| 416 | func_801806E0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801806E0.c` | +| 417 | func_8018A5A4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018A5A4.c` | +| 418 | func_80181AC0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80181AC0.c` | +| 419 | func_801841A0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801841A0.c` | +| 420 | func_80183744 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80183744.c` | +| 421 | func_8018924C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018924C.c` | +| 422 | func_80185778 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80185778.c` | +| 423 | func_801870B4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801870B4.c` | +| 424 | func_80185E3C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80185E3C.c` | +| 425 | func_8017F5E8 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017F5E8.c` | +| 426 | func_801823D4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801823D4.c` | +| 427 | func_80186EE4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80186EE4.c` | +| 428 | func_80180AF4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80180AF4.c` | +| 429 | func_801831FC | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801831FC.c` | +| 430 | func_801862D4 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801862D4.c` | +| 431 | func_80184578 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80184578.c` | +| 432 | func_8017F804 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017F804.c` | +| 433 | func_80183888 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80183888.c` | +| 434 | func_80187224 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80187224.c` | +| 435 | func_801850F8 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801850F8.c` | +| 436 | func_80183F7C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80183F7C.c` | +| 437 | func_801800DC | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801800DC.c` | +| 438 | func_80182190 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80182190.c` | +| 439 | func_80182380 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80182380.c` | +| 440 | func_8018EDB8 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018EDB8.c` | +| 441 | func_80190298 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80190298.c` | +| 442 | func_8018311C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018311C.c` | +| 443 | func_8018A594 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018A594.c` | +| 444 | func_8017DED0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017DED0.c` | +| 445 | func_8018228C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018228C.c` | +| 446 | func_801889E0 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_801889E0.c` | +| 447 | func_8017DEEC | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017DEEC.c` | +| 448 | func_8017F300 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8017F300.c` | +| 449 | func_80184794 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80184794.c` | +| 450 | func_80185648 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80185648.c` | +| 451 | func_80186D64 | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_80186D64.c` | +| 452 | func_8018151C | None | | None | near | 10 | residual: 10 mismatch | `.run/backlog_drafts/func_8018151C.c` | +| 453 | func_8017F7E8 | 1 | WAVE | 177 | near | 11 | WAVE: 11 mismatch | `.run/backlog_drafts/func_8017F7E8.c` | +| 454 | func_801824D0 | 1 | WAVE | 181 | near | 11 | WAVE: 11 mismatch | `.run/backlog_drafts/func_801824D0.c` | +| 455 | func_80182F4C | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80182F4C.c` | +| 456 | func_801835C8 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_801835C8.c` | +| 457 | func_8017D6C4 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017D6C4.c` | +| 458 | func_80181960 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80181960.c` | +| 459 | func_8017D7C8 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017D7C8.c` | +| 460 | func_8017F67C | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017F67C.c` | +| 461 | func_80181724 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80181724.c` | +| 462 | func_8017F128 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017F128.c` | +| 463 | func_80180154 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80180154.c` | +| 464 | func_80180240 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80180240.c` | +| 465 | func_80185274 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80185274.c` | +| 466 | func_801833D4 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_801833D4.c` | +| 467 | func_80180EA8 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80180EA8.c` | +| 468 | func_8018F91C | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8018F91C.c` | +| 469 | func_801835F4 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_801835F4.c` | +| 470 | func_801848B4 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_801848B4.c` | +| 471 | func_8017E5D4 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017E5D4.c` | +| 472 | func_80182118 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80182118.c` | +| 473 | func_8017E2C0 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017E2C0.c` | +| 474 | func_80181744 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80181744.c` | +| 475 | func_8017EECC | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017EECC.c` | +| 476 | func_80182F78 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_80182F78.c` | +| 477 | func_8017F154 | None | | None | near | 11 | residual: 11 mismatch | `.run/backlog_drafts/func_8017F154.c` | +| 478 | func_8018150C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018150C.c` | +| 479 | func_801803A4 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801803A4.c` | +| 480 | func_8017D7F8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017D7F8.c` | +| 481 | func_8017FFFC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017FFFC.c` | +| 482 | func_8018766C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018766C.c` | +| 483 | func_8017DFF8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017DFF8.c` | +| 484 | func_8017D08C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017D08C.c` | +| 485 | func_8017DBD8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017DBD8.c` | +| 486 | func_8017F574 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017F574.c` | +| 487 | func_80183AC8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80183AC8.c` | +| 488 | func_80181C08 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80181C08.c` | +| 489 | func_801822C8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801822C8.c` | +| 490 | func_80181388 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80181388.c` | +| 491 | func_80185C2C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80185C2C.c` | +| 492 | func_80183BEC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80183BEC.c` | +| 493 | func_80184DB4 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80184DB4.c` | +| 494 | func_8018AE08 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018AE08.c` | +| 495 | func_80184698 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80184698.c` | +| 496 | func_80184718 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80184718.c` | +| 497 | func_8018134C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018134C.c` | +| 498 | func_8017F4BC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017F4BC.c` | +| 499 | func_80181070 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80181070.c` | +| 500 | func_801810A4 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801810A4.c` | +| 501 | func_801810D8 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801810D8.c` | +| 502 | func_801819CC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801819CC.c` | +| 503 | func_80180554 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80180554.c` | +| 504 | func_80181E5C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80181E5C.c` | +| 505 | func_80189DDC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80189DDC.c` | +| 506 | func_8018ABE0 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018ABE0.c` | +| 507 | func_80189A60 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80189A60.c` | +| 508 | func_8018278C | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8018278C.c` | +| 509 | func_801827C0 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_801827C0.c` | +| 510 | func_80186A58 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_80186A58.c` | +| 511 | func_8017F2BC | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017F2BC.c` | +| 512 | func_8017F184 | None | | None | near | 12 | residual: 12 mismatch | `.run/backlog_drafts/func_8017F184.c` | +| 513 | func_80185F58 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80185F58.c` | +| 514 | func_8018A3C8 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8018A3C8.c` | +| 515 | func_8017EA20 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017EA20.c` | +| 516 | func_80180528 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80180528.c` | +| 517 | func_80180BCC | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80180BCC.c` | +| 518 | func_801818EC | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801818EC.c` | +| 519 | func_8017DA3C | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017DA3C.c` | +| 520 | func_8017EDA8 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017EDA8.c` | +| 521 | func_801816CC | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801816CC.c` | +| 522 | func_8017D914 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017D914.c` | +| 523 | func_801828A8 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801828A8.c` | +| 524 | func_8017FD58 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017FD58.c` | +| 525 | func_8017F830 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017F830.c` | +| 526 | func_8018276C | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8018276C.c` | +| 527 | func_80183AF8 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80183AF8.c` | +| 528 | func_801858D0 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801858D0.c` | +| 529 | func_80180C34 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80180C34.c` | +| 530 | func_8018BDA4 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8018BDA4.c` | +| 531 | func_8017C8E4 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017C8E4.c` | +| 532 | func_80186D30 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80186D30.c` | +| 533 | func_8017F0D8 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017F0D8.c` | +| 534 | func_8017E358 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017E358.c` | +| 535 | func_80180420 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_80180420.c` | +| 536 | func_8017E35C | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017E35C.c` | +| 537 | func_801834E4 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801834E4.c` | +| 538 | func_801811B4 | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_801811B4.c` | +| 539 | func_8017CDBC | None | | None | near | 13 | residual: 13 mismatch | `.run/backlog_drafts/func_8017CDBC.c` | +| 540 | func_80180D10 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80180D10.c` | +| 541 | func_8018316C | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8018316C.c` | +| 542 | func_8017E808 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017E808.c` | +| 543 | func_8017EDC4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017EDC4.c` | +| 544 | func_80180654 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80180654.c` | +| 545 | func_8017C6F4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017C6F4.c` | +| 546 | func_8017E4F0 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017E4F0.c` | +| 547 | func_8018B2DC | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8018B2DC.c` | +| 548 | func_80183398 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80183398.c` | +| 549 | func_80181468 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80181468.c` | +| 550 | func_80184384 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80184384.c` | +| 551 | func_8018A934 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8018A934.c` | +| 552 | func_8018B50C | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8018B50C.c` | +| 553 | func_80182844 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80182844.c` | +| 554 | func_80181B90 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80181B90.c` | +| 555 | func_80185F98 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80185F98.c` | +| 556 | func_80185EEC | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80185EEC.c` | +| 557 | func_80186DE8 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80186DE8.c` | +| 558 | func_801838EC | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_801838EC.c` | +| 559 | func_80182348 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80182348.c` | +| 560 | func_80185CD4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80185CD4.c` | +| 561 | func_801892C0 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_801892C0.c` | +| 562 | func_801859E4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_801859E4.c` | +| 563 | func_80184B70 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80184B70.c` | +| 564 | func_801871C4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_801871C4.c` | +| 565 | func_80189504 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80189504.c` | +| 566 | func_8017C918 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017C918.c` | +| 567 | func_801813F0 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_801813F0.c` | +| 568 | func_80181F6C | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80181F6C.c` | +| 569 | func_8017EA04 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017EA04.c` | +| 570 | func_8017EF68 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017EF68.c` | +| 571 | func_8017EBA8 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017EBA8.c` | +| 572 | func_80185404 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80185404.c` | +| 573 | func_8017D7C4 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017D7C4.c` | +| 574 | func_8017D974 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_8017D974.c` | +| 575 | func_80180950 | None | | None | near | 14 | residual: 14 mismatch | `.run/backlog_drafts/func_80180950.c` | +| 576 | func_80181784 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181784.c` | +| 577 | func_8017FFE8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017FFE8.c` | +| 578 | func_801820F0 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_801820F0.c` | +| 579 | func_8018B0EC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8018B0EC.c` | +| 580 | func_801803F4 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_801803F4.c` | +| 581 | func_8017E818 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E818.c` | +| 582 | func_80181B0C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181B0C.c` | +| 583 | func_80184010 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80184010.c` | +| 584 | func_8018648C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8018648C.c` | +| 585 | func_8017F138 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017F138.c` | +| 586 | func_8017D9B8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D9B8.c` | +| 587 | func_80180DB0 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80180DB0.c` | +| 588 | func_8017E290 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E290.c` | +| 589 | func_8017EDC8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017EDC8.c` | +| 590 | func_80181A94 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181A94.c` | +| 591 | func_8017E318 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E318.c` | +| 592 | func_80181B44 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181B44.c` | +| 593 | func_8017D1B4 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D1B4.c` | +| 594 | func_8017E778 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E778.c` | +| 595 | func_80180D5C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80180D5C.c` | +| 596 | func_8017CDB8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CDB8.c` | +| 597 | func_8017CE20 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CE20.c` | +| 598 | func_8017CE40 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CE40.c` | +| 599 | func_8017D220 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D220.c` | +| 600 | func_80183718 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80183718.c` | +| 601 | func_8017EB1C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017EB1C.c` | +| 602 | func_80181028 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181028.c` | +| 603 | func_8017DACC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017DACC.c` | +| 604 | func_8018533C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8018533C.c` | +| 605 | func_8017D104 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D104.c` | +| 606 | func_8017F268 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017F268.c` | +| 607 | func_8017F120 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017F120.c` | +| 608 | func_80185A68 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80185A68.c` | +| 609 | func_8017CE48 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CE48.c` | +| 610 | func_8017CEB0 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CEB0.c` | +| 611 | func_801801C4 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_801801C4.c` | +| 612 | func_8017CEEC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017CEEC.c` | +| 613 | func_8017DDD8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017DDD8.c` | +| 614 | func_8017DD9C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017DD9C.c` | +| 615 | func_8017DF80 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017DF80.c` | +| 616 | func_8017D49C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D49C.c` | +| 617 | func_8017F5E0 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017F5E0.c` | +| 618 | func_8017DFCC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017DFCC.c` | +| 619 | func_80181C1C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_80181C1C.c` | +| 620 | func_8017D22C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D22C.c` | +| 621 | func_8018338C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8018338C.c` | +| 622 | func_8017EEB8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017EEB8.c` | +| 623 | func_8017E9F4 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E9F4.c` | +| 624 | func_8017E6CC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E6CC.c` | +| 625 | func_8017F3A8 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017F3A8.c` | +| 626 | func_8017D040 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D040.c` | +| 627 | func_8017E7AC | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E7AC.c` | +| 628 | func_8017E304 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E304.c` | +| 629 | func_8017D084 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D084.c` | +| 630 | func_8017D19C | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017D19C.c` | +| 631 | func_8017E700 | None | | None | near | 15 | residual: 15 mismatch | `.run/backlog_drafts/func_8017E700.c` | +| 632 | func_8017E0F0 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017E0F0.c` | +| 633 | func_8017E7D8 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017E7D8.c` | +| 634 | func_80183988 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80183988.c` | +| 635 | func_80184154 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80184154.c` | +| 636 | func_80182D78 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80182D78.c` | +| 637 | func_80183074 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80183074.c` | +| 638 | func_80184EA4 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80184EA4.c` | +| 639 | func_8017F920 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017F920.c` | +| 640 | func_80180EDC | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80180EDC.c` | +| 641 | func_80187A8C | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80187A8C.c` | +| 642 | func_8017F1F8 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017F1F8.c` | +| 643 | func_8017EC84 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017EC84.c` | +| 644 | func_8017E9CC | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017E9CC.c` | +| 645 | func_8017EAE0 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017EAE0.c` | +| 646 | func_80186984 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80186984.c` | +| 647 | func_8017F414 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017F414.c` | +| 648 | func_8017E090 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017E090.c` | +| 649 | func_801853F8 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_801853F8.c` | +| 650 | func_8017F20C | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017F20C.c` | +| 651 | func_80182654 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_80182654.c` | +| 652 | func_8017CDE4 | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017CDE4.c` | +| 653 | func_8017DFAC | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017DFAC.c` | +| 654 | func_8017EF1C | None | | None | near | 16 | residual: 16 mismatch | `.run/backlog_drafts/func_8017EF1C.c` | +| 655 | func_8017EEF4 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017EEF4.c` | +| 656 | func_8017E814 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017E814.c` | +| 657 | func_80184EE0 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80184EE0.c` | +| 658 | func_8017FA44 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017FA44.c` | +| 659 | func_80182D1C | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80182D1C.c` | +| 660 | func_8018384C | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8018384C.c` | +| 661 | func_8017E950 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017E950.c` | +| 662 | func_8017CDD8 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017CDD8.c` | +| 663 | func_80180890 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80180890.c` | +| 664 | func_8017D5F8 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017D5F8.c` | +| 665 | func_80180D74 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80180D74.c` | +| 666 | func_8017F568 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_8017F568.c` | +| 667 | func_80180D14 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80180D14.c` | +| 668 | func_80183C58 | None | | None | near | 17 | residual: 17 mismatch | `.run/backlog_drafts/func_80183C58.c` | +| 669 | func_8018208C | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8018208C.c` | +| 670 | func_8017FD6C | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017FD6C.c` | +| 671 | func_801877DC | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_801877DC.c` | +| 672 | func_8017DA10 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017DA10.c` | +| 673 | func_80189630 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80189630.c` | +| 674 | func_80184630 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80184630.c` | +| 675 | func_80185334 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80185334.c` | +| 676 | func_8017E850 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017E850.c` | +| 677 | func_8017DCF4 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017DCF4.c` | +| 678 | func_8017D988 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017D988.c` | +| 679 | func_80182E38 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80182E38.c` | +| 680 | func_80183138 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80183138.c` | +| 681 | func_80180B54 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_80180B54.c` | +| 682 | func_8017D600 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017D600.c` | +| 683 | func_8017F6C4 | None | | None | near | 18 | residual: 18 mismatch | `.run/backlog_drafts/func_8017F6C4.c` | +| 684 | func_8017E9E4 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017E9E4.c` | +| 685 | func_801827D4 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_801827D4.c` | +| 686 | func_80185888 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80185888.c` | +| 687 | func_80180574 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80180574.c` | +| 688 | func_80183F1C | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80183F1C.c` | +| 689 | func_8017FFCC | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017FFCC.c` | +| 690 | func_80182344 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80182344.c` | +| 691 | func_801811F4 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_801811F4.c` | +| 692 | func_80180DB8 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80180DB8.c` | +| 693 | func_8017D184 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017D184.c` | +| 694 | func_8017F160 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017F160.c` | +| 695 | func_8017F4D0 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017F4D0.c` | +| 696 | func_8018033C | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8018033C.c` | +| 697 | func_80181138 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80181138.c` | +| 698 | func_8017E048 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017E048.c` | +| 699 | func_8017F3BC | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017F3BC.c` | +| 700 | func_80180DEC | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80180DEC.c` | +| 701 | func_801845B4 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_801845B4.c` | +| 702 | func_80181C74 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80181C74.c` | +| 703 | func_80182234 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80182234.c` | +| 704 | func_8017FF30 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_8017FF30.c` | +| 705 | func_80185288 | None | | None | near | 19 | residual: 19 mismatch | `.run/backlog_drafts/func_80185288.c` | +| 706 | func_8017E890 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017E890.c` | +| 707 | func_8018555C | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8018555C.c` | +| 708 | func_801826EC | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_801826EC.c` | +| 709 | func_8017DB00 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017DB00.c` | +| 710 | func_80181054 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_80181054.c` | +| 711 | func_8017F87C | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017F87C.c` | +| 712 | func_8017D704 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017D704.c` | +| 713 | func_80180AD8 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_80180AD8.c` | +| 714 | func_8018774C | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8018774C.c` | +| 715 | func_8017DE7C | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017DE7C.c` | +| 716 | func_8017FA00 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017FA00.c` | +| 717 | func_8018B6F4 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8018B6F4.c` | +| 718 | func_8017EEC8 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017EEC8.c` | +| 719 | func_8017E134 | None | | None | near | 20 | residual: 20 mismatch | `.run/backlog_drafts/func_8017E134.c` | +| 720 | func_8017C6B8 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017C6B8.c` | +| 721 | func_801871E8 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_801871E8.c` | +| 722 | func_80188668 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_80188668.c` | +| 723 | func_8017DB44 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017DB44.c` | +| 724 | func_80187050 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_80187050.c` | +| 725 | func_8017DD18 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017DD18.c` | +| 726 | func_8018288C | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8018288C.c` | +| 727 | func_8017E1C8 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017E1C8.c` | +| 728 | func_8017D308 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017D308.c` | +| 729 | func_8017EAC8 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017EAC8.c` | +| 730 | func_8017D8B0 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017D8B0.c` | +| 731 | func_8017F080 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017F080.c` | +| 732 | func_8017CD14 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017CD14.c` | +| 733 | func_80180548 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_80180548.c` | +| 734 | func_8017DE78 | None | | None | near | 21 | residual: 21 mismatch | `.run/backlog_drafts/func_8017DE78.c` | +| 735 | func_80185A18 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_80185A18.c` | +| 736 | func_8017FF2C | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017FF2C.c` | +| 737 | func_801803E0 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_801803E0.c` | +| 738 | func_8017D828 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017D828.c` | +| 739 | func_8017DC08 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017DC08.c` | +| 740 | func_80184388 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_80184388.c` | +| 741 | func_80187C64 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_80187C64.c` | +| 742 | func_8018A030 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8018A030.c` | +| 743 | func_8017D688 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017D688.c` | +| 744 | func_8017FA90 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017FA90.c` | +| 745 | func_8017F320 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017F320.c` | +| 746 | func_801813AC | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_801813AC.c` | +| 747 | func_80181478 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_80181478.c` | +| 748 | func_801868E0 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_801868E0.c` | +| 749 | func_8018AB74 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8018AB74.c` | +| 750 | func_8017DE70 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8017DE70.c` | +| 751 | func_8018A640 | None | | None | near | 22 | residual: 22 mismatch | `.run/backlog_drafts/func_8018A640.c` | +| 752 | func_8017DC54 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017DC54.c` | +| 753 | func_8017F480 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017F480.c` | +| 754 | func_8017EF7C | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017EF7C.c` | +| 755 | func_80182FF0 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_80182FF0.c` | +| 756 | func_80182EE8 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_80182EE8.c` | +| 757 | func_8017E240 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017E240.c` | +| 758 | func_8017CE94 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017CE94.c` | +| 759 | func_8017D2A4 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017D2A4.c` | +| 760 | func_8017FAC8 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8017FAC8.c` | +| 761 | func_80181E1C | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_80181E1C.c` | +| 762 | func_80181F60 | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_80181F60.c` | +| 763 | func_8018381C | None | | None | near | 23 | residual: 23 mismatch | `.run/backlog_drafts/func_8018381C.c` | +| 764 | func_80182488 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_80182488.c` | +| 765 | func_8017F500 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017F500.c` | +| 766 | func_8017D1E0 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017D1E0.c` | +| 767 | func_8017DDBC | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017DDBC.c` | +| 768 | func_8017F1BC | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017F1BC.c` | +| 769 | func_8017D384 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017D384.c` | +| 770 | func_8017EFB0 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017EFB0.c` | +| 771 | func_80182708 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_80182708.c` | +| 772 | func_8017F8A8 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017F8A8.c` | +| 773 | func_8017EBEC | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017EBEC.c` | +| 774 | func_80184DE8 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_80184DE8.c` | +| 775 | func_801834B4 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_801834B4.c` | +| 776 | func_8018333C | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8018333C.c` | +| 777 | func_8018056C | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8018056C.c` | +| 778 | func_80182C68 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_80182C68.c` | +| 779 | func_8017EA18 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_8017EA18.c` | +| 780 | func_80180EB8 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_80180EB8.c` | +| 781 | func_801856F0 | None | | None | near | 24 | residual: 24 mismatch | `.run/backlog_drafts/func_801856F0.c` | +| 782 | func_8018DFDC | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8018DFDC.c` | +| 783 | func_801827A8 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_801827A8.c` | +| 784 | func_8017CFC4 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8017CFC4.c` | +| 785 | func_8017D7A4 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8017D7A4.c` | +| 786 | func_80182514 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_80182514.c` | +| 787 | func_8018545C | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8018545C.c` | +| 788 | func_80189FCC | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_80189FCC.c` | +| 789 | func_80181134 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_80181134.c` | +| 790 | func_8017FE10 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8017FE10.c` | +| 791 | func_80185AF8 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_80185AF8.c` | +| 792 | func_80182E34 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_80182E34.c` | +| 793 | func_8017D864 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8017D864.c` | +| 794 | func_8017DB70 | None | | None | near | 25 | residual: 25 mismatch | `.run/backlog_drafts/func_8017DB70.c` | +| 795 | func_8017FB68 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8017FB68.c` | +| 796 | func_8018ACB4 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8018ACB4.c` | +| 797 | func_8017EBF4 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8017EBF4.c` | +| 798 | func_80180A5C | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_80180A5C.c` | +| 799 | func_801830EC | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_801830EC.c` | +| 800 | func_801804F4 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_801804F4.c` | +| 801 | func_8017E6C0 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8017E6C0.c` | +| 802 | func_8017DD64 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8017DD64.c` | +| 803 | func_8017F024 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_8017F024.c` | +| 804 | func_80181254 | None | | None | near | 26 | residual: 26 mismatch | `.run/backlog_drafts/func_80181254.c` | +| 805 | func_80181020 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_80181020.c` | +| 806 | func_80184A1C | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_80184A1C.c` | +| 807 | func_80184430 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_80184430.c` | +| 808 | func_80185934 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_80185934.c` | +| 809 | func_801841B0 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_801841B0.c` | +| 810 | func_80180D28 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_80180D28.c` | +| 811 | func_8017E1F4 | None | | None | near | 27 | residual: 27 mismatch | `.run/backlog_drafts/func_8017E1F4.c` | +| 812 | func_80182C24 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80182C24.c` | +| 813 | func_8017DAD0 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017DAD0.c` | +| 814 | func_8017EE08 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017EE08.c` | +| 815 | func_80183C4C | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80183C4C.c` | +| 816 | func_80181300 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80181300.c` | +| 817 | func_8017E218 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017E218.c` | +| 818 | func_8017F8AC | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017F8AC.c` | +| 819 | func_80180E98 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80180E98.c` | +| 820 | func_8017D21C | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017D21C.c` | +| 821 | func_80188650 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80188650.c` | +| 822 | func_801810C0 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_801810C0.c` | +| 823 | func_8017D004 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017D004.c` | +| 824 | func_80183A18 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80183A18.c` | +| 825 | func_80182324 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80182324.c` | +| 826 | func_80183A24 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_80183A24.c` | +| 827 | func_8017D404 | None | | None | near | 28 | residual: 28 mismatch | `.run/backlog_drafts/func_8017D404.c` | +| 828 | func_80182544 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_80182544.c` | +| 829 | func_80180CA0 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_80180CA0.c` | +| 830 | func_8017ED0C | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_8017ED0C.c` | +| 831 | func_8017FB4C | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_8017FB4C.c` | +| 832 | func_801840C0 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_801840C0.c` | +| 833 | func_8017F344 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_8017F344.c` | +| 834 | func_80180214 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_80180214.c` | +| 835 | func_801803DC | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_801803DC.c` | +| 836 | func_80181304 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_80181304.c` | +| 837 | func_8018B9DC | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_8018B9DC.c` | +| 838 | func_80180840 | None | | None | near | 29 | residual: 29 mismatch | `.run/backlog_drafts/func_80180840.c` | +| 839 | func_80182E08 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_80182E08.c` | +| 840 | func_8018AF0C | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8018AF0C.c` | +| 841 | func_8017F750 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8017F750.c` | +| 842 | func_8018133C | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8018133C.c` | +| 843 | func_80183C10 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_80183C10.c` | +| 844 | func_80180B2C | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_80180B2C.c` | +| 845 | func_8017D894 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8017D894.c` | +| 846 | func_8017D1DC | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8017D1DC.c` | +| 847 | func_8017D9A8 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_8017D9A8.c` | +| 848 | func_801845E8 | None | | None | near | 30 | residual: 30 mismatch | `.run/backlog_drafts/func_801845E8.c` | +| 849 | func_8017CE0C | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8017CE0C.c` | +| 850 | func_80182268 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_80182268.c` | +| 851 | func_8018337C | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8018337C.c` | +| 852 | func_801800F4 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_801800F4.c` | +| 853 | func_80181990 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_80181990.c` | +| 854 | func_8017D8C8 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8017D8C8.c` | +| 855 | func_80184AA8 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_80184AA8.c` | +| 856 | func_8017E9EC | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8017E9EC.c` | +| 857 | func_80182D18 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_80182D18.c` | +| 858 | func_8017D524 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8017D524.c` | +| 859 | func_8017D784 | None | | None | near | 31 | residual: 31 mismatch | `.run/backlog_drafts/func_8017D784.c` | +| 860 | func_801856E4 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_801856E4.c` | +| 861 | func_8017EEFC | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017EEFC.c` | +| 862 | func_8017FC50 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017FC50.c` | +| 863 | func_8017D554 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017D554.c` | +| 864 | func_80183018 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_80183018.c` | +| 865 | func_8017F370 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017F370.c` | +| 866 | func_8018739C | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8018739C.c` | +| 867 | func_8017DBC0 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017DBC0.c` | +| 868 | func_80182000 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_80182000.c` | +| 869 | func_8017E55C | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017E55C.c` | +| 870 | func_80182600 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_80182600.c` | +| 871 | func_8017FCE8 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017FCE8.c` | +| 872 | func_8017FEC8 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017FEC8.c` | +| 873 | func_8017D874 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017D874.c` | +| 874 | func_8017FACC | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017FACC.c` | +| 875 | func_8017F7F8 | None | | None | near | 32 | residual: 32 mismatch | `.run/backlog_drafts/func_8017F7F8.c` | +| 876 | func_8017FB78 | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_8017FB78.c` | +| 877 | func_80181A40 | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_80181A40.c` | +| 878 | func_801800D4 | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_801800D4.c` | +| 879 | func_80182E1C | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_80182E1C.c` | +| 880 | func_80181F4C | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_80181F4C.c` | +| 881 | func_8017EEB0 | None | | None | near | 33 | residual: 33 mismatch | `.run/backlog_drafts/func_8017EEB0.c` | +| 882 | func_8017BF14 | None | | None | near | 34 | residual: 34 mismatch | `.run/backlog_drafts/func_8017BF14.c` | +| 883 | func_801859A0 | None | | None | near | 34 | residual: 34 mismatch | `.run/backlog_drafts/func_801859A0.c` | +| 884 | func_8017F8E0 | None | | None | near | 34 | residual: 34 mismatch | `.run/backlog_drafts/func_8017F8E0.c` | +| 885 | func_8017E740 | None | | None | near | 34 | residual: 34 mismatch | `.run/backlog_drafts/func_8017E740.c` | +| 886 | func_8017D804 | None | | None | near | 35 | residual: 35 mismatch | `.run/backlog_drafts/func_8017D804.c` | +| 887 | func_8017DA0C | None | | None | near | 35 | residual: 35 mismatch | `.run/backlog_drafts/func_8017DA0C.c` | +| 888 | func_80180030 | None | | None | near | 35 | residual: 35 mismatch | `.run/backlog_drafts/func_80180030.c` | +| 889 | func_8017E038 | None | | None | near | 35 | residual: 35 mismatch | `.run/backlog_drafts/func_8017E038.c` | +| 890 | func_8017E32C | None | | None | near | 35 | residual: 35 mismatch | `.run/backlog_drafts/func_8017E32C.c` | +| 891 | func_80181090 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_80181090.c` | +| 892 | func_8017EC78 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_8017EC78.c` | +| 893 | func_8017E79C | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_8017E79C.c` | +| 894 | func_80182A08 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_80182A08.c` | +| 895 | func_8017F0E8 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_8017F0E8.c` | +| 896 | func_8017D294 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_8017D294.c` | +| 897 | func_80189B38 | None | | None | near | 36 | residual: 36 mismatch | `.run/backlog_drafts/func_80189B38.c` | +| 898 | func_80180F08 | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_80180F08.c` | +| 899 | func_8017D024 | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017D024.c` | +| 900 | func_8017EB5C | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017EB5C.c` | +| 901 | func_8017EB4C | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017EB4C.c` | +| 902 | func_8017EAD8 | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017EAD8.c` | +| 903 | func_8017D29C | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017D29C.c` | +| 904 | func_8017D450 | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017D450.c` | +| 905 | func_8017E230 | None | | None | near | 37 | residual: 37 mismatch | `.run/backlog_drafts/func_8017E230.c` | +| 906 | func_8017DA00 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017DA00.c` | +| 907 | func_8017E6FC | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017E6FC.c` | +| 908 | func_8017FE08 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017FE08.c` | +| 909 | func_8017D80C | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017D80C.c` | +| 910 | func_8018263C | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8018263C.c` | +| 911 | func_80186FA8 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_80186FA8.c` | +| 912 | func_80180A38 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_80180A38.c` | +| 913 | func_8017D740 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017D740.c` | +| 914 | func_8017DD44 | None | | None | near | 38 | residual: 38 mismatch | `.run/backlog_drafts/func_8017DD44.c` | +| 915 | func_8017E840 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017E840.c` | +| 916 | func_8017E014 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017E014.c` | +| 917 | func_8017EC70 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017EC70.c` | +| 918 | func_80180C2C | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_80180C2C.c` | +| 919 | func_8017F724 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8017F724.c` | +| 920 | func_8018ACD4 | None | | None | near | 39 | residual: 39 mismatch | `.run/backlog_drafts/func_8018ACD4.c` | +| 921 | func_8017ED80 | None | | None | near | 40 | residual: 40 mismatch | `.run/backlog_drafts/func_8017ED80.c` | +| 922 | func_80180850 | None | | None | near | 40 | residual: 40 mismatch | `.run/backlog_drafts/func_80180850.c` | +| 923 | func_80181438 | None | | None | near | 40 | residual: 40 mismatch | `.run/backlog_drafts/func_80181438.c` | +| 924 | func_8017D0BC | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8017D0BC.c` | +| 925 | func_8017E94C | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8017E94C.c` | +| 926 | func_8017E170 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8017E170.c` | +| 927 | func_8018043C | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8018043C.c` | +| 928 | func_8018A3F0 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8018A3F0.c` | +| 929 | func_80183364 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_80183364.c` | +| 930 | func_801824F0 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_801824F0.c` | +| 931 | func_8017F4A0 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_8017F4A0.c` | +| 932 | func_801877E4 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_801877E4.c` | +| 933 | func_80183F4C | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_80183F4C.c` | +| 934 | func_80186044 | None | | None | near | 41 | residual: 41 mismatch | `.run/backlog_drafts/func_80186044.c` | +| 935 | func_80180010 | None | | None | near | 42 | residual: 42 mismatch | `.run/backlog_drafts/func_80180010.c` | +| 936 | func_8017E824 | None | | None | near | 42 | residual: 42 mismatch | `.run/backlog_drafts/func_8017E824.c` | +| 937 | func_80183598 | None | | None | near | 42 | residual: 42 mismatch | `.run/backlog_drafts/func_80183598.c` | +| 938 | func_8017ECF4 | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8017ECF4.c` | +| 939 | func_8018118C | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8018118C.c` | +| 940 | func_8018FB8C | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8018FB8C.c` | +| 941 | func_8017D6D0 | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8017D6D0.c` | +| 942 | func_8017D96C | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8017D96C.c` | +| 943 | func_8017DF44 | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_8017DF44.c` | +| 944 | func_801812FC | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_801812FC.c` | +| 945 | func_80186B08 | None | | None | near | 43 | residual: 43 mismatch | `.run/backlog_drafts/func_80186B08.c` | +| 946 | func_8017E578 | None | | None | near | 44 | residual: 44 mismatch | `.run/backlog_drafts/func_8017E578.c` | +| 947 | func_8017D6FC | None | | None | near | 44 | residual: 44 mismatch | `.run/backlog_drafts/func_8017D6FC.c` | +| 948 | func_8017E7D0 | None | | None | near | 45 | residual: 45 mismatch | `.run/backlog_drafts/func_8017E7D0.c` | +| 949 | func_8017D01C | None | | None | near | 45 | residual: 45 mismatch | `.run/backlog_drafts/func_8017D01C.c` | +| 950 | func_8017E380 | None | | None | near | 45 | residual: 45 mismatch | `.run/backlog_drafts/func_8017E380.c` | +| 951 | func_80180A88 | None | | None | near | 45 | residual: 45 mismatch | `.run/backlog_drafts/func_80180A88.c` | +| 952 | func_80189DB4 | None | | None | near | 45 | residual: 45 mismatch | `.run/backlog_drafts/func_80189DB4.c` | +| 953 | func_8018001C | None | | None | near | 46 | residual: 46 mismatch | `.run/backlog_drafts/func_8018001C.c` | +| 954 | func_8017F2A0 | None | | None | near | 46 | residual: 46 mismatch | `.run/backlog_drafts/func_8017F2A0.c` | +| 955 | func_80185EA8 | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_80185EA8.c` | +| 956 | func_8018912C | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_8018912C.c` | +| 957 | func_80188BEC | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_80188BEC.c` | +| 958 | func_801804DC | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_801804DC.c` | +| 959 | func_801808D8 | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_801808D8.c` | +| 960 | func_8017E8D0 | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_8017E8D0.c` | +| 961 | func_801846AC | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_801846AC.c` | +| 962 | func_801805DC | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_801805DC.c` | +| 963 | func_80184D0C | None | | None | near | 47 | residual: 47 mismatch | `.run/backlog_drafts/func_80184D0C.c` | +| 964 | func_8017F84C | None | | None | near | 48 | residual: 48 mismatch | `.run/backlog_drafts/func_8017F84C.c` | +| 965 | func_8017EF54 | None | | None | near | 48 | residual: 48 mismatch | `.run/backlog_drafts/func_8017EF54.c` | +| 966 | func_80181CE0 | None | | None | near | 48 | residual: 48 mismatch | `.run/backlog_drafts/func_80181CE0.c` | +| 967 | func_8017FCF0 | None | | None | near | 48 | residual: 48 mismatch | `.run/backlog_drafts/func_8017FCF0.c` | +| 968 | func_8017D6F0 | None | | None | near | 49 | residual: 49 mismatch | `.run/backlog_drafts/func_8017D6F0.c` | +| 969 | func_8017DF40 | None | | None | near | 49 | residual: 49 mismatch | `.run/backlog_drafts/func_8017DF40.c` | +| 970 | func_801845EC | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_801845EC.c` | +| 971 | func_8017F4C4 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_8017F4C4.c` | +| 972 | func_80188BB0 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_80188BB0.c` | +| 973 | func_80181B78 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_80181B78.c` | +| 974 | func_8017DE74 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_8017DE74.c` | +| 975 | func_80183D48 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_80183D48.c` | +| 976 | func_80184130 | None | | None | near | 50 | residual: 50 mismatch | `.run/backlog_drafts/func_80184130.c` | +| 977 | func_80181124 | None | | None | near | 52 | residual: 52 mismatch | `.run/backlog_drafts/func_80181124.c` | +| 978 | func_8017FB48 | None | | None | near | 52 | residual: 52 mismatch | `.run/backlog_drafts/func_8017FB48.c` | +| 979 | func_80186A0C | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_80186A0C.c` | +| 980 | func_8017F050 | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_8017F050.c` | +| 981 | func_8018592C | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_8018592C.c` | +| 982 | func_8018CFF4 | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_8018CFF4.c` | +| 983 | func_8017DB6C | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_8017DB6C.c` | +| 984 | func_8018048C | None | | None | near | 53 | residual: 53 mismatch | `.run/backlog_drafts/func_8018048C.c` | +| 985 | func_8018465C | None | | None | near | 54 | residual: 54 mismatch | `.run/backlog_drafts/func_8018465C.c` | +| 986 | func_80180B7C | None | | None | near | 54 | residual: 54 mismatch | `.run/backlog_drafts/func_80180B7C.c` | +| 987 | func_8017FE54 | None | | None | near | 55 | residual: 55 mismatch | `.run/backlog_drafts/func_8017FE54.c` | +| 988 | func_8017ED60 | None | | None | near | 55 | residual: 55 mismatch | `.run/backlog_drafts/func_8017ED60.c` | +| 989 | func_801802BC | None | | None | near | 55 | residual: 55 mismatch | `.run/backlog_drafts/func_801802BC.c` | +| 990 | func_80182030 | None | | None | near | 55 | residual: 55 mismatch | `.run/backlog_drafts/func_80182030.c` | +| 991 | func_80180204 | None | | None | near | 55 | residual: 55 mismatch | `.run/backlog_drafts/func_80180204.c` | +| 992 | func_80181DEC | None | | None | near | 57 | residual: 57 mismatch | `.run/backlog_drafts/func_80181DEC.c` | +| 993 | func_8017E524 | None | | None | near | 57 | residual: 57 mismatch | `.run/backlog_drafts/func_8017E524.c` | +| 994 | func_8018A538 | None | | None | near | 57 | residual: 57 mismatch | `.run/backlog_drafts/func_8018A538.c` | +| 995 | func_8017ECB0 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_8017ECB0.c` | +| 996 | func_801898C8 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_801898C8.c` | +| 997 | func_80184920 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_80184920.c` | +| 998 | func_80182EA0 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_80182EA0.c` | +| 999 | func_8017F1C4 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_8017F1C4.c` | +| 1000 | func_80181A5C | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_80181A5C.c` | +| 1001 | func_8017D544 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_8017D544.c` | +| 1002 | func_8017EA2C | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_8017EA2C.c` | +| 1003 | func_80182BF4 | None | | None | near | 58 | residual: 58 mismatch | `.run/backlog_drafts/func_80182BF4.c` | +| 1004 | func_8017F24C | None | | None | near | 59 | residual: 59 mismatch | `.run/backlog_drafts/func_8017F24C.c` | +| 1005 | func_8017D4CC | None | | None | near | 59 | residual: 59 mismatch | `.run/backlog_drafts/func_8017D4CC.c` | +| 1006 | func_80183624 | None | | None | near | 59 | residual: 59 mismatch | `.run/backlog_drafts/func_80183624.c` | +| 1007 | func_80180B50 | None | | None | near | 59 | residual: 59 mismatch | `.run/backlog_drafts/func_80180B50.c` | +| 1008 | func_8018567C | None | | None | near | 59 | residual: 59 mismatch | `.run/backlog_drafts/func_8018567C.c` | +| 1009 | func_8017E75C | None | | None | near | 61 | residual: 61 mismatch | `.run/backlog_drafts/func_8017E75C.c` | +| 1010 | func_80184778 | None | | None | near | 61 | residual: 61 mismatch | `.run/backlog_drafts/func_80184778.c` | +| 1011 | func_8017EEE0 | None | | None | near | 62 | residual: 62 mismatch | `.run/backlog_drafts/func_8017EEE0.c` | +| 1012 | func_80188204 | None | | None | near | 62 | residual: 62 mismatch | `.run/backlog_drafts/func_80188204.c` | +| 1013 | func_8017F25C | None | | None | near | 62 | residual: 62 mismatch | `.run/backlog_drafts/func_8017F25C.c` | +| 1014 | func_8017EB74 | None | | None | near | 63 | residual: 63 mismatch | `.run/backlog_drafts/func_8017EB74.c` | +| 1015 | func_8017E798 | None | | None | near | 64 | residual: 64 mismatch | `.run/backlog_drafts/func_8017E798.c` | +| 1016 | func_8017D610 | None | | None | near | 64 | residual: 64 mismatch | `.run/backlog_drafts/func_8017D610.c` | +| 1017 | func_8017CD10 | None | | None | near | 64 | residual: 64 mismatch | `.run/backlog_drafts/func_8017CD10.c` | +| 1018 | func_8017F1A0 | None | | None | near | 64 | residual: 64 mismatch | `.run/backlog_drafts/func_8017F1A0.c` | +| 1019 | func_8017D928 | None | | None | near | 64 | residual: 64 mismatch | `.run/backlog_drafts/func_8017D928.c` | +| 1020 | func_8018656C | None | | None | near | 65 | residual: 65 mismatch | `.run/backlog_drafts/func_8018656C.c` | +| 1021 | func_80184854 | None | | None | near | 66 | residual: 66 mismatch | `.run/backlog_drafts/func_80184854.c` | +| 1022 | func_80185B5C | None | | None | near | 67 | residual: 67 mismatch | `.run/backlog_drafts/func_80185B5C.c` | +| 1023 | func_8017E910 | None | | None | near | 68 | residual: 68 mismatch | `.run/backlog_drafts/func_8017E910.c` | +| 1024 | func_80182378 | None | | None | near | 69 | residual: 69 mismatch | `.run/backlog_drafts/func_80182378.c` | +| 1025 | func_80183544 | None | | None | near | 69 | residual: 69 mismatch | `.run/backlog_drafts/func_80183544.c` | +| 1026 | func_8018434C | None | | None | near | 69 | residual: 69 mismatch | `.run/backlog_drafts/func_8018434C.c` | +| 1027 | func_80180224 | None | | None | near | 71 | residual: 71 mismatch | `.run/backlog_drafts/func_80180224.c` | +| 1028 | func_80184238 | None | | None | near | 72 | residual: 72 mismatch | `.run/backlog_drafts/func_80184238.c` | +| 1029 | func_801866B0 | None | | None | near | 72 | residual: 72 mismatch | `.run/backlog_drafts/func_801866B0.c` | +| 1030 | func_8017D9E4 | None | | None | near | 73 | residual: 73 mismatch | `.run/backlog_drafts/func_8017D9E4.c` | +| 1031 | func_80181344 | None | | None | near | 73 | residual: 73 mismatch | `.run/backlog_drafts/func_80181344.c` | +| 1032 | func_80189B3C | None | | None | near | 74 | residual: 74 mismatch | `.run/backlog_drafts/func_80189B3C.c` | +| 1033 | func_80182B90 | None | | None | near | 74 | residual: 74 mismatch | `.run/backlog_drafts/func_80182B90.c` | +| 1034 | func_8018165C | None | | None | near | 74 | residual: 74 mismatch | `.run/backlog_drafts/func_8018165C.c` | +| 1035 | func_8017F468 | None | | None | near | 74 | residual: 74 mismatch | `.run/backlog_drafts/func_8017F468.c` | +| 1036 | func_8017DAB4 | None | | None | near | 75 | residual: 75 mismatch | `.run/backlog_drafts/func_8017DAB4.c` | +| 1037 | func_80181500 | None | | None | near | 75 | residual: 75 mismatch | `.run/backlog_drafts/func_80181500.c` | +| 1038 | func_801814A8 | None | | None | near | 76 | residual: 76 mismatch | `.run/backlog_drafts/func_801814A8.c` | +| 1039 | func_8017E81C | None | | None | near | 76 | residual: 76 mismatch | `.run/backlog_drafts/func_8017E81C.c` | +| 1040 | func_8018474C | None | | None | near | 76 | residual: 76 mismatch | `.run/backlog_drafts/func_8018474C.c` | +| 1041 | func_80184DDC | None | | None | near | 77 | residual: 77 mismatch | `.run/backlog_drafts/func_80184DDC.c` | +| 1042 | func_8017E2F4 | None | | None | near | 77 | residual: 77 mismatch | `.run/backlog_drafts/func_8017E2F4.c` | +| 1043 | func_8017EDBC | None | | None | near | 78 | residual: 78 mismatch | `.run/backlog_drafts/func_8017EDBC.c` | +| 1044 | func_8017E5F0 | None | | None | near | 79 | residual: 79 mismatch | `.run/backlog_drafts/func_8017E5F0.c` | +| 1045 | func_801815AC | None | | None | near | 79 | residual: 79 mismatch | `.run/backlog_drafts/func_801815AC.c` | +| 1046 | func_8017D54C | None | | None | near | 79 | residual: 79 mismatch | `.run/backlog_drafts/func_8017D54C.c` | +| 1047 | func_80181260 | None | | None | near | 79 | residual: 79 mismatch | `.run/backlog_drafts/func_80181260.c` | +| 1048 | func_801805D0 | None | | None | near | 79 | residual: 79 mismatch | `.run/backlog_drafts/func_801805D0.c` | +| 1049 | func_8017F290 | 1 | regalloc-order | 86 | near | 81 | none — MATCH. Two levers: (1) hold &D_801270CC in a `int *state` local so its | `.run/backlog_drafts/func_8017F290.c` | +| 1050 | func_80181068 | None | | None | near | 81 | residual: 81 mismatch | `.run/backlog_drafts/func_80181068.c` | +| 1051 | func_80184E00 | None | | None | near | 82 | residual: 82 mismatch | `.run/backlog_drafts/func_80184E00.c` | +| 1052 | func_8017EB88 | None | | None | near | 82 | residual: 82 mismatch | `.run/backlog_drafts/func_8017EB88.c` | +| 1053 | func_8017FB3C | None | | None | near | 82 | residual: 82 mismatch | `.run/backlog_drafts/func_8017FB3C.c` | +| 1054 | func_8017F840 | None | | None | near | 82 | residual: 82 mismatch | `.run/backlog_drafts/func_8017F840.c` | +| 1055 | func_8017DA9C | None | | None | near | 83 | residual: 83 mismatch | `.run/backlog_drafts/func_8017DA9C.c` | +| 1056 | func_801829F0 | None | | None | near | 83 | residual: 83 mismatch | `.run/backlog_drafts/func_801829F0.c` | +| 1057 | func_8017FBA4 | None | | None | near | 83 | residual: 83 mismatch | `.run/backlog_drafts/func_8017FBA4.c` | +| 1058 | func_801848AC | None | | None | near | 84 | residual: 84 mismatch | `.run/backlog_drafts/func_801848AC.c` | +| 1059 | func_8017DC9C | None | | None | near | 84 | residual: 84 mismatch | `.run/backlog_drafts/func_8017DC9C.c` | +| 1060 | func_801840FC | None | | None | near | 85 | residual: 85 mismatch | `.run/backlog_drafts/func_801840FC.c` | +| 1061 | func_80186094 | None | | None | near | 85 | residual: 85 mismatch | `.run/backlog_drafts/func_80186094.c` | +| 1062 | func_801847FC | None | | None | near | 86 | residual: 86 mismatch | `.run/backlog_drafts/func_801847FC.c` | +| 1063 | func_8018006C | None | | None | near | 86 | residual: 86 mismatch | `.run/backlog_drafts/func_8018006C.c` | +| 1064 | func_8017DFD8 | None | | None | near | 87 | residual: 87 mismatch | `.run/backlog_drafts/func_8017DFD8.c` | +| 1065 | func_8017D1F8 | None | | None | near | 87 | residual: 87 mismatch | `.run/backlog_drafts/func_8017D1F8.c` | +| 1066 | func_8017CE68 | None | | None | near | 87 | residual: 87 mismatch | `.run/backlog_drafts/func_8017CE68.c` | +| 1067 | func_8017D7D0 | None | | None | near | 88 | residual: 88 mismatch | `.run/backlog_drafts/func_8017D7D0.c` | +| 1068 | func_80181838 | None | | None | near | 88 | residual: 88 mismatch | `.run/backlog_drafts/func_80181838.c` | +| 1069 | func_801821D4 | None | | None | near | 90 | residual: 90 mismatch | `.run/backlog_drafts/func_801821D4.c` | +| 1070 | func_8017F0A8 | None | | None | near | 90 | residual: 90 mismatch | `.run/backlog_drafts/func_8017F0A8.c` | +| 1071 | func_8018AD3C | None | | None | near | 90 | residual: 90 mismatch | `.run/backlog_drafts/func_8018AD3C.c` | +| 1072 | func_8017DD5C | None | | None | near | 90 | residual: 90 mismatch | `.run/backlog_drafts/func_8017DD5C.c` | +| 1073 | func_8017EDC0 | None | | None | near | 91 | residual: 91 mismatch | `.run/backlog_drafts/func_8017EDC0.c` | +| 1074 | func_801807DC | None | | None | near | 92 | residual: 92 mismatch | `.run/backlog_drafts/func_801807DC.c` | +| 1075 | func_80180170 | None | | None | near | 92 | residual: 92 mismatch | `.run/backlog_drafts/func_80180170.c` | +| 1076 | func_8017D98C | 1 | plumbing | 31 | near | 93 | none — MATCH (expected): straight global stores + tail call; const 0x140 reused for two halves | `.run/backlog_drafts/func_8017D98C.c` | +| 1077 | func_8017EFFC | None | | None | near | 93 | residual: 93 mismatch | `.run/backlog_drafts/func_8017EFFC.c` | +| 1078 | func_8017D940 | None | | None | near | 94 | residual: 94 mismatch | `.run/backlog_drafts/func_8017D940.c` | +| 1079 | func_8017D934 | None | | None | near | 95 | residual: 95 mismatch | `.run/backlog_drafts/func_8017D934.c` | +| 1080 | func_8017DAB8 | None | | None | near | 97 | residual: 97 mismatch | `.run/backlog_drafts/func_8017DAB8.c` | +| 1081 | func_80180040 | None | | None | near | 97 | residual: 97 mismatch | `.run/backlog_drafts/func_80180040.c` | +| 1082 | func_8017FBE0 | None | | None | near | 97 | residual: 97 mismatch | `.run/backlog_drafts/func_8017FBE0.c` | +| 1083 | func_8017F240 | 1 | regalloc-order | 20 | near | 98 | none — MATCH (base &D_801270D0 pinned to $s0 holds across call; one lui/addiu reused for load+store) | `.run/backlog_drafts/func_8017F240.c` | +| 1084 | func_801863B0 | None | | None | near | 98 | residual: 98 mismatch | `.run/backlog_drafts/func_801863B0.c` | +| 1085 | func_80182728 | None | | None | near | 98 | residual: 98 mismatch | `.run/backlog_drafts/func_80182728.c` | +| 1086 | func_8018038C | None | | None | near | 100 | residual: 100 mismatch | `.run/backlog_drafts/func_8018038C.c` | +| 1087 | func_8017D808 | None | | None | near | 102 | residual: 102 mismatch | `.run/backlog_drafts/func_8017D808.c` | +| 1088 | func_80182D10 | None | | None | near | 102 | residual: 102 mismatch | `.run/backlog_drafts/func_80182D10.c` | +| 1089 | func_8017DC40 | None | | None | near | 104 | residual: 104 mismatch | `.run/backlog_drafts/func_8017DC40.c` | +| 1090 | func_80180F34 | None | | None | near | 105 | residual: 105 mismatch | `.run/backlog_drafts/func_80180F34.c` | +| 1091 | func_80181C44 | None | | None | near | 105 | residual: 105 mismatch | `.run/backlog_drafts/func_80181C44.c` | +| 1092 | func_8017F96C | None | | None | near | 106 | residual: 106 mismatch | `.run/backlog_drafts/func_8017F96C.c` | +| 1093 | func_8017EFEC | None | | None | near | 107 | residual: 107 mismatch | `.run/backlog_drafts/func_8017EFEC.c` | +| 1094 | func_80182BC8 | None | | None | near | 107 | residual: 107 mismatch | `.run/backlog_drafts/func_80182BC8.c` | +| 1095 | func_8017F69C | None | | None | near | 107 | residual: 107 mismatch | `.run/backlog_drafts/func_8017F69C.c` | +| 1096 | func_80184828 | None | | None | near | 109 | residual: 109 mismatch | `.run/backlog_drafts/func_80184828.c` | +| 1097 | func_8017F3E4 | None | | None | near | 110 | residual: 110 mismatch | `.run/backlog_drafts/func_8017F3E4.c` | +| 1098 | func_8017DAF4 | None | | None | near | 111 | residual: 111 mismatch | `.run/backlog_drafts/func_8017DAF4.c` | +| 1099 | func_8017FE9C | None | | None | near | 111 | residual: 111 mismatch | `.run/backlog_drafts/func_8017FE9C.c` | +| 1100 | func_8017F768 | None | | None | near | 112 | residual: 112 mismatch | `.run/backlog_drafts/func_8017F768.c` | +| 1101 | func_8017F3B8 | None | | None | near | 112 | residual: 112 mismatch | `.run/backlog_drafts/func_8017F3B8.c` | +| 1102 | func_8017D508 | None | | None | near | 113 | residual: 113 mismatch | `.run/backlog_drafts/func_8017D508.c` | +| 1103 | func_8018788C | None | | None | near | 113 | residual: 113 mismatch | `.run/backlog_drafts/func_8018788C.c` | +| 1104 | func_8017E978 | None | | None | near | 115 | residual: 115 mismatch | `.run/backlog_drafts/func_8017E978.c` | +| 1105 | func_80181858 | None | | None | near | 117 | residual: 117 mismatch | `.run/backlog_drafts/func_80181858.c` | +| 1106 | func_80184CD0 | None | | None | near | 118 | residual: 118 mismatch | `.run/backlog_drafts/func_80184CD0.c` | +| 1107 | func_8017E8F8 | None | | None | near | 120 | residual: 120 mismatch | `.run/backlog_drafts/func_8017E8F8.c` | +| 1108 | func_80184358 | None | | None | near | 121 | residual: 121 mismatch | `.run/backlog_drafts/func_80184358.c` | +| 1109 | func_8017F074 | None | | None | near | 121 | residual: 121 mismatch | `.run/backlog_drafts/func_8017F074.c` | +| 1110 | func_8017D890 | None | | None | near | 124 | residual: 124 mismatch | `.run/backlog_drafts/func_8017D890.c` | +| 1111 | func_8017DECC | None | | None | near | 125 | residual: 125 mismatch | `.run/backlog_drafts/func_8017DECC.c` | +| 1112 | func_80185020 | None | | None | near | 125 | residual: 125 mismatch | `.run/backlog_drafts/func_80185020.c` | +| 1113 | func_8017DD2C | None | | None | near | 125 | residual: 125 mismatch | `.run/backlog_drafts/func_8017DD2C.c` | +| 1114 | func_801884BC | None | | None | near | 125 | residual: 125 mismatch | `.run/backlog_drafts/func_801884BC.c` | +| 1115 | func_801892CC | None | | None | near | 127 | residual: 127 mismatch | `.run/backlog_drafts/func_801892CC.c` | +| 1116 | func_8017EB00 | None | | None | near | 127 | residual: 127 mismatch | `.run/backlog_drafts/func_8017EB00.c` | +| 1117 | func_8017E538 | None | | None | near | 128 | residual: 128 mismatch | `.run/backlog_drafts/func_8017E538.c` | +| 1118 | func_8017D50C | None | | None | near | 128 | residual: 128 mismatch | `.run/backlog_drafts/func_8017D50C.c` | +| 1119 | func_801803F8 | None | | None | near | 129 | residual: 129 mismatch | `.run/backlog_drafts/func_801803F8.c` | +| 1120 | func_80185E68 | 1 | STRUCT | 132 | near | 131 | STRUCT: 131 mismatch | `.run/backlog_drafts/func_80185E68.c` | +| 1121 | func_8017E378 | None | | None | near | 134 | residual: 134 mismatch | `.run/backlog_drafts/func_8017E378.c` | +| 1122 | func_80185730 | None | | None | near | 136 | residual: 136 mismatch | `.run/backlog_drafts/func_80185730.c` | +| 1123 | func_8018523C | None | | None | near | 136 | residual: 136 mismatch | `.run/backlog_drafts/func_8018523C.c` | +| 1124 | func_80186530 | None | | None | near | 139 | residual: 139 mismatch | `.run/backlog_drafts/func_80186530.c` | +| 1125 | func_80184F08 | None | regalloc-order | None | near | 141 | none — MATCH (145/145 ins, match_one confirmed) | `.run/backlog_drafts/func_80184F08.c` | +| 1126 | func_80185668 | None | | None | near | 142 | residual: 142 mismatch | `.run/backlog_drafts/func_80185668.c` | +| 1127 | func_8017DB0C | None | | None | near | 142 | residual: 142 mismatch | `.run/backlog_drafts/func_8017DB0C.c` | +| 1128 | func_801814B0 | None | | None | near | 144 | residual: 144 mismatch | `.run/backlog_drafts/func_801814B0.c` | +| 1129 | func_801801A4 | None | | None | near | 148 | residual: 148 mismatch | `.run/backlog_drafts/func_801801A4.c` | +| 1130 | func_80180868 | None | | None | near | 148 | residual: 148 mismatch | `.run/backlog_drafts/func_80180868.c` | +| 1131 | func_801829BC | None | | None | near | 150 | residual: 150 mismatch | `.run/backlog_drafts/func_801829BC.c` | +| 1132 | func_8017FBE8 | None | | None | near | 151 | residual: 151 mismatch | `.run/backlog_drafts/func_8017FBE8.c` | +| 1133 | func_8018200C | None | | None | near | 152 | residual: 152 mismatch | `.run/backlog_drafts/func_8018200C.c` | +| 1134 | func_80181984 | None | | None | near | 153 | residual: 153 mismatch | `.run/backlog_drafts/func_80181984.c` | +| 1135 | func_80183280 | None | | None | near | 154 | residual: 154 mismatch | `.run/backlog_drafts/func_80183280.c` | +| 1136 | func_80184CA0 | None | | None | near | 162 | residual: 162 mismatch | `.run/backlog_drafts/func_80184CA0.c` | +| 1137 | func_8017FA54 | None | | None | near | 166 | residual: 166 mismatch | `.run/backlog_drafts/func_8017FA54.c` | +| 1138 | func_8017D708 | None | | None | near | 166 | residual: 166 mismatch | `.run/backlog_drafts/func_8017D708.c` | +| 1139 | func_8017E6EC | None | | None | near | 172 | residual: 172 mismatch | `.run/backlog_drafts/func_8017E6EC.c` | +| 1140 | func_8017D5DC | None | | None | near | 173 | residual: 173 mismatch | `.run/backlog_drafts/func_8017D5DC.c` | +| 1141 | func_8017D47C | None | | None | near | 173 | residual: 173 mismatch | `.run/backlog_drafts/func_8017D47C.c` | +| 1142 | func_8017F40C | None | | None | near | 174 | residual: 174 mismatch | `.run/backlog_drafts/func_8017F40C.c` | +| 1143 | func_80184210 | None | | None | near | 176 | residual: 176 mismatch | `.run/backlog_drafts/func_80184210.c` | +| 1144 | func_80185E34 | None | | None | near | 185 | residual: 185 mismatch | `.run/backlog_drafts/func_80185E34.c` | +| 1145 | func_80180568 | None | | None | near | 185 | residual: 185 mismatch | `.run/backlog_drafts/func_80180568.c` | +| 1146 | func_801809C4 | None | | None | near | 190 | residual: 190 mismatch | `.run/backlog_drafts/func_801809C4.c` | +| 1147 | func_80183D84 | None | | None | near | 192 | residual: 192 mismatch | `.run/backlog_drafts/func_80183D84.c` | +| 1148 | func_80183FEC | None | | None | near | 198 | residual: 198 mismatch | `.run/backlog_drafts/func_80183FEC.c` | +| 1149 | func_801823B8 | None | | None | near | 204 | residual: 204 mismatch | `.run/backlog_drafts/func_801823B8.c` | +| 1150 | func_801826C4 | None | | None | near | 207 | residual: 207 mismatch | `.run/backlog_drafts/func_801826C4.c` | +| 1151 | func_8017E374 | None | | None | near | 234 | residual: 234 mismatch | `.run/backlog_drafts/func_8017E374.c` | +| 1152 | func_8018C3F8 | None | | None | near | 236 | residual: 236 mismatch | `.run/backlog_drafts/func_8018C3F8.c` | +| 1153 | func_80183438 | None | | None | near | 237 | residual: 237 mismatch | `.run/backlog_drafts/func_80183438.c` | +| 1154 | func_8017E7D4 | None | | None | near | 241 | residual: 241 mismatch | `.run/backlog_drafts/func_8017E7D4.c` | +| 1155 | func_80183BF8 | None | | None | near | 258 | residual: 258 mismatch | `.run/backlog_drafts/func_80183BF8.c` | +| 1156 | func_8017EB30 | None | | None | near | 278 | residual: 278 mismatch | `.run/backlog_drafts/func_8017EB30.c` | +| 1157 | func_801804A0 | None | | None | near | 280 | residual: 280 mismatch | `.run/backlog_drafts/func_801804A0.c` | +| 1158 | func_80187EDC | None | | None | near | 296 | residual: 296 mismatch | `.run/backlog_drafts/func_80187EDC.c` | +| 1159 | func_8017F554 | None | | None | near | 299 | residual: 299 mismatch | `.run/backlog_drafts/func_8017F554.c` | +| 1160 | func_8017FEF0 | None | | None | near | 304 | residual: 304 mismatch | `.run/backlog_drafts/func_8017FEF0.c` | +| 1161 | func_80181670 | None | | None | near | 311 | residual: 311 mismatch | `.run/backlog_drafts/func_80181670.c` | +| 1162 | func_801833F0 | None | | None | near | 328 | residual: 328 mismatch | `.run/backlog_drafts/func_801833F0.c` | +| 1163 | func_80181128 | None | | None | near | 385 | residual: 385 mismatch | `.run/backlog_drafts/func_80181128.c` | +| 1164 | func_8017EA84 | None | | None | near | 578 | residual: 578 mismatch | `.run/backlog_drafts/func_8017EA84.c` | +| 1165 | func_8018057C | None | | None | near | 897 | residual: 897 mismatch | `.run/backlog_drafts/func_8018057C.c` | +| 1166 | func_80184A68 | 1 | regalloc-order | 33 | failed | | none — MATCH | `.run/backlog_drafts/func_80184A68.c` | +| 1167 | func_80180B64 | 1 | struct | 75 | failed | | none — MATCH (75 ins, relocation-masked) | `.run/backlog_drafts/func_80180B64.c` | +| 1168 | func_80183DE0 | 1 | regalloc-order | 91 | failed | | testing if(!=1) layout + counter-before-pointer init order | `.run/backlog_drafts/func_80183DE0.c` | +| 1169 | func_80182C9C | 1 | schedule | 101 | failed | | none — MATCH (101 ins). Inner-switch break-to-shared-tail must be written as | `.run/backlog_drafts/func_80182C9C.c` | +| 1170 | func_80183FB8 | 1 | loose-typing | 101 | failed | | none — MATCH (relocation-masked match_one, 101/101 ins) | `.run/backlog_drafts/func_80183FB8.c` | +| 1171 | func_80185BA4 | 1 | WAVE | 177 | failed | | won't compile standalone (loose-typing / missing decl) | | +| 1172 | func_8017D8DC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017D8DC.c` | +| 1173 | func_80187750 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80187750.c` | +| 1174 | func_8017FFEC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFEC.c` | +| 1175 | func_80184018 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80184018.c` | +| 1176 | func_8017DC18 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017DC18.c` | +| 1177 | func_801853CC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801853CC.c` | +| 1178 | func_80181894 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181894.c` | +| 1179 | func_8018BFBC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8018BFBC.c` | +| 1180 | func_801807F4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801807F4.c` | +| 1181 | func_8017FFC8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFC8.c` | +| 1182 | func_8017E99C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E99C.c` | +| 1183 | func_80180294 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80180294.c` | +| 1184 | func_8017E76C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E76C.c` | +| 1185 | func_8017F29C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F29C.c` | +| 1186 | func_8018253C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8018253C.c` | +| 1187 | func_8017F00C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F00C.c` | +| 1188 | func_801802B0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801802B0.c` | +| 1189 | func_80181FDC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181FDC.c` | +| 1190 | func_8017DA1C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017DA1C.c` | +| 1191 | func_8017FFC4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017FFC4.c` | +| 1192 | func_8017E2F0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E2F0.c` | +| 1193 | func_801841E4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801841E4.c` | +| 1194 | func_80181738 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181738.c` | +| 1195 | func_801873D8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801873D8.c` | +| 1196 | func_80181E90 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181E90.c` | +| 1197 | func_80185628 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80185628.c` | +| 1198 | func_80182384 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80182384.c` | +| 1199 | func_801829D8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801829D8.c` | +| 1200 | func_80181A78 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80181A78.c` | +| 1201 | func_80186E58 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80186E58.c` | +| 1202 | func_801805D4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801805D4.c` | +| 1203 | func_8017EA1C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017EA1C.c` | +| 1204 | func_8017F098 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017F098.c` | +| 1205 | func_801822CC | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801822CC.c` | +| 1206 | func_80185BA8 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80185BA8.c` | +| 1207 | func_8018E710 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8018E710.c` | +| 1208 | func_801852D0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_801852D0.c` | +| 1209 | func_8017E3F4 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8017E3F4.c` | +| 1210 | func_800D1658 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D1658.c` | +| 1211 | func_800D1984 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D1984.c` | +| 1212 | func_800D24A0 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_800D24A0.c` | +| 1213 | func_8018457C | None | regalloc-order | None | failed | | none — MATCH (160 ins). case1-tail needed a $a0 pin on the state temp | `.run/backlog_drafts/func_8018457C.c` | +| 1214 | func_8018D870 | None | regalloc-order | None | failed | | none — MATCH (match_one 380/380, relocation-masked). Levers: &&-DeMorgan for the mult block layout; lhu-corrected reads; split temps (t=func_8012C658 ret->v1, d8p=d8 load-temp->a0, s60/amt pinned $v1/$a1 for the mult chain); accumulate-in-place for the 0xe add; unsigned-short store for ori 0x8800; d8-load-via-temp to force the addu s3,a0 copy (fixes -1 length drift). | `.run/backlog_drafts/func_8018D870.c` | +| 1215 | func_80144B9C | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_80144B9C.c` | +| 1216 | func_8013DD68 | None | | None | failed | | won't compile standalone (loose-typing / missing decl) | `.run/backlog_drafts/func_8013DD68.c` | diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md index 615e7cb80a..aff30acf9a 100644 --- a/docs/cookbook-index.md +++ b/docs/cookbook-index.md @@ -2,7 +2,7 @@ > **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section. > -> `docs/matching-cookbook.md` is ~716 KB / 359 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses. +> `docs/matching-cookbook.md` is ~716 KB / 360 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses. **How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win. @@ -262,7 +262,7 @@ - **§127a** — §71 (sibling-first) is the strongest `-O0` lever, and it beats the index L8370 - **§132** — The `JR-PAIR-IN-ONE-O0-OBJECT` "wall" was TWO instrument defects: a merged-double span the carve could not see, and a truncated object no rule deleted (P30 S29, `func_8013B83C` + `func_8013BD74`) L8563 -### family propagation & sweeps (65) +### family propagation & sweeps (66) - **§8d** — Templating a body INTO a TU must not CHANGE its declaration environment — demote the carried data externs (Phase 26 session 8, byte-proven on `func_8015AE2C` ×133) L483 - **§11** — Cross-binary dedup & code-sharing (Phase 11 — "one match unlocks many") L908 @@ -329,6 +329,7 @@ - **§123** — PROPAGATE A FAMILY WITH THE TOOL ITS TIER NEEDS: `dedup_propagate` is h_exact-only; its refusals are statements about the TOOL (P30 wave 1, 2026-07-30) L8109 - **§124** — A "not matched" verdict can mean the definition is there under a DIFFERENT C NAME: the asm-label alias blind spot (P30 SESSION-28, `func_8016191C` ×137) L8146 - **§124a** — a family sweep's `0 matched-exemplar families` may be a FILTER, not a wall L8191 +- **§134** — MULTI-LINE BLINDNESS: one root cause, four faces, in `family_remap`'s preamble scanner (P30 S6, 190 zero-crack families) L8704 ### integration / TU plumbing (32) @@ -365,7 +366,7 @@ - **§112** — A macro-scoped declaration only collides where the macro is INSTANTIATED (Phase 29 T67/T69, `audit_header_sigs.py`) L7723 - **§114** — The THIRD decl axis: a CALLEE the draft declares differently from the target TU (Phase 29 T76/T77) L7801 -### build graph, splat & the harness (89) +### build graph, splat & the harness (90) - **§4** — Flag/toolchain gotchas L190 - **Build** — mechanism — per-file opt override (splat resegmentation) L288 @@ -456,6 +457,7 @@ - **§130** — An INCREMENTAL build can report BYTE-IDENTICAL for a change the CLEAN build cannot even LINK (P30 S28, the jr pair) L8479 - **§132** — The `JR-PAIR-IN-ONE-O0-OBJECT` "wall" was TWO instrument defects: a merged-double span the carve could not see, and a truncated object no rule deleted (P30 S29, `func_8013B83C` + `func_8013BD74`) L8563 - **§133** — The DEFAULT-FILTER class: three times in one session, a tool silently answered a narrower question than the one asked (P30 S1–S3) L8678 +- **§134** — MULTI-LINE BLINDNESS: one root cause, four faces, in `family_remap`'s preamble scanner (P30 S6, 190 zero-crack families) L8704 ### process, measurement & doctrine (47) @@ -971,3 +973,4 @@ - **§132a** — `--like` is for a sibling with NO record; against one that HAS a record it over-derives (P30 S29, `ov_SC07_010`) L8628 - **§132b** — When the span's already-matched owner is ITSELF multi-switch: `--span-rel` (P30 S1, `func_8014032C`) L8653 - **§133** — The DEFAULT-FILTER class: three times in one session, a tool silently answered a narrower question than the one asked (P30 S1–S3) L8678 +- **§134** — MULTI-LINE BLINDNESS: one root cause, four faces, in `family_remap`'s preamble scanner (P30 S6, 190 zero-crack families) L8704 diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index 4a5d808990..0768230ce4 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -8700,3 +8700,57 @@ your own filter, not the world. State the filter out loud in the same breath as families **with ≥100 members, any size**"), and re-run once with it removed before any conclusion is allowed to shape a plan. A number that scoped a phase deserves the same instrument-check R35 demands of a probe. + +## §134 — MULTI-LINE BLINDNESS: one root cause, four faces, in `family_remap`'s preamble scanner (P30 S6, 190 zero-crack families) + +`extract_unit` builds a templatable unit by walking UP from a definition line, accepting lines that +"look like" preamble (`extern` / `//` / `/*` / `*` / `typedef` / blank). That scanner is **line-at-a-time +over a language whose constructs span lines**, and every construct that wraps was misread. Four faces, +all found in one session by probing eight zero-banked families with ONE build each (`.run/s6_diag.py` +— remap → splice → build that overlay → read the compiler's own error → revert): + +| face | the construct | what the scanner concluded | the symptom, in the sibling | +|---|---|---|---| +| **D1** | a block comment containing `{` — e.g. `* => { u16, u16, s32 }` | the `{`-guard (a real T65 fix for `extern void f(int); int g(){…}` on one line) fired on *documentation* | carry stops MID-comment; the draft opens with ` * …` and an unmatched `*/` → **`parse error before 'the'`** | +| **D2** | a wrapped DECLARATION — `extern void func_801466F0(s32 a0, …,`⏎` s32 sp8);` | `_def_head_at`'s fallback: "param list continues past this line ⇒ ANSI definition" | line 457 accepted as a definition head → unit is a **16-line fragment with no body** (a neighbouring `DEFINE_func_*()`, an `#include`, a comment), closed by the `{ u16, … }` *inside that comment* → **0/137, reads as a compiler wall** | +| **D4** | a wrapped asm-label alias — `extern void aF…(…,`⏎` s32 sp8) __asm__("func_801466F0");` | `_alias_decl_for` is a single-line `rx.match` | the definition is invisible → "no matched unit" | +| **D5** | a multi-line `typedef struct {…} T;` | the backscan meets the CLOSING line `} T;` first; `}` is not an accepted prefix, so it stops | the type never travels → **`T undeclared`**, measured at **17 families / 24,332 templatable ins** | + +**Why it matters more than four bugs.** D2 and D5 produce a *silent, uniform, whole-family* failure — +exactly the shape a compiler wall produces. The tell is **bimodality**: S6's first sweep banked +842/2,735, and the residue split **57 families all-banked / 52 zero / 8 partial**. Per-member codegen +residuals do not cluster like that; one per-family blocker does. **Bimodal bank rates are a +tooling signature — probe one member before writing the family off** (R35, and the fifth consecutive +"structural wall" in this project to resolve to our own instrument after §53/§124/§126/§132). + +**The fixes** (all in `tools/family_remap.py`, all blast-radius-verified against the pre-fix tool by +diffing `extract_unit` output over every affected exemplar — **157 of 181 byte-identical**, the rest +changed only in the intended direction): +- `_def_head_at(ln, paren_idx, more=())` — the caller passes the following lines, so a wrapped list + closes and the same `;`-vs-`{` test answers correctly. With lookahead supplied and no close, it + returns **False** ("unknown" is not "definition"); with no lookahead it keeps the historical answer, + so un-updated callers cannot silently change behaviour. +- the `{`-guard exempts comment-only lines (`*`, `//`, or an unclosed `/*`), plus an **R32 backstop** + that drops-and-announces a preamble that still opens inside a comment. +- the forward body scan counts braces in **`cdecl._mask`ed** text (R33: one masking oracle), so a + brace inside a comment or string can never close a function body. +- `_typedef_block_start()` — on a `} T;` closing line, walk up to the matching `typedef` (both the + `typedef struct {` and brace-on-its-own-line forms) and carry the WHOLE block. Only blocks that + literally begin with `typedef` are carried: a struct VARIABLE (`struct {…} g;`) closes identically + and defining it in the sibling would be a duplicate global. Safe because `harvest_verify` already + strips a typedef the sibling TU provides (`cdecl.strip_provided_typedefs`), so a duplicate cannot + break the sibling — and the whole-binary gate remains the sole arbiter (G3/P9). + +**Measured payoff, one command each:** D1+D2 recovered **+323 members** from families that had banked +**zero**; D5 then banked the 139-member `func_8012B77C` family **139/139** (8,062 ins) and took +`func_80128C98` to 137/275. S6 total: **1,582 members** off a population that the pre-fix tool scored +at 842. D4 was measured (1 exemplar / 3,288 ins, with a second blocker behind it) and deliberately left +UNFIXED — but it now returns `None`, so the sweep reports it as `skipped {'no matched unit for func'}` +rather than failing 137 times. **A known gap that announces itself is not the same defect as a silent +one** (R32). + +**The general practice.** Any scanner that classifies C by reading one line at a time is wrong on +wrapped declarations, wrapped attributes/asm-labels, multi-line typedefs, and comments containing +braces — and its failures will look like walls, not bugs. Give it lookahead, mask comments/strings +before counting delimiters, and when a family banks 0/N with every member failing identically, **read +one compiler error before believing the compiler.** diff --git a/docs/progress.fleet.md b/docs/progress.fleet.md index eb72815158..e4ce33a3a9 100644 --- a/docs/progress.fleet.md +++ b/docs/progress.fleet.md @@ -4,157 +4,157 @@ # cross-binary collapsible-byte leverage: docs/duplicates.cross.md. # THREE progress metrics (all matter — see the labels): -FLEET fn-count byte-ident: 334873 / 353721 = 94.67% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay) -FLEET instr-weighted : 12039773 / 13141652 = 91.6% (shipped .text across main + resident + 138 overlays; the decomp.dev-DISPLAY number) -FLEET distinct-code(uniq): 4758745 / 5634875 = 84.5% (74401/87459 unique fns; the DISTINCT-RE number) +FLEET fn-count byte-ident: 335613 / 353721 = 94.88% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay) +FLEET instr-weighted : 12072870 / 13141652 = 91.9% (shipped .text across main + resident + 138 overlays; the decomp.dev-DISPLAY number) +FLEET distinct-code(uniq): 4767563 / 5634875 = 84.6% (74648/87459 unique fns; the DISTINCT-RE number) MAIN game-code weighted : 436 / 60201 = 0.7% (INCLUDED in the fleet numbers above since 2026-07-22 — roadmap §1 metrics contract; LINKED-excluding Ghidra sig dated 2026-06-14; caveat is R34: no independent second oracle for a PS-X EXE, NOT drift) - (fleet EXCLUDING main, for continuity with pre-2026-07-22 readings: 12039337 / 13081451 = 92.0%) + (fleet EXCLUDING main, for continuity with pre-2026-07-22 readings: 12072434 / 13081451 = 92.3%) -FLEET REAL substantive : 333018 (of which dedup-shared 240422 via 1905 groups / 240496 instances) +FLEET REAL substantive : 333758 (of which dedup-shared 240422 via 1905 groups / 240496 instances) FLEET LINKED PsyQ objs : 959 FLEET NON_MATCHING : 7 (0 in any default build — G4) -FLEET INCLUDE_ASM stubs : 18841 +FLEET INCLUDE_ASM stubs : 18101 FLEET matchable : 353721 | binary | REAL | shared | LINKED | byte-ident | matchable | byte-ident % | |---|---:|---:|---:|---:|---:|---:| | main | 54 | 2 | 959 | 1055 | 2096 | 50.3% | | resident | 129 | 0 | 0 | 131 | 145 | 90.3% | -| ov_SC01_000 | 2370 | 1748 | 0 | 2370 | 2403 | 98.6% | -| ov_SC01_001 | 2377 | 1749 | 0 | 2379 | 2466 | 96.5% | -| ov_SC01_004 | 2368 | 1740 | 0 | 2369 | 2414 | 98.1% | -| ov_SC01_005 | 2399 | 1763 | 0 | 2399 | 2503 | 95.8% | -| ov_SC01_006 | 2399 | 1763 | 0 | 2399 | 2503 | 95.8% | -| ov_SC01_008 | 2368 | 1740 | 0 | 2370 | 2426 | 97.7% | -| ov_SC01_009 | 2393 | 1741 | 0 | 2394 | 2507 | 95.5% | -| ov_SC01_074 | 2374 | 1741 | 0 | 2376 | 2425 | 98.0% | -| ov_SC01_077 | 2535 | 1707 | 0 | 2537 | 2586 | 98.1% | -| ov_SC01_080 | 2408 | 1744 | 0 | 2408 | 2512 | 95.9% | -| ov_SC01_084 | 2429 | 1749 | 0 | 2434 | 2579 | 94.4% | -| ov_SC02_000 | 2490 | 1788 | 0 | 2490 | 2683 | 92.8% | -| ov_SC02_003 | 2489 | 1788 | 0 | 2489 | 2683 | 92.8% | -| ov_SC02_004 | 2373 | 1744 | 0 | 2373 | 2401 | 98.8% | -| ov_SC02_005 | 2510 | 1740 | 0 | 2520 | 2927 | 86.1% | -| ov_SC02_011 | 2526 | 1747 | 0 | 2537 | 2893 | 87.7% | -| ov_SC02_015 | 2379 | 1746 | 0 | 2379 | 2414 | 98.6% | -| ov_SC02_016 | 2428 | 1746 | 0 | 2431 | 2545 | 95.5% | -| ov_SC02_017 | 2490 | 1746 | 0 | 2498 | 2732 | 91.4% | -| ov_SC02_021 | 2383 | 1746 | 0 | 2383 | 2437 | 97.8% | -| ov_SC02_026 | 2411 | 1744 | 0 | 2417 | 2572 | 94.0% | -| ov_SC02_027 | 2449 | 1744 | 0 | 2458 | 2692 | 91.3% | -| ov_SC02_028 | 2449 | 1744 | 0 | 2459 | 2701 | 91.0% | -| ov_SC02_031 | 2429 | 1745 | 0 | 2434 | 2562 | 95.0% | -| ov_SC02_035 | 2400 | 1744 | 0 | 2403 | 2520 | 95.4% | -| ov_SC02_039 | 2372 | 1744 | 0 | 2372 | 2416 | 98.2% | -| ov_SC02_041 | 2426 | 1744 | 0 | 2429 | 2561 | 94.8% | -| ov_SC03_001 | 2533 | 1745 | 0 | 2550 | 2869 | 88.9% | -| ov_SC03_002 | 2439 | 1749 | 0 | 2454 | 2631 | 93.3% | -| ov_SC03_003 | 2380 | 1744 | 0 | 2381 | 2423 | 98.3% | -| ov_SC03_006 | 2480 | 1750 | 0 | 2489 | 2767 | 90.0% | -| ov_SC03_007 | 2437 | 1744 | 0 | 2441 | 2623 | 93.1% | -| ov_SC03_010 | 2391 | 1744 | 0 | 2391 | 2471 | 96.8% | -| ov_SC03_011 | 2396 | 1744 | 0 | 2402 | 2527 | 95.1% | -| ov_SC03_012 | 2370 | 1744 | 0 | 2371 | 2406 | 98.5% | -| ov_SC03_013 | 2397 | 1744 | 0 | 2397 | 2493 | 96.1% | -| ov_SC03_014 | 2490 | 1772 | 0 | 2490 | 2685 | 92.7% | -| ov_SC03_015 | 2484 | 1772 | 0 | 2484 | 2685 | 92.5% | -| ov_SC03_023 | 2381 | 1744 | 0 | 2382 | 2435 | 97.8% | -| ov_SC03_024 | 2447 | 1749 | 0 | 2454 | 2641 | 92.9% | -| ov_SC03_028 | 2419 | 1744 | 0 | 2423 | 2664 | 91.0% | -| ov_SC03_029 | 2440 | 1746 | 0 | 2450 | 2644 | 92.7% | -| ov_SC03_030 | 2398 | 1749 | 0 | 2400 | 2495 | 96.2% | -| ov_SC03_031 | 2398 | 1744 | 0 | 2401 | 2514 | 95.5% | -| ov_SC03_089 | 2426 | 1749 | 0 | 2433 | 2581 | 94.3% | -| ov_SC03_090 | 2430 | 1749 | 0 | 2438 | 2625 | 92.9% | -| ov_SC03_091 | 2432 | 1744 | 0 | 2440 | 2640 | 92.4% | -| ov_SC03_092 | 2445 | 1749 | 0 | 2457 | 2587 | 95.0% | -| ov_SC03_093 | 2418 | 1744 | 0 | 2422 | 2563 | 94.5% | -| ov_SC03_094 | 2408 | 1744 | 0 | 2414 | 2577 | 93.7% | -| ov_SC03_095 | 2391 | 1744 | 0 | 2394 | 2474 | 96.8% | -| ov_SC03_096 | 2391 | 1744 | 0 | 2394 | 2465 | 97.1% | -| ov_SC03_097 | 2439 | 1744 | 0 | 2446 | 2603 | 94.0% | -| ov_SC03_098 | 2409 | 1744 | 0 | 2412 | 2541 | 94.9% | -| ov_SC03_099 | 2399 | 1744 | 0 | 2402 | 2504 | 95.9% | -| ov_SC03_100 | 2416 | 1744 | 0 | 2420 | 2539 | 95.3% | -| ov_SC03_101 | 2418 | 1749 | 0 | 2422 | 2528 | 95.8% | -| ov_SC03_102 | 2394 | 1744 | 0 | 2397 | 2492 | 96.2% | -| ov_SC03_103 | 2404 | 1746 | 0 | 2407 | 2510 | 95.9% | -| ov_SC03_104 | 2432 | 1749 | 0 | 2439 | 2616 | 93.2% | -| ov_SC03_105 | 2413 | 1744 | 0 | 2420 | 2597 | 93.2% | -| ov_SC03_108 | 2375 | 1744 | 0 | 2375 | 2443 | 97.2% | -| ov_SC03_109 | 2378 | 1744 | 0 | 2380 | 2424 | 98.2% | -| ov_SC03_110 | 2392 | 1744 | 0 | 2392 | 2468 | 96.9% | -| ov_SC03_111 | 2405 | 1744 | 0 | 2408 | 2510 | 95.9% | -| ov_SC03_112 | 2400 | 1746 | 0 | 2402 | 2526 | 95.1% | -| ov_SC03_113 | 2386 | 1746 | 0 | 2389 | 2468 | 96.8% | -| ov_SC03_114 | 2368 | 1744 | 0 | 2370 | 2415 | 98.1% | -| ov_SC03_115 | 2399 | 1744 | 0 | 2401 | 2472 | 97.1% | -| ov_SC03_116 | 2376 | 1744 | 0 | 2379 | 2438 | 97.6% | -| ov_SC03_117 | 2420 | 1744 | 0 | 2426 | 2557 | 94.9% | -| ov_SC03_118 | 2467 | 1768 | 0 | 2468 | 2685 | 91.9% | -| ov_SC03_119 | 2463 | 1768 | 0 | 2464 | 2685 | 91.8% | -| ov_SC03_121 | 2386 | 1744 | 0 | 2389 | 2459 | 97.2% | -| ov_SC03_124 | 2480 | 1740 | 0 | 2500 | 2741 | 91.2% | -| ov_SC03_125 | 2425 | 1744 | 0 | 2437 | 2588 | 94.2% | -| ov_SC03_126 | 2381 | 1746 | 0 | 2381 | 2423 | 98.3% | -| ov_SC04_000 | 2417 | 1748 | 0 | 2426 | 2546 | 95.3% | -| ov_SC04_002 | 2444 | 1744 | 0 | 2448 | 2636 | 92.9% | -| ov_SC04_003 | 2398 | 1744 | 0 | 2402 | 2502 | 96.0% | -| ov_SC04_004 | 2420 | 1744 | 0 | 2422 | 2558 | 94.7% | -| ov_SC04_005 | 2430 | 1744 | 0 | 2436 | 2612 | 93.3% | -| ov_SC04_006 | 2389 | 1744 | 0 | 2391 | 2454 | 97.4% | -| ov_SC04_007 | 2423 | 1744 | 0 | 2427 | 2569 | 94.5% | -| ov_SC04_008 | 2377 | 1744 | 0 | 2377 | 2415 | 98.4% | -| ov_SC04_009 | 2391 | 1744 | 0 | 2394 | 2441 | 98.1% | -| ov_SC04_010 | 2379 | 1744 | 0 | 2380 | 2419 | 98.4% | -| ov_SC04_011 | 2461 | 1749 | 0 | 2467 | 2803 | 88.0% | -| ov_SC04_012 | 2378 | 1744 | 0 | 2379 | 2420 | 98.3% | -| ov_SC04_015 | 2449 | 1745 | 0 | 2460 | 2611 | 94.2% | -| ov_SC04_016 | 2377 | 1744 | 0 | 2379 | 2440 | 97.5% | -| ov_SC04_018 | 2536 | 1780 | 0 | 2536 | 2857 | 88.8% | -| ov_SC04_019 | 2536 | 1780 | 0 | 2536 | 2857 | 88.8% | -| ov_SC04_020 | 2413 | 1744 | 0 | 2425 | 2567 | 94.5% | -| ov_SC04_021 | 2381 | 1746 | 0 | 2381 | 2423 | 98.3% | -| ov_SC05_000 | 2379 | 1748 | 0 | 2382 | 2422 | 98.3% | -| ov_SC05_001 | 2422 | 1744 | 0 | 2427 | 2574 | 94.3% | -| ov_SC05_002 | 2390 | 1744 | 0 | 2393 | 2442 | 98.0% | -| ov_SC05_003 | 2387 | 1744 | 0 | 2388 | 2481 | 96.3% | -| ov_SC05_004 | 2380 | 1744 | 0 | 2382 | 2464 | 96.7% | -| ov_SC05_005 | 2395 | 1749 | 0 | 2396 | 2491 | 96.2% | -| ov_SC05_006 | 2384 | 1744 | 0 | 2384 | 2430 | 98.1% | -| ov_SC05_007 | 2397 | 1744 | 0 | 2402 | 2482 | 96.8% | -| ov_SC05_008 | 2407 | 1744 | 0 | 2409 | 2543 | 94.7% | -| ov_SC05_009 | 2383 | 1744 | 0 | 2387 | 2438 | 97.9% | -| ov_SC05_010 | 2418 | 1744 | 0 | 2422 | 2588 | 93.6% | -| ov_SC05_011 | 2376 | 1744 | 0 | 2377 | 2409 | 98.7% | -| ov_SC05_017 | 2518 | 1741 | 0 | 2529 | 2842 | 89.0% | -| ov_SC05_018 | 2444 | 1744 | 0 | 2457 | 2673 | 91.9% | -| ov_SC05_019 | 2381 | 1746 | 0 | 2381 | 2423 | 98.3% | -| ov_SC06_000 | 2473 | 1753 | 0 | 2476 | 2691 | 92.0% | -| ov_SC06_006 | 2402 | 1744 | 0 | 2403 | 2511 | 95.7% | -| ov_SC06_008 | 2427 | 1746 | 0 | 2433 | 2542 | 95.7% | -| ov_SC06_010 | 2408 | 1744 | 0 | 2413 | 2517 | 95.9% | -| ov_SC06_011 | 2385 | 1744 | 0 | 2389 | 2468 | 96.8% | -| ov_SC06_013 | 2379 | 1744 | 0 | 2380 | 2425 | 98.1% | -| ov_SC06_014 | 2388 | 1744 | 0 | 2390 | 2453 | 97.4% | -| ov_SC06_015 | 2384 | 1744 | 0 | 2384 | 2421 | 98.5% | -| ov_SC06_016 | 2404 | 1744 | 0 | 2406 | 2549 | 94.4% | -| ov_SC06_018 | 2432 | 1746 | 0 | 2439 | 2665 | 91.5% | -| ov_SC06_020 | 2401 | 1746 | 0 | 2402 | 2518 | 95.4% | -| ov_SC06_022 | 2429 | 1744 | 0 | 2437 | 2642 | 92.2% | -| ov_SC06_024 | 2440 | 1744 | 0 | 2446 | 2667 | 91.7% | -| ov_SC06_025 | 2414 | 1744 | 0 | 2419 | 2572 | 94.1% | -| ov_SC06_027 | 2371 | 1744 | 0 | 2372 | 2408 | 98.5% | -| ov_SC06_029 | 2438 | 1744 | 0 | 2450 | 2662 | 92.0% | -| ov_SC06_030 | 2384 | 1744 | 0 | 2384 | 2456 | 97.1% | -| ov_SC06_032 | 2424 | 1745 | 0 | 2431 | 2658 | 91.5% | -| ov_SC06_033 | 2425 | 1745 | 0 | 2432 | 2631 | 92.4% | -| ov_SC07_000 | 2398 | 1748 | 0 | 2400 | 2521 | 95.2% | -| ov_SC07_001 | 2384 | 1744 | 0 | 2386 | 2454 | 97.2% | -| ov_SC07_002 | 2412 | 1744 | 0 | 2416 | 2579 | 93.7% | -| ov_SC07_006 | 2276 | 1560 | 0 | 2356 | 2456 | 95.9% | -| ov_SC07_007 | 2303 | 1592 | 0 | 2387 | 2613 | 91.4% | -| ov_SC07_008 | 2365 | 1744 | 0 | 2365 | 2386 | 99.1% | -| ov_SC07_009 | 2376 | 1744 | 0 | 2378 | 2430 | 97.9% | -| ov_SC07_010 | 2286 | 1614 | 0 | 2369 | 2524 | 93.9% | -| ov_SC07_011 | 2297 | 1591 | 0 | 2377 | 2449 | 97.1% | +| ov_SC01_000 | 2375 | 1748 | 0 | 2375 | 2403 | 98.8% | +| ov_SC01_001 | 2382 | 1749 | 0 | 2384 | 2466 | 96.7% | +| ov_SC01_004 | 2372 | 1740 | 0 | 2373 | 2414 | 98.3% | +| ov_SC01_005 | 2403 | 1763 | 0 | 2403 | 2503 | 96.0% | +| ov_SC01_006 | 2403 | 1763 | 0 | 2403 | 2503 | 96.0% | +| ov_SC01_008 | 2372 | 1740 | 0 | 2374 | 2426 | 97.9% | +| ov_SC01_009 | 2397 | 1741 | 0 | 2398 | 2507 | 95.7% | +| ov_SC01_074 | 2378 | 1741 | 0 | 2380 | 2425 | 98.1% | +| ov_SC01_077 | 2536 | 1707 | 0 | 2538 | 2586 | 98.1% | +| ov_SC01_080 | 2412 | 1744 | 0 | 2412 | 2512 | 96.0% | +| ov_SC01_084 | 2433 | 1749 | 0 | 2438 | 2579 | 94.5% | +| ov_SC02_000 | 2496 | 1788 | 0 | 2496 | 2683 | 93.0% | +| ov_SC02_003 | 2496 | 1788 | 0 | 2496 | 2683 | 93.0% | +| ov_SC02_004 | 2377 | 1744 | 0 | 2377 | 2401 | 99.0% | +| ov_SC02_005 | 2514 | 1740 | 0 | 2524 | 2927 | 86.2% | +| ov_SC02_011 | 2535 | 1747 | 0 | 2546 | 2893 | 88.0% | +| ov_SC02_015 | 2383 | 1746 | 0 | 2383 | 2414 | 98.7% | +| ov_SC02_016 | 2434 | 1746 | 0 | 2437 | 2545 | 95.8% | +| ov_SC02_017 | 2496 | 1746 | 0 | 2504 | 2732 | 91.7% | +| ov_SC02_021 | 2387 | 1746 | 0 | 2387 | 2437 | 97.9% | +| ov_SC02_026 | 2415 | 1744 | 0 | 2421 | 2572 | 94.1% | +| ov_SC02_027 | 2455 | 1744 | 0 | 2464 | 2692 | 91.5% | +| ov_SC02_028 | 2457 | 1744 | 0 | 2467 | 2701 | 91.3% | +| ov_SC02_031 | 2435 | 1745 | 0 | 2440 | 2562 | 95.2% | +| ov_SC02_035 | 2404 | 1744 | 0 | 2407 | 2520 | 95.5% | +| ov_SC02_039 | 2376 | 1744 | 0 | 2376 | 2416 | 98.3% | +| ov_SC02_041 | 2431 | 1744 | 0 | 2434 | 2561 | 95.0% | +| ov_SC03_001 | 2537 | 1745 | 0 | 2554 | 2869 | 89.0% | +| ov_SC03_002 | 2443 | 1749 | 0 | 2458 | 2631 | 93.4% | +| ov_SC03_003 | 2384 | 1744 | 0 | 2385 | 2423 | 98.4% | +| ov_SC03_006 | 2486 | 1750 | 0 | 2495 | 2767 | 90.2% | +| ov_SC03_007 | 2441 | 1744 | 0 | 2445 | 2623 | 93.2% | +| ov_SC03_010 | 2395 | 1744 | 0 | 2395 | 2471 | 96.9% | +| ov_SC03_011 | 2400 | 1744 | 0 | 2406 | 2527 | 95.2% | +| ov_SC03_012 | 2374 | 1744 | 0 | 2375 | 2406 | 98.7% | +| ov_SC03_013 | 2401 | 1744 | 0 | 2401 | 2493 | 96.3% | +| ov_SC03_014 | 2496 | 1772 | 0 | 2496 | 2685 | 93.0% | +| ov_SC03_015 | 2498 | 1772 | 0 | 2498 | 2685 | 93.0% | +| ov_SC03_023 | 2385 | 1744 | 0 | 2386 | 2435 | 98.0% | +| ov_SC03_024 | 2456 | 1749 | 0 | 2463 | 2641 | 93.3% | +| ov_SC03_028 | 2423 | 1744 | 0 | 2427 | 2664 | 91.1% | +| ov_SC03_029 | 2446 | 1746 | 0 | 2456 | 2644 | 92.9% | +| ov_SC03_030 | 2402 | 1749 | 0 | 2404 | 2495 | 96.4% | +| ov_SC03_031 | 2404 | 1744 | 0 | 2407 | 2514 | 95.7% | +| ov_SC03_089 | 2432 | 1749 | 0 | 2439 | 2581 | 94.5% | +| ov_SC03_090 | 2436 | 1749 | 0 | 2444 | 2625 | 93.1% | +| ov_SC03_091 | 2438 | 1744 | 0 | 2446 | 2640 | 92.7% | +| ov_SC03_092 | 2451 | 1749 | 0 | 2463 | 2587 | 95.2% | +| ov_SC03_093 | 2426 | 1744 | 0 | 2430 | 2563 | 94.8% | +| ov_SC03_094 | 2415 | 1744 | 0 | 2421 | 2577 | 93.9% | +| ov_SC03_095 | 2396 | 1744 | 0 | 2399 | 2474 | 97.0% | +| ov_SC03_096 | 2395 | 1744 | 0 | 2398 | 2465 | 97.3% | +| ov_SC03_097 | 2447 | 1744 | 0 | 2454 | 2603 | 94.3% | +| ov_SC03_098 | 2417 | 1744 | 0 | 2420 | 2541 | 95.2% | +| ov_SC03_099 | 2405 | 1744 | 0 | 2408 | 2504 | 96.2% | +| ov_SC03_100 | 2423 | 1744 | 0 | 2427 | 2539 | 95.6% | +| ov_SC03_101 | 2427 | 1749 | 0 | 2431 | 2528 | 96.2% | +| ov_SC03_102 | 2398 | 1744 | 0 | 2401 | 2492 | 96.3% | +| ov_SC03_103 | 2411 | 1746 | 0 | 2414 | 2510 | 96.2% | +| ov_SC03_104 | 2440 | 1749 | 0 | 2447 | 2616 | 93.5% | +| ov_SC03_105 | 2417 | 1744 | 0 | 2424 | 2597 | 93.3% | +| ov_SC03_108 | 2379 | 1744 | 0 | 2379 | 2443 | 97.4% | +| ov_SC03_109 | 2382 | 1744 | 0 | 2384 | 2424 | 98.3% | +| ov_SC03_110 | 2398 | 1744 | 0 | 2398 | 2468 | 97.2% | +| ov_SC03_111 | 2411 | 1744 | 0 | 2414 | 2510 | 96.2% | +| ov_SC03_112 | 2404 | 1746 | 0 | 2406 | 2526 | 95.2% | +| ov_SC03_113 | 2391 | 1746 | 0 | 2394 | 2468 | 97.0% | +| ov_SC03_114 | 2373 | 1744 | 0 | 2375 | 2415 | 98.3% | +| ov_SC03_115 | 2403 | 1744 | 0 | 2405 | 2472 | 97.3% | +| ov_SC03_116 | 2381 | 1744 | 0 | 2384 | 2438 | 97.8% | +| ov_SC03_117 | 2424 | 1744 | 0 | 2430 | 2557 | 95.0% | +| ov_SC03_118 | 2474 | 1768 | 0 | 2475 | 2685 | 92.2% | +| ov_SC03_119 | 2470 | 1768 | 0 | 2471 | 2685 | 92.0% | +| ov_SC03_121 | 2390 | 1744 | 0 | 2393 | 2459 | 97.3% | +| ov_SC03_124 | 2484 | 1740 | 0 | 2504 | 2741 | 91.4% | +| ov_SC03_125 | 2429 | 1744 | 0 | 2441 | 2588 | 94.3% | +| ov_SC03_126 | 2385 | 1746 | 0 | 2385 | 2423 | 98.4% | +| ov_SC04_000 | 2424 | 1748 | 0 | 2433 | 2546 | 95.6% | +| ov_SC04_002 | 2453 | 1744 | 0 | 2457 | 2636 | 93.2% | +| ov_SC04_003 | 2405 | 1744 | 0 | 2409 | 2502 | 96.3% | +| ov_SC04_004 | 2429 | 1744 | 0 | 2431 | 2558 | 95.0% | +| ov_SC04_005 | 2440 | 1744 | 0 | 2446 | 2612 | 93.6% | +| ov_SC04_006 | 2395 | 1744 | 0 | 2397 | 2454 | 97.7% | +| ov_SC04_007 | 2433 | 1744 | 0 | 2437 | 2569 | 94.9% | +| ov_SC04_008 | 2382 | 1744 | 0 | 2382 | 2415 | 98.6% | +| ov_SC04_009 | 2396 | 1744 | 0 | 2399 | 2441 | 98.3% | +| ov_SC04_010 | 2384 | 1744 | 0 | 2385 | 2419 | 98.6% | +| ov_SC04_011 | 2470 | 1749 | 0 | 2476 | 2803 | 88.3% | +| ov_SC04_012 | 2383 | 1744 | 0 | 2384 | 2420 | 98.5% | +| ov_SC04_015 | 2453 | 1745 | 0 | 2464 | 2611 | 94.4% | +| ov_SC04_016 | 2382 | 1744 | 0 | 2384 | 2440 | 97.7% | +| ov_SC04_018 | 2540 | 1780 | 0 | 2540 | 2857 | 88.9% | +| ov_SC04_019 | 2540 | 1780 | 0 | 2540 | 2857 | 88.9% | +| ov_SC04_020 | 2417 | 1744 | 0 | 2429 | 2567 | 94.6% | +| ov_SC04_021 | 2385 | 1746 | 0 | 2385 | 2423 | 98.4% | +| ov_SC05_000 | 2383 | 1748 | 0 | 2386 | 2422 | 98.5% | +| ov_SC05_001 | 2428 | 1744 | 0 | 2433 | 2574 | 94.5% | +| ov_SC05_002 | 2395 | 1744 | 0 | 2398 | 2442 | 98.2% | +| ov_SC05_003 | 2391 | 1744 | 0 | 2392 | 2481 | 96.4% | +| ov_SC05_004 | 2384 | 1744 | 0 | 2386 | 2464 | 96.8% | +| ov_SC05_005 | 2401 | 1749 | 0 | 2402 | 2491 | 96.4% | +| ov_SC05_006 | 2390 | 1744 | 0 | 2390 | 2430 | 98.4% | +| ov_SC05_007 | 2401 | 1744 | 0 | 2406 | 2482 | 96.9% | +| ov_SC05_008 | 2411 | 1744 | 0 | 2413 | 2543 | 94.9% | +| ov_SC05_009 | 2390 | 1744 | 0 | 2394 | 2438 | 98.2% | +| ov_SC05_010 | 2423 | 1744 | 0 | 2427 | 2588 | 93.8% | +| ov_SC05_011 | 2381 | 1744 | 0 | 2382 | 2409 | 98.9% | +| ov_SC05_017 | 2522 | 1741 | 0 | 2533 | 2842 | 89.1% | +| ov_SC05_018 | 2448 | 1744 | 0 | 2461 | 2673 | 92.1% | +| ov_SC05_019 | 2385 | 1746 | 0 | 2385 | 2423 | 98.4% | +| ov_SC06_000 | 2483 | 1753 | 0 | 2486 | 2691 | 92.4% | +| ov_SC06_006 | 2407 | 1744 | 0 | 2408 | 2511 | 95.9% | +| ov_SC06_008 | 2431 | 1746 | 0 | 2437 | 2542 | 95.9% | +| ov_SC06_010 | 2412 | 1744 | 0 | 2417 | 2517 | 96.0% | +| ov_SC06_011 | 2394 | 1744 | 0 | 2398 | 2468 | 97.2% | +| ov_SC06_013 | 2385 | 1744 | 0 | 2386 | 2425 | 98.4% | +| ov_SC06_014 | 2394 | 1744 | 0 | 2396 | 2453 | 97.7% | +| ov_SC06_015 | 2389 | 1744 | 0 | 2389 | 2421 | 98.7% | +| ov_SC06_016 | 2411 | 1744 | 0 | 2413 | 2549 | 94.7% | +| ov_SC06_018 | 2437 | 1746 | 0 | 2444 | 2665 | 91.7% | +| ov_SC06_020 | 2406 | 1746 | 0 | 2407 | 2518 | 95.6% | +| ov_SC06_022 | 2434 | 1744 | 0 | 2442 | 2642 | 92.4% | +| ov_SC06_024 | 2445 | 1744 | 0 | 2451 | 2667 | 91.9% | +| ov_SC06_025 | 2418 | 1744 | 0 | 2423 | 2572 | 94.2% | +| ov_SC06_027 | 2375 | 1744 | 0 | 2376 | 2408 | 98.7% | +| ov_SC06_029 | 2442 | 1744 | 0 | 2454 | 2662 | 92.2% | +| ov_SC06_030 | 2388 | 1744 | 0 | 2388 | 2456 | 97.2% | +| ov_SC06_032 | 2430 | 1745 | 0 | 2437 | 2658 | 91.7% | +| ov_SC06_033 | 2430 | 1745 | 0 | 2437 | 2631 | 92.6% | +| ov_SC07_000 | 2404 | 1748 | 0 | 2406 | 2521 | 95.4% | +| ov_SC07_001 | 2388 | 1744 | 0 | 2390 | 2454 | 97.4% | +| ov_SC07_002 | 2418 | 1744 | 0 | 2422 | 2579 | 93.9% | +| ov_SC07_006 | 2280 | 1560 | 0 | 2360 | 2456 | 96.1% | +| ov_SC07_007 | 2308 | 1592 | 0 | 2392 | 2613 | 91.5% | +| ov_SC07_008 | 2370 | 1744 | 0 | 2370 | 2386 | 99.3% | +| ov_SC07_009 | 2380 | 1744 | 0 | 2382 | 2430 | 98.0% | +| ov_SC07_010 | 2292 | 1614 | 0 | 2375 | 2524 | 94.1% | +| ov_SC07_011 | 2303 | 1591 | 0 | 2383 | 2449 | 97.3% | diff --git a/phase-ends/CURRENT_PHASE.md b/phase-ends/CURRENT_PHASE.md index 7a3f30431f..e7713dddfd 100644 --- a/phase-ends/CURRENT_PHASE.md +++ b/phase-ends/CURRENT_PHASE.md @@ -559,6 +559,41 @@ one is a genuine byte DIFF.** Two are proven defects in `tools/family_remap.py`, `_def_head_at('extern void func_801466F0(s32 a0, s32 a1, s32 a2, s32 a3,', idx) -> True`. This is the §110/R35 class again — a silent 0/137 wearing a compiler wall's clothes. +**S6b — the fix belongs in the TOOL, not in 17 exemplars (R33).** The plan was to hand-move each +MISSING-TYPE exemplar's typedef into its function body (§100, byte-neutral, 17 edits + 17 verifications). +Probing the class first showed it is the SAME root cause as D1/D2 — a multi-line construct read one line +at a time — so it was fixed once, in `family_remap`, for every future family instead: +- **D5 — `_typedef_block_start()`**: on a `} T;` closing line, walk up to the matching `typedef` (both + the `typedef struct {` and brace-on-its-own-line forms) and carry the WHOLE block. Only blocks that + literally begin with `typedef` are carried (a struct VARIABLE closes identically but would be a + duplicate global in the sibling); safe because `harvest_verify` already strips a typedef the sibling + TU provides. The old code comment claimed these functions "route through the engine_types.h lift" — + measured, they routed **nowhere**: 17 families / 24,332 ins were simply dropped. +- **D4 — the wrapped asm-label alias** (`_alias_decl_for` is a single-line `rx.match`) was MEASURED + (1 exemplar, `0x801466f0`, 137 members / 3,288 ins, with a second blocker behind it) and deliberately + **left unfixed**. It now returns `None`, so the sweep reports `skipped {'no matched unit for func'}` + instead of failing 137 times. **A known gap that announces itself is not the same defect as a silent + one** (R32). +- Also hardened: the forward body scan now counts braces in `cdecl._mask`ed text (R33 — one masking + oracle), so a brace inside a comment or string can never close a function body. + +**Blast radius verified, not assumed (R14):** `extract_unit` output diffed against the pre-S6 tool over +all 181 zero-crack exemplars — **157 byte-IDENTICAL**, 24 changed, every change in the intended +direction (more preamble carried; one → `None`, the D4 case that previously produced garbage). + +**Measured payoff of the repairs, one sweep each:** +· D1+D2 → **+323 members** recovered from families that had banked **zero**. +· D5 → **+417 members**, including `func_8012B77C` **139/139** (8,062 ins — the head prize) and + `func_80128C98` 137/275; `func_80146AFC` 135/137, `func_80176144` 99/137. +· **S6 total: 1,582 member-matches.** The pre-fix tool scored this same population at 842. +**R22 clean-fleet `make clean` + extract-all + check-all → 140 passed, 0 failed of 140.** +Fleet **94.43→94.88% fn-count · 91.4→91.9% instr · 84.0→84.6% distinct**; phase arc from open +(92.00 / 87.5 / 78.0) = **+2.88pp fn · +4.4pp instr · +6.6pp distinct**. + +**Family state now: 70 ALL-banked · 17 partial · 94 zero-banked; 64,050 templatable ins still open.** +Distilled to **cookbook §134** (the MULTI-LINE BLINDNESS class + the bimodality tell: 57/52/8 is a +tooling signature, not a codegen one — read ONE compiler error before believing the compiler). + ### ✅ S3 — the close=0 stored-draft DIAGNOSTIC pass: measured, classified, and correctly NOT scaled (2026-08-01) Chartered as "classify, and only build a fix if ≥3 share a named class". Ran exactly that; the answer is that no cheap shared class exists, so nothing was scaled. **The population is bigger than the plan diff --git a/src/ov_SC01_000/ov_SC01_000.c b/src/ov_SC01_000/ov_SC01_000.c index f3ed673ab7..f2c99d8967 100644 --- a/src/ov_SC01_000/ov_SC01_000.c +++ b/src/ov_SC01_000/ov_SC01_000.c @@ -385,7 +385,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017EEB8[]; + s16 idx = D_8017EEB8[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A3234, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000", func_80128CFC); diff --git a/src/ov_SC01_000/ov_SC01_000_after.c b/src/ov_SC01_000/ov_SC01_000_after.c index 40df2bac9a..853d6a1533 100644 --- a/src/ov_SC01_000/ov_SC01_000_after.c +++ b/src/ov_SC01_000/ov_SC01_000_after.c @@ -479,7 +479,84 @@ INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC01_000/ov_SC01_000_jr_8012ACE0.c b/src/ov_SC01_000/ov_SC01_000_jr_8012ACE0.c index 4c60d3ec33..5f9f0e8f86 100644 --- a/src/ov_SC01_000/ov_SC01_000_jr_8012ACE0.c +++ b/src/ov_SC01_000/ov_SC01_000_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC01_000/ov_SC01_000_jr_801734BC.c b/src/ov_SC01_000/ov_SC01_000_jr_801734BC.c index d770b27196..398e90288e 100644 --- a/src/ov_SC01_000/ov_SC01_000_jr_801734BC.c +++ b/src/ov_SC01_000/ov_SC01_000_jr_801734BC.c @@ -3222,7 +3222,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC01_000/ov_SC01_000_jr_8017BEBC.c b/src/ov_SC01_000/ov_SC01_000_jr_8017BEBC.c index e5e7e11c05..8da217a436 100644 --- a/src/ov_SC01_000/ov_SC01_000_jr_8017BEBC.c +++ b/src/ov_SC01_000/ov_SC01_000_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3243,7 +3242,32 @@ void func_8017D1B4(void *a0) { } -INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8017BEBC", func_8017D1F0); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D1F0; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D290(s32 param_1, s16 *param_2); + +void func_8017D1F0(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_801826B0[]; + extern Blk8_80126940_8017D1F0 D_80126940; + Blk8_80126940_8017D1F0 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_801826B0[t]; + } + sp10 = D_80126940; + func_8017D290(a0, sp10.v); +} + // @class: schedule diff --git a/src/ov_SC01_001/ov_SC01_001.c b/src/ov_SC01_001/ov_SC01_001.c index fe171c88c2..2c01a96094 100644 --- a/src/ov_SC01_001/ov_SC01_001.c +++ b/src/ov_SC01_001/ov_SC01_001.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80183B08[]; + s16 idx = D_80183B08[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801EB30C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001", func_80128CFC); diff --git a/src/ov_SC01_001/ov_SC01_001_after.c b/src/ov_SC01_001/ov_SC01_001_after.c index c5470cd296..1cb3800591 100644 --- a/src/ov_SC01_001/ov_SC01_001_after.c +++ b/src/ov_SC01_001/ov_SC01_001_after.c @@ -479,7 +479,84 @@ INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC01_001/ov_SC01_001_jr_8012ACE0.c b/src/ov_SC01_001/ov_SC01_001_jr_8012ACE0.c index 8a8fe5187d..fd86a20c0d 100644 --- a/src/ov_SC01_001/ov_SC01_001_jr_8012ACE0.c +++ b/src/ov_SC01_001/ov_SC01_001_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC01_001/ov_SC01_001_jr_801734BC.c b/src/ov_SC01_001/ov_SC01_001_jr_801734BC.c index 1e5ed3414b..a6d6ba458b 100644 --- a/src/ov_SC01_001/ov_SC01_001_jr_801734BC.c +++ b/src/ov_SC01_001/ov_SC01_001_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC01_001/ov_SC01_001_jr_8017BEBC.c b/src/ov_SC01_001/ov_SC01_001_jr_8017BEBC.c index 85c45443f9..d550bb3772 100644 --- a/src/ov_SC01_001/ov_SC01_001_jr_8017BEBC.c +++ b/src/ov_SC01_001/ov_SC01_001_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3223,7 +3222,32 @@ void func_8017D060(void *a0) { } -INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8017BEBC", func_8017D09C); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D09C; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D13C(s32 param_1, s16 *param_2); + +void func_8017D09C(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_801872BC[]; + extern Blk8_80126940_8017D09C D_80126940; + Blk8_80126940_8017D09C sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_801872BC[t]; + } + sp10 = D_80126940; + func_8017D13C(a0, sp10.v); +} + // @class: schedule diff --git a/src/ov_SC01_004/ov_SC01_004.c b/src/ov_SC01_004/ov_SC01_004.c index 0249c4fabb..2d4a2c8d73 100644 --- a/src/ov_SC01_004/ov_SC01_004.c +++ b/src/ov_SC01_004/ov_SC01_004.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017F4CC[]; + s16 idx = D_8017F4CC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8018D6EC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004", func_80128CFC); diff --git a/src/ov_SC01_004/ov_SC01_004_after.c b/src/ov_SC01_004/ov_SC01_004_after.c index d06404889b..ffd1fe18c7 100644 --- a/src/ov_SC01_004/ov_SC01_004_after.c +++ b/src/ov_SC01_004/ov_SC01_004_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC01_004/ov_SC01_004_jr_8012ACE0.c b/src/ov_SC01_004/ov_SC01_004_jr_8012ACE0.c index 9e0fb00aec..d928ed6a37 100644 --- a/src/ov_SC01_004/ov_SC01_004_jr_8012ACE0.c +++ b/src/ov_SC01_004/ov_SC01_004_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC01_004/ov_SC01_004_jr_801734BC.c b/src/ov_SC01_004/ov_SC01_004_jr_801734BC.c index 6fe1a0b9fe..6743fdc65d 100644 --- a/src/ov_SC01_004/ov_SC01_004_jr_801734BC.c +++ b/src/ov_SC01_004/ov_SC01_004_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC01_005/ov_SC01_005.c b/src/ov_SC01_005/ov_SC01_005.c index f495176973..6674e25417 100644 --- a/src/ov_SC01_005/ov_SC01_005.c +++ b/src/ov_SC01_005/ov_SC01_005.c @@ -388,7 +388,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80182660[]; + s16 idx = D_80182660[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801CAE4C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005", func_80128CFC); diff --git a/src/ov_SC01_005/ov_SC01_005_after.c b/src/ov_SC01_005/ov_SC01_005_after.c index a9095557ae..1eaa7cd294 100644 --- a/src/ov_SC01_005/ov_SC01_005_after.c +++ b/src/ov_SC01_005/ov_SC01_005_after.c @@ -482,7 +482,84 @@ INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC01_005/ov_SC01_005_jr_8012ACE0.c b/src/ov_SC01_005/ov_SC01_005_jr_8012ACE0.c index 81020ef085..78b80731e0 100644 --- a/src/ov_SC01_005/ov_SC01_005_jr_8012ACE0.c +++ b/src/ov_SC01_005/ov_SC01_005_jr_8012ACE0.c @@ -325,7 +325,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC01_005/ov_SC01_005_jr_801734BC.c b/src/ov_SC01_005/ov_SC01_005_jr_801734BC.c index b4326af9be..251a75f04f 100644 --- a/src/ov_SC01_005/ov_SC01_005_jr_801734BC.c +++ b/src/ov_SC01_005/ov_SC01_005_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC01_006/ov_SC01_006.c b/src/ov_SC01_006/ov_SC01_006.c index 48c660630c..cbb3d9a71b 100644 --- a/src/ov_SC01_006/ov_SC01_006.c +++ b/src/ov_SC01_006/ov_SC01_006.c @@ -388,7 +388,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80182660[]; + s16 idx = D_80182660[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801CAE4C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006", func_80128CFC); diff --git a/src/ov_SC01_006/ov_SC01_006_after.c b/src/ov_SC01_006/ov_SC01_006_after.c index 93a05f2482..1580e717fd 100644 --- a/src/ov_SC01_006/ov_SC01_006_after.c +++ b/src/ov_SC01_006/ov_SC01_006_after.c @@ -482,7 +482,84 @@ INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC01_006/ov_SC01_006_jr_8012ACE0.c b/src/ov_SC01_006/ov_SC01_006_jr_8012ACE0.c index 70f971e8b5..39bec39714 100644 --- a/src/ov_SC01_006/ov_SC01_006_jr_8012ACE0.c +++ b/src/ov_SC01_006/ov_SC01_006_jr_8012ACE0.c @@ -325,7 +325,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC01_006/ov_SC01_006_jr_801734BC.c b/src/ov_SC01_006/ov_SC01_006_jr_801734BC.c index 576f8e5178..fa17d9fa4a 100644 --- a/src/ov_SC01_006/ov_SC01_006_jr_801734BC.c +++ b/src/ov_SC01_006/ov_SC01_006_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC01_008/ov_SC01_008.c b/src/ov_SC01_008/ov_SC01_008.c index c8bf9a5da9..8f58a2d018 100644 --- a/src/ov_SC01_008/ov_SC01_008.c +++ b/src/ov_SC01_008/ov_SC01_008.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017FA40[]; + s16 idx = D_8017FA40[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A08FC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008", func_80128CFC); diff --git a/src/ov_SC01_008/ov_SC01_008_after.c b/src/ov_SC01_008/ov_SC01_008_after.c index 9f76aed523..cfd7dd69fe 100644 --- a/src/ov_SC01_008/ov_SC01_008_after.c +++ b/src/ov_SC01_008/ov_SC01_008_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC01_008/ov_SC01_008_jr_8012ACE0.c b/src/ov_SC01_008/ov_SC01_008_jr_8012ACE0.c index defa2aac75..062d1de754 100644 --- a/src/ov_SC01_008/ov_SC01_008_jr_8012ACE0.c +++ b/src/ov_SC01_008/ov_SC01_008_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC01_008/ov_SC01_008_jr_801734BC.c b/src/ov_SC01_008/ov_SC01_008_jr_801734BC.c index 582d45e8d4..0967919bc5 100644 --- a/src/ov_SC01_008/ov_SC01_008_jr_801734BC.c +++ b/src/ov_SC01_008/ov_SC01_008_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC01_009/ov_SC01_009.c b/src/ov_SC01_009/ov_SC01_009.c index 76e80f31a5..33f2013b33 100644 --- a/src/ov_SC01_009/ov_SC01_009.c +++ b/src/ov_SC01_009/ov_SC01_009.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80182C28[]; + s16 idx = D_80182C28[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801F06C0, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009", func_80128CFC); diff --git a/src/ov_SC01_009/ov_SC01_009_after.c b/src/ov_SC01_009/ov_SC01_009_after.c index 001ec660a5..96fe9f0702 100644 --- a/src/ov_SC01_009/ov_SC01_009_after.c +++ b/src/ov_SC01_009/ov_SC01_009_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC01_009/ov_SC01_009_jr_8012ACE0.c b/src/ov_SC01_009/ov_SC01_009_jr_8012ACE0.c index 9cf2c5a5c2..4436ac923a 100644 --- a/src/ov_SC01_009/ov_SC01_009_jr_8012ACE0.c +++ b/src/ov_SC01_009/ov_SC01_009_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC01_009/ov_SC01_009_jr_801734BC.c b/src/ov_SC01_009/ov_SC01_009_jr_801734BC.c index a748a9a811..6cd3f69ede 100644 --- a/src/ov_SC01_009/ov_SC01_009_jr_801734BC.c +++ b/src/ov_SC01_009/ov_SC01_009_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC01_074/ov_SC01_074.c b/src/ov_SC01_074/ov_SC01_074.c index 4395067cde..eb4fc02a79 100644 --- a/src/ov_SC01_074/ov_SC01_074.c +++ b/src/ov_SC01_074/ov_SC01_074.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017E8A8[]; + s16 idx = D_8017E8A8[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80199750, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074", func_80128CFC); diff --git a/src/ov_SC01_074/ov_SC01_074_after.c b/src/ov_SC01_074/ov_SC01_074_after.c index be69f5cf96..6e5e40a7da 100644 --- a/src/ov_SC01_074/ov_SC01_074_after.c +++ b/src/ov_SC01_074/ov_SC01_074_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC01_074/ov_SC01_074_jr_8012ACE0.c b/src/ov_SC01_074/ov_SC01_074_jr_8012ACE0.c index f9dbe16155..bcbf9b4767 100644 --- a/src/ov_SC01_074/ov_SC01_074_jr_8012ACE0.c +++ b/src/ov_SC01_074/ov_SC01_074_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC01_074/ov_SC01_074_jr_801734BC.c b/src/ov_SC01_074/ov_SC01_074_jr_801734BC.c index 5fc6a8de5d..ca55a62ac4 100644 --- a/src/ov_SC01_074/ov_SC01_074_jr_801734BC.c +++ b/src/ov_SC01_074/ov_SC01_074_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c b/src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c index dcd09d46ad..da09611f5c 100644 --- a/src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c +++ b/src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c @@ -397,7 +397,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC01_080/ov_SC01_080.c b/src/ov_SC01_080/ov_SC01_080.c index 8e1ab01c24..0ee686dbbf 100644 --- a/src/ov_SC01_080/ov_SC01_080.c +++ b/src/ov_SC01_080/ov_SC01_080.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80183808[]; + s16 idx = D_80183808[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C3570, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080", func_80128CFC); diff --git a/src/ov_SC01_080/ov_SC01_080_after.c b/src/ov_SC01_080/ov_SC01_080_after.c index 699d406292..027d40bef0 100644 --- a/src/ov_SC01_080/ov_SC01_080_after.c +++ b/src/ov_SC01_080/ov_SC01_080_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC01_080/ov_SC01_080_jr_8012ACE0.c b/src/ov_SC01_080/ov_SC01_080_jr_8012ACE0.c index 5c0f44b757..9bf35193c6 100644 --- a/src/ov_SC01_080/ov_SC01_080_jr_8012ACE0.c +++ b/src/ov_SC01_080/ov_SC01_080_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC01_080/ov_SC01_080_jr_801734BC.c b/src/ov_SC01_080/ov_SC01_080_jr_801734BC.c index dec4f5db4f..6daf51bfc6 100644 --- a/src/ov_SC01_080/ov_SC01_080_jr_801734BC.c +++ b/src/ov_SC01_080/ov_SC01_080_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC01_084/ov_SC01_084.c b/src/ov_SC01_084/ov_SC01_084.c index 9236469753..35f50e0130 100644 --- a/src/ov_SC01_084/ov_SC01_084.c +++ b/src/ov_SC01_084/ov_SC01_084.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80186AFC[]; + s16 idx = D_80186AFC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C4F40, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084", func_80128CFC); diff --git a/src/ov_SC01_084/ov_SC01_084_after.c b/src/ov_SC01_084/ov_SC01_084_after.c index 9c0018172c..f62c125ad5 100644 --- a/src/ov_SC01_084/ov_SC01_084_after.c +++ b/src/ov_SC01_084/ov_SC01_084_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC01_084/ov_SC01_084_jr_8012ACE0.c b/src/ov_SC01_084/ov_SC01_084_jr_8012ACE0.c index 3fed465d18..5ef19ad3a5 100644 --- a/src/ov_SC01_084/ov_SC01_084_jr_8012ACE0.c +++ b/src/ov_SC01_084/ov_SC01_084_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC01_084/ov_SC01_084_jr_801734BC.c b/src/ov_SC01_084/ov_SC01_084_jr_801734BC.c index 945e6afbc3..cdd37b6055 100644 --- a/src/ov_SC01_084/ov_SC01_084_jr_801734BC.c +++ b/src/ov_SC01_084/ov_SC01_084_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_000/ov_SC02_000.c b/src/ov_SC02_000/ov_SC02_000.c index e7cf0ed86f..020c22df1b 100644 --- a/src/ov_SC02_000/ov_SC02_000.c +++ b/src/ov_SC02_000/ov_SC02_000.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018AEAC[]; + s16 idx = D_8018AEAC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801E5794, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000", func_80128CFC); diff --git a/src/ov_SC02_000/ov_SC02_000_after.c b/src/ov_SC02_000/ov_SC02_000_after.c index d6a7e37e29..fa689dd268 100644 --- a/src/ov_SC02_000/ov_SC02_000_after.c +++ b/src/ov_SC02_000/ov_SC02_000_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_000/ov_SC02_000_jr_8012ACE0.c b/src/ov_SC02_000/ov_SC02_000_jr_8012ACE0.c index 6c5338ea9f..1d517ae739 100644 --- a/src/ov_SC02_000/ov_SC02_000_jr_8012ACE0.c +++ b/src/ov_SC02_000/ov_SC02_000_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_000/ov_SC02_000_jr_801734BC.c b/src/ov_SC02_000/ov_SC02_000_jr_801734BC.c index f7fbc736af..d638d204a9 100644 --- a/src/ov_SC02_000/ov_SC02_000_jr_801734BC.c +++ b/src/ov_SC02_000/ov_SC02_000_jr_801734BC.c @@ -3170,7 +3170,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_000/ov_SC02_000_jr_8017AE2C.c b/src/ov_SC02_000/ov_SC02_000_jr_8017AE2C.c index 7005386234..48f3585512 100644 --- a/src/ov_SC02_000/ov_SC02_000_jr_8017AE2C.c +++ b/src/ov_SC02_000/ov_SC02_000_jr_8017AE2C.c @@ -3355,7 +3355,47 @@ void func_8017BF84(int param_1) } -INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8017AE2C", func_8017BFE0); + +/* Entity record touched by func_8017BFE0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017BFE0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017BFE0; + +extern void func_80147324(s32 arg0); +extern void func_8017C218(int); + +void func_8017BFE0(Ent_8017BFE0_8017BFE0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017BFE0 *))func_8017C218)(param_1); +} + INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8017AE2C", func_8017C064); @@ -3483,7 +3523,72 @@ void func_8017C7C4(void *a0) { } -INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8017AE2C", func_8017C800); + +/* func_8017C800 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017C800(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + DEFINE_func_8017C8B4() /* dedup: shared engine-core @0x8017C8B4 (src/shared) */ diff --git a/src/ov_SC02_003/ov_SC02_003.c b/src/ov_SC02_003/ov_SC02_003.c index 397facff7f..4cd2778399 100644 --- a/src/ov_SC02_003/ov_SC02_003.c +++ b/src/ov_SC02_003/ov_SC02_003.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018AEAC[]; + s16 idx = D_8018AEAC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801E5794, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003", func_80128CFC); diff --git a/src/ov_SC02_003/ov_SC02_003_after.c b/src/ov_SC02_003/ov_SC02_003_after.c index 7395951418..de221f9fd7 100644 --- a/src/ov_SC02_003/ov_SC02_003_after.c +++ b/src/ov_SC02_003/ov_SC02_003_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_003/ov_SC02_003_jr_8012ACE0.c b/src/ov_SC02_003/ov_SC02_003_jr_8012ACE0.c index 2bf9d820a4..c68873d8d4 100644 --- a/src/ov_SC02_003/ov_SC02_003_jr_8012ACE0.c +++ b/src/ov_SC02_003/ov_SC02_003_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_003/ov_SC02_003_jr_801734BC.c b/src/ov_SC02_003/ov_SC02_003_jr_801734BC.c index 38224416bd..70bf498ca8 100644 --- a/src/ov_SC02_003/ov_SC02_003_jr_801734BC.c +++ b/src/ov_SC02_003/ov_SC02_003_jr_801734BC.c @@ -3170,7 +3170,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_003/ov_SC02_003_jr_8017AE2C.c b/src/ov_SC02_003/ov_SC02_003_jr_8017AE2C.c index f8d8ecdd6e..ffe68f9f2d 100644 --- a/src/ov_SC02_003/ov_SC02_003_jr_8017AE2C.c +++ b/src/ov_SC02_003/ov_SC02_003_jr_8017AE2C.c @@ -3355,7 +3355,47 @@ void func_8017BF84(int param_1) } -INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8017AE2C", func_8017BFE0); + +/* Entity record touched by func_8017BFE0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017BFE0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017BFE0; + +extern void func_80147324(s32 arg0); +extern void func_8017C218(int); + +void func_8017BFE0(Ent_8017BFE0_8017BFE0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017BFE0 *))func_8017C218)(param_1); +} + INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8017AE2C", func_8017C064); @@ -3483,7 +3523,72 @@ void func_8017C7C4(void *a0) { } -INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8017AE2C", func_8017C800); + +/* func_8017C800 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017C800(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + DEFINE_func_8017C8B4() /* dedup: shared engine-core @0x8017C8B4 (src/shared) */ diff --git a/src/ov_SC02_003/ov_SC02_003_jr_8017FCB0.c b/src/ov_SC02_003/ov_SC02_003_jr_8017FCB0.c index b3c71d2db5..290cc19812 100644 --- a/src/ov_SC02_003/ov_SC02_003_jr_8017FCB0.c +++ b/src/ov_SC02_003/ov_SC02_003_jr_8017FCB0.c @@ -4164,7 +4164,67 @@ INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8017FCB0", func_8018A3F INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8017FCB0", func_8018A440); -INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8017FCB0", func_8018A550); + +extern void func_8001D074(s32 a0, s32 a1); +extern void func_8001CD04(s32 a0, s32 a1); + +typedef struct Obj_8018A550_8018A550 { + s32 f0; /* 0x00 */ + u32 f4; /* 0x04 */ + s32 f8; /* 0x08 */ + s32 fC; /* 0x0C */ + s32 f10; /* 0x10 */ + s32 f14; /* 0x14 */ + s16 f18; /* 0x18 */ + s16 f1A; /* 0x1A */ + s16 f1C; /* 0x1C */ + s16 f1E; /* 0x1E */ +} Obj_8018A550_8018A550; + +typedef struct Rec_8018A550_8018A550 { + u16 f0; /* 0x00 */ + u16 f2; /* 0x02 */ + s16 f4; /* 0x04 */ + s16 f6; /* 0x06 */ + s32 f8; /* 0x08 */ + s32 fC; /* 0x0C */ +} Rec_8018A550_8018A550; + +typedef struct Ctl_8018A550_8018A550 { + s32 f0; /* 0x00 */ + s16 ids[8]; /* 0x04 */ + Obj_8018A550_8018A550 *slots[8]; /* 0x14 */ +} Ctl_8018A550_8018A550; + +void func_8018A550(Ctl_8018A550_8018A550 *ctl, Rec_8018A550_8018A550 *rec) +{ + s32 i; + Obj_8018A550_8018A550 *m; + s16 v; + u16 t; + + do { + for (i = 0; i < 8; i++) { + if (ctl->slots[i] == 0) { + break; + } + } + m = (Obj_8018A550_8018A550 *)((s32 (*)(s32, s32))func_8001D074)(0x7E, 0x100); + if (m != 0) { + ((void (*)(Obj_8018A550_8018A550 *, s32))func_8001CD04)(m, rec->fC); + m->f4 |= 0xF0000000; + v = rec->f6; + m->f1C = v; + m->f1A = v; + m->f18 = v; + ctl->slots[i] = m; + ctl->ids[i] = rec->f4; + } + t = rec->f0; + rec++; + } while (t != 0xFF); +} + diff --git a/src/ov_SC02_004/ov_SC02_004.c b/src/ov_SC02_004/ov_SC02_004.c index ffe3a923cb..9b94fa2892 100644 --- a/src/ov_SC02_004/ov_SC02_004.c +++ b/src/ov_SC02_004/ov_SC02_004.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017DF8C[]; + s16 idx = D_8017DF8C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80193DA4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004", func_80128CFC); diff --git a/src/ov_SC02_004/ov_SC02_004_after.c b/src/ov_SC02_004/ov_SC02_004_after.c index 51438a1964..75d1328146 100644 --- a/src/ov_SC02_004/ov_SC02_004_after.c +++ b/src/ov_SC02_004/ov_SC02_004_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_004/ov_SC02_004_jr_8012ACE0.c b/src/ov_SC02_004/ov_SC02_004_jr_8012ACE0.c index 1e7bf8b01f..a0540d30a8 100644 --- a/src/ov_SC02_004/ov_SC02_004_jr_8012ACE0.c +++ b/src/ov_SC02_004/ov_SC02_004_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_004/ov_SC02_004_jr_801734BC.c b/src/ov_SC02_004/ov_SC02_004_jr_801734BC.c index fef61d5ec4..6257668058 100644 --- a/src/ov_SC02_004/ov_SC02_004_jr_801734BC.c +++ b/src/ov_SC02_004/ov_SC02_004_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_005/ov_SC02_005.c b/src/ov_SC02_005/ov_SC02_005.c index 65c82cf43e..5c8985be2a 100644 --- a/src/ov_SC02_005/ov_SC02_005.c +++ b/src/ov_SC02_005/ov_SC02_005.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80190B90[]; + s16 idx = D_80190B90[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801E1AD8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005", func_80128CFC); diff --git a/src/ov_SC02_005/ov_SC02_005_after.c b/src/ov_SC02_005/ov_SC02_005_after.c index c329a7ef60..eb1f3089f9 100644 --- a/src/ov_SC02_005/ov_SC02_005_after.c +++ b/src/ov_SC02_005/ov_SC02_005_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_005/ov_SC02_005_jr_8012ACE0.c b/src/ov_SC02_005/ov_SC02_005_jr_8012ACE0.c index 16bfd8050b..b17e314433 100644 --- a/src/ov_SC02_005/ov_SC02_005_jr_8012ACE0.c +++ b/src/ov_SC02_005/ov_SC02_005_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_005/ov_SC02_005_jr_801734BC.c b/src/ov_SC02_005/ov_SC02_005_jr_801734BC.c index 852db4154e..35145d124e 100644 --- a/src/ov_SC02_005/ov_SC02_005_jr_801734BC.c +++ b/src/ov_SC02_005/ov_SC02_005_jr_801734BC.c @@ -3174,7 +3174,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_011/ov_SC02_011.c b/src/ov_SC02_011/ov_SC02_011.c index 7abb8ca710..9ed24011ce 100644 --- a/src/ov_SC02_011/ov_SC02_011.c +++ b/src/ov_SC02_011/ov_SC02_011.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80190FE0[]; + s16 idx = D_80190FE0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801E8C34, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011", func_80128CFC); diff --git a/src/ov_SC02_011/ov_SC02_011_after.c b/src/ov_SC02_011/ov_SC02_011_after.c index 6887347b34..9b893904c7 100644 --- a/src/ov_SC02_011/ov_SC02_011_after.c +++ b/src/ov_SC02_011/ov_SC02_011_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_011/ov_SC02_011_jr_8012ACE0.c b/src/ov_SC02_011/ov_SC02_011_jr_8012ACE0.c index a7da6d9c9a..0195435aa2 100644 --- a/src/ov_SC02_011/ov_SC02_011_jr_8012ACE0.c +++ b/src/ov_SC02_011/ov_SC02_011_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_011/ov_SC02_011_jr_801734BC.c b/src/ov_SC02_011/ov_SC02_011_jr_801734BC.c index 5bbc58b2dd..291aa2a060 100644 --- a/src/ov_SC02_011/ov_SC02_011_jr_801734BC.c +++ b/src/ov_SC02_011/ov_SC02_011_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c b/src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c index cfb6e6de8a..ab8b584f56 100644 --- a/src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c +++ b/src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c @@ -3664,7 +3664,67 @@ INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8017FCA INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8017FD2C); -INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8017FD9C); + +/* func_8017FD9C — fade the 4-byte colour quad at D_801EB488 one step toward 0 + * (func_80012F74 = "step a value toward a target"), splat the byte over the + * three sibling bytes, mirror the whole quad into the three following quads, + * then tear the entity down once the byte reaches 0. + * + * §71 sibling-first: DEFINE_func_801685EC() (engine_core.h L8520) is the same + * `if ( == 0) ((void (*)(s32))func_80146C3C)(arg0);` teardown tail. + * In-TU sibling func_8017D678 shows D_801EB489/D_801EB48A are SEPARATE u8 + * globals (each gets its own lui/%lo sb) while D_801EB488's address lives in a + * callee-saved register. + * + * @class: schedule (LENGTH-DRIFT/-1) + * @stuck: none — MATCH 50/50 (match_one AND rtu_match), iteration 2. + * THE CRACK (one edit): the TRAILING reload `if (*p == 0)` was being hoisted by + * sched2 up past the third block move, where the swl/swr pair covered its load + * delay — costing exactly the one `nop` the target keeps (49 vs 50 ins, + * LENGTH-DRIFT/-1). A second zero-byte `__asm__("")` fence between the last + * struct assignment and the `if` pins the lbu after the copies and the load-delay + * nop reappears. Lesson: an inline block move (swl/swr) is a fat delay-slot + * SPONGE — any following narrow load will be sucked up into it unless fenced. + * The first fence (after the chained byte stores) is what keeps the block moves + * from being interleaved with them. + * Other levers already in this draft, all load-bearing: + * - `u8 *p = &D_801EB488;` (§20) — one address register ($s0, callee-saved + * across the jal) serves the lbu, the sb and all three block-move sources. + * - chained assignment `D_801EB489 = D_801EB48A = *p = f(...)` gives the + * target's store order 880, 882, 881 (right-to-left after the *p store). + * - the 4×u8 struct (align 1) is what makes the assignment expand to inline + * lwl/lwr + swl/swr instead of a `jal memcpy` (cf. §38). + */ + +typedef struct { + u8 b0, b1, b2, b3; +} Quad_801EA880_8017FD9C; /* align 1 => movstrsi expands to lwl/lwr + swl/swr */ + + +extern s32 func_80012F74(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_80146C3C(void); + +void func_8017FD9C(s32 arg0) { + + extern u8 D_801EB488; + extern u8 D_801EB489; + extern u8 D_801EB48A; + extern u8 D_801EB48C; + extern u8 D_801EB490; + extern u8 D_801EB494; + u8 *p = &D_801EB488; + + D_801EB489 = D_801EB48A = *p = func_80012F74(*p, 0, 10, 1); + __asm__(""); + *(Quad_801EA880_8017FD9C *)&D_801EB48C = *(Quad_801EA880_8017FD9C *)p; + *(Quad_801EA880_8017FD9C *)&D_801EB490 = *(Quad_801EA880_8017FD9C *)p; + *(Quad_801EA880_8017FD9C *)&D_801EB494 = *(Quad_801EA880_8017FD9C *)p; + __asm__(""); + if (*p == 0) { + ((void (*)(s32))func_80146C3C)(arg0); + } +} + INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8017FE64); @@ -3788,7 +3848,47 @@ void func_801804E8(int param_1) } -INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_80180544); + +/* Entity record touched by func_80180544 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_80180544 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_80180544; + +extern void func_80147324(s32 arg0); +extern void func_8018077C(int); + +void func_80180544(Ent_8017BFE0_80180544 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_80180544 *))func_8018077C)(param_1); +} + INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_801805C8); @@ -3953,7 +4053,72 @@ void func_80180D28(void *a0) { } -INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_80180D64); + +/* func_80180D64 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_80180D64(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); @@ -5029,7 +5194,53 @@ void func_8018A708(void) { } -INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8018A72C); + +/* func_8018A72C — cookbook §71 (sibling-first). + * func_8018A7CC is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_8018A7CC(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_8018A8E8 (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_8018A72C; + +extern void func_8018A7CC(s32 arg0, s32 arg1, s32 arg2); +extern void func_8018A8E8(s32 arg0, Rec_8018A6A4_8018A72C *arg1, s32 arg2, s32 arg3); + +void func_8018A72C(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_8018A72C sp10; + s32 i; + s32 ang; + + func_8018A7CC(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_8018A8E8(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + extern s16 D_801EB6DC; @@ -5061,7 +5272,57 @@ INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8018A9B INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8018A9F8); -INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8018AA44); + +/* func_8018AA44 — 16-entry table walk, stride 0xE, over D_801EB6E4. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801EB6E4; s16 *p = &D_801EB6E4; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_8018AB20(s32 arg0); + +void func_8018AA44(void) { + + extern s16 D_801EB6E4; + s16 *p = &D_801EB6E4; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_8018AB20(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8017AE2C", func_8018AB20); diff --git a/src/ov_SC02_015/ov_SC02_015.c b/src/ov_SC02_015/ov_SC02_015.c index f0e844441a..c9b68f9001 100644 --- a/src/ov_SC02_015/ov_SC02_015.c +++ b/src/ov_SC02_015/ov_SC02_015.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_015/nonmatchings/ov_SC02_015", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017E4F4[]; + s16 idx = D_8017E4F4[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8018DE8C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_015/nonmatchings/ov_SC02_015", func_80128CFC); diff --git a/src/ov_SC02_015/ov_SC02_015_after.c b/src/ov_SC02_015/ov_SC02_015_after.c index dca471700d..4e0ae65fe0 100644 --- a/src/ov_SC02_015/ov_SC02_015_after.c +++ b/src/ov_SC02_015/ov_SC02_015_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_015/nonmatchings/ov_SC02_015_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_015/nonmatchings/ov_SC02_015_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_015/ov_SC02_015_jr_8012ACE0.c b/src/ov_SC02_015/ov_SC02_015_jr_8012ACE0.c index c3ea77b041..351ecddc49 100644 --- a/src/ov_SC02_015/ov_SC02_015_jr_8012ACE0.c +++ b/src/ov_SC02_015/ov_SC02_015_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_015/nonmatchings/ov_SC02_015_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_015/ov_SC02_015_jr_801734BC.c b/src/ov_SC02_015/ov_SC02_015_jr_801734BC.c index f3ec70552d..2bdb58f1e6 100644 --- a/src/ov_SC02_015/ov_SC02_015_jr_801734BC.c +++ b/src/ov_SC02_015/ov_SC02_015_jr_801734BC.c @@ -3170,7 +3170,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_015/nonmatchings/ov_SC02_015_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_016/ov_SC02_016.c b/src/ov_SC02_016/ov_SC02_016.c index 3a6d1198f7..2c469cf406 100644 --- a/src/ov_SC02_016/ov_SC02_016.c +++ b/src/ov_SC02_016/ov_SC02_016.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_016/nonmatchings/ov_SC02_016", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018472C[]; + s16 idx = D_8018472C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B1A6C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_016/nonmatchings/ov_SC02_016", func_80128CFC); diff --git a/src/ov_SC02_016/ov_SC02_016_after.c b/src/ov_SC02_016/ov_SC02_016_after.c index 7f11986be5..d60eaab886 100644 --- a/src/ov_SC02_016/ov_SC02_016_after.c +++ b/src/ov_SC02_016/ov_SC02_016_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_016/nonmatchings/ov_SC02_016_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_016/nonmatchings/ov_SC02_016_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_016/ov_SC02_016_jr_8012ACE0.c b/src/ov_SC02_016/ov_SC02_016_jr_8012ACE0.c index 901948d67c..e9afc26a52 100644 --- a/src/ov_SC02_016/ov_SC02_016_jr_8012ACE0.c +++ b/src/ov_SC02_016/ov_SC02_016_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_016/nonmatchings/ov_SC02_016_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_016/ov_SC02_016_jr_801734BC.c b/src/ov_SC02_016/ov_SC02_016_jr_801734BC.c index 5efe338171..8f514608f4 100644 --- a/src/ov_SC02_016/ov_SC02_016_jr_801734BC.c +++ b/src/ov_SC02_016/ov_SC02_016_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_016/nonmatchings/ov_SC02_016_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_016/ov_SC02_016_jr_8017AE2C.c b/src/ov_SC02_016/ov_SC02_016_jr_8017AE2C.c index a5e06ebaca..45f0fe50ab 100644 --- a/src/ov_SC02_016/ov_SC02_016_jr_8017AE2C.c +++ b/src/ov_SC02_016/ov_SC02_016_jr_8017AE2C.c @@ -3518,7 +3518,47 @@ void func_8017D174(int param_1) } -INCLUDE_ASM("asm/ov_SC02_016/nonmatchings/ov_SC02_016_jr_8017AE2C", func_8017D1D0); + +/* Entity record touched by func_8017D1D0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017D1D0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017D1D0; + +extern void func_80147324(s32 arg0); +extern void func_8017D408(int); + +void func_8017D1D0(Ent_8017BFE0_8017D1D0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017D1D0 *))func_8017D408)(param_1); +} + INCLUDE_ASM("asm/ov_SC02_016/nonmatchings/ov_SC02_016_jr_8017AE2C", func_8017D254); @@ -3683,7 +3723,72 @@ void func_8017D9B4(void *a0) { } -INCLUDE_ASM("asm/ov_SC02_016/nonmatchings/ov_SC02_016_jr_8017AE2C", func_8017D9F0); + +/* func_8017D9F0 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D9F0(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC02_017/ov_SC02_017.c b/src/ov_SC02_017/ov_SC02_017.c index bc2849ae14..d1bcad9aa6 100644 --- a/src/ov_SC02_017/ov_SC02_017.c +++ b/src/ov_SC02_017/ov_SC02_017.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_017/nonmatchings/ov_SC02_017", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018A784[]; + s16 idx = D_8018A784[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801ED28C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_017/nonmatchings/ov_SC02_017", func_80128CFC); diff --git a/src/ov_SC02_017/ov_SC02_017_after.c b/src/ov_SC02_017/ov_SC02_017_after.c index 44f1c0564f..b293d267d1 100644 --- a/src/ov_SC02_017/ov_SC02_017_after.c +++ b/src/ov_SC02_017/ov_SC02_017_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_017/nonmatchings/ov_SC02_017_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_017/nonmatchings/ov_SC02_017_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_017/ov_SC02_017_jr_8012ACE0.c b/src/ov_SC02_017/ov_SC02_017_jr_8012ACE0.c index 47f1258762..3d67d5ba08 100644 --- a/src/ov_SC02_017/ov_SC02_017_jr_8012ACE0.c +++ b/src/ov_SC02_017/ov_SC02_017_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_017/nonmatchings/ov_SC02_017_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_017/ov_SC02_017_jr_801734BC.c b/src/ov_SC02_017/ov_SC02_017_jr_801734BC.c index efa7f8e529..c5cac5d2d6 100644 --- a/src/ov_SC02_017/ov_SC02_017_jr_801734BC.c +++ b/src/ov_SC02_017/ov_SC02_017_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_017/nonmatchings/ov_SC02_017_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_017/ov_SC02_017_jr_8017AE2C.c b/src/ov_SC02_017/ov_SC02_017_jr_8017AE2C.c index 7de4b5ea89..ff3eafdb31 100644 --- a/src/ov_SC02_017/ov_SC02_017_jr_8017AE2C.c +++ b/src/ov_SC02_017/ov_SC02_017_jr_8017AE2C.c @@ -3512,7 +3512,47 @@ void func_8017D174(int param_1) } -INCLUDE_ASM("asm/ov_SC02_017/nonmatchings/ov_SC02_017_jr_8017AE2C", func_8017D1D0); + +/* Entity record touched by func_8017D1D0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017D1D0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017D1D0; + +extern void func_80147324(s32 arg0); +extern void func_8017D408(int); + +void func_8017D1D0(Ent_8017BFE0_8017D1D0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017D1D0 *))func_8017D408)(param_1); +} + INCLUDE_ASM("asm/ov_SC02_017/nonmatchings/ov_SC02_017_jr_8017AE2C", func_8017D254); @@ -3677,7 +3717,72 @@ void func_8017D9B4(void *a0) { } -INCLUDE_ASM("asm/ov_SC02_017/nonmatchings/ov_SC02_017_jr_8017AE2C", func_8017D9F0); + +/* func_8017D9F0 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D9F0(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC02_021/ov_SC02_021.c b/src/ov_SC02_021/ov_SC02_021.c index ef49450149..406119d561 100644 --- a/src/ov_SC02_021/ov_SC02_021.c +++ b/src/ov_SC02_021/ov_SC02_021.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_021/nonmatchings/ov_SC02_021", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017FD78[]; + s16 idx = D_8017FD78[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80190808, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_021/nonmatchings/ov_SC02_021", func_80128CFC); diff --git a/src/ov_SC02_021/ov_SC02_021_after.c b/src/ov_SC02_021/ov_SC02_021_after.c index 50b4370319..a1e53d5ede 100644 --- a/src/ov_SC02_021/ov_SC02_021_after.c +++ b/src/ov_SC02_021/ov_SC02_021_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_021/nonmatchings/ov_SC02_021_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_021/nonmatchings/ov_SC02_021_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_021/ov_SC02_021_jr_8012ACE0.c b/src/ov_SC02_021/ov_SC02_021_jr_8012ACE0.c index 0bb6c55dd2..b129f2bad1 100644 --- a/src/ov_SC02_021/ov_SC02_021_jr_8012ACE0.c +++ b/src/ov_SC02_021/ov_SC02_021_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_021/nonmatchings/ov_SC02_021_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_021/ov_SC02_021_jr_801734BC.c b/src/ov_SC02_021/ov_SC02_021_jr_801734BC.c index 3e96bd070f..02e193f876 100644 --- a/src/ov_SC02_021/ov_SC02_021_jr_801734BC.c +++ b/src/ov_SC02_021/ov_SC02_021_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_021/nonmatchings/ov_SC02_021_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_026/ov_SC02_026.c b/src/ov_SC02_026/ov_SC02_026.c index c236841129..190d128464 100644 --- a/src/ov_SC02_026/ov_SC02_026.c +++ b/src/ov_SC02_026/ov_SC02_026.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801863CC[]; + s16 idx = D_801863CC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801CDC3C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026", func_80128CFC); diff --git a/src/ov_SC02_026/ov_SC02_026_after.c b/src/ov_SC02_026/ov_SC02_026_after.c index 8f83e51fe7..97b9af80fa 100644 --- a/src/ov_SC02_026/ov_SC02_026_after.c +++ b/src/ov_SC02_026/ov_SC02_026_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_026/ov_SC02_026_jr_8012ACE0.c b/src/ov_SC02_026/ov_SC02_026_jr_8012ACE0.c index a916dedb61..ec42d2913d 100644 --- a/src/ov_SC02_026/ov_SC02_026_jr_8012ACE0.c +++ b/src/ov_SC02_026/ov_SC02_026_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_026/ov_SC02_026_jr_801734BC.c b/src/ov_SC02_026/ov_SC02_026_jr_801734BC.c index 34330f9550..f86b92684c 100644 --- a/src/ov_SC02_026/ov_SC02_026_jr_801734BC.c +++ b/src/ov_SC02_026/ov_SC02_026_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_027/ov_SC02_027.c b/src/ov_SC02_027/ov_SC02_027.c index 3212d92369..2ff870dfc9 100644 --- a/src/ov_SC02_027/ov_SC02_027.c +++ b/src/ov_SC02_027/ov_SC02_027.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_027/nonmatchings/ov_SC02_027", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018B4F0[]; + s16 idx = D_8018B4F0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801D79A8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_027/nonmatchings/ov_SC02_027", func_80128CFC); diff --git a/src/ov_SC02_027/ov_SC02_027_after.c b/src/ov_SC02_027/ov_SC02_027_after.c index e42b58911e..2c2899f66f 100644 --- a/src/ov_SC02_027/ov_SC02_027_after.c +++ b/src/ov_SC02_027/ov_SC02_027_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_027/nonmatchings/ov_SC02_027_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_027/nonmatchings/ov_SC02_027_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_027/ov_SC02_027_jr_8012ACE0.c b/src/ov_SC02_027/ov_SC02_027_jr_8012ACE0.c index 7a1546b03b..7ac7dd4820 100644 --- a/src/ov_SC02_027/ov_SC02_027_jr_8012ACE0.c +++ b/src/ov_SC02_027/ov_SC02_027_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_027/nonmatchings/ov_SC02_027_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_027/ov_SC02_027_jr_801734BC.c b/src/ov_SC02_027/ov_SC02_027_jr_801734BC.c index a62f96a4b8..f8d068a52f 100644 --- a/src/ov_SC02_027/ov_SC02_027_jr_801734BC.c +++ b/src/ov_SC02_027/ov_SC02_027_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_027/nonmatchings/ov_SC02_027_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_027/ov_SC02_027_jr_8017AE2C.c b/src/ov_SC02_027/ov_SC02_027_jr_8017AE2C.c index b991fbe394..5659193180 100644 --- a/src/ov_SC02_027/ov_SC02_027_jr_8017AE2C.c +++ b/src/ov_SC02_027/ov_SC02_027_jr_8017AE2C.c @@ -3403,7 +3403,47 @@ void func_8017CD9C(int param_1) } -INCLUDE_ASM("asm/ov_SC02_027/nonmatchings/ov_SC02_027_jr_8017AE2C", func_8017CDF8); + +/* Entity record touched by func_8017CDF8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017CDF8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017CDF8; + +extern void func_80147324(s32 arg0); +extern void func_8017D030(int); + +void func_8017CDF8(Ent_8017BFE0_8017CDF8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017CDF8 *))func_8017D030)(param_1); +} + INCLUDE_ASM("asm/ov_SC02_027/nonmatchings/ov_SC02_027_jr_8017AE2C", func_8017CE7C); @@ -3568,7 +3608,72 @@ void func_8017D5DC(void *a0) { } -INCLUDE_ASM("asm/ov_SC02_027/nonmatchings/ov_SC02_027_jr_8017AE2C", func_8017D618); + +/* func_8017D618 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D618(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC02_028/ov_SC02_028.c b/src/ov_SC02_028/ov_SC02_028.c index c7d59f9d24..0d254c3461 100644 --- a/src/ov_SC02_028/ov_SC02_028.c +++ b/src/ov_SC02_028/ov_SC02_028.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018B6F4[]; + s16 idx = D_8018B6F4[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801D092C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028", func_80128CFC); diff --git a/src/ov_SC02_028/ov_SC02_028_after.c b/src/ov_SC02_028/ov_SC02_028_after.c index 800d1d27ba..e2b1df6b4c 100644 --- a/src/ov_SC02_028/ov_SC02_028_after.c +++ b/src/ov_SC02_028/ov_SC02_028_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_028/ov_SC02_028_jr_8012ACE0.c b/src/ov_SC02_028/ov_SC02_028_jr_8012ACE0.c index 67cc38f239..3fb09fd2ab 100644 --- a/src/ov_SC02_028/ov_SC02_028_jr_8012ACE0.c +++ b/src/ov_SC02_028/ov_SC02_028_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_028/ov_SC02_028_jr_801734BC.c b/src/ov_SC02_028/ov_SC02_028_jr_801734BC.c index 9144721644..234583428d 100644 --- a/src/ov_SC02_028/ov_SC02_028_jr_801734BC.c +++ b/src/ov_SC02_028/ov_SC02_028_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_028/ov_SC02_028_jr_8017AE2C.c b/src/ov_SC02_028/ov_SC02_028_jr_8017AE2C.c index 6f6a6a2609..22e61010f8 100644 --- a/src/ov_SC02_028/ov_SC02_028_jr_8017AE2C.c +++ b/src/ov_SC02_028/ov_SC02_028_jr_8017AE2C.c @@ -3403,7 +3403,47 @@ void func_8017CD9C(int param_1) } -INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_jr_8017AE2C", func_8017CDF8); + +/* Entity record touched by func_8017CDF8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017CDF8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017CDF8; + +extern void func_80147324(s32 arg0); +extern void func_8017D030(int); + +void func_8017CDF8(Ent_8017BFE0_8017CDF8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017CDF8 *))func_8017D030)(param_1); +} + INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_jr_8017AE2C", func_8017CE7C); @@ -3568,7 +3608,72 @@ void func_8017D5DC(void *a0) { } -INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_jr_8017AE2C", func_8017D618); + +/* func_8017D618 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D618(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC02_028/ov_SC02_028_jr_8017D898.c b/src/ov_SC02_028/ov_SC02_028_jr_8017D898.c index b337d274ce..cc379ea105 100644 --- a/src/ov_SC02_028/ov_SC02_028_jr_8017D898.c +++ b/src/ov_SC02_028/ov_SC02_028_jr_8017D898.c @@ -3869,7 +3869,53 @@ void func_80183918(void) { } -INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_jr_8017D898", func_8018393C); + +/* func_8018393C — cookbook §71 (sibling-first). + * func_801839DC is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_801839DC(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_80183AF8 (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_8018393C; + +extern void func_801839DC(s32 arg0, s32 arg1, s32 arg2); +extern void func_80183AF8(s32 arg0, Rec_8018A6A4_8018393C *arg1, s32 arg2, s32 arg3); + +void func_8018393C(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_8018393C sp10; + s32 i; + s32 ang; + + func_801839DC(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_80183AF8(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + extern s16 D_801D328C; extern s16 D_801D328E; @@ -3899,7 +3945,57 @@ INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_jr_8017D898", func_80183BC INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_jr_8017D898", func_80183C08); -INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_jr_8017D898", func_80183C54); + +/* func_80183C54 — 16-entry table walk, stride 0xE, over D_801D3294. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801D3294; s16 *p = &D_801D3294; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_80183D30(s32 arg0); + +void func_80183C54(void) { + + extern s16 D_801D3294; + s16 *p = &D_801D3294; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_80183D30(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC02_028/nonmatchings/ov_SC02_028_jr_8017D898", func_80183D30); diff --git a/src/ov_SC02_031/ov_SC02_031.c b/src/ov_SC02_031/ov_SC02_031.c index 5164ddd225..d3a86cde8b 100644 --- a/src/ov_SC02_031/ov_SC02_031.c +++ b/src/ov_SC02_031/ov_SC02_031.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_031/nonmatchings/ov_SC02_031", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80184F20[]; + s16 idx = D_80184F20[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B5128, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_031/nonmatchings/ov_SC02_031", func_80128CFC); diff --git a/src/ov_SC02_031/ov_SC02_031_after.c b/src/ov_SC02_031/ov_SC02_031_after.c index d30b64026e..8ec5ea60ea 100644 --- a/src/ov_SC02_031/ov_SC02_031_after.c +++ b/src/ov_SC02_031/ov_SC02_031_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_031/nonmatchings/ov_SC02_031_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_031/nonmatchings/ov_SC02_031_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_031/ov_SC02_031_jr_8012ACE0.c b/src/ov_SC02_031/ov_SC02_031_jr_8012ACE0.c index c3d6e532c2..91da215771 100644 --- a/src/ov_SC02_031/ov_SC02_031_jr_8012ACE0.c +++ b/src/ov_SC02_031/ov_SC02_031_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_031/nonmatchings/ov_SC02_031_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_031/ov_SC02_031_jr_801734BC.c b/src/ov_SC02_031/ov_SC02_031_jr_801734BC.c index c44197042b..e859d5662f 100644 --- a/src/ov_SC02_031/ov_SC02_031_jr_801734BC.c +++ b/src/ov_SC02_031/ov_SC02_031_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_031/nonmatchings/ov_SC02_031_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_031/ov_SC02_031_jr_8017AE2C.c b/src/ov_SC02_031/ov_SC02_031_jr_8017AE2C.c index 7f95a305c5..8025ebca3e 100644 --- a/src/ov_SC02_031/ov_SC02_031_jr_8017AE2C.c +++ b/src/ov_SC02_031/ov_SC02_031_jr_8017AE2C.c @@ -3415,7 +3415,47 @@ void func_8017D060(int param_1) } -INCLUDE_ASM("asm/ov_SC02_031/nonmatchings/ov_SC02_031_jr_8017AE2C", func_8017D0BC); + +/* Entity record touched by func_8017D0BC (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017D0BC { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017D0BC; + +extern void func_80147324(s32 arg0); +extern void func_8017D2F4(int); + +void func_8017D0BC(Ent_8017BFE0_8017D0BC *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017D0BC *))func_8017D2F4)(param_1); +} + INCLUDE_ASM("asm/ov_SC02_031/nonmatchings/ov_SC02_031_jr_8017AE2C", func_8017D140); @@ -3580,7 +3620,72 @@ void func_8017D8A0(void *a0) { } -INCLUDE_ASM("asm/ov_SC02_031/nonmatchings/ov_SC02_031_jr_8017AE2C", func_8017D8DC); + +/* func_8017D8DC — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D8DC(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC02_035/ov_SC02_035.c b/src/ov_SC02_035/ov_SC02_035.c index e48920b280..a188dfe914 100644 --- a/src/ov_SC02_035/ov_SC02_035.c +++ b/src/ov_SC02_035/ov_SC02_035.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_035/nonmatchings/ov_SC02_035", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80184780[]; + s16 idx = D_80184780[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801BC3F0, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_035/nonmatchings/ov_SC02_035", func_80128CFC); diff --git a/src/ov_SC02_035/ov_SC02_035_after.c b/src/ov_SC02_035/ov_SC02_035_after.c index 948842ff33..954770a41c 100644 --- a/src/ov_SC02_035/ov_SC02_035_after.c +++ b/src/ov_SC02_035/ov_SC02_035_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_035/nonmatchings/ov_SC02_035_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_035/nonmatchings/ov_SC02_035_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_035/ov_SC02_035_jr_8012ACE0.c b/src/ov_SC02_035/ov_SC02_035_jr_8012ACE0.c index dfd543c8fe..bee5ef504d 100644 --- a/src/ov_SC02_035/ov_SC02_035_jr_8012ACE0.c +++ b/src/ov_SC02_035/ov_SC02_035_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_035/nonmatchings/ov_SC02_035_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_035/ov_SC02_035_jr_801734BC.c b/src/ov_SC02_035/ov_SC02_035_jr_801734BC.c index 195712ac71..3692622949 100644 --- a/src/ov_SC02_035/ov_SC02_035_jr_801734BC.c +++ b/src/ov_SC02_035/ov_SC02_035_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_035/nonmatchings/ov_SC02_035_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_039/ov_SC02_039.c b/src/ov_SC02_039/ov_SC02_039.c index 91b91b0051..947c67efd8 100644 --- a/src/ov_SC02_039/ov_SC02_039.c +++ b/src/ov_SC02_039/ov_SC02_039.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_039/nonmatchings/ov_SC02_039", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017F3AC[]; + s16 idx = D_8017F3AC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019E7DC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_039/nonmatchings/ov_SC02_039", func_80128CFC); diff --git a/src/ov_SC02_039/ov_SC02_039_after.c b/src/ov_SC02_039/ov_SC02_039_after.c index 46c7be132a..8f2b3dff2a 100644 --- a/src/ov_SC02_039/ov_SC02_039_after.c +++ b/src/ov_SC02_039/ov_SC02_039_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_039/nonmatchings/ov_SC02_039_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_039/nonmatchings/ov_SC02_039_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_039/ov_SC02_039_jr_8012ACE0.c b/src/ov_SC02_039/ov_SC02_039_jr_8012ACE0.c index b0bda13401..c9bb00789f 100644 --- a/src/ov_SC02_039/ov_SC02_039_jr_8012ACE0.c +++ b/src/ov_SC02_039/ov_SC02_039_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_039/nonmatchings/ov_SC02_039_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_039/ov_SC02_039_jr_801734BC.c b/src/ov_SC02_039/ov_SC02_039_jr_801734BC.c index fb860d303e..c0f814c822 100644 --- a/src/ov_SC02_039/ov_SC02_039_jr_801734BC.c +++ b/src/ov_SC02_039/ov_SC02_039_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_039/nonmatchings/ov_SC02_039_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_041/ov_SC02_041.c b/src/ov_SC02_041/ov_SC02_041.c index e3f3eca028..c9f0f5a93d 100644 --- a/src/ov_SC02_041/ov_SC02_041.c +++ b/src/ov_SC02_041/ov_SC02_041.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_041/nonmatchings/ov_SC02_041", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018507C[]; + s16 idx = D_8018507C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B6B48, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC02_041/nonmatchings/ov_SC02_041", func_80128CFC); diff --git a/src/ov_SC02_041/ov_SC02_041_after.c b/src/ov_SC02_041/ov_SC02_041_after.c index 1f07b752f2..731a749ede 100644 --- a/src/ov_SC02_041/ov_SC02_041_after.c +++ b/src/ov_SC02_041/ov_SC02_041_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC02_041/nonmatchings/ov_SC02_041_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_041/nonmatchings/ov_SC02_041_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC02_041/ov_SC02_041_jr_8012ACE0.c b/src/ov_SC02_041/ov_SC02_041_jr_8012ACE0.c index bc4649df58..70de740574 100644 --- a/src/ov_SC02_041/ov_SC02_041_jr_8012ACE0.c +++ b/src/ov_SC02_041/ov_SC02_041_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC02_041/nonmatchings/ov_SC02_041_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC02_041/ov_SC02_041_jr_801734BC.c b/src/ov_SC02_041/ov_SC02_041_jr_801734BC.c index 8d5d6e3c90..a606d57654 100644 --- a/src/ov_SC02_041/ov_SC02_041_jr_801734BC.c +++ b/src/ov_SC02_041/ov_SC02_041_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC02_041/nonmatchings/ov_SC02_041_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC02_041/ov_SC02_041_jr_8017BEBC.c b/src/ov_SC02_041/ov_SC02_041_jr_8017BEBC.c index d10dfbfafe..02bbc9e820 100644 --- a/src/ov_SC02_041/ov_SC02_041_jr_8017BEBC.c +++ b/src/ov_SC02_041/ov_SC02_041_jr_8017BEBC.c @@ -3375,7 +3375,31 @@ void func_8017E27C(void *a0) { INCLUDE_ASM("asm/ov_SC02_041/nonmatchings/ov_SC02_041_jr_8017BEBC", func_8017E2B8); -INCLUDE_ASM("asm/ov_SC02_041/nonmatchings/ov_SC02_041_jr_8017BEBC", func_8017E374); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017E374; + +extern u16 func_80148800(s32 *a0); +extern void func_8017E414(s32 param_1, s16 *param_2); + +void func_8017E374(s32 a0) { + + extern s16 D_80188C84[]; + extern Blk8_80126940_8017E374 D_80126940; + Blk8_80126940_8017E374 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80188C84[t]; + } + sp10 = D_80126940; + func_8017E414(a0, sp10.v); +} + // @class: schedule diff --git a/src/ov_SC03_001/ov_SC03_001.c b/src/ov_SC03_001/ov_SC03_001.c index a46fd4e365..03a3d2e821 100644 --- a/src/ov_SC03_001/ov_SC03_001.c +++ b/src/ov_SC03_001/ov_SC03_001.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_001/nonmatchings/ov_SC03_001", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018D7BC[]; + s16 idx = D_8018D7BC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801EBC68, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_001/nonmatchings/ov_SC03_001", func_80128CFC); diff --git a/src/ov_SC03_001/ov_SC03_001_after.c b/src/ov_SC03_001/ov_SC03_001_after.c index 88ce05e5d6..f8ba25480d 100644 --- a/src/ov_SC03_001/ov_SC03_001_after.c +++ b/src/ov_SC03_001/ov_SC03_001_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_001/nonmatchings/ov_SC03_001_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_001/nonmatchings/ov_SC03_001_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_001/ov_SC03_001_jr_8012ACE0.c b/src/ov_SC03_001/ov_SC03_001_jr_8012ACE0.c index 6ee9fd971e..a02ef71663 100644 --- a/src/ov_SC03_001/ov_SC03_001_jr_8012ACE0.c +++ b/src/ov_SC03_001/ov_SC03_001_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_001/nonmatchings/ov_SC03_001_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_001/ov_SC03_001_jr_801734BC.c b/src/ov_SC03_001/ov_SC03_001_jr_801734BC.c index 66acf4164e..0a8499bd90 100644 --- a/src/ov_SC03_001/ov_SC03_001_jr_801734BC.c +++ b/src/ov_SC03_001/ov_SC03_001_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_001/nonmatchings/ov_SC03_001_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_002/ov_SC03_002.c b/src/ov_SC03_002/ov_SC03_002.c index c44d1b1fd3..ece2e2f814 100644 --- a/src/ov_SC03_002/ov_SC03_002.c +++ b/src/ov_SC03_002/ov_SC03_002.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_002/nonmatchings/ov_SC03_002", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801857AC[]; + s16 idx = D_801857AC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C91C4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_002/nonmatchings/ov_SC03_002", func_80128CFC); diff --git a/src/ov_SC03_002/ov_SC03_002_after.c b/src/ov_SC03_002/ov_SC03_002_after.c index 0915c93b6f..fa24dfc5c5 100644 --- a/src/ov_SC03_002/ov_SC03_002_after.c +++ b/src/ov_SC03_002/ov_SC03_002_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_002/nonmatchings/ov_SC03_002_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_002/nonmatchings/ov_SC03_002_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_002/ov_SC03_002_jr_8012ACE0.c b/src/ov_SC03_002/ov_SC03_002_jr_8012ACE0.c index cd16cc541e..cf1a54e16c 100644 --- a/src/ov_SC03_002/ov_SC03_002_jr_8012ACE0.c +++ b/src/ov_SC03_002/ov_SC03_002_jr_8012ACE0.c @@ -329,7 +329,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_002/nonmatchings/ov_SC03_002_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_002/ov_SC03_002_jr_801734BC.c b/src/ov_SC03_002/ov_SC03_002_jr_801734BC.c index 0c90a466aa..17f88b9d8c 100644 --- a/src/ov_SC03_002/ov_SC03_002_jr_801734BC.c +++ b/src/ov_SC03_002/ov_SC03_002_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_002/nonmatchings/ov_SC03_002_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_003/ov_SC03_003.c b/src/ov_SC03_003/ov_SC03_003.c index b51094e308..2e3b8444fa 100644 --- a/src/ov_SC03_003/ov_SC03_003.c +++ b/src/ov_SC03_003/ov_SC03_003.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_003/nonmatchings/ov_SC03_003", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017F574[]; + s16 idx = D_8017F574[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8018D544, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_003/nonmatchings/ov_SC03_003", func_80128CFC); diff --git a/src/ov_SC03_003/ov_SC03_003_after.c b/src/ov_SC03_003/ov_SC03_003_after.c index 90e2f66d8f..711975c60c 100644 --- a/src/ov_SC03_003/ov_SC03_003_after.c +++ b/src/ov_SC03_003/ov_SC03_003_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_003/nonmatchings/ov_SC03_003_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_003/nonmatchings/ov_SC03_003_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_003/ov_SC03_003_jr_8012ACE0.c b/src/ov_SC03_003/ov_SC03_003_jr_8012ACE0.c index 78673d0044..17bafb7440 100644 --- a/src/ov_SC03_003/ov_SC03_003_jr_8012ACE0.c +++ b/src/ov_SC03_003/ov_SC03_003_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_003/nonmatchings/ov_SC03_003_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_003/ov_SC03_003_jr_801734BC.c b/src/ov_SC03_003/ov_SC03_003_jr_801734BC.c index 43577badd0..e5ab12ca2c 100644 --- a/src/ov_SC03_003/ov_SC03_003_jr_801734BC.c +++ b/src/ov_SC03_003/ov_SC03_003_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_003/nonmatchings/ov_SC03_003_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_006/ov_SC03_006.c b/src/ov_SC03_006/ov_SC03_006.c index 159ee0d7f1..e3aeae279d 100644 --- a/src/ov_SC03_006/ov_SC03_006.c +++ b/src/ov_SC03_006/ov_SC03_006.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_006/nonmatchings/ov_SC03_006", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018C890[]; + s16 idx = D_8018C890[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801F4E00, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_006/nonmatchings/ov_SC03_006", func_80128CFC); diff --git a/src/ov_SC03_006/ov_SC03_006_after.c b/src/ov_SC03_006/ov_SC03_006_after.c index 7724c56872..ba3a05cd39 100644 --- a/src/ov_SC03_006/ov_SC03_006_after.c +++ b/src/ov_SC03_006/ov_SC03_006_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_006/nonmatchings/ov_SC03_006_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_006/nonmatchings/ov_SC03_006_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_006/ov_SC03_006_jr_8012ACE0.c b/src/ov_SC03_006/ov_SC03_006_jr_8012ACE0.c index 226e8f58f2..cd1e56db24 100644 --- a/src/ov_SC03_006/ov_SC03_006_jr_8012ACE0.c +++ b/src/ov_SC03_006/ov_SC03_006_jr_8012ACE0.c @@ -329,7 +329,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_006/nonmatchings/ov_SC03_006_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_006/ov_SC03_006_jr_801734BC.c b/src/ov_SC03_006/ov_SC03_006_jr_801734BC.c index 57be487586..bccba7abfa 100644 --- a/src/ov_SC03_006/ov_SC03_006_jr_801734BC.c +++ b/src/ov_SC03_006/ov_SC03_006_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_006/nonmatchings/ov_SC03_006_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c b/src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c index 87b0e7ade9..cb8076b458 100644 --- a/src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c +++ b/src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c @@ -3509,7 +3509,47 @@ void func_8017D174(int param_1) } -INCLUDE_ASM("asm/ov_SC03_006/nonmatchings/ov_SC03_006_jr_8017AE2C", func_8017D1D0); + +/* Entity record touched by func_8017D1D0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017D1D0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017D1D0; + +extern void func_80147324(s32 arg0); +extern void func_8017D408(int); + +void func_8017D1D0(Ent_8017BFE0_8017D1D0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017D1D0 *))func_8017D408)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_006/nonmatchings/ov_SC03_006_jr_8017AE2C", func_8017D254); @@ -3674,7 +3714,72 @@ void func_8017D9B4(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_006/nonmatchings/ov_SC03_006_jr_8017AE2C", func_8017D9F0); + +/* func_8017D9F0 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D9F0(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_007/ov_SC03_007.c b/src/ov_SC03_007/ov_SC03_007.c index b89ad2970d..adcbe83dae 100644 --- a/src/ov_SC03_007/ov_SC03_007.c +++ b/src/ov_SC03_007/ov_SC03_007.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_007/nonmatchings/ov_SC03_007", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80187688[]; + s16 idx = D_80187688[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801E7788, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_007/nonmatchings/ov_SC03_007", func_80128CFC); diff --git a/src/ov_SC03_007/ov_SC03_007_after.c b/src/ov_SC03_007/ov_SC03_007_after.c index f2e33a34df..af265442d8 100644 --- a/src/ov_SC03_007/ov_SC03_007_after.c +++ b/src/ov_SC03_007/ov_SC03_007_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_007/nonmatchings/ov_SC03_007_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_007/nonmatchings/ov_SC03_007_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_007/ov_SC03_007_jr_8012ACE0.c b/src/ov_SC03_007/ov_SC03_007_jr_8012ACE0.c index 063deb25ea..d01a58327d 100644 --- a/src/ov_SC03_007/ov_SC03_007_jr_8012ACE0.c +++ b/src/ov_SC03_007/ov_SC03_007_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_007/nonmatchings/ov_SC03_007_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_007/ov_SC03_007_jr_801734BC.c b/src/ov_SC03_007/ov_SC03_007_jr_801734BC.c index 8f09b189ff..fa2298835b 100644 --- a/src/ov_SC03_007/ov_SC03_007_jr_801734BC.c +++ b/src/ov_SC03_007/ov_SC03_007_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_007/nonmatchings/ov_SC03_007_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_010/ov_SC03_010.c b/src/ov_SC03_010/ov_SC03_010.c index 1be56806c0..e7203c2aea 100644 --- a/src/ov_SC03_010/ov_SC03_010.c +++ b/src/ov_SC03_010/ov_SC03_010.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_010/nonmatchings/ov_SC03_010", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801801A8[]; + s16 idx = D_801801A8[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019DA64, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_010/nonmatchings/ov_SC03_010", func_80128CFC); diff --git a/src/ov_SC03_010/ov_SC03_010_after.c b/src/ov_SC03_010/ov_SC03_010_after.c index 78903abf9c..c379fcf528 100644 --- a/src/ov_SC03_010/ov_SC03_010_after.c +++ b/src/ov_SC03_010/ov_SC03_010_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_010/nonmatchings/ov_SC03_010_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_010/nonmatchings/ov_SC03_010_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_010/ov_SC03_010_jr_8012ACE0.c b/src/ov_SC03_010/ov_SC03_010_jr_8012ACE0.c index f2f6ab5923..96ad129d45 100644 --- a/src/ov_SC03_010/ov_SC03_010_jr_8012ACE0.c +++ b/src/ov_SC03_010/ov_SC03_010_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_010/nonmatchings/ov_SC03_010_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_010/ov_SC03_010_jr_801734BC.c b/src/ov_SC03_010/ov_SC03_010_jr_801734BC.c index bab313b538..ed848283c8 100644 --- a/src/ov_SC03_010/ov_SC03_010_jr_801734BC.c +++ b/src/ov_SC03_010/ov_SC03_010_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_010/nonmatchings/ov_SC03_010_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_011/ov_SC03_011.c b/src/ov_SC03_011/ov_SC03_011.c index a6c8de8196..c50bd04e2f 100644 --- a/src/ov_SC03_011/ov_SC03_011.c +++ b/src/ov_SC03_011/ov_SC03_011.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_011/nonmatchings/ov_SC03_011", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80181518[]; + s16 idx = D_80181518[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019FCD4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_011/nonmatchings/ov_SC03_011", func_80128CFC); diff --git a/src/ov_SC03_011/ov_SC03_011_after.c b/src/ov_SC03_011/ov_SC03_011_after.c index cc62f9778e..750d57033e 100644 --- a/src/ov_SC03_011/ov_SC03_011_after.c +++ b/src/ov_SC03_011/ov_SC03_011_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_011/nonmatchings/ov_SC03_011_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_011/nonmatchings/ov_SC03_011_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_011/ov_SC03_011_jr_8012ACE0.c b/src/ov_SC03_011/ov_SC03_011_jr_8012ACE0.c index 803545c931..06b3a8cd0f 100644 --- a/src/ov_SC03_011/ov_SC03_011_jr_8012ACE0.c +++ b/src/ov_SC03_011/ov_SC03_011_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_011/nonmatchings/ov_SC03_011_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_011/ov_SC03_011_jr_801734BC.c b/src/ov_SC03_011/ov_SC03_011_jr_801734BC.c index 4b3eb6f160..39e909c56b 100644 --- a/src/ov_SC03_011/ov_SC03_011_jr_801734BC.c +++ b/src/ov_SC03_011/ov_SC03_011_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_011/nonmatchings/ov_SC03_011_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_012/ov_SC03_012.c b/src/ov_SC03_012/ov_SC03_012.c index 9877a4e246..8679a55430 100644 --- a/src/ov_SC03_012/ov_SC03_012.c +++ b/src/ov_SC03_012/ov_SC03_012.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_012/nonmatchings/ov_SC03_012", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017E3F8[]; + s16 idx = D_8017E3F8[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80192B30, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_012/nonmatchings/ov_SC03_012", func_80128CFC); diff --git a/src/ov_SC03_012/ov_SC03_012_after.c b/src/ov_SC03_012/ov_SC03_012_after.c index fa44ab87fd..41cbe724f1 100644 --- a/src/ov_SC03_012/ov_SC03_012_after.c +++ b/src/ov_SC03_012/ov_SC03_012_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_012/nonmatchings/ov_SC03_012_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_012/nonmatchings/ov_SC03_012_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_012/ov_SC03_012_jr_8012ACE0.c b/src/ov_SC03_012/ov_SC03_012_jr_8012ACE0.c index 09a6170137..1db0fc3b3c 100644 --- a/src/ov_SC03_012/ov_SC03_012_jr_8012ACE0.c +++ b/src/ov_SC03_012/ov_SC03_012_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_012/nonmatchings/ov_SC03_012_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_012/ov_SC03_012_jr_801734BC.c b/src/ov_SC03_012/ov_SC03_012_jr_801734BC.c index d33f16089d..9f0691b105 100644 --- a/src/ov_SC03_012/ov_SC03_012_jr_801734BC.c +++ b/src/ov_SC03_012/ov_SC03_012_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_012/nonmatchings/ov_SC03_012_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_013/ov_SC03_013.c b/src/ov_SC03_013/ov_SC03_013.c index 52ab0c4365..b4142df202 100644 --- a/src/ov_SC03_013/ov_SC03_013.c +++ b/src/ov_SC03_013/ov_SC03_013.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_013/nonmatchings/ov_SC03_013", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801811E0[]; + s16 idx = D_801811E0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801AADC8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_013/nonmatchings/ov_SC03_013", func_80128CFC); diff --git a/src/ov_SC03_013/ov_SC03_013_after.c b/src/ov_SC03_013/ov_SC03_013_after.c index 0f6b6598b7..2489a9bd99 100644 --- a/src/ov_SC03_013/ov_SC03_013_after.c +++ b/src/ov_SC03_013/ov_SC03_013_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_013/nonmatchings/ov_SC03_013_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_013/nonmatchings/ov_SC03_013_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_013/ov_SC03_013_jr_8012ACE0.c b/src/ov_SC03_013/ov_SC03_013_jr_8012ACE0.c index 7bf79fac3e..5084cf72ef 100644 --- a/src/ov_SC03_013/ov_SC03_013_jr_8012ACE0.c +++ b/src/ov_SC03_013/ov_SC03_013_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_013/nonmatchings/ov_SC03_013_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_013/ov_SC03_013_jr_801734BC.c b/src/ov_SC03_013/ov_SC03_013_jr_801734BC.c index 35c1d080e4..0b236012cd 100644 --- a/src/ov_SC03_013/ov_SC03_013_jr_801734BC.c +++ b/src/ov_SC03_013/ov_SC03_013_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_013/nonmatchings/ov_SC03_013_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_014/ov_SC03_014.c b/src/ov_SC03_014/ov_SC03_014.c index d8ae60381e..fa5e33d89f 100644 --- a/src/ov_SC03_014/ov_SC03_014.c +++ b/src/ov_SC03_014/ov_SC03_014.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018B81C[]; + s16 idx = D_8018B81C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801E819C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014", func_80128CFC); diff --git a/src/ov_SC03_014/ov_SC03_014_after.c b/src/ov_SC03_014/ov_SC03_014_after.c index 8eb12a5717..baf37ce648 100644 --- a/src/ov_SC03_014/ov_SC03_014_after.c +++ b/src/ov_SC03_014/ov_SC03_014_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_014/ov_SC03_014_jr_8012ACE0.c b/src/ov_SC03_014/ov_SC03_014_jr_8012ACE0.c index bb60174bb1..c7428ee51e 100644 --- a/src/ov_SC03_014/ov_SC03_014_jr_8012ACE0.c +++ b/src/ov_SC03_014/ov_SC03_014_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_014/ov_SC03_014_jr_801734BC.c b/src/ov_SC03_014/ov_SC03_014_jr_801734BC.c index c7e1446368..2586454302 100644 --- a/src/ov_SC03_014/ov_SC03_014_jr_801734BC.c +++ b/src/ov_SC03_014/ov_SC03_014_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c b/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c index 77b6a68535..aebc394abc 100644 --- a/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c +++ b/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c @@ -4088,7 +4088,47 @@ void func_801820B4(int param_1) } -INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017EB7C", func_80182110); + +/* Entity record touched by func_80182110 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_80182110 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_80182110; + +extern void func_80147324(s32 arg0); +extern void func_80182348(int); + +void func_80182110(Ent_8017BFE0_80182110 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_80182110 *))func_80182348)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017EB7C", func_80182194); @@ -4253,7 +4293,72 @@ void func_801828F4(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017EB7C", func_80182930); + +/* func_80182930 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_80182930(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_015/ov_SC03_015.c b/src/ov_SC03_015/ov_SC03_015.c index e7436f99e2..b47375d280 100644 --- a/src/ov_SC03_015/ov_SC03_015.c +++ b/src/ov_SC03_015/ov_SC03_015.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018B81C[]; + s16 idx = D_8018B81C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801E819C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015", func_80128CFC); diff --git a/src/ov_SC03_015/ov_SC03_015_after.c b/src/ov_SC03_015/ov_SC03_015_after.c index 348aae6f47..81df88ce0d 100644 --- a/src/ov_SC03_015/ov_SC03_015_after.c +++ b/src/ov_SC03_015/ov_SC03_015_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_015/ov_SC03_015_jr_8012ACE0.c b/src/ov_SC03_015/ov_SC03_015_jr_8012ACE0.c index 8ee47ade55..1e03f60db4 100644 --- a/src/ov_SC03_015/ov_SC03_015_jr_8012ACE0.c +++ b/src/ov_SC03_015/ov_SC03_015_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_015/ov_SC03_015_jr_801734BC.c b/src/ov_SC03_015/ov_SC03_015_jr_801734BC.c index 4dedf9d12b..dcfc9c2658 100644 --- a/src/ov_SC03_015/ov_SC03_015_jr_801734BC.c +++ b/src/ov_SC03_015/ov_SC03_015_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_015/ov_SC03_015_jr_8017AE2C.c b/src/ov_SC03_015/ov_SC03_015_jr_8017AE2C.c index 830662f605..3da53b3e2a 100644 --- a/src/ov_SC03_015/ov_SC03_015_jr_8017AE2C.c +++ b/src/ov_SC03_015/ov_SC03_015_jr_8017AE2C.c @@ -3462,7 +3462,67 @@ INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_8017AE2C", func_8017D80 INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_8017AE2C", func_8017D890); -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_8017AE2C", func_8017D900); + +/* func_8017D900 — fade the 4-byte colour quad at D_801EA880 one step toward 0 + * (func_80012F74 = "step a value toward a target"), splat the byte over the + * three sibling bytes, mirror the whole quad into the three following quads, + * then tear the entity down once the byte reaches 0. + * + * §71 sibling-first: DEFINE_func_801685EC() (engine_core.h L8520) is the same + * `if ( == 0) ((void (*)(s32))func_80146C3C)(arg0);` teardown tail. + * In-TU sibling func_8017D678 shows D_801EA881/D_801EA882 are SEPARATE u8 + * globals (each gets its own lui/%lo sb) while D_801EA880's address lives in a + * callee-saved register. + * + * @class: schedule (LENGTH-DRIFT/-1) + * @stuck: none — MATCH 50/50 (match_one AND rtu_match), iteration 2. + * THE CRACK (one edit): the TRAILING reload `if (*p == 0)` was being hoisted by + * sched2 up past the third block move, where the swl/swr pair covered its load + * delay — costing exactly the one `nop` the target keeps (49 vs 50 ins, + * LENGTH-DRIFT/-1). A second zero-byte `__asm__("")` fence between the last + * struct assignment and the `if` pins the lbu after the copies and the load-delay + * nop reappears. Lesson: an inline block move (swl/swr) is a fat delay-slot + * SPONGE — any following narrow load will be sucked up into it unless fenced. + * The first fence (after the chained byte stores) is what keeps the block moves + * from being interleaved with them. + * Other levers already in this draft, all load-bearing: + * - `u8 *p = &D_801EA880;` (§20) — one address register ($s0, callee-saved + * across the jal) serves the lbu, the sb and all three block-move sources. + * - chained assignment `D_801EA881 = D_801EA882 = *p = f(...)` gives the + * target's store order 880, 882, 881 (right-to-left after the *p store). + * - the 4×u8 struct (align 1) is what makes the assignment expand to inline + * lwl/lwr + swl/swr instead of a `jal memcpy` (cf. §38). + */ + +typedef struct { + u8 b0, b1, b2, b3; +} Quad_801EA880_8017D900; /* align 1 => movstrsi expands to lwl/lwr + swl/swr */ + + +extern s32 func_80012F74(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_80146C3C(void); + +void func_8017D900(s32 arg0) { + + extern u8 D_801EA880; + extern u8 D_801EA881; + extern u8 D_801EA882; + extern u8 D_801EA884; + extern u8 D_801EA888; + extern u8 D_801EA88C; + u8 *p = &D_801EA880; + + D_801EA881 = D_801EA882 = *p = func_80012F74(*p, 0, 10, 1); + __asm__(""); + *(Quad_801EA880_8017D900 *)&D_801EA884 = *(Quad_801EA880_8017D900 *)p; + *(Quad_801EA880_8017D900 *)&D_801EA888 = *(Quad_801EA880_8017D900 *)p; + *(Quad_801EA880_8017D900 *)&D_801EA88C = *(Quad_801EA880_8017D900 *)p; + __asm__(""); + if (*p == 0) { + ((void (*)(s32))func_80146C3C)(arg0); + } +} + INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_8017AE2C", func_8017D9C8); diff --git a/src/ov_SC03_015/ov_SC03_015_jr_8017EB7C.c b/src/ov_SC03_015/ov_SC03_015_jr_8017EB7C.c index 8e253a4e82..09d87a30de 100644 --- a/src/ov_SC03_015/ov_SC03_015_jr_8017EB7C.c +++ b/src/ov_SC03_015/ov_SC03_015_jr_8017EB7C.c @@ -3992,7 +3992,47 @@ void func_801820B4(int param_1) } -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_8017EB7C", func_80182110); + +/* Entity record touched by func_80182110 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_80182110 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_80182110; + +extern void func_80147324(s32 arg0); +extern void func_80182348(int); + +void func_80182110(Ent_8017BFE0_80182110 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_80182110 *))func_80182348)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_8017EB7C", func_80182194); @@ -4157,7 +4197,72 @@ void func_801828F4(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_8017EB7C", func_80182930); + +/* func_80182930 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_80182930(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_015/ov_SC03_015_jr_801848E4.c b/src/ov_SC03_015/ov_SC03_015_jr_801848E4.c index 69f1b29cfc..74599f1765 100644 --- a/src/ov_SC03_015/ov_SC03_015_jr_801848E4.c +++ b/src/ov_SC03_015/ov_SC03_015_jr_801848E4.c @@ -3271,7 +3271,53 @@ void func_8018A680(void) { } -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_801848E4", func_8018A6A4); + +/* func_8018A6A4 — cookbook §71 (sibling-first). + * func_8018A744 is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_8018A744(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_8018A860 (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_8018A6A4; + +extern void func_8018A744(s32 arg0, s32 arg1, s32 arg2); +extern void func_8018A860(s32 arg0, Rec_8018A6A4_8018A6A4 *arg1, s32 arg2, s32 arg3); + +void func_8018A6A4(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_8018A6A4 sp10; + s32 i; + s32 ang; + + func_8018A744(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_8018A860(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + extern s16 D_801EADE4; @@ -3303,7 +3349,57 @@ INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_801848E4", func_8018A93 INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_801848E4", func_8018A970); -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_801848E4", func_8018A9BC); + +/* func_8018A9BC — 16-entry table walk, stride 0xE, over D_801EADEC. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801EADEC; s16 *p = &D_801EADEC; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_8018AA98(s32 arg0); + +void func_8018A9BC(void) { + + extern s16 D_801EADEC; + s16 *p = &D_801EADEC; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_8018AA98(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_jr_801848E4", func_8018AA98); diff --git a/src/ov_SC03_015/ov_SC03_015_o0c.c b/src/ov_SC03_015/ov_SC03_015_o0c.c index 323b2f56d7..cbb1ef984d 100644 --- a/src/ov_SC03_015/ov_SC03_015_o0c.c +++ b/src/ov_SC03_015/ov_SC03_015_o0c.c @@ -382,7 +382,6 @@ extern s32 func_80149F2C(s32 a0, s32 a1); extern s32 func_80149E94(s32 arg0); extern void func_80149FA8(void); extern s32 D_8018D124[]; -extern u8 D_80078E78[]; extern s32 func_80149FB0(s32 a0); extern s32 func_80135260(s32 arg0, s32 arg1, s16 *arg2, s16 *arg3); extern void func_8014A1B0(s32 a0, s32 a1); @@ -2750,11 +2749,116 @@ extern void func_80183B58(s32 param_1, s16 *param_2); /* ==== end §8b carried decl layer ==== */ -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_o0c", func_80183CF0); -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_o0c", func_80183D50); +typedef struct Ent_80183CF0_80183CF0 { + u8 unk0[2]; /* 0x00 */ + u16 unk2; /* 0x02 */ +} Ent_80183CF0_80183CF0; + + +void func_80183CF0(Ent_80183CF0_80183CF0 *arg) { + + extern void (*D_8018FB30[])(Ent_80183CF0_80183CF0 *); + D_8018FB30[arg->unk2](arg); +} + + + +typedef struct Ent_80183D50_80183D50 { + u8 unk0[2]; /* 0x00 */ + u16 unk2; /* 0x02 */ + u8 unk4[0xD8]; /* 0x04 */ + s16 unkDC; /* 0xDC */ + u8 unkDE[4]; /* 0xDE */ + s16 unkE2; /* 0xE2 */ + s16 unkE4; /* 0xE4 */ + u8 unkE6[2]; /* 0xE6 */ + s16 unkE8; /* 0xE8 */ + s16 unkEA; /* 0xEA */ +} Ent_80183D50_80183D50; + +typedef struct Gs_80078E78_80183D50 { + u8 pad0[0x37]; /* 0x00 */ + u8 unk37; /* 0x37 */ +} Gs_80078E78_80183D50; + +extern void func_8013C0F8(u8 *a0); +extern void func_80184440(void); +extern s32 func_80029178(s32 arg); +extern void func_8013373C(s32 a0); + +void func_80183D50(Ent_80183D50_80183D50 *arg) { + + extern u8 D_80078E78[]; + extern u8 D_801B5864[]; + extern u8 D_801B5E30[]; + extern u8 D_801B75CC[]; + Gs_80078E78_80183D50 *p = (Gs_80078E78_80183D50 *)D_80078E78; + + func_8013C0F8(D_801B5864); + func_8013C0F8(D_801B5E30); + func_8013C0F8(D_801B75CC); + arg->unkDC = 0; + arg->unkE4 = 0; + arg->unkE8 = 1; + arg->unkEA = 0x3C; + arg->unkE2 = -0x3C0; + func_80184440(); + arg->unk2++; + if (func_80029178(0xB9) & 0xFF) { + func_8013373C(1); + arg->unkE2 = -0x68; + arg->unkE2 = 0; + arg->unkE4 = 0; + arg->unk2 = 3; + } else if (p->unk37 == 0 || p->unk37 == 3 || p->unk37 == 4) { + arg->unkE2 = -0x3C0; + arg->unkE2 = 0; + arg->unkE4 = 2; + } else { + func_8013373C(0); + arg->unkE2 = -0x2C9; + arg->unkE2 = 0; + arg->unkE4 = 1; + } +} + + + +typedef struct Ent80183F28_80183F28 { + /* 0x00 */ s16 unk00; + /* 0x02 */ s16 unk02; + /* 0x04 */ u8 pad04[0xD8]; + /* 0xDC */ s16 unkDC; + /* 0xDE */ s16 unkDE; + /* 0xE0 */ s16 unkE0; + /* 0xE2 */ s16 unkE2; + /* 0xE4 */ s16 unkE4; + /* 0xE6 */ s16 unkE6; + /* 0xE8 */ s16 unkE8; + /* 0xEA */ s16 unkEA; +} Ent80183F28_80183F28; + +extern void func_8017DF84(void *a0, s32 a1, s32 a2, s32 a3); +extern s32 func_80029178(s32 a0); +extern void func_80184354(void); + +void func_80183F28(Ent80183F28_80183F28 *arg0) { + + extern s32 D_801270C8; + extern s32 D_801EAFD0; + extern s32 D_8018F858[]; + func_8017DF84(&D_801EAFD0, D_8018F858[arg0->unkE4], arg0->unkDC, arg0->unkE2); + arg0->unkDC += 8; + if ((func_80029178(0xB9) & 0xFF) == 0) { + if (D_801270C8 != 0) { + ++arg0->unk02; + } + arg0->unkEA = 0x3C; + func_80184354(); + } +} -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_o0c", func_80183F28); @@ -2768,7 +2872,24 @@ s32 func_80184028(void) { INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_o0c", func_80184058); -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_o0c", func_80184264); + +extern void func_8017FA5C(s32 arg0, s32 arg1, s32 arg2); +extern void func_80184474(void); + +typedef struct Ent_80184264_80184264 { + u8 pad0[0xE2]; + s16 unkE2; + s16 unkE4; +} Ent_80184264_80184264; + +void func_80184264(Ent_80184264_80184264 *param_1) { + + extern s32 D_801EAFD0; + extern s32 D_8018F858[]; + func_8017FA5C((s32)&D_801EAFD0, D_8018F858[param_1->unkE4], param_1->unkE2); + func_80184474(); +} + diff --git a/src/ov_SC03_015/ov_SC03_015_o0d.c b/src/ov_SC03_015/ov_SC03_015_o0d.c index 5691c32332..7ebf6fc882 100644 --- a/src/ov_SC03_015/ov_SC03_015_o0d.c +++ b/src/ov_SC03_015/ov_SC03_015_o0d.c @@ -2771,7 +2771,42 @@ void func_80184474(void) { } -INCLUDE_ASM("asm/ov_SC03_015/nonmatchings/ov_SC03_015_o0d", func_80184538); + +typedef struct { + s32 unk00; /* 0x00 */ + s32 unk04; /* 0x04 */ + u16 unk08; /* 0x08 */ + u16 unk0A; /* 0x0A */ + u16 unk0C; /* 0x0C */ + u16 unk0E; /* 0x0E */ + u16 unk10; /* 0x10 */ + u16 unk12; /* 0x12 */ +} Unk8018F8C4_80184538; /* sizeof == 0x14 */ + + +extern void MoveImage(void *a0, s32 a1, s32 a2); +extern void func_800183E0(s32 a0); + +void func_80184538(s32 arg0) { + + extern Unk8018F8C4_80184538 D_8018F8C4[]; + s16 rect[4]; + s32 x; + s32 y; + + if (D_8018F8C4[arg0].unk00 == 0) { + rect[0] = D_8018F8C4[arg0].unk08; + rect[1] = D_8018F8C4[arg0].unk0A; + rect[2] = D_8018F8C4[arg0].unk0C; + rect[3] = D_8018F8C4[arg0].unk0E; + x = D_8018F8C4[arg0].unk10; + y = D_8018F8C4[arg0].unk12; + MoveImage(rect, x, y); + } else { + func_800183E0(D_8018F8C4[arg0].unk04); + } +} + extern s32 func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 sp10); extern u8 D_800AEE50; diff --git a/src/ov_SC03_023/ov_SC03_023.c b/src/ov_SC03_023/ov_SC03_023.c index c704a7d2dc..984000a705 100644 --- a/src/ov_SC03_023/ov_SC03_023.c +++ b/src/ov_SC03_023/ov_SC03_023.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_023/nonmatchings/ov_SC03_023", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017F198[]; + s16 idx = D_8017F198[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80196774, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_023/nonmatchings/ov_SC03_023", func_80128CFC); diff --git a/src/ov_SC03_023/ov_SC03_023_after.c b/src/ov_SC03_023/ov_SC03_023_after.c index ff40dbe6e0..311ae11425 100644 --- a/src/ov_SC03_023/ov_SC03_023_after.c +++ b/src/ov_SC03_023/ov_SC03_023_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_023/nonmatchings/ov_SC03_023_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_023/nonmatchings/ov_SC03_023_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_023/ov_SC03_023_jr_8012ACE0.c b/src/ov_SC03_023/ov_SC03_023_jr_8012ACE0.c index 3458c6aa68..dc221b8390 100644 --- a/src/ov_SC03_023/ov_SC03_023_jr_8012ACE0.c +++ b/src/ov_SC03_023/ov_SC03_023_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_023/nonmatchings/ov_SC03_023_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_023/ov_SC03_023_jr_801734BC.c b/src/ov_SC03_023/ov_SC03_023_jr_801734BC.c index 0e9d263fde..20f289c56b 100644 --- a/src/ov_SC03_023/ov_SC03_023_jr_801734BC.c +++ b/src/ov_SC03_023/ov_SC03_023_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_023/nonmatchings/ov_SC03_023_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_024/ov_SC03_024.c b/src/ov_SC03_024/ov_SC03_024.c index ee8e069329..2c498c2157 100644 --- a/src/ov_SC03_024/ov_SC03_024.c +++ b/src/ov_SC03_024/ov_SC03_024.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801871BC[]; + s16 idx = D_801871BC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801BEBFC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024", func_80128CFC); diff --git a/src/ov_SC03_024/ov_SC03_024_after.c b/src/ov_SC03_024/ov_SC03_024_after.c index 256ce2734f..907342dade 100644 --- a/src/ov_SC03_024/ov_SC03_024_after.c +++ b/src/ov_SC03_024/ov_SC03_024_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_024/ov_SC03_024_jr_8012ACE0.c b/src/ov_SC03_024/ov_SC03_024_jr_8012ACE0.c index 9f2f8c4066..7c3c370923 100644 --- a/src/ov_SC03_024/ov_SC03_024_jr_8012ACE0.c +++ b/src/ov_SC03_024/ov_SC03_024_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_024/ov_SC03_024_jr_801734BC.c b/src/ov_SC03_024/ov_SC03_024_jr_801734BC.c index c165722e24..d2fd1e9569 100644 --- a/src/ov_SC03_024/ov_SC03_024_jr_801734BC.c +++ b/src/ov_SC03_024/ov_SC03_024_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_024/ov_SC03_024_jr_8017AE2C.c b/src/ov_SC03_024/ov_SC03_024_jr_8017AE2C.c index d959196cba..78742e3f5f 100644 --- a/src/ov_SC03_024/ov_SC03_024_jr_8017AE2C.c +++ b/src/ov_SC03_024/ov_SC03_024_jr_8017AE2C.c @@ -3468,7 +3468,67 @@ INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017AE2C", func_8017D80 INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017AE2C", func_8017D890); -INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017AE2C", func_8017D900); + +/* func_8017D900 — fade the 4-byte colour quad at D_801C11F0 one step toward 0 + * (func_80012F74 = "step a value toward a target"), splat the byte over the + * three sibling bytes, mirror the whole quad into the three following quads, + * then tear the entity down once the byte reaches 0. + * + * §71 sibling-first: DEFINE_func_801685EC() (engine_core.h L8520) is the same + * `if ( == 0) ((void (*)(s32))func_80146C3C)(arg0);` teardown tail. + * In-TU sibling func_8017D678 shows D_801C11F1/D_801C11F2 are SEPARATE u8 + * globals (each gets its own lui/%lo sb) while D_801C11F0's address lives in a + * callee-saved register. + * + * @class: schedule (LENGTH-DRIFT/-1) + * @stuck: none — MATCH 50/50 (match_one AND rtu_match), iteration 2. + * THE CRACK (one edit): the TRAILING reload `if (*p == 0)` was being hoisted by + * sched2 up past the third block move, where the swl/swr pair covered its load + * delay — costing exactly the one `nop` the target keeps (49 vs 50 ins, + * LENGTH-DRIFT/-1). A second zero-byte `__asm__("")` fence between the last + * struct assignment and the `if` pins the lbu after the copies and the load-delay + * nop reappears. Lesson: an inline block move (swl/swr) is a fat delay-slot + * SPONGE — any following narrow load will be sucked up into it unless fenced. + * The first fence (after the chained byte stores) is what keeps the block moves + * from being interleaved with them. + * Other levers already in this draft, all load-bearing: + * - `u8 *p = &D_801C11F0;` (§20) — one address register ($s0, callee-saved + * across the jal) serves the lbu, the sb and all three block-move sources. + * - chained assignment `D_801C11F1 = D_801C11F2 = *p = f(...)` gives the + * target's store order 880, 882, 881 (right-to-left after the *p store). + * - the 4×u8 struct (align 1) is what makes the assignment expand to inline + * lwl/lwr + swl/swr instead of a `jal memcpy` (cf. §38). + */ + +typedef struct { + u8 b0, b1, b2, b3; +} Quad_801EA880_8017D900; /* align 1 => movstrsi expands to lwl/lwr + swl/swr */ + + +extern s32 func_80012F74(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_80146C3C(void); + +void func_8017D900(s32 arg0) { + + extern u8 D_801C11F0; + extern u8 D_801C11F1; + extern u8 D_801C11F2; + extern u8 D_801C11F4; + extern u8 D_801C11F8; + extern u8 D_801C11FC; + u8 *p = &D_801C11F0; + + D_801C11F1 = D_801C11F2 = *p = func_80012F74(*p, 0, 10, 1); + __asm__(""); + *(Quad_801EA880_8017D900 *)&D_801C11F4 = *(Quad_801EA880_8017D900 *)p; + *(Quad_801EA880_8017D900 *)&D_801C11F8 = *(Quad_801EA880_8017D900 *)p; + *(Quad_801EA880_8017D900 *)&D_801C11FC = *(Quad_801EA880_8017D900 *)p; + __asm__(""); + if (*p == 0) { + ((void (*)(s32))func_80146C3C)(arg0); + } +} + INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017AE2C", func_8017D9C8); diff --git a/src/ov_SC03_024/ov_SC03_024_jr_8017DF84.c b/src/ov_SC03_024/ov_SC03_024_jr_8017DF84.c index 6ee35159d8..aadac6b318 100644 --- a/src/ov_SC03_024/ov_SC03_024_jr_8017DF84.c +++ b/src/ov_SC03_024/ov_SC03_024_jr_8017DF84.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3475,11 +3474,53 @@ void func_80180CCC(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017DF84", func_80180D08); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_80180D08; + +extern u16 func_80148800(s32 *a0); +extern void func_80180EA8(s32 param_1, s16 *param_2); + +void func_80180D08(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_8018B080[]; + extern Blk8_80126940_80180D08 D_80126940; + Blk8_80126940_80180D08 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_8018B080[t]; + } + sp10 = D_80126940; + func_80180EA8(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017DF84", func_80180DA8); -INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017DF84", func_80180E60); + +/* 8-byte, alignment-1 blob: the target copies it with lwl/lwr + swl/swr, + * which is gcc's emit_block_move for align < 4. */ +typedef struct { + char b[8]; +} Blob8_8018A47C_80180E60; + +extern void func_80180EA8(s32, s16*); + +void func_80180E60(s32 a0) { + + extern Blob8_8018A47C_80180E60 D_801BFD88; + Blob8_8018A47C_80180E60 tmp; + + tmp = D_801BFD88; + ((void (*)(s32, Blob8_8018A47C_80180E60 *))func_80180EA8)(a0, &tmp); +} + // @class: schedule @@ -4014,7 +4055,53 @@ void func_80185A20(void) { } -INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017DF84", func_80185A44); + +/* func_80185A44 — cookbook §71 (sibling-first). + * func_80185AE4 is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_80185AE4(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_80185C00 (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_80185A44; + +extern void func_80185AE4(s32 arg0, s32 arg1, s32 arg2); +extern void func_80185C00(s32 arg0, Rec_8018A6A4_80185A44 *arg1, s32 arg2, s32 arg3); + +void func_80185A44(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_80185A44 sp10; + s32 i; + s32 ang; + + func_80185AE4(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_80185C00(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + extern s16 D_801C15F4; @@ -4045,7 +4132,57 @@ INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017DF84", func_80185CD INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017DF84", func_80185D10); -INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017DF84", func_80185D5C); + +/* func_80185D5C — 16-entry table walk, stride 0xE, over D_801C15FC. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801C15FC; s16 *p = &D_801C15FC; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_80185E38(s32 arg0); + +void func_80185D5C(void) { + + extern s16 D_801C15FC; + s16 *p = &D_801C15FC; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_80185E38(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC03_024/nonmatchings/ov_SC03_024_jr_8017DF84", func_80185E38); diff --git a/src/ov_SC03_028/ov_SC03_028.c b/src/ov_SC03_028/ov_SC03_028.c index 89c692614e..e2ea0ab699 100644 --- a/src/ov_SC03_028/ov_SC03_028.c +++ b/src/ov_SC03_028/ov_SC03_028.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_028/nonmatchings/ov_SC03_028", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018BC88[]; + s16 idx = D_8018BC88[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801E8D84, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_028/nonmatchings/ov_SC03_028", func_80128CFC); diff --git a/src/ov_SC03_028/ov_SC03_028_after.c b/src/ov_SC03_028/ov_SC03_028_after.c index 5e5be4205e..45a5441306 100644 --- a/src/ov_SC03_028/ov_SC03_028_after.c +++ b/src/ov_SC03_028/ov_SC03_028_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_028/nonmatchings/ov_SC03_028_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_028/nonmatchings/ov_SC03_028_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_028/ov_SC03_028_jr_8012ACE0.c b/src/ov_SC03_028/ov_SC03_028_jr_8012ACE0.c index e53fb97da8..16c94c5b5d 100644 --- a/src/ov_SC03_028/ov_SC03_028_jr_8012ACE0.c +++ b/src/ov_SC03_028/ov_SC03_028_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_028/nonmatchings/ov_SC03_028_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_028/ov_SC03_028_jr_801734BC.c b/src/ov_SC03_028/ov_SC03_028_jr_801734BC.c index 89ee6e27fb..d4f4a3bc6d 100644 --- a/src/ov_SC03_028/ov_SC03_028_jr_801734BC.c +++ b/src/ov_SC03_028/ov_SC03_028_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_028/nonmatchings/ov_SC03_028_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_029/ov_SC03_029.c b/src/ov_SC03_029/ov_SC03_029.c index 0da4069c2b..b1b06f8e9c 100644 --- a/src/ov_SC03_029/ov_SC03_029.c +++ b/src/ov_SC03_029/ov_SC03_029.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_029/nonmatchings/ov_SC03_029", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80187AC0[]; + s16 idx = D_80187AC0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801D6EB8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_029/nonmatchings/ov_SC03_029", func_80128CFC); diff --git a/src/ov_SC03_029/ov_SC03_029_after.c b/src/ov_SC03_029/ov_SC03_029_after.c index 8138784e1f..7f0b38c902 100644 --- a/src/ov_SC03_029/ov_SC03_029_after.c +++ b/src/ov_SC03_029/ov_SC03_029_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_029/nonmatchings/ov_SC03_029_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_029/nonmatchings/ov_SC03_029_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_029/ov_SC03_029_jr_8012ACE0.c b/src/ov_SC03_029/ov_SC03_029_jr_8012ACE0.c index 55601d6a54..9267678c4b 100644 --- a/src/ov_SC03_029/ov_SC03_029_jr_8012ACE0.c +++ b/src/ov_SC03_029/ov_SC03_029_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_029/nonmatchings/ov_SC03_029_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_029/ov_SC03_029_jr_801734BC.c b/src/ov_SC03_029/ov_SC03_029_jr_801734BC.c index 922acf6cd4..f5d50dbbe9 100644 --- a/src/ov_SC03_029/ov_SC03_029_jr_801734BC.c +++ b/src/ov_SC03_029/ov_SC03_029_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_029/nonmatchings/ov_SC03_029_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_029/ov_SC03_029_jr_8017AE2C.c b/src/ov_SC03_029/ov_SC03_029_jr_8017AE2C.c index 93f1c0f9ea..b80263eaef 100644 --- a/src/ov_SC03_029/ov_SC03_029_jr_8017AE2C.c +++ b/src/ov_SC03_029/ov_SC03_029_jr_8017AE2C.c @@ -3512,7 +3512,47 @@ void func_8017D174(int param_1) } -INCLUDE_ASM("asm/ov_SC03_029/nonmatchings/ov_SC03_029_jr_8017AE2C", func_8017D1D0); + +/* Entity record touched by func_8017D1D0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017D1D0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017D1D0; + +extern void func_80147324(s32 arg0); +extern void func_8017D408(int); + +void func_8017D1D0(Ent_8017BFE0_8017D1D0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017D1D0 *))func_8017D408)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_029/nonmatchings/ov_SC03_029_jr_8017AE2C", func_8017D254); @@ -3677,7 +3717,72 @@ void func_8017D9B4(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_029/nonmatchings/ov_SC03_029_jr_8017AE2C", func_8017D9F0); + +/* func_8017D9F0 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D9F0(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_030/ov_SC03_030.c b/src/ov_SC03_030/ov_SC03_030.c index b575d37261..a7dd5823c0 100644 --- a/src/ov_SC03_030/ov_SC03_030.c +++ b/src/ov_SC03_030/ov_SC03_030.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_030/nonmatchings/ov_SC03_030", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801820FC[]; + s16 idx = D_801820FC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801DF55C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_030/nonmatchings/ov_SC03_030", func_80128CFC); diff --git a/src/ov_SC03_030/ov_SC03_030_after.c b/src/ov_SC03_030/ov_SC03_030_after.c index fa3d17bcba..b24541788a 100644 --- a/src/ov_SC03_030/ov_SC03_030_after.c +++ b/src/ov_SC03_030/ov_SC03_030_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_030/nonmatchings/ov_SC03_030_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_030/nonmatchings/ov_SC03_030_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_030/ov_SC03_030_jr_8012ACE0.c b/src/ov_SC03_030/ov_SC03_030_jr_8012ACE0.c index 5934f85b01..a04c003034 100644 --- a/src/ov_SC03_030/ov_SC03_030_jr_8012ACE0.c +++ b/src/ov_SC03_030/ov_SC03_030_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_030/nonmatchings/ov_SC03_030_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_030/ov_SC03_030_jr_801734BC.c b/src/ov_SC03_030/ov_SC03_030_jr_801734BC.c index e78f1680d3..c913163e22 100644 --- a/src/ov_SC03_030/ov_SC03_030_jr_801734BC.c +++ b/src/ov_SC03_030/ov_SC03_030_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_030/nonmatchings/ov_SC03_030_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_031/ov_SC03_031.c b/src/ov_SC03_031/ov_SC03_031.c index aee5a1a638..40b7b3118c 100644 --- a/src/ov_SC03_031/ov_SC03_031.c +++ b/src/ov_SC03_031/ov_SC03_031.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_031/nonmatchings/ov_SC03_031", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80182618[]; + s16 idx = D_80182618[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C3A00, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_031/nonmatchings/ov_SC03_031", func_80128CFC); diff --git a/src/ov_SC03_031/ov_SC03_031_after.c b/src/ov_SC03_031/ov_SC03_031_after.c index 4831a62304..4d06e9f0a3 100644 --- a/src/ov_SC03_031/ov_SC03_031_after.c +++ b/src/ov_SC03_031/ov_SC03_031_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_031/nonmatchings/ov_SC03_031_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_031/nonmatchings/ov_SC03_031_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_031/ov_SC03_031_jr_8012ACE0.c b/src/ov_SC03_031/ov_SC03_031_jr_8012ACE0.c index 7759c2e6ea..b654451496 100644 --- a/src/ov_SC03_031/ov_SC03_031_jr_8012ACE0.c +++ b/src/ov_SC03_031/ov_SC03_031_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_031/nonmatchings/ov_SC03_031_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_031/ov_SC03_031_jr_801734BC.c b/src/ov_SC03_031/ov_SC03_031_jr_801734BC.c index 2d2ce3ff2c..da4cc8ed05 100644 --- a/src/ov_SC03_031/ov_SC03_031_jr_801734BC.c +++ b/src/ov_SC03_031/ov_SC03_031_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_031/nonmatchings/ov_SC03_031_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_031/ov_SC03_031_jr_8017AE2C.c b/src/ov_SC03_031/ov_SC03_031_jr_8017AE2C.c index 8d3370b15e..53ec1fa5e5 100644 --- a/src/ov_SC03_031/ov_SC03_031_jr_8017AE2C.c +++ b/src/ov_SC03_031/ov_SC03_031_jr_8017AE2C.c @@ -3417,7 +3417,47 @@ void func_8017D060(int param_1) } -INCLUDE_ASM("asm/ov_SC03_031/nonmatchings/ov_SC03_031_jr_8017AE2C", func_8017D0BC); + +/* Entity record touched by func_8017D0BC (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017D0BC { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017D0BC; + +extern void func_80147324(s32 arg0); +extern void func_8017D2F4(int); + +void func_8017D0BC(Ent_8017BFE0_8017D0BC *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017D0BC *))func_8017D2F4)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_031/nonmatchings/ov_SC03_031_jr_8017AE2C", func_8017D140); @@ -3582,7 +3622,72 @@ void func_8017D8A0(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_031/nonmatchings/ov_SC03_031_jr_8017AE2C", func_8017D8DC); + +/* func_8017D8DC — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D8DC(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_089/ov_SC03_089.c b/src/ov_SC03_089/ov_SC03_089.c index 22826e4aa3..540e7d3625 100644 --- a/src/ov_SC03_089/ov_SC03_089.c +++ b/src/ov_SC03_089/ov_SC03_089.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80189914[]; + s16 idx = D_80189914[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C426C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089", func_80128CFC); diff --git a/src/ov_SC03_089/ov_SC03_089_after.c b/src/ov_SC03_089/ov_SC03_089_after.c index 31de64d8ac..3e2962dfef 100644 --- a/src/ov_SC03_089/ov_SC03_089_after.c +++ b/src/ov_SC03_089/ov_SC03_089_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_089/ov_SC03_089_jr_8012ACE0.c b/src/ov_SC03_089/ov_SC03_089_jr_8012ACE0.c index f554e48ebd..743dff97b2 100644 --- a/src/ov_SC03_089/ov_SC03_089_jr_8012ACE0.c +++ b/src/ov_SC03_089/ov_SC03_089_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_089/ov_SC03_089_jr_801734BC.c b/src/ov_SC03_089/ov_SC03_089_jr_801734BC.c index 0023fcd999..064c0eef07 100644 --- a/src/ov_SC03_089/ov_SC03_089_jr_801734BC.c +++ b/src/ov_SC03_089/ov_SC03_089_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_089/ov_SC03_089_jr_8017AE2C.c b/src/ov_SC03_089/ov_SC03_089_jr_8017AE2C.c index f0a78d1e39..2455b1b921 100644 --- a/src/ov_SC03_089/ov_SC03_089_jr_8017AE2C.c +++ b/src/ov_SC03_089/ov_SC03_089_jr_8017AE2C.c @@ -3357,7 +3357,47 @@ void func_8017BF84(int param_1) } -INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089_jr_8017AE2C", func_8017BFE0); + +/* Entity record touched by func_8017BFE0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017BFE0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017BFE0; + +extern void func_80147324(s32 arg0); +extern void func_8017C218(int); + +void func_8017BFE0(Ent_8017BFE0_8017BFE0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017BFE0 *))func_8017C218)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089_jr_8017AE2C", func_8017C064); @@ -3485,7 +3525,72 @@ void func_8017C7C4(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_089/nonmatchings/ov_SC03_089_jr_8017AE2C", func_8017C800); + +/* func_8017C800 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017C800(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + DEFINE_func_8017C8B4() /* dedup: shared engine-core @0x8017C8B4 (src/shared) */ diff --git a/src/ov_SC03_090/ov_SC03_090.c b/src/ov_SC03_090/ov_SC03_090.c index 05495985ec..1d244180d1 100644 --- a/src/ov_SC03_090/ov_SC03_090.c +++ b/src/ov_SC03_090/ov_SC03_090.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_090/nonmatchings/ov_SC03_090", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018BD38[]; + s16 idx = D_8018BD38[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C96D8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_090/nonmatchings/ov_SC03_090", func_80128CFC); diff --git a/src/ov_SC03_090/ov_SC03_090_after.c b/src/ov_SC03_090/ov_SC03_090_after.c index 6af665e03a..b17620537e 100644 --- a/src/ov_SC03_090/ov_SC03_090_after.c +++ b/src/ov_SC03_090/ov_SC03_090_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_090/nonmatchings/ov_SC03_090_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_090/nonmatchings/ov_SC03_090_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_090/ov_SC03_090_jr_8012ACE0.c b/src/ov_SC03_090/ov_SC03_090_jr_8012ACE0.c index 1eb1a8a2a2..d41323a716 100644 --- a/src/ov_SC03_090/ov_SC03_090_jr_8012ACE0.c +++ b/src/ov_SC03_090/ov_SC03_090_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_090/nonmatchings/ov_SC03_090_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_090/ov_SC03_090_jr_801734BC.c b/src/ov_SC03_090/ov_SC03_090_jr_801734BC.c index e2e621371c..5ff2a545b1 100644 --- a/src/ov_SC03_090/ov_SC03_090_jr_801734BC.c +++ b/src/ov_SC03_090/ov_SC03_090_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_090/nonmatchings/ov_SC03_090_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_090/ov_SC03_090_jr_8017AE2C.c b/src/ov_SC03_090/ov_SC03_090_jr_8017AE2C.c index c13ecbdcd6..65e5b29c7f 100644 --- a/src/ov_SC03_090/ov_SC03_090_jr_8017AE2C.c +++ b/src/ov_SC03_090/ov_SC03_090_jr_8017AE2C.c @@ -3357,7 +3357,47 @@ void func_8017BF84(int param_1) } -INCLUDE_ASM("asm/ov_SC03_090/nonmatchings/ov_SC03_090_jr_8017AE2C", func_8017BFE0); + +/* Entity record touched by func_8017BFE0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017BFE0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017BFE0; + +extern void func_80147324(s32 arg0); +extern void func_8017C218(int); + +void func_8017BFE0(Ent_8017BFE0_8017BFE0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017BFE0 *))func_8017C218)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_090/nonmatchings/ov_SC03_090_jr_8017AE2C", func_8017C064); @@ -3485,7 +3525,72 @@ void func_8017C7C4(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_090/nonmatchings/ov_SC03_090_jr_8017AE2C", func_8017C800); + +/* func_8017C800 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017C800(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + DEFINE_func_8017C8B4() /* dedup: shared engine-core @0x8017C8B4 (src/shared) */ diff --git a/src/ov_SC03_091/ov_SC03_091.c b/src/ov_SC03_091/ov_SC03_091.c index 48937a9249..2810d2abcf 100644 --- a/src/ov_SC03_091/ov_SC03_091.c +++ b/src/ov_SC03_091/ov_SC03_091.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_091/nonmatchings/ov_SC03_091", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018CBE0[]; + s16 idx = D_8018CBE0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801CFDA4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_091/nonmatchings/ov_SC03_091", func_80128CFC); diff --git a/src/ov_SC03_091/ov_SC03_091_after.c b/src/ov_SC03_091/ov_SC03_091_after.c index ae33f79a45..24b7915b1d 100644 --- a/src/ov_SC03_091/ov_SC03_091_after.c +++ b/src/ov_SC03_091/ov_SC03_091_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_091/nonmatchings/ov_SC03_091_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_091/nonmatchings/ov_SC03_091_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_091/ov_SC03_091_jr_8012ACE0.c b/src/ov_SC03_091/ov_SC03_091_jr_8012ACE0.c index 80a3265bf5..0f3e1ddee0 100644 --- a/src/ov_SC03_091/ov_SC03_091_jr_8012ACE0.c +++ b/src/ov_SC03_091/ov_SC03_091_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_091/nonmatchings/ov_SC03_091_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_091/ov_SC03_091_jr_801734BC.c b/src/ov_SC03_091/ov_SC03_091_jr_801734BC.c index 0029af9c78..65b9d38af9 100644 --- a/src/ov_SC03_091/ov_SC03_091_jr_801734BC.c +++ b/src/ov_SC03_091/ov_SC03_091_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_091/nonmatchings/ov_SC03_091_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_091/ov_SC03_091_jr_8017AE2C.c b/src/ov_SC03_091/ov_SC03_091_jr_8017AE2C.c index 3ae55665be..e0b1517ca8 100644 --- a/src/ov_SC03_091/ov_SC03_091_jr_8017AE2C.c +++ b/src/ov_SC03_091/ov_SC03_091_jr_8017AE2C.c @@ -3403,7 +3403,47 @@ void func_8017CD9C(int param_1) } -INCLUDE_ASM("asm/ov_SC03_091/nonmatchings/ov_SC03_091_jr_8017AE2C", func_8017CDF8); + +/* Entity record touched by func_8017CDF8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017CDF8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017CDF8; + +extern void func_80147324(s32 arg0); +extern void func_8017D030(int); + +void func_8017CDF8(Ent_8017BFE0_8017CDF8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017CDF8 *))func_8017D030)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_091/nonmatchings/ov_SC03_091_jr_8017AE2C", func_8017CE7C); @@ -3568,7 +3608,72 @@ void func_8017D5DC(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_091/nonmatchings/ov_SC03_091_jr_8017AE2C", func_8017D618); + +/* func_8017D618 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D618(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_092/ov_SC03_092.c b/src/ov_SC03_092/ov_SC03_092.c index 35d84c960b..9ae3c2dc94 100644 --- a/src/ov_SC03_092/ov_SC03_092.c +++ b/src/ov_SC03_092/ov_SC03_092.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_092/nonmatchings/ov_SC03_092", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80184FB0[]; + s16 idx = D_80184FB0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B097C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_092/nonmatchings/ov_SC03_092", func_80128CFC); diff --git a/src/ov_SC03_092/ov_SC03_092_after.c b/src/ov_SC03_092/ov_SC03_092_after.c index 5b44bb566a..689a49a1f6 100644 --- a/src/ov_SC03_092/ov_SC03_092_after.c +++ b/src/ov_SC03_092/ov_SC03_092_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_092/nonmatchings/ov_SC03_092_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_092/nonmatchings/ov_SC03_092_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_092/ov_SC03_092_jr_8012ACE0.c b/src/ov_SC03_092/ov_SC03_092_jr_8012ACE0.c index 2d858f7390..aec2880b08 100644 --- a/src/ov_SC03_092/ov_SC03_092_jr_8012ACE0.c +++ b/src/ov_SC03_092/ov_SC03_092_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_092/nonmatchings/ov_SC03_092_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_092/ov_SC03_092_jr_801734BC.c b/src/ov_SC03_092/ov_SC03_092_jr_801734BC.c index 80b2cc3c92..7338f508fa 100644 --- a/src/ov_SC03_092/ov_SC03_092_jr_801734BC.c +++ b/src/ov_SC03_092/ov_SC03_092_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_092/nonmatchings/ov_SC03_092_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_092/ov_SC03_092_jr_8017AE2C.c b/src/ov_SC03_092/ov_SC03_092_jr_8017AE2C.c index a979a8cfed..9a71636983 100644 --- a/src/ov_SC03_092/ov_SC03_092_jr_8017AE2C.c +++ b/src/ov_SC03_092/ov_SC03_092_jr_8017AE2C.c @@ -3357,7 +3357,47 @@ void func_8017BF84(int param_1) } -INCLUDE_ASM("asm/ov_SC03_092/nonmatchings/ov_SC03_092_jr_8017AE2C", func_8017BFE0); + +/* Entity record touched by func_8017BFE0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017BFE0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017BFE0; + +extern void func_80147324(s32 arg0); +extern void func_8017C218(int); + +void func_8017BFE0(Ent_8017BFE0_8017BFE0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017BFE0 *))func_8017C218)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_092/nonmatchings/ov_SC03_092_jr_8017AE2C", func_8017C064); @@ -3485,7 +3525,72 @@ void func_8017C7C4(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_092/nonmatchings/ov_SC03_092_jr_8017AE2C", func_8017C800); + +/* func_8017C800 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017C800(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + DEFINE_func_8017C8B4() /* dedup: shared engine-core @0x8017C8B4 (src/shared) */ diff --git a/src/ov_SC03_093/ov_SC03_093.c b/src/ov_SC03_093/ov_SC03_093.c index 3d9fa344c3..357a718835 100644 --- a/src/ov_SC03_093/ov_SC03_093.c +++ b/src/ov_SC03_093/ov_SC03_093.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80186188[]; + s16 idx = D_80186188[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C9DD0, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093", func_80128CFC); diff --git a/src/ov_SC03_093/ov_SC03_093_after.c b/src/ov_SC03_093/ov_SC03_093_after.c index a23744778f..614944e260 100644 --- a/src/ov_SC03_093/ov_SC03_093_after.c +++ b/src/ov_SC03_093/ov_SC03_093_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_093/ov_SC03_093_jr_8012ACE0.c b/src/ov_SC03_093/ov_SC03_093_jr_8012ACE0.c index 4a9063fdad..841a4263cf 100644 --- a/src/ov_SC03_093/ov_SC03_093_jr_8012ACE0.c +++ b/src/ov_SC03_093/ov_SC03_093_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_093/ov_SC03_093_jr_801734BC.c b/src/ov_SC03_093/ov_SC03_093_jr_801734BC.c index c8cd995065..a89819fc80 100644 --- a/src/ov_SC03_093/ov_SC03_093_jr_801734BC.c +++ b/src/ov_SC03_093/ov_SC03_093_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_093/ov_SC03_093_jr_8017AE2C.c b/src/ov_SC03_093/ov_SC03_093_jr_8017AE2C.c index 5e206730f6..f48ed783b7 100644 --- a/src/ov_SC03_093/ov_SC03_093_jr_8017AE2C.c +++ b/src/ov_SC03_093/ov_SC03_093_jr_8017AE2C.c @@ -3403,7 +3403,47 @@ void func_8017CD9C(int param_1) } -INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017AE2C", func_8017CDF8); + +/* Entity record touched by func_8017CDF8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017CDF8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017CDF8; + +extern void func_80147324(s32 arg0); +extern void func_8017D030(int); + +void func_8017CDF8(Ent_8017BFE0_8017CDF8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017CDF8 *))func_8017D030)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017AE2C", func_8017CE7C); @@ -3568,7 +3608,72 @@ void func_8017D5DC(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017AE2C", func_8017D618); + +/* func_8017D618 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D618(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_093/ov_SC03_093_jr_8017D898.c b/src/ov_SC03_093/ov_SC03_093_jr_8017D898.c index 8a5ee7672f..66f82a6937 100644 --- a/src/ov_SC03_093/ov_SC03_093_jr_8017D898.c +++ b/src/ov_SC03_093/ov_SC03_093_jr_8017D898.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3310,9 +3309,59 @@ void func_8017ECBC(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017D898", func_8017ECF8); -INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017D898", func_8017ED98); +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017ECF8; + +extern u16 func_80148800(s32 *a0); +extern void func_8017EF20(s32 param_1, s16 *param_2); + +void func_8017ECF8(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80189BD0[]; + extern Blk8_80126940_8017ECF8 D_80126940; + Blk8_80126940_8017ECF8 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80189BD0[t]; + } + sp10 = D_80126940; + func_8017EF20(a0, sp10.v); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017ED98; + +extern u16 func_80148800(s32 *a0); +extern void func_8017EF20(s32 param_1, s16 *param_2); + +void func_8017ED98(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80189BD4[]; + extern Blk8_80126940_8017ED98 D_80126940; + Blk8_80126940_8017ED98 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80189BD4[t]; + } + sp10 = D_80126940; + func_8017EF20(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017D898", func_8017EE38); diff --git a/src/ov_SC03_094/ov_SC03_094.c b/src/ov_SC03_094/ov_SC03_094.c index a4051ffb99..69d94fc976 100644 --- a/src/ov_SC03_094/ov_SC03_094.c +++ b/src/ov_SC03_094/ov_SC03_094.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80187B84[]; + s16 idx = D_80187B84[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801D0C0C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094", func_80128CFC); diff --git a/src/ov_SC03_094/ov_SC03_094_after.c b/src/ov_SC03_094/ov_SC03_094_after.c index 46124cf412..28555ef6fa 100644 --- a/src/ov_SC03_094/ov_SC03_094_after.c +++ b/src/ov_SC03_094/ov_SC03_094_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_094/ov_SC03_094_jr_8012ACE0.c b/src/ov_SC03_094/ov_SC03_094_jr_8012ACE0.c index 838e38e071..e1ad4a539e 100644 --- a/src/ov_SC03_094/ov_SC03_094_jr_8012ACE0.c +++ b/src/ov_SC03_094/ov_SC03_094_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_094/ov_SC03_094_jr_801734BC.c b/src/ov_SC03_094/ov_SC03_094_jr_801734BC.c index c1aba92004..deaf232928 100644 --- a/src/ov_SC03_094/ov_SC03_094_jr_801734BC.c +++ b/src/ov_SC03_094/ov_SC03_094_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_094/ov_SC03_094_jr_8017BEBC.c b/src/ov_SC03_094/ov_SC03_094_jr_8017BEBC.c index 66bd50a8fe..bd8d6e33ea 100644 --- a/src/ov_SC03_094/ov_SC03_094_jr_8017BEBC.c +++ b/src/ov_SC03_094/ov_SC03_094_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3313,13 +3312,63 @@ void func_8017D37C(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094_jr_8017BEBC", func_8017D3B8); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D3B8; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D6D0(s32 param_1, s16 *param_2); + +void func_8017D3B8(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_8018B488[]; + extern Blk8_80126940_8017D3B8 D_80126940; + Blk8_80126940_8017D3B8 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_8018B488[t]; + } + sp10 = D_80126940; + func_8017D6D0(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094_jr_8017BEBC", func_8017D458); INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094_jr_8017BEBC", func_8017D544); -INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094_jr_8017BEBC", func_8017D630); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D630; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D6D0(s32 param_1, s16 *param_2); + +void func_8017D630(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_8018B494[]; + extern Blk8_80126940_8017D630 D_80126940; + Blk8_80126940_8017D630 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_8018B494[t]; + } + sp10 = D_80126940; + func_8017D6D0(a0, sp10.v); +} + // @class: schedule @@ -3896,7 +3945,38 @@ void func_801820DC(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094_jr_8017BEBC", func_80182158); + +extern s32 rand(void); +extern s32 func_8012C354(s32, s32); +extern void func_8012A828(s32, s32); +extern void func_80143994(s32 *a0, s32 a1); + + +void func_80182158(void *arg0) { + + extern s32 D_801AC134; + extern s32 D_801AC178; + extern s32 D_801AE690; + s32 t; + + if (((s32 (*)(s32 *, s32))func_8012C354)(arg0, &D_801AC134)) { + *(u8 *)((char *)arg0 + 0xC0) = 1; + *(s32 *)((char *)arg0 + 0xB4) = -1; + *(s32 **)((char *)arg0 + 0xBC) = &D_801AC178; + *(u32 *)((char *)arg0 + 0xC4) |= 1; + *(s32 *)((char *)arg0 + 0xE4) = -((rand() % 8 + 0xC) << 16); + ((void (*)(s32 *, s32))func_8012A828)(arg0, &D_801AE690); + func_80143994(arg0, 0x1000); + t = *(u16 *)((char *)arg0 + 0x70) & 0x10; + if (t != 0) { + t = 3; + } else { + t = 1; + } + *(s16 *)((char *)arg0 + 0x2) = t; + } +} + INCLUDE_ASM("asm/ov_SC03_094/nonmatchings/ov_SC03_094_jr_8017BEBC", func_80182218); diff --git a/src/ov_SC03_095/ov_SC03_095.c b/src/ov_SC03_095/ov_SC03_095.c index 00ebf0b160..4cd388716d 100644 --- a/src/ov_SC03_095/ov_SC03_095.c +++ b/src/ov_SC03_095/ov_SC03_095.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_095/nonmatchings/ov_SC03_095", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801811E4[]; + s16 idx = D_801811E4[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80199838, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_095/nonmatchings/ov_SC03_095", func_80128CFC); diff --git a/src/ov_SC03_095/ov_SC03_095_after.c b/src/ov_SC03_095/ov_SC03_095_after.c index 7aebfb298b..09bc696a3b 100644 --- a/src/ov_SC03_095/ov_SC03_095_after.c +++ b/src/ov_SC03_095/ov_SC03_095_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_095/nonmatchings/ov_SC03_095_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_095/nonmatchings/ov_SC03_095_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_095/ov_SC03_095_jr_8012ACE0.c b/src/ov_SC03_095/ov_SC03_095_jr_8012ACE0.c index 6fe6fbe2fe..6856e88caa 100644 --- a/src/ov_SC03_095/ov_SC03_095_jr_8012ACE0.c +++ b/src/ov_SC03_095/ov_SC03_095_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_095/nonmatchings/ov_SC03_095_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_095/ov_SC03_095_jr_801734BC.c b/src/ov_SC03_095/ov_SC03_095_jr_801734BC.c index f2b54404b2..3b55081fe5 100644 --- a/src/ov_SC03_095/ov_SC03_095_jr_801734BC.c +++ b/src/ov_SC03_095/ov_SC03_095_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_095/nonmatchings/ov_SC03_095_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_095/ov_SC03_095_jr_8017BEBC.c b/src/ov_SC03_095/ov_SC03_095_jr_8017BEBC.c index 87651d00da..d5fe1af619 100644 --- a/src/ov_SC03_095/ov_SC03_095_jr_8017BEBC.c +++ b/src/ov_SC03_095/ov_SC03_095_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3273,7 +3272,32 @@ void func_8017D1CC(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_095/nonmatchings/ov_SC03_095_jr_8017BEBC", func_8017D208); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D208; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D390(s32 param_1, s16 *param_2); + +void func_8017D208(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_801849F0[]; + extern Blk8_80126940_8017D208 D_80126940; + Blk8_80126940_8017D208 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_801849F0[t]; + } + sp10 = D_80126940; + func_8017D390(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC03_095/nonmatchings/ov_SC03_095_jr_8017BEBC", func_8017D2A8); diff --git a/src/ov_SC03_096/ov_SC03_096.c b/src/ov_SC03_096/ov_SC03_096.c index 8d7f49388b..37637fe6e3 100644 --- a/src/ov_SC03_096/ov_SC03_096.c +++ b/src/ov_SC03_096/ov_SC03_096.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_096/nonmatchings/ov_SC03_096", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80180D64[]; + s16 idx = D_80180D64[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801982EC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_096/nonmatchings/ov_SC03_096", func_80128CFC); diff --git a/src/ov_SC03_096/ov_SC03_096_after.c b/src/ov_SC03_096/ov_SC03_096_after.c index b9865cc747..25654633a2 100644 --- a/src/ov_SC03_096/ov_SC03_096_after.c +++ b/src/ov_SC03_096/ov_SC03_096_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_096/nonmatchings/ov_SC03_096_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_096/nonmatchings/ov_SC03_096_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_096/ov_SC03_096_jr_8012ACE0.c b/src/ov_SC03_096/ov_SC03_096_jr_8012ACE0.c index 1c4dd758fb..42c0939194 100644 --- a/src/ov_SC03_096/ov_SC03_096_jr_8012ACE0.c +++ b/src/ov_SC03_096/ov_SC03_096_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_096/nonmatchings/ov_SC03_096_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_096/ov_SC03_096_jr_801734BC.c b/src/ov_SC03_096/ov_SC03_096_jr_801734BC.c index c7e4e6a706..b8d04fc3fe 100644 --- a/src/ov_SC03_096/ov_SC03_096_jr_801734BC.c +++ b/src/ov_SC03_096/ov_SC03_096_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_096/nonmatchings/ov_SC03_096_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_097/ov_SC03_097.c b/src/ov_SC03_097/ov_SC03_097.c index 5d0bcfb624..3afdc6104a 100644 --- a/src/ov_SC03_097/ov_SC03_097.c +++ b/src/ov_SC03_097/ov_SC03_097.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80186144[]; + s16 idx = D_80186144[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A835C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097", func_80128CFC); diff --git a/src/ov_SC03_097/ov_SC03_097_after.c b/src/ov_SC03_097/ov_SC03_097_after.c index c50fd681c3..51101e84a3 100644 --- a/src/ov_SC03_097/ov_SC03_097_after.c +++ b/src/ov_SC03_097/ov_SC03_097_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_097/ov_SC03_097_jr_8012ACE0.c b/src/ov_SC03_097/ov_SC03_097_jr_8012ACE0.c index d826214798..414c1984a6 100644 --- a/src/ov_SC03_097/ov_SC03_097_jr_8012ACE0.c +++ b/src/ov_SC03_097/ov_SC03_097_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_097/ov_SC03_097_jr_801734BC.c b/src/ov_SC03_097/ov_SC03_097_jr_801734BC.c index 52634e81b2..f473645259 100644 --- a/src/ov_SC03_097/ov_SC03_097_jr_801734BC.c +++ b/src/ov_SC03_097/ov_SC03_097_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_097/ov_SC03_097_jr_8017AE2C.c b/src/ov_SC03_097/ov_SC03_097_jr_8017AE2C.c index 5ec1e29019..5102ba8cdb 100644 --- a/src/ov_SC03_097/ov_SC03_097_jr_8017AE2C.c +++ b/src/ov_SC03_097/ov_SC03_097_jr_8017AE2C.c @@ -3403,7 +3403,47 @@ void func_8017CD9C(int param_1) } -INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_8017AE2C", func_8017CDF8); + +/* Entity record touched by func_8017CDF8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017CDF8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017CDF8; + +extern void func_80147324(s32 arg0); +extern void func_8017D030(int); + +void func_8017CDF8(Ent_8017BFE0_8017CDF8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017CDF8 *))func_8017D030)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_8017AE2C", func_8017CE7C); @@ -3568,7 +3608,72 @@ void func_8017D5DC(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_8017AE2C", func_8017D618); + +/* func_8017D618 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D618(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_097/ov_SC03_097_jr_8017D898.c b/src/ov_SC03_097/ov_SC03_097_jr_8017D898.c index 6452779636..d7cf233ad3 100644 --- a/src/ov_SC03_097/ov_SC03_097_jr_8017D898.c +++ b/src/ov_SC03_097/ov_SC03_097_jr_8017D898.c @@ -3729,7 +3729,53 @@ void func_801818DC(void) { } -INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_8017D898", func_80181900); + +/* func_80181900 — cookbook §71 (sibling-first). + * func_801819A0 is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_801819A0(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_80181ABC (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_80181900; + +extern void func_801819A0(s32 arg0, s32 arg1, s32 arg2); +extern void func_80181ABC(s32 arg0, Rec_8018A6A4_80181900 *arg1, s32 arg2, s32 arg3); + +void func_80181900(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_80181900 sp10; + s32 i; + s32 ang; + + func_801819A0(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_80181ABC(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_8017D898", func_801819A0); @@ -3754,7 +3800,57 @@ INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_8017D898", func_80181B9 INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_8017D898", func_80181BCC); -INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_8017D898", func_80181C18); + +/* func_80181C18 — 16-entry table walk, stride 0xE, over D_801AAC74. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801AAC74; s16 *p = &D_801AAC74; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_80181CF4(s32 arg0); + +void func_80181C18(void) { + + extern s16 D_801AAC74; + s16 *p = &D_801AAC74; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_80181CF4(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_8017D898", func_80181CF4); diff --git a/src/ov_SC03_098/ov_SC03_098.c b/src/ov_SC03_098/ov_SC03_098.c index af1fb62658..47a020ff46 100644 --- a/src/ov_SC03_098/ov_SC03_098.c +++ b/src/ov_SC03_098/ov_SC03_098.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_098/nonmatchings/ov_SC03_098", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801855D0[]; + s16 idx = D_801855D0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C2FE0, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_098/nonmatchings/ov_SC03_098", func_80128CFC); diff --git a/src/ov_SC03_098/ov_SC03_098_after.c b/src/ov_SC03_098/ov_SC03_098_after.c index 7a23fadfa8..5f9045fae0 100644 --- a/src/ov_SC03_098/ov_SC03_098_after.c +++ b/src/ov_SC03_098/ov_SC03_098_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_098/nonmatchings/ov_SC03_098_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_098/nonmatchings/ov_SC03_098_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_098/ov_SC03_098_jr_8012ACE0.c b/src/ov_SC03_098/ov_SC03_098_jr_8012ACE0.c index e4a0886fdb..6944a22a17 100644 --- a/src/ov_SC03_098/ov_SC03_098_jr_8012ACE0.c +++ b/src/ov_SC03_098/ov_SC03_098_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_098/nonmatchings/ov_SC03_098_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_098/ov_SC03_098_jr_801734BC.c b/src/ov_SC03_098/ov_SC03_098_jr_801734BC.c index 9a5223019c..33ee90edd5 100644 --- a/src/ov_SC03_098/ov_SC03_098_jr_801734BC.c +++ b/src/ov_SC03_098/ov_SC03_098_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_098/nonmatchings/ov_SC03_098_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_098/ov_SC03_098_jr_8017AE2C.c b/src/ov_SC03_098/ov_SC03_098_jr_8017AE2C.c index a41888957d..603dff901d 100644 --- a/src/ov_SC03_098/ov_SC03_098_jr_8017AE2C.c +++ b/src/ov_SC03_098/ov_SC03_098_jr_8017AE2C.c @@ -3403,7 +3403,47 @@ void func_8017CD9C(int param_1) } -INCLUDE_ASM("asm/ov_SC03_098/nonmatchings/ov_SC03_098_jr_8017AE2C", func_8017CDF8); + +/* Entity record touched by func_8017CDF8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017CDF8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017CDF8; + +extern void func_80147324(s32 arg0); +extern void func_8017D030(int); + +void func_8017CDF8(Ent_8017BFE0_8017CDF8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017CDF8 *))func_8017D030)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_098/nonmatchings/ov_SC03_098_jr_8017AE2C", func_8017CE7C); @@ -3568,7 +3608,72 @@ void func_8017D5DC(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_098/nonmatchings/ov_SC03_098_jr_8017AE2C", func_8017D618); + +/* func_8017D618 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D618(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_098/ov_SC03_098_jr_8017D898.c b/src/ov_SC03_098/ov_SC03_098_jr_8017D898.c index 8eef5bf2d3..341fdfc4ee 100644 --- a/src/ov_SC03_098/ov_SC03_098_jr_8017D898.c +++ b/src/ov_SC03_098/ov_SC03_098_jr_8017D898.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3293,9 +3292,59 @@ void func_8017EBE4(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_098/nonmatchings/ov_SC03_098_jr_8017D898", func_8017EC20); -INCLUDE_ASM("asm/ov_SC03_098/nonmatchings/ov_SC03_098_jr_8017D898", func_8017ECC0); +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017EC20; + +extern u16 func_80148800(s32 *a0); +extern void func_8017ED60(s32 param_1, s16 *param_2); + +void func_8017EC20(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80188F74[]; + extern Blk8_80126940_8017EC20 D_80126940; + Blk8_80126940_8017EC20 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80188F74[t]; + } + sp10 = D_80126940; + func_8017ED60(a0, sp10.v); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017ECC0; + +extern u16 func_80148800(s32 *a0); +extern void func_8017ED60(s32 param_1, s16 *param_2); + +void func_8017ECC0(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80188F78[]; + extern Blk8_80126940_8017ECC0 D_80126940; + Blk8_80126940_8017ECC0 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80188F78[t]; + } + sp10 = D_80126940; + func_8017ED60(a0, sp10.v); +} + // @class: schedule diff --git a/src/ov_SC03_099/ov_SC03_099.c b/src/ov_SC03_099/ov_SC03_099.c index 43f6d10ed2..e6b7dd1721 100644 --- a/src/ov_SC03_099/ov_SC03_099.c +++ b/src/ov_SC03_099/ov_SC03_099.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_099/nonmatchings/ov_SC03_099", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801836D0[]; + s16 idx = D_801836D0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801BCCB4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_099/nonmatchings/ov_SC03_099", func_80128CFC); diff --git a/src/ov_SC03_099/ov_SC03_099_after.c b/src/ov_SC03_099/ov_SC03_099_after.c index 64af7b3140..3a25652a8f 100644 --- a/src/ov_SC03_099/ov_SC03_099_after.c +++ b/src/ov_SC03_099/ov_SC03_099_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_099/nonmatchings/ov_SC03_099_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_099/nonmatchings/ov_SC03_099_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_099/ov_SC03_099_jr_8012ACE0.c b/src/ov_SC03_099/ov_SC03_099_jr_8012ACE0.c index 26a81d0f31..c93c77fafc 100644 --- a/src/ov_SC03_099/ov_SC03_099_jr_8012ACE0.c +++ b/src/ov_SC03_099/ov_SC03_099_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_099/nonmatchings/ov_SC03_099_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_099/ov_SC03_099_jr_801734BC.c b/src/ov_SC03_099/ov_SC03_099_jr_801734BC.c index f670d5b221..a60c3a1bbd 100644 --- a/src/ov_SC03_099/ov_SC03_099_jr_801734BC.c +++ b/src/ov_SC03_099/ov_SC03_099_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_099/nonmatchings/ov_SC03_099_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_099/ov_SC03_099_jr_8017BEBC.c b/src/ov_SC03_099/ov_SC03_099_jr_8017BEBC.c index 07e7f62036..a6823dda1a 100644 --- a/src/ov_SC03_099/ov_SC03_099_jr_8017BEBC.c +++ b/src/ov_SC03_099/ov_SC03_099_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3275,7 +3274,32 @@ void func_8017D1D0(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_099/nonmatchings/ov_SC03_099_jr_8017BEBC", func_8017D20C); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D20C; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D364(s32 param_1, s16 *param_2); + +void func_8017D20C(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80186EDC[]; + extern Blk8_80126940_8017D20C D_80126940; + Blk8_80126940_8017D20C sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80186EDC[t]; + } + sp10 = D_80126940; + func_8017D364(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC03_099/nonmatchings/ov_SC03_099_jr_8017BEBC", func_8017D2AC); @@ -3817,7 +3841,38 @@ void func_8017F5F0(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_099/nonmatchings/ov_SC03_099_jr_8017BEBC", func_8017F66C); + +extern s32 rand(void); +extern s32 func_8012C354(s32, s32); +extern void func_8012A828(s32 *a0, s32 a1); +extern void func_80143994(s32 *a0, s32 a1); + + +void func_8017F66C(void *arg0) { + + extern s32 D_8019CA0C; + extern s32 D_8019CA50; + extern s32 D_8019EF68; + s32 t; + + if (((s32 (*)(s32 *, s32))func_8012C354)(arg0, &D_8019CA0C)) { + *(u8 *)((char *)arg0 + 0xC0) = 1; + *(s32 *)((char *)arg0 + 0xB4) = -1; + *(s32 **)((char *)arg0 + 0xBC) = &D_8019CA50; + *(u32 *)((char *)arg0 + 0xC4) |= 1; + *(s32 *)((char *)arg0 + 0xE4) = -((rand() % 8 + 0xC) << 16); + func_8012A828(arg0, &D_8019EF68); + func_80143994(arg0, 0x1000); + t = *(u16 *)((char *)arg0 + 0x70) & 0x10; + if (t != 0) { + t = 3; + } else { + t = 1; + } + *(s16 *)((char *)arg0 + 0x2) = t; + } +} + INCLUDE_ASM("asm/ov_SC03_099/nonmatchings/ov_SC03_099_jr_8017BEBC", func_8017F72C); diff --git a/src/ov_SC03_100/ov_SC03_100.c b/src/ov_SC03_100/ov_SC03_100.c index 3d6f3489f3..4939b21898 100644 --- a/src/ov_SC03_100/ov_SC03_100.c +++ b/src/ov_SC03_100/ov_SC03_100.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_100/nonmatchings/ov_SC03_100", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80184B9C[]; + s16 idx = D_80184B9C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C5F38, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_100/nonmatchings/ov_SC03_100", func_80128CFC); diff --git a/src/ov_SC03_100/ov_SC03_100_after.c b/src/ov_SC03_100/ov_SC03_100_after.c index 128c81f46f..3e6ad9d895 100644 --- a/src/ov_SC03_100/ov_SC03_100_after.c +++ b/src/ov_SC03_100/ov_SC03_100_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_100/nonmatchings/ov_SC03_100_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_100/nonmatchings/ov_SC03_100_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_100/ov_SC03_100_jr_8012ACE0.c b/src/ov_SC03_100/ov_SC03_100_jr_8012ACE0.c index 5e86e78630..2039c3bd71 100644 --- a/src/ov_SC03_100/ov_SC03_100_jr_8012ACE0.c +++ b/src/ov_SC03_100/ov_SC03_100_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_100/nonmatchings/ov_SC03_100_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_100/ov_SC03_100_jr_801734BC.c b/src/ov_SC03_100/ov_SC03_100_jr_801734BC.c index 033dbbcfe0..3cf0d7f350 100644 --- a/src/ov_SC03_100/ov_SC03_100_jr_801734BC.c +++ b/src/ov_SC03_100/ov_SC03_100_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_100/nonmatchings/ov_SC03_100_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_100/ov_SC03_100_jr_8017AE2C.c b/src/ov_SC03_100/ov_SC03_100_jr_8017AE2C.c index 252512e9dc..ec92623f96 100644 --- a/src/ov_SC03_100/ov_SC03_100_jr_8017AE2C.c +++ b/src/ov_SC03_100/ov_SC03_100_jr_8017AE2C.c @@ -3403,7 +3403,47 @@ void func_8017CD9C(int param_1) } -INCLUDE_ASM("asm/ov_SC03_100/nonmatchings/ov_SC03_100_jr_8017AE2C", func_8017CDF8); + +/* Entity record touched by func_8017CDF8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017CDF8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017CDF8; + +extern void func_80147324(s32 arg0); +extern void func_8017D030(int); + +void func_8017CDF8(Ent_8017BFE0_8017CDF8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017CDF8 *))func_8017D030)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_100/nonmatchings/ov_SC03_100_jr_8017AE2C", func_8017CE7C); @@ -3568,7 +3608,72 @@ void func_8017D5DC(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_100/nonmatchings/ov_SC03_100_jr_8017AE2C", func_8017D618); + +/* func_8017D618 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D618(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_100/ov_SC03_100_jr_8017D898.c b/src/ov_SC03_100/ov_SC03_100_jr_8017D898.c index 7a7f343a7e..55f2be4d0d 100644 --- a/src/ov_SC03_100/ov_SC03_100_jr_8017D898.c +++ b/src/ov_SC03_100/ov_SC03_100_jr_8017D898.c @@ -3283,7 +3283,31 @@ void func_8017EBA8(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_100/nonmatchings/ov_SC03_100_jr_8017D898", func_8017EBE4); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017EBE4; + +extern u16 func_80148800(s32 *a0); +extern void func_8017ED90(s32 param_1, s16 *param_2); + +void func_8017EBE4(s32 a0) { + + extern s16 D_80188540[]; + extern Blk8_80126940_8017EBE4 D_80126940; + Blk8_80126940_8017EBE4 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80188540[t]; + } + sp10 = D_80126940; + func_8017ED90(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC03_100/nonmatchings/ov_SC03_100_jr_8017D898", func_8017EC84); diff --git a/src/ov_SC03_101/ov_SC03_101.c b/src/ov_SC03_101/ov_SC03_101.c index d808127b67..a54273a761 100644 --- a/src/ov_SC03_101/ov_SC03_101.c +++ b/src/ov_SC03_101/ov_SC03_101.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80183B78[]; + s16 idx = D_80183B78[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019B800, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101", func_80128CFC); diff --git a/src/ov_SC03_101/ov_SC03_101_after.c b/src/ov_SC03_101/ov_SC03_101_after.c index ee3b8486a1..ba7684a8cc 100644 --- a/src/ov_SC03_101/ov_SC03_101_after.c +++ b/src/ov_SC03_101/ov_SC03_101_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_101/ov_SC03_101_jr_8012ACE0.c b/src/ov_SC03_101/ov_SC03_101_jr_8012ACE0.c index fd7758b01c..1ca9e5701f 100644 --- a/src/ov_SC03_101/ov_SC03_101_jr_8012ACE0.c +++ b/src/ov_SC03_101/ov_SC03_101_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_101/ov_SC03_101_jr_801734BC.c b/src/ov_SC03_101/ov_SC03_101_jr_801734BC.c index 96efaf0c25..ab0c865ea5 100644 --- a/src/ov_SC03_101/ov_SC03_101_jr_801734BC.c +++ b/src/ov_SC03_101/ov_SC03_101_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_101/ov_SC03_101_jr_8017AE2C.c b/src/ov_SC03_101/ov_SC03_101_jr_8017AE2C.c index 459ecdc6b6..ed177566d8 100644 --- a/src/ov_SC03_101/ov_SC03_101_jr_8017AE2C.c +++ b/src/ov_SC03_101/ov_SC03_101_jr_8017AE2C.c @@ -3357,7 +3357,47 @@ void func_8017BF84(int param_1) } -INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_8017AE2C", func_8017BFE0); + +/* Entity record touched by func_8017BFE0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017BFE0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017BFE0; + +extern void func_80147324(s32 arg0); +extern void func_8017C218(int); + +void func_8017BFE0(Ent_8017BFE0_8017BFE0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017BFE0 *))func_8017C218)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_8017AE2C", func_8017C064); @@ -3485,7 +3525,72 @@ void func_8017C7C4(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_8017AE2C", func_8017C800); + +/* func_8017C800 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017C800(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + DEFINE_func_8017C8B4() /* dedup: shared engine-core @0x8017C8B4 (src/shared) */ diff --git a/src/ov_SC03_101/ov_SC03_101_jr_8017CA80.c b/src/ov_SC03_101/ov_SC03_101_jr_8017CA80.c index 552bd64d68..291ce41f80 100644 --- a/src/ov_SC03_101/ov_SC03_101_jr_8017CA80.c +++ b/src/ov_SC03_101/ov_SC03_101_jr_8017CA80.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3340,7 +3339,32 @@ void func_8017DFE0(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_8017CA80", func_8017E01C); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017E01C; + +extern u16 func_80148800(s32 *a0); +extern void func_8017E174(s32 param_1, s16 *param_2); + +void func_8017E01C(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_801873FC[]; + extern Blk8_80126940_8017E01C D_80126940; + Blk8_80126940_8017E01C sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_801873FC[t]; + } + sp10 = D_80126940; + func_8017E174(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_8017CA80", func_8017E0BC); @@ -3983,7 +4007,53 @@ void func_80181E3C(void) { } -INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_8017CA80", func_80181E60); + +/* func_80181E60 — cookbook §71 (sibling-first). + * func_80181F00 is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_80181F00(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_8018201C (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_80181E60; + +extern void func_80181F00(s32 arg0, s32 arg1, s32 arg2); +extern void func_8018201C(s32 arg0, Rec_8018A6A4_80181E60 *arg1, s32 arg2, s32 arg3); + +void func_80181E60(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_80181E60 sp10; + s32 i; + s32 ang; + + func_80181F00(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_8018201C(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + extern s16 D_8019DE84; @@ -4014,7 +4084,57 @@ INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_8017CA80", func_801820F INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_8017CA80", func_8018212C); -INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_8017CA80", func_80182178); + +/* func_80182178 — 16-entry table walk, stride 0xE, over D_8019DE8C. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_8019DE8C; s16 *p = &D_8019DE8C; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_80182254(s32 arg0); + +void func_80182178(void) { + + extern s16 D_8019DE8C; + s16 *p = &D_8019DE8C; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_80182254(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC03_101/nonmatchings/ov_SC03_101_jr_8017CA80", func_80182254); diff --git a/src/ov_SC03_102/ov_SC03_102.c b/src/ov_SC03_102/ov_SC03_102.c index b5d4ec59be..99048a4dd0 100644 --- a/src/ov_SC03_102/ov_SC03_102.c +++ b/src/ov_SC03_102/ov_SC03_102.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_102/nonmatchings/ov_SC03_102", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80186430[]; + s16 idx = D_80186430[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B747C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_102/nonmatchings/ov_SC03_102", func_80128CFC); diff --git a/src/ov_SC03_102/ov_SC03_102_after.c b/src/ov_SC03_102/ov_SC03_102_after.c index b753a45850..039de3d9a7 100644 --- a/src/ov_SC03_102/ov_SC03_102_after.c +++ b/src/ov_SC03_102/ov_SC03_102_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_102/nonmatchings/ov_SC03_102_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_102/nonmatchings/ov_SC03_102_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_102/ov_SC03_102_jr_8012ACE0.c b/src/ov_SC03_102/ov_SC03_102_jr_8012ACE0.c index 7b8b430e50..4b6fd1fad2 100644 --- a/src/ov_SC03_102/ov_SC03_102_jr_8012ACE0.c +++ b/src/ov_SC03_102/ov_SC03_102_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_102/nonmatchings/ov_SC03_102_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_102/ov_SC03_102_jr_801734BC.c b/src/ov_SC03_102/ov_SC03_102_jr_801734BC.c index 20627e5383..02289f4874 100644 --- a/src/ov_SC03_102/ov_SC03_102_jr_801734BC.c +++ b/src/ov_SC03_102/ov_SC03_102_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_102/nonmatchings/ov_SC03_102_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_103/ov_SC03_103.c b/src/ov_SC03_103/ov_SC03_103.c index 2c81931461..f223cd72b6 100644 --- a/src/ov_SC03_103/ov_SC03_103.c +++ b/src/ov_SC03_103/ov_SC03_103.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_103/nonmatchings/ov_SC03_103", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801843E0[]; + s16 idx = D_801843E0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C2630, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_103/nonmatchings/ov_SC03_103", func_80128CFC); diff --git a/src/ov_SC03_103/ov_SC03_103_after.c b/src/ov_SC03_103/ov_SC03_103_after.c index 088d3a1e86..34248e7e55 100644 --- a/src/ov_SC03_103/ov_SC03_103_after.c +++ b/src/ov_SC03_103/ov_SC03_103_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_103/nonmatchings/ov_SC03_103_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_103/nonmatchings/ov_SC03_103_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_103/ov_SC03_103_jr_8012ACE0.c b/src/ov_SC03_103/ov_SC03_103_jr_8012ACE0.c index 756df331bc..b66ba2a848 100644 --- a/src/ov_SC03_103/ov_SC03_103_jr_8012ACE0.c +++ b/src/ov_SC03_103/ov_SC03_103_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_103/nonmatchings/ov_SC03_103_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_103/ov_SC03_103_jr_801734BC.c b/src/ov_SC03_103/ov_SC03_103_jr_801734BC.c index 8378ff5012..42198fb7f0 100644 --- a/src/ov_SC03_103/ov_SC03_103_jr_801734BC.c +++ b/src/ov_SC03_103/ov_SC03_103_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_103/nonmatchings/ov_SC03_103_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_103/ov_SC03_103_jr_8017C294.c b/src/ov_SC03_103/ov_SC03_103_jr_8017C294.c index 881c3cfd07..27adf2a093 100644 --- a/src/ov_SC03_103/ov_SC03_103_jr_8017C294.c +++ b/src/ov_SC03_103/ov_SC03_103_jr_8017C294.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3297,9 +3296,59 @@ void func_8017E290(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_103/nonmatchings/ov_SC03_103_jr_8017C294", func_8017E2CC); -INCLUDE_ASM("asm/ov_SC03_103/nonmatchings/ov_SC03_103_jr_8017C294", func_8017E36C); +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017E2CC; + +extern u16 func_80148800(s32 *a0); +extern void func_8017E5A4(s32 param_1, s16 *param_2); + +void func_8017E2CC(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80188064[]; + extern Blk8_80126940_8017E2CC D_80126940; + Blk8_80126940_8017E2CC sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80188064[t]; + } + sp10 = D_80126940; + func_8017E5A4(a0, sp10.v); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017E36C; + +extern u16 func_80148800(s32 *a0); +extern void func_8017E40C(s32 param_1, s16 *param_2); + +void func_8017E36C(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80188068[]; + extern Blk8_80126940_8017E36C D_80126940; + Blk8_80126940_8017E36C sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80188068[t]; + } + sp10 = D_80126940; + func_8017E40C(a0, sp10.v); +} + // @class: schedule @@ -3756,7 +3805,38 @@ void func_80180300(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_103/nonmatchings/ov_SC03_103_jr_8017C294", func_8018037C); + +extern s32 rand(void); +extern s32 func_8012C354(s32, s32); +extern void func_8012A828(s32, s32); +extern void func_80143994(s32 *a0, s32 a1); + + +void func_8018037C(void *arg0) { + + extern s32 D_801A2388; + extern s32 D_801A23CC; + extern s32 D_801A48E4; + s32 t; + + if (((s32 (*)(s32 *, s32))func_8012C354)(arg0, &D_801A2388)) { + *(u8 *)((char *)arg0 + 0xC0) = 1; + *(s32 *)((char *)arg0 + 0xB4) = -1; + *(s32 **)((char *)arg0 + 0xBC) = &D_801A23CC; + *(u32 *)((char *)arg0 + 0xC4) |= 1; + *(s32 *)((char *)arg0 + 0xE4) = -((rand() % 8 + 0xC) << 16); + ((void (*)(s32 *, s32))func_8012A828)(arg0, &D_801A48E4); + func_80143994(arg0, 0x1000); + t = *(u16 *)((char *)arg0 + 0x70) & 0x10; + if (t != 0) { + t = 3; + } else { + t = 1; + } + *(s16 *)((char *)arg0 + 0x2) = t; + } +} + INCLUDE_ASM("asm/ov_SC03_103/nonmatchings/ov_SC03_103_jr_8017C294", func_8018043C); diff --git a/src/ov_SC03_104/ov_SC03_104.c b/src/ov_SC03_104/ov_SC03_104.c index 6d0bb421c5..1d6758b7a5 100644 --- a/src/ov_SC03_104/ov_SC03_104.c +++ b/src/ov_SC03_104/ov_SC03_104.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018AF70[]; + s16 idx = D_8018AF70[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801BDB90, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104", func_80128CFC); diff --git a/src/ov_SC03_104/ov_SC03_104_after.c b/src/ov_SC03_104/ov_SC03_104_after.c index ffb3552ebf..baea482fcd 100644 --- a/src/ov_SC03_104/ov_SC03_104_after.c +++ b/src/ov_SC03_104/ov_SC03_104_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_104/ov_SC03_104_jr_8012ACE0.c b/src/ov_SC03_104/ov_SC03_104_jr_8012ACE0.c index 99221fa504..a961c0b2aa 100644 --- a/src/ov_SC03_104/ov_SC03_104_jr_8012ACE0.c +++ b/src/ov_SC03_104/ov_SC03_104_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_104/ov_SC03_104_jr_801734BC.c b/src/ov_SC03_104/ov_SC03_104_jr_801734BC.c index 7e5844cb0d..8a6be8980e 100644 --- a/src/ov_SC03_104/ov_SC03_104_jr_801734BC.c +++ b/src/ov_SC03_104/ov_SC03_104_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_104/ov_SC03_104_jr_8017AE2C.c b/src/ov_SC03_104/ov_SC03_104_jr_8017AE2C.c index ca4f889b2c..430afd0ae6 100644 --- a/src/ov_SC03_104/ov_SC03_104_jr_8017AE2C.c +++ b/src/ov_SC03_104/ov_SC03_104_jr_8017AE2C.c @@ -3357,7 +3357,47 @@ void func_8017BF84(int param_1) } -INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_jr_8017AE2C", func_8017BFE0); + +/* Entity record touched by func_8017BFE0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017BFE0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017BFE0; + +extern void func_80147324(s32 arg0); +extern void func_8017C218(int); + +void func_8017BFE0(Ent_8017BFE0_8017BFE0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017BFE0 *))func_8017C218)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_jr_8017AE2C", func_8017C064); @@ -3485,7 +3525,72 @@ void func_8017C7C4(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_jr_8017AE2C", func_8017C800); + +/* func_8017C800 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017C800(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + DEFINE_func_8017C8B4() /* dedup: shared engine-core @0x8017C8B4 (src/shared) */ diff --git a/src/ov_SC03_104/ov_SC03_104_jr_8017CA80.c b/src/ov_SC03_104/ov_SC03_104_jr_8017CA80.c index 29c23fe72b..f9387144d2 100644 --- a/src/ov_SC03_104/ov_SC03_104_jr_8017CA80.c +++ b/src/ov_SC03_104/ov_SC03_104_jr_8017CA80.c @@ -4391,7 +4391,53 @@ void func_80185278(void) { } -INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_jr_8017CA80", func_8018529C); + +/* func_8018529C — cookbook §71 (sibling-first). + * func_8018533C is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_8018533C(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_80185458 (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_8018529C; + +extern void func_8018533C(s32 arg0, s32 arg1, s32 arg2); +extern void func_80185458(s32 arg0, Rec_8018A6A4_8018529C *arg1, s32 arg2, s32 arg3); + +void func_8018529C(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_8018529C sp10; + s32 i; + s32 ang; + + func_8018533C(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_80185458(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_jr_8017CA80", func_8018533C); @@ -4411,7 +4457,57 @@ INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_jr_8017CA80", func_8018552 INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_jr_8017CA80", func_80185568); -INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_jr_8017CA80", func_801855B4); + +/* func_801855B4 — 16-entry table walk, stride 0xE, over D_801C0244. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801C0244; s16 *p = &D_801C0244; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_80185690(s32 arg0); + +void func_801855B4(void) { + + extern s16 D_801C0244; + s16 *p = &D_801C0244; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_80185690(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC03_104/nonmatchings/ov_SC03_104_jr_8017CA80", func_80185690); diff --git a/src/ov_SC03_105/ov_SC03_105.c b/src/ov_SC03_105/ov_SC03_105.c index b26ccc152e..3685998c00 100644 --- a/src/ov_SC03_105/ov_SC03_105.c +++ b/src/ov_SC03_105/ov_SC03_105.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_105/nonmatchings/ov_SC03_105", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018A5F8[]; + s16 idx = D_8018A5F8[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B6E88, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_105/nonmatchings/ov_SC03_105", func_80128CFC); diff --git a/src/ov_SC03_105/ov_SC03_105_after.c b/src/ov_SC03_105/ov_SC03_105_after.c index c061a728d4..c55972d06c 100644 --- a/src/ov_SC03_105/ov_SC03_105_after.c +++ b/src/ov_SC03_105/ov_SC03_105_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_105/nonmatchings/ov_SC03_105_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_105/nonmatchings/ov_SC03_105_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_105/ov_SC03_105_jr_8012ACE0.c b/src/ov_SC03_105/ov_SC03_105_jr_8012ACE0.c index 7782173811..2ccb6cfb66 100644 --- a/src/ov_SC03_105/ov_SC03_105_jr_8012ACE0.c +++ b/src/ov_SC03_105/ov_SC03_105_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_105/nonmatchings/ov_SC03_105_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_105/ov_SC03_105_jr_801734BC.c b/src/ov_SC03_105/ov_SC03_105_jr_801734BC.c index 7a18c96a5c..537b2dd4c3 100644 --- a/src/ov_SC03_105/ov_SC03_105_jr_801734BC.c +++ b/src/ov_SC03_105/ov_SC03_105_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_105/nonmatchings/ov_SC03_105_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_108/ov_SC03_108.c b/src/ov_SC03_108/ov_SC03_108.c index 993aa00acd..58a9c2e459 100644 --- a/src/ov_SC03_108/ov_SC03_108.c +++ b/src/ov_SC03_108/ov_SC03_108.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_108/nonmatchings/ov_SC03_108", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80180F50[]; + s16 idx = D_80180F50[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019F390, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_108/nonmatchings/ov_SC03_108", func_80128CFC); diff --git a/src/ov_SC03_108/ov_SC03_108_after.c b/src/ov_SC03_108/ov_SC03_108_after.c index 22d425c5cc..a366c11b9a 100644 --- a/src/ov_SC03_108/ov_SC03_108_after.c +++ b/src/ov_SC03_108/ov_SC03_108_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_108/nonmatchings/ov_SC03_108_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_108/nonmatchings/ov_SC03_108_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_108/ov_SC03_108_jr_8012ACE0.c b/src/ov_SC03_108/ov_SC03_108_jr_8012ACE0.c index 1ed09ec57d..ba469eb12e 100644 --- a/src/ov_SC03_108/ov_SC03_108_jr_8012ACE0.c +++ b/src/ov_SC03_108/ov_SC03_108_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_108/nonmatchings/ov_SC03_108_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_108/ov_SC03_108_jr_801734BC.c b/src/ov_SC03_108/ov_SC03_108_jr_801734BC.c index 77a3acc335..12c3964a53 100644 --- a/src/ov_SC03_108/ov_SC03_108_jr_801734BC.c +++ b/src/ov_SC03_108/ov_SC03_108_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_108/nonmatchings/ov_SC03_108_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_109/ov_SC03_109.c b/src/ov_SC03_109/ov_SC03_109.c index 644ef7f638..13829a3812 100644 --- a/src/ov_SC03_109/ov_SC03_109.c +++ b/src/ov_SC03_109/ov_SC03_109.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_109/nonmatchings/ov_SC03_109", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017E5FC[]; + s16 idx = D_8017E5FC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80197EA0, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_109/nonmatchings/ov_SC03_109", func_80128CFC); diff --git a/src/ov_SC03_109/ov_SC03_109_after.c b/src/ov_SC03_109/ov_SC03_109_after.c index bb318222b5..c4c030a7cf 100644 --- a/src/ov_SC03_109/ov_SC03_109_after.c +++ b/src/ov_SC03_109/ov_SC03_109_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_109/nonmatchings/ov_SC03_109_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_109/nonmatchings/ov_SC03_109_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_109/ov_SC03_109_jr_8012ACE0.c b/src/ov_SC03_109/ov_SC03_109_jr_8012ACE0.c index 748ee0dbcd..b1ea2586d4 100644 --- a/src/ov_SC03_109/ov_SC03_109_jr_8012ACE0.c +++ b/src/ov_SC03_109/ov_SC03_109_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_109/nonmatchings/ov_SC03_109_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_109/ov_SC03_109_jr_801734BC.c b/src/ov_SC03_109/ov_SC03_109_jr_801734BC.c index fc0504e52e..343a4ff0e8 100644 --- a/src/ov_SC03_109/ov_SC03_109_jr_801734BC.c +++ b/src/ov_SC03_109/ov_SC03_109_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_109/nonmatchings/ov_SC03_109_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_110/ov_SC03_110.c b/src/ov_SC03_110/ov_SC03_110.c index 7248d9db2f..996f5dc0fe 100644 --- a/src/ov_SC03_110/ov_SC03_110.c +++ b/src/ov_SC03_110/ov_SC03_110.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_110/nonmatchings/ov_SC03_110", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018201C[]; + s16 idx = D_8018201C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019FB3C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_110/nonmatchings/ov_SC03_110", func_80128CFC); diff --git a/src/ov_SC03_110/ov_SC03_110_after.c b/src/ov_SC03_110/ov_SC03_110_after.c index 38228cec27..1c347c3437 100644 --- a/src/ov_SC03_110/ov_SC03_110_after.c +++ b/src/ov_SC03_110/ov_SC03_110_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_110/nonmatchings/ov_SC03_110_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_110/nonmatchings/ov_SC03_110_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_110/ov_SC03_110_jr_8012ACE0.c b/src/ov_SC03_110/ov_SC03_110_jr_8012ACE0.c index c9d872502f..65d409ccf4 100644 --- a/src/ov_SC03_110/ov_SC03_110_jr_8012ACE0.c +++ b/src/ov_SC03_110/ov_SC03_110_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_110/nonmatchings/ov_SC03_110_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_110/ov_SC03_110_jr_801734BC.c b/src/ov_SC03_110/ov_SC03_110_jr_801734BC.c index 2f8e0a89b3..78f1248444 100644 --- a/src/ov_SC03_110/ov_SC03_110_jr_801734BC.c +++ b/src/ov_SC03_110/ov_SC03_110_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_110/nonmatchings/ov_SC03_110_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_110/ov_SC03_110_jr_8017AE2C.c b/src/ov_SC03_110/ov_SC03_110_jr_8017AE2C.c index e7eed316f3..b2460aabec 100644 --- a/src/ov_SC03_110/ov_SC03_110_jr_8017AE2C.c +++ b/src/ov_SC03_110/ov_SC03_110_jr_8017AE2C.c @@ -3403,7 +3403,47 @@ void func_8017CD9C(int param_1) } -INCLUDE_ASM("asm/ov_SC03_110/nonmatchings/ov_SC03_110_jr_8017AE2C", func_8017CDF8); + +/* Entity record touched by func_8017CDF8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017CDF8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017CDF8; + +extern void func_80147324(s32 arg0); +extern void func_8017D030(int); + +void func_8017CDF8(Ent_8017BFE0_8017CDF8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017CDF8 *))func_8017D030)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_110/nonmatchings/ov_SC03_110_jr_8017AE2C", func_8017CE7C); @@ -3568,7 +3608,72 @@ void func_8017D5DC(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_110/nonmatchings/ov_SC03_110_jr_8017AE2C", func_8017D618); + +/* func_8017D618 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D618(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_111/ov_SC03_111.c b/src/ov_SC03_111/ov_SC03_111.c index 69d5212d9d..6f7745e229 100644 --- a/src/ov_SC03_111/ov_SC03_111.c +++ b/src/ov_SC03_111/ov_SC03_111.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_111/nonmatchings/ov_SC03_111", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80184BD0[]; + s16 idx = D_80184BD0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B70BC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_111/nonmatchings/ov_SC03_111", func_80128CFC); diff --git a/src/ov_SC03_111/ov_SC03_111_after.c b/src/ov_SC03_111/ov_SC03_111_after.c index d03c89b396..b7d1bd29ed 100644 --- a/src/ov_SC03_111/ov_SC03_111_after.c +++ b/src/ov_SC03_111/ov_SC03_111_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_111/nonmatchings/ov_SC03_111_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_111/nonmatchings/ov_SC03_111_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_111/ov_SC03_111_jr_8012ACE0.c b/src/ov_SC03_111/ov_SC03_111_jr_8012ACE0.c index 6eced7d0df..2033df4c48 100644 --- a/src/ov_SC03_111/ov_SC03_111_jr_8012ACE0.c +++ b/src/ov_SC03_111/ov_SC03_111_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_111/nonmatchings/ov_SC03_111_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_111/ov_SC03_111_jr_801734BC.c b/src/ov_SC03_111/ov_SC03_111_jr_801734BC.c index 5accbbacce..f07717ae76 100644 --- a/src/ov_SC03_111/ov_SC03_111_jr_801734BC.c +++ b/src/ov_SC03_111/ov_SC03_111_jr_801734BC.c @@ -3173,7 +3173,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_111/nonmatchings/ov_SC03_111_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_111/ov_SC03_111_jr_8017AE2C.c b/src/ov_SC03_111/ov_SC03_111_jr_8017AE2C.c index 3841cdfee6..0a1e0feae7 100644 --- a/src/ov_SC03_111/ov_SC03_111_jr_8017AE2C.c +++ b/src/ov_SC03_111/ov_SC03_111_jr_8017AE2C.c @@ -3590,7 +3590,47 @@ void func_8017E15C(int param_1) } -INCLUDE_ASM("asm/ov_SC03_111/nonmatchings/ov_SC03_111_jr_8017AE2C", func_8017E1B8); + +/* Entity record touched by func_8017E1B8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017E1B8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017E1B8; + +extern void func_80147324(s32 arg0); +extern void func_8017E3F0(int); + +void func_8017E1B8(Ent_8017BFE0_8017E1B8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017E1B8 *))func_8017E3F0)(param_1); +} + INCLUDE_ASM("asm/ov_SC03_111/nonmatchings/ov_SC03_111_jr_8017AE2C", func_8017E23C); @@ -3755,7 +3795,72 @@ void func_8017E99C(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_111/nonmatchings/ov_SC03_111_jr_8017AE2C", func_8017E9D8); + +/* func_8017E9D8 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017E9D8(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC03_112/ov_SC03_112.c b/src/ov_SC03_112/ov_SC03_112.c index cb6bee298c..74526dc211 100644 --- a/src/ov_SC03_112/ov_SC03_112.c +++ b/src/ov_SC03_112/ov_SC03_112.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_112/nonmatchings/ov_SC03_112", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801859D8[]; + s16 idx = D_801859D8[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801AA824, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_112/nonmatchings/ov_SC03_112", func_80128CFC); diff --git a/src/ov_SC03_112/ov_SC03_112_after.c b/src/ov_SC03_112/ov_SC03_112_after.c index 1a355867f0..c74c26be55 100644 --- a/src/ov_SC03_112/ov_SC03_112_after.c +++ b/src/ov_SC03_112/ov_SC03_112_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_112/nonmatchings/ov_SC03_112_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_112/nonmatchings/ov_SC03_112_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_112/ov_SC03_112_jr_8012ACE0.c b/src/ov_SC03_112/ov_SC03_112_jr_8012ACE0.c index 8b7de65875..0b55b55f7a 100644 --- a/src/ov_SC03_112/ov_SC03_112_jr_8012ACE0.c +++ b/src/ov_SC03_112/ov_SC03_112_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_112/nonmatchings/ov_SC03_112_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_112/ov_SC03_112_jr_801734BC.c b/src/ov_SC03_112/ov_SC03_112_jr_801734BC.c index d609175cf7..9079437fab 100644 --- a/src/ov_SC03_112/ov_SC03_112_jr_801734BC.c +++ b/src/ov_SC03_112/ov_SC03_112_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_112/nonmatchings/ov_SC03_112_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_113/ov_SC03_113.c b/src/ov_SC03_113/ov_SC03_113.c index 699fa66f9d..6d8ecb28af 100644 --- a/src/ov_SC03_113/ov_SC03_113.c +++ b/src/ov_SC03_113/ov_SC03_113.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_113/nonmatchings/ov_SC03_113", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80183088[]; + s16 idx = D_80183088[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A34AC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_113/nonmatchings/ov_SC03_113", func_80128CFC); diff --git a/src/ov_SC03_113/ov_SC03_113_after.c b/src/ov_SC03_113/ov_SC03_113_after.c index b55a878392..4cc2a27e14 100644 --- a/src/ov_SC03_113/ov_SC03_113_after.c +++ b/src/ov_SC03_113/ov_SC03_113_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_113/nonmatchings/ov_SC03_113_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_113/nonmatchings/ov_SC03_113_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_113/ov_SC03_113_jr_8012ACE0.c b/src/ov_SC03_113/ov_SC03_113_jr_8012ACE0.c index f65c9515b5..edbd270dc2 100644 --- a/src/ov_SC03_113/ov_SC03_113_jr_8012ACE0.c +++ b/src/ov_SC03_113/ov_SC03_113_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_113/nonmatchings/ov_SC03_113_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_113/ov_SC03_113_jr_801734BC.c b/src/ov_SC03_113/ov_SC03_113_jr_801734BC.c index 39aba97f8a..5bf01f8f9e 100644 --- a/src/ov_SC03_113/ov_SC03_113_jr_801734BC.c +++ b/src/ov_SC03_113/ov_SC03_113_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_113/nonmatchings/ov_SC03_113_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_113/ov_SC03_113_jr_8017C294.c b/src/ov_SC03_113/ov_SC03_113_jr_8017C294.c index 60893f764f..e81413e259 100644 --- a/src/ov_SC03_113/ov_SC03_113_jr_8017C294.c +++ b/src/ov_SC03_113/ov_SC03_113_jr_8017C294.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3303,7 +3302,32 @@ void func_8017F120(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_113/nonmatchings/ov_SC03_113_jr_8017C294", func_8017F15C); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017F15C; + +extern u16 func_80148800(s32 *a0); +extern void func_8017F1FC(s32 param_1, s16 *param_2); + +void func_8017F15C(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80186FA0[]; + extern Blk8_80126940_8017F15C D_80126940; + Blk8_80126940_8017F15C sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80186FA0[t]; + } + sp10 = D_80126940; + func_8017F1FC(a0, sp10.v); +} + // @class: schedule diff --git a/src/ov_SC03_114/ov_SC03_114.c b/src/ov_SC03_114/ov_SC03_114.c index c9d1bcb0ed..ad27ebf704 100644 --- a/src/ov_SC03_114/ov_SC03_114.c +++ b/src/ov_SC03_114/ov_SC03_114.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_114/nonmatchings/ov_SC03_114", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017ECF0[]; + s16 idx = D_8017ECF0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A71B8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_114/nonmatchings/ov_SC03_114", func_80128CFC); diff --git a/src/ov_SC03_114/ov_SC03_114_after.c b/src/ov_SC03_114/ov_SC03_114_after.c index bc5235d101..e85bc9e381 100644 --- a/src/ov_SC03_114/ov_SC03_114_after.c +++ b/src/ov_SC03_114/ov_SC03_114_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_114/nonmatchings/ov_SC03_114_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_114/nonmatchings/ov_SC03_114_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_114/ov_SC03_114_jr_8012ACE0.c b/src/ov_SC03_114/ov_SC03_114_jr_8012ACE0.c index 6cbc84e7d5..b6e92d3ef0 100644 --- a/src/ov_SC03_114/ov_SC03_114_jr_8012ACE0.c +++ b/src/ov_SC03_114/ov_SC03_114_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_114/nonmatchings/ov_SC03_114_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_114/ov_SC03_114_jr_801734BC.c b/src/ov_SC03_114/ov_SC03_114_jr_801734BC.c index dfa923c38a..b409c1060e 100644 --- a/src/ov_SC03_114/ov_SC03_114_jr_801734BC.c +++ b/src/ov_SC03_114/ov_SC03_114_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_114/nonmatchings/ov_SC03_114_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_114/ov_SC03_114_jr_8017BEBC.c b/src/ov_SC03_114/ov_SC03_114_jr_8017BEBC.c index 799bb93bf5..bc911ee48f 100644 --- a/src/ov_SC03_114/ov_SC03_114_jr_8017BEBC.c +++ b/src/ov_SC03_114/ov_SC03_114_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3240,7 +3239,32 @@ void func_8017D008(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_114/nonmatchings/ov_SC03_114_jr_8017BEBC", func_8017D044); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D044; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D0E4(void*); + +void func_8017D044(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_801824A4[]; + extern Blk8_80126940_8017D044 D_80126940; + Blk8_80126940_8017D044 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_801824A4[t]; + } + sp10 = D_80126940; + ((void (*)(s32, s16 *))func_8017D0E4)(a0, sp10.v); +} + void func_8017D0E4(void * arg0) { *(s32 *)((char *)arg0 + 0x40) = -0x38D; diff --git a/src/ov_SC03_115/ov_SC03_115.c b/src/ov_SC03_115/ov_SC03_115.c index 6bfec691ce..3ed79ac904 100644 --- a/src/ov_SC03_115/ov_SC03_115.c +++ b/src/ov_SC03_115/ov_SC03_115.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_115/nonmatchings/ov_SC03_115", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018075C[]; + s16 idx = D_8018075C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80192B2C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_115/nonmatchings/ov_SC03_115", func_80128CFC); diff --git a/src/ov_SC03_115/ov_SC03_115_after.c b/src/ov_SC03_115/ov_SC03_115_after.c index 7c2c110c93..6a7bb4dec1 100644 --- a/src/ov_SC03_115/ov_SC03_115_after.c +++ b/src/ov_SC03_115/ov_SC03_115_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_115/nonmatchings/ov_SC03_115_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_115/nonmatchings/ov_SC03_115_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_115/ov_SC03_115_jr_8012ACE0.c b/src/ov_SC03_115/ov_SC03_115_jr_8012ACE0.c index 8cee2539c5..563a193a66 100644 --- a/src/ov_SC03_115/ov_SC03_115_jr_8012ACE0.c +++ b/src/ov_SC03_115/ov_SC03_115_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_115/nonmatchings/ov_SC03_115_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_115/ov_SC03_115_jr_801734BC.c b/src/ov_SC03_115/ov_SC03_115_jr_801734BC.c index a48831b7d9..959b59398c 100644 --- a/src/ov_SC03_115/ov_SC03_115_jr_801734BC.c +++ b/src/ov_SC03_115/ov_SC03_115_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_115/nonmatchings/ov_SC03_115_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_116/ov_SC03_116.c b/src/ov_SC03_116/ov_SC03_116.c index 070397dc33..258a414550 100644 --- a/src/ov_SC03_116/ov_SC03_116.c +++ b/src/ov_SC03_116/ov_SC03_116.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_116/nonmatchings/ov_SC03_116", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80182B60[]; + s16 idx = D_80182B60[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801956C8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_116/nonmatchings/ov_SC03_116", func_80128CFC); diff --git a/src/ov_SC03_116/ov_SC03_116_after.c b/src/ov_SC03_116/ov_SC03_116_after.c index 3f8afaea7c..11f38f45d0 100644 --- a/src/ov_SC03_116/ov_SC03_116_after.c +++ b/src/ov_SC03_116/ov_SC03_116_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_116/nonmatchings/ov_SC03_116_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_116/nonmatchings/ov_SC03_116_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_116/ov_SC03_116_jr_8012ACE0.c b/src/ov_SC03_116/ov_SC03_116_jr_8012ACE0.c index 7946f14b2a..ad5a31c3fe 100644 --- a/src/ov_SC03_116/ov_SC03_116_jr_8012ACE0.c +++ b/src/ov_SC03_116/ov_SC03_116_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_116/nonmatchings/ov_SC03_116_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_116/ov_SC03_116_jr_801734BC.c b/src/ov_SC03_116/ov_SC03_116_jr_801734BC.c index 67190545f3..a0975a966a 100644 --- a/src/ov_SC03_116/ov_SC03_116_jr_801734BC.c +++ b/src/ov_SC03_116/ov_SC03_116_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_116/nonmatchings/ov_SC03_116_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_116/ov_SC03_116_jr_8017AE2C.c b/src/ov_SC03_116/ov_SC03_116_jr_8017AE2C.c index b0080dbbf9..c0ac5f34ea 100644 --- a/src/ov_SC03_116/ov_SC03_116_jr_8017AE2C.c +++ b/src/ov_SC03_116/ov_SC03_116_jr_8017AE2C.c @@ -50,7 +50,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -4260,7 +4259,32 @@ void func_80180D04(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_116/nonmatchings/ov_SC03_116_jr_8017AE2C", func_80180D40); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_80180D40; + +extern u16 func_80148800(s32 *a0); +extern void func_80180DE0(s32 param_1, s16 *param_2); + +void func_80180D40(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80186318[]; + extern Blk8_80126940_80180D40 D_80126940; + Blk8_80126940_80180D40 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80186318[t]; + } + sp10 = D_80126940; + func_80180DE0(a0, sp10.v); +} + // @class: schedule diff --git a/src/ov_SC03_117/ov_SC03_117.c b/src/ov_SC03_117/ov_SC03_117.c index a657490c67..2a2112ed51 100644 --- a/src/ov_SC03_117/ov_SC03_117.c +++ b/src/ov_SC03_117/ov_SC03_117.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_117/nonmatchings/ov_SC03_117", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80184B6C[]; + s16 idx = D_80184B6C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801CBD68, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_117/nonmatchings/ov_SC03_117", func_80128CFC); diff --git a/src/ov_SC03_117/ov_SC03_117_after.c b/src/ov_SC03_117/ov_SC03_117_after.c index 13898f964a..a4ac2dea94 100644 --- a/src/ov_SC03_117/ov_SC03_117_after.c +++ b/src/ov_SC03_117/ov_SC03_117_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_117/nonmatchings/ov_SC03_117_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_117/nonmatchings/ov_SC03_117_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_117/ov_SC03_117_jr_8012ACE0.c b/src/ov_SC03_117/ov_SC03_117_jr_8012ACE0.c index 032011c992..d117c69e60 100644 --- a/src/ov_SC03_117/ov_SC03_117_jr_8012ACE0.c +++ b/src/ov_SC03_117/ov_SC03_117_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_117/nonmatchings/ov_SC03_117_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_117/ov_SC03_117_jr_801734BC.c b/src/ov_SC03_117/ov_SC03_117_jr_801734BC.c index 5c402e029a..fdf0bcce43 100644 --- a/src/ov_SC03_117/ov_SC03_117_jr_801734BC.c +++ b/src/ov_SC03_117/ov_SC03_117_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_117/nonmatchings/ov_SC03_117_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_118/ov_SC03_118.c b/src/ov_SC03_118/ov_SC03_118.c index 8d7916c48f..bc8a247c1f 100644 --- a/src/ov_SC03_118/ov_SC03_118.c +++ b/src/ov_SC03_118/ov_SC03_118.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80189C18[]; + s16 idx = D_80189C18[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801D1CC4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118", func_80128CFC); diff --git a/src/ov_SC03_118/ov_SC03_118_after.c b/src/ov_SC03_118/ov_SC03_118_after.c index 8ac8a5398d..ee96ee15f9 100644 --- a/src/ov_SC03_118/ov_SC03_118_after.c +++ b/src/ov_SC03_118/ov_SC03_118_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_118/ov_SC03_118_jr_8012ACE0.c b/src/ov_SC03_118/ov_SC03_118_jr_8012ACE0.c index 3ef376787c..9dd846349d 100644 --- a/src/ov_SC03_118/ov_SC03_118_jr_8012ACE0.c +++ b/src/ov_SC03_118/ov_SC03_118_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_118/ov_SC03_118_jr_801734BC.c b/src/ov_SC03_118/ov_SC03_118_jr_801734BC.c index 97e9429d08..1ed3763db5 100644 --- a/src/ov_SC03_118/ov_SC03_118_jr_801734BC.c +++ b/src/ov_SC03_118/ov_SC03_118_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_118/ov_SC03_118_jr_8017AE2C.c b/src/ov_SC03_118/ov_SC03_118_jr_8017AE2C.c index ecc6fe10ed..3b74bcf3a6 100644 --- a/src/ov_SC03_118/ov_SC03_118_jr_8017AE2C.c +++ b/src/ov_SC03_118/ov_SC03_118_jr_8017AE2C.c @@ -3464,7 +3464,67 @@ INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_8017AE2C", func_8017D80 INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_8017AE2C", func_8017D890); -INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_8017AE2C", func_8017D900); + +/* func_8017D900 — fade the 4-byte colour quad at D_801D4268 one step toward 0 + * (func_80012F74 = "step a value toward a target"), splat the byte over the + * three sibling bytes, mirror the whole quad into the three following quads, + * then tear the entity down once the byte reaches 0. + * + * §71 sibling-first: DEFINE_func_801685EC() (engine_core.h L8520) is the same + * `if ( == 0) ((void (*)(s32))func_80146C3C)(arg0);` teardown tail. + * In-TU sibling func_8017D678 shows D_801D4269/D_801D426A are SEPARATE u8 + * globals (each gets its own lui/%lo sb) while D_801D4268's address lives in a + * callee-saved register. + * + * @class: schedule (LENGTH-DRIFT/-1) + * @stuck: none — MATCH 50/50 (match_one AND rtu_match), iteration 2. + * THE CRACK (one edit): the TRAILING reload `if (*p == 0)` was being hoisted by + * sched2 up past the third block move, where the swl/swr pair covered its load + * delay — costing exactly the one `nop` the target keeps (49 vs 50 ins, + * LENGTH-DRIFT/-1). A second zero-byte `__asm__("")` fence between the last + * struct assignment and the `if` pins the lbu after the copies and the load-delay + * nop reappears. Lesson: an inline block move (swl/swr) is a fat delay-slot + * SPONGE — any following narrow load will be sucked up into it unless fenced. + * The first fence (after the chained byte stores) is what keeps the block moves + * from being interleaved with them. + * Other levers already in this draft, all load-bearing: + * - `u8 *p = &D_801D4268;` (§20) — one address register ($s0, callee-saved + * across the jal) serves the lbu, the sb and all three block-move sources. + * - chained assignment `D_801D4269 = D_801D426A = *p = f(...)` gives the + * target's store order 880, 882, 881 (right-to-left after the *p store). + * - the 4×u8 struct (align 1) is what makes the assignment expand to inline + * lwl/lwr + swl/swr instead of a `jal memcpy` (cf. §38). + */ + +typedef struct { + u8 b0, b1, b2, b3; +} Quad_801EA880_8017D900; /* align 1 => movstrsi expands to lwl/lwr + swl/swr */ + + +extern s32 func_80012F74(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_80146C3C(void); + +void func_8017D900(s32 arg0) { + + extern u8 D_801D4268; + extern u8 D_801D4269; + extern u8 D_801D426A; + extern u8 D_801D426C; + extern u8 D_801D4270; + extern u8 D_801D4274; + u8 *p = &D_801D4268; + + D_801D4269 = D_801D426A = *p = func_80012F74(*p, 0, 10, 1); + __asm__(""); + *(Quad_801EA880_8017D900 *)&D_801D426C = *(Quad_801EA880_8017D900 *)p; + *(Quad_801EA880_8017D900 *)&D_801D4270 = *(Quad_801EA880_8017D900 *)p; + *(Quad_801EA880_8017D900 *)&D_801D4274 = *(Quad_801EA880_8017D900 *)p; + __asm__(""); + if (*p == 0) { + ((void (*)(s32))func_80146C3C)(arg0); + } +} + INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_8017AE2C", func_8017D9C8); diff --git a/src/ov_SC03_118/ov_SC03_118_jr_8017FB84.c b/src/ov_SC03_118/ov_SC03_118_jr_8017FB84.c index 9465115814..58141fee6f 100644 --- a/src/ov_SC03_118/ov_SC03_118_jr_8017FB84.c +++ b/src/ov_SC03_118/ov_SC03_118_jr_8017FB84.c @@ -3785,7 +3785,53 @@ void func_8018552C(void) { } -INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_8017FB84", func_80185550); + +/* func_80185550 — cookbook §71 (sibling-first). + * func_801855F0 is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_801855F0(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_8018570C (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_80185550; + +extern void func_801855F0(s32 arg0, s32 arg1, s32 arg2); +extern void func_8018570C(s32 arg0, Rec_8018A6A4_80185550 *arg1, s32 arg2, s32 arg3); + +void func_80185550(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_80185550 sp10; + s32 i; + s32 ang; + + func_801855F0(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_8018570C(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + extern s16 D_801D446C; @@ -3817,7 +3863,57 @@ INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_8017FB84", func_801857E INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_8017FB84", func_8018581C); -INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_8017FB84", func_80185868); + +/* func_80185868 — 16-entry table walk, stride 0xE, over D_801D4474. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801D4474; s16 *p = &D_801D4474; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_80185944(s32 arg0); + +void func_80185868(void) { + + extern s16 D_801D4474; + s16 *p = &D_801D4474; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_80185944(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_8017FB84", func_80185944); diff --git a/src/ov_SC03_119/ov_SC03_119.c b/src/ov_SC03_119/ov_SC03_119.c index 8522f0c1b2..4ebd5c8796 100644 --- a/src/ov_SC03_119/ov_SC03_119.c +++ b/src/ov_SC03_119/ov_SC03_119.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80189C18[]; + s16 idx = D_80189C18[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801D1CC4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119", func_80128CFC); diff --git a/src/ov_SC03_119/ov_SC03_119_after.c b/src/ov_SC03_119/ov_SC03_119_after.c index 6431a0d607..09794587fe 100644 --- a/src/ov_SC03_119/ov_SC03_119_after.c +++ b/src/ov_SC03_119/ov_SC03_119_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_119/ov_SC03_119_jr_8012ACE0.c b/src/ov_SC03_119/ov_SC03_119_jr_8012ACE0.c index c87c502e27..e1e0917ae8 100644 --- a/src/ov_SC03_119/ov_SC03_119_jr_8012ACE0.c +++ b/src/ov_SC03_119/ov_SC03_119_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_119/ov_SC03_119_jr_801734BC.c b/src/ov_SC03_119/ov_SC03_119_jr_801734BC.c index 7712f7a89f..3df81cc8ac 100644 --- a/src/ov_SC03_119/ov_SC03_119_jr_801734BC.c +++ b/src/ov_SC03_119/ov_SC03_119_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_119/ov_SC03_119_jr_8017AE2C.c b/src/ov_SC03_119/ov_SC03_119_jr_8017AE2C.c index e80d8c4b5f..c84cc406d4 100644 --- a/src/ov_SC03_119/ov_SC03_119_jr_8017AE2C.c +++ b/src/ov_SC03_119/ov_SC03_119_jr_8017AE2C.c @@ -3458,7 +3458,67 @@ INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8017AE2C", func_8017D80 INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8017AE2C", func_8017D890); -INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8017AE2C", func_8017D900); + +/* func_8017D900 — fade the 4-byte colour quad at D_801D4268 one step toward 0 + * (func_80012F74 = "step a value toward a target"), splat the byte over the + * three sibling bytes, mirror the whole quad into the three following quads, + * then tear the entity down once the byte reaches 0. + * + * §71 sibling-first: DEFINE_func_801685EC() (engine_core.h L8520) is the same + * `if ( == 0) ((void (*)(s32))func_80146C3C)(arg0);` teardown tail. + * In-TU sibling func_8017D678 shows D_801D4269/D_801D426A are SEPARATE u8 + * globals (each gets its own lui/%lo sb) while D_801D4268's address lives in a + * callee-saved register. + * + * @class: schedule (LENGTH-DRIFT/-1) + * @stuck: none — MATCH 50/50 (match_one AND rtu_match), iteration 2. + * THE CRACK (one edit): the TRAILING reload `if (*p == 0)` was being hoisted by + * sched2 up past the third block move, where the swl/swr pair covered its load + * delay — costing exactly the one `nop` the target keeps (49 vs 50 ins, + * LENGTH-DRIFT/-1). A second zero-byte `__asm__("")` fence between the last + * struct assignment and the `if` pins the lbu after the copies and the load-delay + * nop reappears. Lesson: an inline block move (swl/swr) is a fat delay-slot + * SPONGE — any following narrow load will be sucked up into it unless fenced. + * The first fence (after the chained byte stores) is what keeps the block moves + * from being interleaved with them. + * Other levers already in this draft, all load-bearing: + * - `u8 *p = &D_801D4268;` (§20) — one address register ($s0, callee-saved + * across the jal) serves the lbu, the sb and all three block-move sources. + * - chained assignment `D_801D4269 = D_801D426A = *p = f(...)` gives the + * target's store order 880, 882, 881 (right-to-left after the *p store). + * - the 4×u8 struct (align 1) is what makes the assignment expand to inline + * lwl/lwr + swl/swr instead of a `jal memcpy` (cf. §38). + */ + +typedef struct { + u8 b0, b1, b2, b3; +} Quad_801EA880_8017D900; /* align 1 => movstrsi expands to lwl/lwr + swl/swr */ + + +extern s32 func_80012F74(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_80146C3C(void); + +void func_8017D900(s32 arg0) { + + extern u8 D_801D4268; + extern u8 D_801D4269; + extern u8 D_801D426A; + extern u8 D_801D426C; + extern u8 D_801D4270; + extern u8 D_801D4274; + u8 *p = &D_801D4268; + + D_801D4269 = D_801D426A = *p = func_80012F74(*p, 0, 10, 1); + __asm__(""); + *(Quad_801EA880_8017D900 *)&D_801D426C = *(Quad_801EA880_8017D900 *)p; + *(Quad_801EA880_8017D900 *)&D_801D4270 = *(Quad_801EA880_8017D900 *)p; + *(Quad_801EA880_8017D900 *)&D_801D4274 = *(Quad_801EA880_8017D900 *)p; + __asm__(""); + if (*p == 0) { + ((void (*)(s32))func_80146C3C)(arg0); + } +} + INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8017AE2C", func_8017D9C8); diff --git a/src/ov_SC03_119/ov_SC03_119_jr_8017FB84.c b/src/ov_SC03_119/ov_SC03_119_jr_8017FB84.c index 22b0a0e610..5364838080 100644 --- a/src/ov_SC03_119/ov_SC03_119_jr_8017FB84.c +++ b/src/ov_SC03_119/ov_SC03_119_jr_8017FB84.c @@ -3773,7 +3773,53 @@ void func_8018552C(void) { } -INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8017FB84", func_80185550); + +/* func_80185550 — cookbook §71 (sibling-first). + * func_801855F0 is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_801855F0(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_8018570C (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_80185550; + +extern void func_801855F0(s32 arg0, s32 arg1, s32 arg2); +extern void func_8018570C(s32 arg0, Rec_8018A6A4_80185550 *arg1, s32 arg2, s32 arg3); + +void func_80185550(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_80185550 sp10; + s32 i; + s32 ang; + + func_801855F0(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_8018570C(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8017FB84", func_801855F0); @@ -3793,7 +3839,57 @@ INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8017FB84", func_801857E INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8017FB84", func_8018581C); -INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8017FB84", func_80185868); + +/* func_80185868 — 16-entry table walk, stride 0xE, over D_801D4474. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801D4474; s16 *p = &D_801D4474; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_80185944(s32 arg0); + +void func_80185868(void) { + + extern s16 D_801D4474; + s16 *p = &D_801D4474; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_80185944(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC03_119/nonmatchings/ov_SC03_119_jr_8017FB84", func_80185944); diff --git a/src/ov_SC03_121/ov_SC03_121.c b/src/ov_SC03_121/ov_SC03_121.c index 492c246deb..6f8be55eb1 100644 --- a/src/ov_SC03_121/ov_SC03_121.c +++ b/src/ov_SC03_121/ov_SC03_121.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_121/nonmatchings/ov_SC03_121", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80182434[]; + s16 idx = D_80182434[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801AC7CC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_121/nonmatchings/ov_SC03_121", func_80128CFC); diff --git a/src/ov_SC03_121/ov_SC03_121_after.c b/src/ov_SC03_121/ov_SC03_121_after.c index 3c42e36047..67b133a181 100644 --- a/src/ov_SC03_121/ov_SC03_121_after.c +++ b/src/ov_SC03_121/ov_SC03_121_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_121/nonmatchings/ov_SC03_121_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_121/nonmatchings/ov_SC03_121_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_121/ov_SC03_121_jr_8012ACE0.c b/src/ov_SC03_121/ov_SC03_121_jr_8012ACE0.c index 3e006afc57..f2c5b6f93c 100644 --- a/src/ov_SC03_121/ov_SC03_121_jr_8012ACE0.c +++ b/src/ov_SC03_121/ov_SC03_121_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_121/nonmatchings/ov_SC03_121_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_121/ov_SC03_121_jr_801734BC.c b/src/ov_SC03_121/ov_SC03_121_jr_801734BC.c index bce4dac9f9..679855e0eb 100644 --- a/src/ov_SC03_121/ov_SC03_121_jr_801734BC.c +++ b/src/ov_SC03_121/ov_SC03_121_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_121/nonmatchings/ov_SC03_121_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_124/ov_SC03_124.c b/src/ov_SC03_124/ov_SC03_124.c index 13efd5b1ce..e7cb01164d 100644 --- a/src/ov_SC03_124/ov_SC03_124.c +++ b/src/ov_SC03_124/ov_SC03_124.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_124/nonmatchings/ov_SC03_124", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018AE60[]; + s16 idx = D_8018AE60[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801DEF20, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_124/nonmatchings/ov_SC03_124", func_80128CFC); diff --git a/src/ov_SC03_124/ov_SC03_124_after.c b/src/ov_SC03_124/ov_SC03_124_after.c index e4917ebeac..7c5ad7743d 100644 --- a/src/ov_SC03_124/ov_SC03_124_after.c +++ b/src/ov_SC03_124/ov_SC03_124_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_124/nonmatchings/ov_SC03_124_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_124/nonmatchings/ov_SC03_124_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_124/ov_SC03_124_jr_8012ACE0.c b/src/ov_SC03_124/ov_SC03_124_jr_8012ACE0.c index ceef8b354f..b05f5db0b3 100644 --- a/src/ov_SC03_124/ov_SC03_124_jr_8012ACE0.c +++ b/src/ov_SC03_124/ov_SC03_124_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_124/nonmatchings/ov_SC03_124_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_124/ov_SC03_124_jr_801734BC.c b/src/ov_SC03_124/ov_SC03_124_jr_801734BC.c index e6f020e6c9..65aa079a7e 100644 --- a/src/ov_SC03_124/ov_SC03_124_jr_801734BC.c +++ b/src/ov_SC03_124/ov_SC03_124_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_124/nonmatchings/ov_SC03_124_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_125/ov_SC03_125.c b/src/ov_SC03_125/ov_SC03_125.c index e0f599e6f8..e2a5a57f3e 100644 --- a/src/ov_SC03_125/ov_SC03_125.c +++ b/src/ov_SC03_125/ov_SC03_125.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_125/nonmatchings/ov_SC03_125", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80184030[]; + s16 idx = D_80184030[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C1C0C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_125/nonmatchings/ov_SC03_125", func_80128CFC); diff --git a/src/ov_SC03_125/ov_SC03_125_after.c b/src/ov_SC03_125/ov_SC03_125_after.c index eb6d84cabb..60276a84de 100644 --- a/src/ov_SC03_125/ov_SC03_125_after.c +++ b/src/ov_SC03_125/ov_SC03_125_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_125/nonmatchings/ov_SC03_125_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_125/nonmatchings/ov_SC03_125_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_125/ov_SC03_125_jr_8012ACE0.c b/src/ov_SC03_125/ov_SC03_125_jr_8012ACE0.c index f4a1e3ef89..7d08242834 100644 --- a/src/ov_SC03_125/ov_SC03_125_jr_8012ACE0.c +++ b/src/ov_SC03_125/ov_SC03_125_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_125/nonmatchings/ov_SC03_125_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_125/ov_SC03_125_jr_801734BC.c b/src/ov_SC03_125/ov_SC03_125_jr_801734BC.c index 0749f869c6..71ad36a232 100644 --- a/src/ov_SC03_125/ov_SC03_125_jr_801734BC.c +++ b/src/ov_SC03_125/ov_SC03_125_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_125/nonmatchings/ov_SC03_125_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC03_126/ov_SC03_126.c b/src/ov_SC03_126/ov_SC03_126.c index 06297877f7..42003eb14a 100644 --- a/src/ov_SC03_126/ov_SC03_126.c +++ b/src/ov_SC03_126/ov_SC03_126.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_126/nonmatchings/ov_SC03_126", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017F528[]; + s16 idx = D_8017F528[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8018D4F8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC03_126/nonmatchings/ov_SC03_126", func_80128CFC); diff --git a/src/ov_SC03_126/ov_SC03_126_after.c b/src/ov_SC03_126/ov_SC03_126_after.c index 8e28935d5e..758e175d66 100644 --- a/src/ov_SC03_126/ov_SC03_126_after.c +++ b/src/ov_SC03_126/ov_SC03_126_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC03_126/nonmatchings/ov_SC03_126_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_126/nonmatchings/ov_SC03_126_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC03_126/ov_SC03_126_jr_8012ACE0.c b/src/ov_SC03_126/ov_SC03_126_jr_8012ACE0.c index 418e965441..b0bb0c2d9f 100644 --- a/src/ov_SC03_126/ov_SC03_126_jr_8012ACE0.c +++ b/src/ov_SC03_126/ov_SC03_126_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_126/nonmatchings/ov_SC03_126_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC03_126/ov_SC03_126_jr_801734BC.c b/src/ov_SC03_126/ov_SC03_126_jr_801734BC.c index d13491c56a..1f061018f6 100644 --- a/src/ov_SC03_126/ov_SC03_126_jr_801734BC.c +++ b/src/ov_SC03_126/ov_SC03_126_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC03_126/nonmatchings/ov_SC03_126_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_000/ov_SC04_000.c b/src/ov_SC04_000/ov_SC04_000.c index 95752e487c..30072f73a2 100644 --- a/src/ov_SC04_000/ov_SC04_000.c +++ b/src/ov_SC04_000/ov_SC04_000.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80183534[]; + s16 idx = D_80183534[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A7574, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000", func_80128CFC); diff --git a/src/ov_SC04_000/ov_SC04_000_after.c b/src/ov_SC04_000/ov_SC04_000_after.c index 6b935da35f..adf38c5692 100644 --- a/src/ov_SC04_000/ov_SC04_000_after.c +++ b/src/ov_SC04_000/ov_SC04_000_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_000/ov_SC04_000_jr_8012ACE0.c b/src/ov_SC04_000/ov_SC04_000_jr_8012ACE0.c index 528c421dd2..9044cec325 100644 --- a/src/ov_SC04_000/ov_SC04_000_jr_8012ACE0.c +++ b/src/ov_SC04_000/ov_SC04_000_jr_8012ACE0.c @@ -329,7 +329,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_000/ov_SC04_000_jr_801734BC.c b/src/ov_SC04_000/ov_SC04_000_jr_801734BC.c index 872c771902..17ff321178 100644 --- a/src/ov_SC04_000/ov_SC04_000_jr_801734BC.c +++ b/src/ov_SC04_000/ov_SC04_000_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_000/ov_SC04_000_jr_8017BEBC.c b/src/ov_SC04_000/ov_SC04_000_jr_8017BEBC.c index a2ab8d0408..c0988dcc56 100644 --- a/src/ov_SC04_000/ov_SC04_000_jr_8017BEBC.c +++ b/src/ov_SC04_000/ov_SC04_000_jr_8017BEBC.c @@ -3248,7 +3248,47 @@ void func_8017DC7C(int param_1) } -INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000_jr_8017BEBC", func_8017DCD8); + +/* Entity record touched by func_8017DCD8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017DCD8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017DCD8; + +extern void func_80147324(s32 arg0); +extern void func_8017DF10(int); + +void func_8017DCD8(Ent_8017BFE0_8017DCD8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017DCD8 *))func_8017DF10)(param_1); +} + INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000_jr_8017BEBC", func_8017DD5C); @@ -3413,7 +3453,72 @@ void func_8017E4BC(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000_jr_8017BEBC", func_8017E4F8); + +/* func_8017E4F8 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017E4F8(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); @@ -3748,7 +3853,72 @@ void func_8017F750(int param_1) INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000_jr_8017BEBC", func_8017F834); -INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000_jr_8017BEBC", func_8017F8A0); + +/* func_8017F8A0 — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_8017F8A0; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(void); + +void func_8017F8A0(int param_1) +{ + UVec_8017EA1C_8017F8A0 v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + INCLUDE_ASM("asm/ov_SC04_000/nonmatchings/ov_SC04_000_jr_8017BEBC", func_8017F98C); diff --git a/src/ov_SC04_002/ov_SC04_002.c b/src/ov_SC04_002/ov_SC04_002.c index dc1b9c3e41..7b2b9db4f0 100644 --- a/src/ov_SC04_002/ov_SC04_002.c +++ b/src/ov_SC04_002/ov_SC04_002.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801886A0[]; + s16 idx = D_801886A0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801BE8C4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002", func_80128CFC); diff --git a/src/ov_SC04_002/ov_SC04_002_after.c b/src/ov_SC04_002/ov_SC04_002_after.c index d2959795f4..f753ab7e51 100644 --- a/src/ov_SC04_002/ov_SC04_002_after.c +++ b/src/ov_SC04_002/ov_SC04_002_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_002/ov_SC04_002_jr_8012ACE0.c b/src/ov_SC04_002/ov_SC04_002_jr_8012ACE0.c index 2d88d5cb70..e043eb802d 100644 --- a/src/ov_SC04_002/ov_SC04_002_jr_8012ACE0.c +++ b/src/ov_SC04_002/ov_SC04_002_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_002/ov_SC04_002_jr_801734BC.c b/src/ov_SC04_002/ov_SC04_002_jr_801734BC.c index 43cdb678e6..32cd2e0412 100644 --- a/src/ov_SC04_002/ov_SC04_002_jr_801734BC.c +++ b/src/ov_SC04_002/ov_SC04_002_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_002/ov_SC04_002_jr_8017BEBC.c b/src/ov_SC04_002/ov_SC04_002_jr_8017BEBC.c index 1385f18093..65857fa708 100644 --- a/src/ov_SC04_002/ov_SC04_002_jr_8017BEBC.c +++ b/src/ov_SC04_002/ov_SC04_002_jr_8017BEBC.c @@ -75,7 +75,6 @@ extern s32 func_80146128(void); extern void func_80146360(void); extern void func_801463A0(); extern void func_8014607C(void); -extern s32 *D_80126B78; extern u8 D_80078EC1; extern s32 D_80078EC8; extern s32 D_80126B9C; @@ -595,7 +594,7 @@ extern s32 func_8014E284(s32 a0, s16 *a1, s16 *a2); extern s32 func_8014E048(s32 a0, u16 *a1, u16 *a2); /* u16*: def lhu semantics (T5b reconcile; ptr param type codegen-neutral for the caller) */ extern s32 func_80135A4C(s32 a0, s32 a1, s32 *a2, s32 a3); extern s32 func_80133784(s32 a0, void *a1, s32 a2); -extern u8 D_801152A8[]; /* canonical TU type (engine_core) — read via *(u16*) cast */ +/* canonical TU type (engine_core) — read via *(u16*) cast */ extern s16 D_801152AC; extern s32 func_8014E048(s32 param_1, u16 * param_2, u16 * param_3); extern void func_8014E48C(s32 a0); @@ -631,7 +630,6 @@ extern s32 func_8014F468(void); extern int func_8014F74C(); extern int func_8014F6F4(void); extern u8 D_800D3918[]; -extern u8 D_801152A8[]; extern s32 D_801152BC; extern int func_8014F74C(s32 arg0); extern s32 func_8014FA70(s32 a0); @@ -3284,7 +3282,47 @@ void func_8017DF98(int param_1) } -INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8017BEBC", func_8017DFF4); + +/* Entity record touched by func_8017DFF4 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017DFF4 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017DFF4; + +extern void func_80147324(s32 arg0); +extern void func_8017E22C(int); + +void func_8017DFF4(Ent_8017BFE0_8017DFF4 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017DFF4 *))func_8017E22C)(param_1); +} + INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8017BEBC", func_8017E078); @@ -3449,7 +3487,72 @@ void func_8017E7D8(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8017BEBC", func_8017E814); + +/* func_8017E814 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017E814(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); @@ -3637,7 +3740,32 @@ void func_8017FC5C(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8017BEBC", func_8017FC98); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017FC98; + +extern u16 func_80148800(s32 *a0); +extern void func_8017FE28(s32 param_1, s16 *param_2); + +void func_8017FC98(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_8018C48C[]; + extern Blk8_80126940_8017FC98 D_80126940; + Blk8_80126940_8017FC98 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_8018C48C[t]; + } + sp10 = D_80126940; + func_8017FE28(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8017BEBC", func_8017FD38); @@ -3849,7 +3977,72 @@ void func_801805A4(int param_1) INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8017BEBC", func_80180688); -INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8017BEBC", func_801806F4); + +/* func_801806F4 — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_801806F4; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(void); + +void func_801806F4(int param_1) +{ + UVec_8017EA1C_801806F4 v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + extern void func_80019064(void *a0); @@ -4869,7 +5062,29 @@ INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8017BEBC", func_8018615 INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8017BEBC", func_801861D0); -INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8017BEBC", func_801862F0); + + +extern void func_8012F14C(s32); +extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_8012F568(s32 a0, s32 a1, s32 a2, s32 a3, s32 a4, s32 a5); + +s32 func_801862F0(s32 arg0) { + + extern s32 *D_80126B78; + extern u8 D_801B50F8[]; + extern u8 D_801152A8[]; + s32 buf1[2]; + s32 buf2[2]; + + ((void (*)(s32, s32, s32))func_8012F14C)((s32)D_80126B78 + 0x34, (s32)D_801B50F8, (s32)buf1); + ((void (*)(s32, s32, s32))func_8012F14C)((s32)D_80126B78 + 0x34, (s32)(D_801B50F8 + 8), (s32)buf2); + if (func_80135888(*(s32 *)(arg0 + 0x20), *(s32 *)(arg0 + 0x58), (s32)buf1, (s32)buf2) != 0) { + func_8012F568(1, 0x18, *(s16 *)(*(s32 *)(arg0 + 0x20) + 0x12), 0x18, (s32)buf2, (s32)D_801152A8); + return 1; + } + return 0; +} + INCLUDE_ASM("asm/ov_SC04_002/nonmatchings/ov_SC04_002_jr_8017BEBC", func_801863A4); diff --git a/src/ov_SC04_003/ov_SC04_003.c b/src/ov_SC04_003/ov_SC04_003.c index ebf4ae73b1..73bce80bae 100644 --- a/src/ov_SC04_003/ov_SC04_003.c +++ b/src/ov_SC04_003/ov_SC04_003.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_003/nonmatchings/ov_SC04_003", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018243C[]; + s16 idx = D_8018243C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80199540, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_003/nonmatchings/ov_SC04_003", func_80128CFC); diff --git a/src/ov_SC04_003/ov_SC04_003_after.c b/src/ov_SC04_003/ov_SC04_003_after.c index 58fe25e2c2..75eeaaacf4 100644 --- a/src/ov_SC04_003/ov_SC04_003_after.c +++ b/src/ov_SC04_003/ov_SC04_003_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_003/nonmatchings/ov_SC04_003_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_003/nonmatchings/ov_SC04_003_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_003/ov_SC04_003_jr_8012ACE0.c b/src/ov_SC04_003/ov_SC04_003_jr_8012ACE0.c index df3e645ec6..8eb10e2773 100644 --- a/src/ov_SC04_003/ov_SC04_003_jr_8012ACE0.c +++ b/src/ov_SC04_003/ov_SC04_003_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_003/nonmatchings/ov_SC04_003_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_003/ov_SC04_003_jr_801734BC.c b/src/ov_SC04_003/ov_SC04_003_jr_801734BC.c index cd4e76fa05..f389213d6b 100644 --- a/src/ov_SC04_003/ov_SC04_003_jr_801734BC.c +++ b/src/ov_SC04_003/ov_SC04_003_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_003/nonmatchings/ov_SC04_003_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_003/ov_SC04_003_jr_8017BEBC.c b/src/ov_SC04_003/ov_SC04_003_jr_8017BEBC.c index 216645a484..d6fac33440 100644 --- a/src/ov_SC04_003/ov_SC04_003_jr_8017BEBC.c +++ b/src/ov_SC04_003/ov_SC04_003_jr_8017BEBC.c @@ -3255,9 +3255,57 @@ void func_8017D22C(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_003/nonmatchings/ov_SC04_003_jr_8017BEBC", func_8017D268); -INCLUDE_ASM("asm/ov_SC04_003/nonmatchings/ov_SC04_003_jr_8017BEBC", func_8017D308); +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D268; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D3A8(s32 param_1, s16 *param_2); + +void func_8017D268(s32 a0) { + + extern s16 D_80185C50[]; + extern Blk8_80126940_8017D268 D_80126940; + Blk8_80126940_8017D268 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80185C50[t]; + } + sp10 = D_80126940; + func_8017D3A8(a0, sp10.v); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D308; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D3A8(s32 param_1, s16 *param_2); + +void func_8017D308(s32 a0) { + + extern s16 D_80185C54[]; + extern Blk8_80126940_8017D308 D_80126940; + Blk8_80126940_8017D308 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80185C54[t]; + } + sp10 = D_80126940; + func_8017D3A8(a0, sp10.v); +} + // @class: schedule @@ -3466,7 +3514,72 @@ void func_8017D9E4(int param_1) INCLUDE_ASM("asm/ov_SC04_003/nonmatchings/ov_SC04_003_jr_8017BEBC", func_8017DAC8); -INCLUDE_ASM("asm/ov_SC04_003/nonmatchings/ov_SC04_003_jr_8017BEBC", func_8017DB34); + +/* func_8017DB34 — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_8017DB34; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(void); + +void func_8017DB34(int param_1) +{ + UVec_8017EA1C_8017DB34 v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + INCLUDE_ASM("asm/ov_SC04_003/nonmatchings/ov_SC04_003_jr_8017BEBC", func_8017DC20); diff --git a/src/ov_SC04_004/ov_SC04_004.c b/src/ov_SC04_004/ov_SC04_004.c index 626f0c3069..d42156826e 100644 --- a/src/ov_SC04_004/ov_SC04_004.c +++ b/src/ov_SC04_004/ov_SC04_004.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80184970[]; + s16 idx = D_80184970[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B133C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004", func_80128CFC); diff --git a/src/ov_SC04_004/ov_SC04_004_after.c b/src/ov_SC04_004/ov_SC04_004_after.c index c0d84c9748..17305855aa 100644 --- a/src/ov_SC04_004/ov_SC04_004_after.c +++ b/src/ov_SC04_004/ov_SC04_004_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_004/ov_SC04_004_jr_8012ACE0.c b/src/ov_SC04_004/ov_SC04_004_jr_8012ACE0.c index a4998c2afd..eae80976ff 100644 --- a/src/ov_SC04_004/ov_SC04_004_jr_8012ACE0.c +++ b/src/ov_SC04_004/ov_SC04_004_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_004/ov_SC04_004_jr_801734BC.c b/src/ov_SC04_004/ov_SC04_004_jr_801734BC.c index ea86ec1870..aadf375c71 100644 --- a/src/ov_SC04_004/ov_SC04_004_jr_801734BC.c +++ b/src/ov_SC04_004/ov_SC04_004_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_004/ov_SC04_004_jr_8017AE2C.c b/src/ov_SC04_004/ov_SC04_004_jr_8017AE2C.c index 1064df10b5..66b4805474 100644 --- a/src/ov_SC04_004/ov_SC04_004_jr_8017AE2C.c +++ b/src/ov_SC04_004/ov_SC04_004_jr_8017AE2C.c @@ -3859,7 +3859,47 @@ void func_8017DC7C(int param_1) } -INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_jr_8017AE2C", func_8017DCD8); + +/* Entity record touched by func_8017DCD8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017DCD8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017DCD8; + +extern void func_80147324(s32 arg0); +extern void func_8017DF10(int); + +void func_8017DCD8(Ent_8017BFE0_8017DCD8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017DCD8 *))func_8017DF10)(param_1); +} + INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_jr_8017AE2C", func_8017DD5C); @@ -4024,7 +4064,72 @@ void func_8017E4BC(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_jr_8017AE2C", func_8017E4F8); + +/* func_8017E4F8 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017E4F8(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); @@ -4132,9 +4237,59 @@ void func_8017EC08(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_jr_8017AE2C", func_8017EC44); -INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_jr_8017AE2C", func_8017ECE4); +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017EC44; + +extern u16 func_80148800(s32 *a0); +extern void func_8017ED84(s32 param_1, s16 *param_2); + +void func_8017EC44(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80188344[]; + extern Blk8_80126940_8017EC44 D_80126940; + Blk8_80126940_8017EC44 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80188344[t]; + } + sp10 = D_80126940; + func_8017ED84(a0, sp10.v); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017ECE4; + +extern u16 func_80148800(s32 *a0); +extern void func_8017ED84(s32 param_1, s16 *param_2); + +void func_8017ECE4(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80188348[]; + extern Blk8_80126940_8017ECE4 D_80126940; + Blk8_80126940_8017ECE4 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80188348[t]; + } + sp10 = D_80126940; + func_8017ED84(a0, sp10.v); +} + // @class: schedule @@ -4397,7 +4552,72 @@ void func_8017FF70(int param_1) INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_jr_8017AE2C", func_80180054); -INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_jr_8017AE2C", func_801800C0); + +/* func_801800C0 — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_801800C0; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(void); + +void func_801800C0(int param_1) +{ + UVec_8017EA1C_801800C0 v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + INCLUDE_ASM("asm/ov_SC04_004/nonmatchings/ov_SC04_004_jr_8017AE2C", func_801801AC); diff --git a/src/ov_SC04_005/ov_SC04_005.c b/src/ov_SC04_005/ov_SC04_005.c index 0b43e897d4..ef2fd34d28 100644 --- a/src/ov_SC04_005/ov_SC04_005.c +++ b/src/ov_SC04_005/ov_SC04_005.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80187DA4[]; + s16 idx = D_80187DA4[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801BF500, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005", func_80128CFC); diff --git a/src/ov_SC04_005/ov_SC04_005_after.c b/src/ov_SC04_005/ov_SC04_005_after.c index 7456bf70d2..4d9846406e 100644 --- a/src/ov_SC04_005/ov_SC04_005_after.c +++ b/src/ov_SC04_005/ov_SC04_005_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_005/ov_SC04_005_jr_8012ACE0.c b/src/ov_SC04_005/ov_SC04_005_jr_8012ACE0.c index dcfb29d043..bc1755fbe7 100644 --- a/src/ov_SC04_005/ov_SC04_005_jr_8012ACE0.c +++ b/src/ov_SC04_005/ov_SC04_005_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_005/ov_SC04_005_jr_801734BC.c b/src/ov_SC04_005/ov_SC04_005_jr_801734BC.c index 50e5f21530..a89bd3ecf3 100644 --- a/src/ov_SC04_005/ov_SC04_005_jr_801734BC.c +++ b/src/ov_SC04_005/ov_SC04_005_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_005/ov_SC04_005_jr_8017BEBC.c b/src/ov_SC04_005/ov_SC04_005_jr_8017BEBC.c index e918f74b2d..7c913fd33e 100644 --- a/src/ov_SC04_005/ov_SC04_005_jr_8017BEBC.c +++ b/src/ov_SC04_005/ov_SC04_005_jr_8017BEBC.c @@ -76,7 +76,6 @@ extern s32 func_80146128(void); extern void func_80146360(void); extern void func_801463A0(); extern void func_8014607C(void); -extern s32 *D_80126B78; extern u8 D_80078EC1; extern s32 D_80078EC8; extern s32 D_80126B9C; @@ -597,7 +596,7 @@ extern s32 func_8014E284(s32 a0, s16 *a1, s16 *a2); extern s32 func_8014E048(s32 a0, u16 *a1, u16 *a2); /* u16*: def lhu semantics (T5b reconcile; ptr param type codegen-neutral for the caller) */ extern s32 func_80135A4C(s32 a0, s32 a1, s32 *a2, s32 a3); extern s32 func_80133784(s32 a0, void *a1, s32 a2); -extern u8 D_801152A8[]; /* canonical TU type (engine_core) — read via *(u16*) cast */ +/* canonical TU type (engine_core) — read via *(u16*) cast */ extern s16 D_801152AC; extern s32 func_8014E048(s32 param_1, u16 * param_2, u16 * param_3); extern void func_8014E48C(s32 a0); @@ -633,7 +632,6 @@ extern s32 func_8014F468(void); extern int func_8014F74C(); extern int func_8014F6F4(void); extern u8 D_800D3918[]; -extern u8 D_801152A8[]; extern s32 D_801152BC; extern int func_8014F74C(s32 arg0); extern s32 func_8014FA70(s32 a0); @@ -3286,7 +3284,47 @@ void func_8017DF98(int param_1) } -INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8017BEBC", func_8017DFF4); + +/* Entity record touched by func_8017DFF4 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017DFF4 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017DFF4; + +extern void func_80147324(s32 arg0); +extern void func_8017E22C(int); + +void func_8017DFF4(Ent_8017BFE0_8017DFF4 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017DFF4 *))func_8017E22C)(param_1); +} + INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8017BEBC", func_8017E078); @@ -3451,7 +3489,72 @@ void func_8017E7D8(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8017BEBC", func_8017E814); + +/* func_8017E814 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017E814(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); @@ -3559,9 +3662,50 @@ void func_8017EF24(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8017BEBC", func_8017EF60); -INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8017BEBC", func_8017EFA8); +/* 8-byte, alignment-1 blob: the target copies it with lwl/lwr + swl/swr, + * which is gcc's emit_block_move for align < 4. */ +typedef struct { + char b[8]; +} Blob8_8018A47C_8017EF60; + +extern void func_8017F048(s32, s16*); + +void func_8017EF60(s32 a0) { + + extern Blob8_8018A47C_8017EF60 D_80126940; + Blob8_8018A47C_8017EF60 tmp; + + tmp = D_80126940; + ((void (*)(s32, Blob8_8018A47C_8017EF60 *))func_8017F048)(a0, &tmp); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017EFA8; + +extern u16 func_80148800(s32 *a0); +extern void func_8017F048(s32 param_1, s16 *param_2); + +void func_8017EFA8(s32 a0) { + + extern s16 D_8018B7F4[]; + extern Blk8_80126940_8017EFA8 D_80126940; + Blk8_80126940_8017EFA8 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_8018B7F4[t]; + } + sp10 = D_80126940; + func_8017F048(a0, sp10.v); +} + // @class: schedule @@ -3797,7 +3941,72 @@ void func_8017F9BC(int param_1) INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8017BEBC", func_8017FAA0); -INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8017BEBC", func_8017FB0C); + +/* func_8017FB0C — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_8017FB0C; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(void); + +void func_8017FB0C(int param_1) +{ + UVec_8017EA1C_8017FB0C v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + extern void func_80019064(void *a0); @@ -4491,7 +4700,29 @@ INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8017BEBC", func_8018552 INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8017BEBC", func_801855A0); -INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8017BEBC", func_801856C0); + + +extern void func_8012F14C(s32); +extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_8012F568(s32 a0, s32 a1, s32 a2, s32 a3, s32 a4, s32 a5); + +s32 func_801856C0(s32 arg0) { + + extern s32 *D_80126B78; + extern u8 D_801B5B84[]; + extern u8 D_801152A8[]; + s32 buf1[2]; + s32 buf2[2]; + + ((void (*)(s32, s32, s32))func_8012F14C)((s32)D_80126B78 + 0x34, (s32)D_801B5B84, (s32)buf1); + ((void (*)(s32, s32, s32))func_8012F14C)((s32)D_80126B78 + 0x34, (s32)(D_801B5B84 + 8), (s32)buf2); + if (func_80135888(*(s32 *)(arg0 + 0x20), *(s32 *)(arg0 + 0x58), (s32)buf1, (s32)buf2) != 0) { + func_8012F568(1, 0x18, *(s16 *)(*(s32 *)(arg0 + 0x20) + 0x12), 0x18, (s32)buf2, (s32)D_801152A8); + return 1; + } + return 0; +} + INCLUDE_ASM("asm/ov_SC04_005/nonmatchings/ov_SC04_005_jr_8017BEBC", func_80185774); diff --git a/src/ov_SC04_006/ov_SC04_006.c b/src/ov_SC04_006/ov_SC04_006.c index 5c23a7495e..9647a70f27 100644 --- a/src/ov_SC04_006/ov_SC04_006.c +++ b/src/ov_SC04_006/ov_SC04_006.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_006/nonmatchings/ov_SC04_006", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017FE84[]; + s16 idx = D_8017FE84[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019B7A8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_006/nonmatchings/ov_SC04_006", func_80128CFC); diff --git a/src/ov_SC04_006/ov_SC04_006_after.c b/src/ov_SC04_006/ov_SC04_006_after.c index e99850d288..f21fc65117 100644 --- a/src/ov_SC04_006/ov_SC04_006_after.c +++ b/src/ov_SC04_006/ov_SC04_006_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_006/nonmatchings/ov_SC04_006_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_006/nonmatchings/ov_SC04_006_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_006/ov_SC04_006_jr_8012ACE0.c b/src/ov_SC04_006/ov_SC04_006_jr_8012ACE0.c index 789a8e316e..05d5fb2d69 100644 --- a/src/ov_SC04_006/ov_SC04_006_jr_8012ACE0.c +++ b/src/ov_SC04_006/ov_SC04_006_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_006/nonmatchings/ov_SC04_006_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_006/ov_SC04_006_jr_801734BC.c b/src/ov_SC04_006/ov_SC04_006_jr_801734BC.c index 1ff013642d..eabb4ac288 100644 --- a/src/ov_SC04_006/ov_SC04_006_jr_801734BC.c +++ b/src/ov_SC04_006/ov_SC04_006_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_006/nonmatchings/ov_SC04_006_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_006/ov_SC04_006_jr_8017BEBC.c b/src/ov_SC04_006/ov_SC04_006_jr_8017BEBC.c index bff2adecd1..d04372d75d 100644 --- a/src/ov_SC04_006/ov_SC04_006_jr_8017BEBC.c +++ b/src/ov_SC04_006/ov_SC04_006_jr_8017BEBC.c @@ -3258,7 +3258,31 @@ void func_8017D22C(void *a0) { INCLUDE_ASM("asm/ov_SC04_006/nonmatchings/ov_SC04_006_jr_8017BEBC", func_8017D268); -INCLUDE_ASM("asm/ov_SC04_006/nonmatchings/ov_SC04_006_jr_8017BEBC", func_8017D344); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D344; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D3E4(s32 param_1, s16 *param_2); + +void func_8017D344(s32 a0) { + + extern s16 D_801836EC[]; + extern Blk8_80126940_8017D344 D_80126940; + Blk8_80126940_8017D344 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_801836EC[t]; + } + sp10 = D_80126940; + func_8017D3E4(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC04_006/nonmatchings/ov_SC04_006_jr_8017BEBC", func_8017D3E4); @@ -3397,7 +3421,72 @@ void func_8017D928(int param_1) INCLUDE_ASM("asm/ov_SC04_006/nonmatchings/ov_SC04_006_jr_8017BEBC", func_8017DA0C); -INCLUDE_ASM("asm/ov_SC04_006/nonmatchings/ov_SC04_006_jr_8017BEBC", func_8017DA78); + +/* func_8017DA78 — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_8017DA78; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(void); + +void func_8017DA78(int param_1) +{ + UVec_8017EA1C_8017DA78 v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + /* func_8017DB64 — tiny matrix wrapper. diff --git a/src/ov_SC04_007/ov_SC04_007.c b/src/ov_SC04_007/ov_SC04_007.c index 5021c089c1..9b11bb0902 100644 --- a/src/ov_SC04_007/ov_SC04_007.c +++ b/src/ov_SC04_007/ov_SC04_007.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80185E3C[]; + s16 idx = D_80185E3C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B2D64, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007", func_80128CFC); diff --git a/src/ov_SC04_007/ov_SC04_007_after.c b/src/ov_SC04_007/ov_SC04_007_after.c index 29ff5bf4fd..fcc2b41651 100644 --- a/src/ov_SC04_007/ov_SC04_007_after.c +++ b/src/ov_SC04_007/ov_SC04_007_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_007/ov_SC04_007_jr_8012ACE0.c b/src/ov_SC04_007/ov_SC04_007_jr_8012ACE0.c index d847beb000..34676935db 100644 --- a/src/ov_SC04_007/ov_SC04_007_jr_8012ACE0.c +++ b/src/ov_SC04_007/ov_SC04_007_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_007/ov_SC04_007_jr_801734BC.c b/src/ov_SC04_007/ov_SC04_007_jr_801734BC.c index d807b91b0c..fd28810c13 100644 --- a/src/ov_SC04_007/ov_SC04_007_jr_801734BC.c +++ b/src/ov_SC04_007/ov_SC04_007_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_007/ov_SC04_007_jr_8017BEBC.c b/src/ov_SC04_007/ov_SC04_007_jr_8017BEBC.c index 24d1194418..56f74627d3 100644 --- a/src/ov_SC04_007/ov_SC04_007_jr_8017BEBC.c +++ b/src/ov_SC04_007/ov_SC04_007_jr_8017BEBC.c @@ -76,7 +76,6 @@ extern s32 func_80146128(void); extern void func_80146360(void); extern void func_801463A0(); extern void func_8014607C(void); -extern s32 *D_80126B78; extern u8 D_80078EC1; extern s32 D_80078EC8; extern s32 D_80126B9C; @@ -597,7 +596,7 @@ extern s32 func_8014E284(s32 a0, s16 *a1, s16 *a2); extern s32 func_8014E048(s32 a0, u16 *a1, u16 *a2); /* u16*: def lhu semantics (T5b reconcile; ptr param type codegen-neutral for the caller) */ extern s32 func_80135A4C(s32 a0, s32 a1, s32 *a2, s32 a3); extern s32 func_80133784(s32 a0, void *a1, s32 a2); -extern u8 D_801152A8[]; /* canonical TU type (engine_core) — read via *(u16*) cast */ +/* canonical TU type (engine_core) — read via *(u16*) cast */ extern s16 D_801152AC; extern s32 func_8014E048(s32 param_1, u16 * param_2, u16 * param_3); extern void func_8014E48C(s32 a0); @@ -633,7 +632,6 @@ extern s32 func_8014F468(void); extern int func_8014F74C(); extern int func_8014F6F4(void); extern u8 D_800D3918[]; -extern u8 D_801152A8[]; extern s32 D_801152BC; extern int func_8014F74C(s32 arg0); extern s32 func_8014FA70(s32 a0); @@ -3250,7 +3248,47 @@ void func_8017DC7C(int param_1) } -INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_8017DCD8); + +/* Entity record touched by func_8017DCD8 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017DCD8 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017DCD8; + +extern void func_80147324(s32 arg0); +extern void func_8017DF10(int); + +void func_8017DCD8(Ent_8017BFE0_8017DCD8 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017DCD8 *))func_8017DF10)(param_1); +} + INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_8017DD5C); @@ -3415,7 +3453,72 @@ void func_8017E4BC(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_8017E4F8); + +/* func_8017E4F8 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017E4F8(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); @@ -3523,9 +3626,50 @@ void func_8017EC08(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_8017EC44); -INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_8017EC8C); +/* 8-byte, alignment-1 blob: the target copies it with lwl/lwr + swl/swr, + * which is gcc's emit_block_move for align < 4. */ +typedef struct { + char b[8]; +} Blob8_8018A47C_8017EC44; + +extern void func_8017ED2C(s32, s16*); + +void func_8017EC44(s32 a0) { + + extern Blob8_8018A47C_8017EC44 D_80126940; + Blob8_8018A47C_8017EC44 tmp; + + tmp = D_80126940; + ((void (*)(s32, Blob8_8018A47C_8017EC44 *))func_8017ED2C)(a0, &tmp); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017EC8C; + +extern u16 func_80148800(s32 *a0); +extern void func_8017ED2C(s32 param_1, s16 *param_2); + +void func_8017EC8C(s32 a0) { + + extern s16 D_801897E8[]; + extern Blk8_80126940_8017EC8C D_80126940; + Blk8_80126940_8017EC8C sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_801897E8[t]; + } + sp10 = D_80126940; + func_8017ED2C(a0, sp10.v); +} + // @class: schedule @@ -3734,7 +3878,72 @@ void func_8017F3F8(int param_1) INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_8017F4DC); -INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_8017F548); + +/* func_8017F548 — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_8017F548; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(void); + +void func_8017F548(int param_1) +{ + UVec_8017EA1C_8017F548 v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_8017F634); @@ -3897,7 +4106,29 @@ INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_80181B9 INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_80181C0C); -INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_80181D2C); + + +extern void func_8012F14C(s32); +extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_8012F568(s32 a0, s32 a1, s32 a2, s32 a3, s32 a4, s32 a5); + +s32 func_80181D2C(s32 arg0) { + + extern s32 *D_80126B78; + extern u8 D_8019822C[]; + extern u8 D_801152A8[]; + s32 buf1[2]; + s32 buf2[2]; + + ((void (*)(s32, s32, s32))func_8012F14C)((s32)D_80126B78 + 0x34, (s32)D_8019822C, (s32)buf1); + ((void (*)(s32, s32, s32))func_8012F14C)((s32)D_80126B78 + 0x34, (s32)(D_8019822C + 8), (s32)buf2); + if (func_80135888(*(s32 *)(arg0 + 0x20), *(s32 *)(arg0 + 0x58), (s32)buf1, (s32)buf2) != 0) { + func_8012F568(1, 0x18, *(s16 *)(*(s32 *)(arg0 + 0x20) + 0x12), 0x18, (s32)buf2, (s32)D_801152A8); + return 1; + } + return 0; +} + INCLUDE_ASM("asm/ov_SC04_007/nonmatchings/ov_SC04_007_jr_8017BEBC", func_80181DE0); diff --git a/src/ov_SC04_008/ov_SC04_008.c b/src/ov_SC04_008/ov_SC04_008.c index 95d99d8e69..2f9d5a60e8 100644 --- a/src/ov_SC04_008/ov_SC04_008.c +++ b/src/ov_SC04_008/ov_SC04_008.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_008/nonmatchings/ov_SC04_008", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017ED74[]; + s16 idx = D_8017ED74[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8018FA4C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_008/nonmatchings/ov_SC04_008", func_80128CFC); diff --git a/src/ov_SC04_008/ov_SC04_008_after.c b/src/ov_SC04_008/ov_SC04_008_after.c index df1adb03dc..c01ca3c2d3 100644 --- a/src/ov_SC04_008/ov_SC04_008_after.c +++ b/src/ov_SC04_008/ov_SC04_008_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_008/nonmatchings/ov_SC04_008_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_008/nonmatchings/ov_SC04_008_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_008/ov_SC04_008_jr_8012ACE0.c b/src/ov_SC04_008/ov_SC04_008_jr_8012ACE0.c index 1de2da095a..1108ba69fa 100644 --- a/src/ov_SC04_008/ov_SC04_008_jr_8012ACE0.c +++ b/src/ov_SC04_008/ov_SC04_008_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_008/nonmatchings/ov_SC04_008_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_008/ov_SC04_008_jr_801734BC.c b/src/ov_SC04_008/ov_SC04_008_jr_801734BC.c index d3318ef518..6b978dbd76 100644 --- a/src/ov_SC04_008/ov_SC04_008_jr_801734BC.c +++ b/src/ov_SC04_008/ov_SC04_008_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_008/nonmatchings/ov_SC04_008_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_008/ov_SC04_008_jr_8017AE2C.c b/src/ov_SC04_008/ov_SC04_008_jr_8017AE2C.c index 99d4e44206..161c9237c8 100644 --- a/src/ov_SC04_008/ov_SC04_008_jr_8017AE2C.c +++ b/src/ov_SC04_008/ov_SC04_008_jr_8017AE2C.c @@ -4115,7 +4115,72 @@ void func_8017E158(int param_1) INCLUDE_ASM("asm/ov_SC04_008/nonmatchings/ov_SC04_008_jr_8017AE2C", func_8017E23C); -INCLUDE_ASM("asm/ov_SC04_008/nonmatchings/ov_SC04_008_jr_8017AE2C", func_8017E2A8); + +/* func_8017E2A8 — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_8017E2A8; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(void); + +void func_8017E2A8(int param_1) +{ + UVec_8017EA1C_8017E2A8 v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + INCLUDE_ASM("asm/ov_SC04_008/nonmatchings/ov_SC04_008_jr_8017AE2C", func_8017E394); diff --git a/src/ov_SC04_009/ov_SC04_009.c b/src/ov_SC04_009/ov_SC04_009.c index bd60b89859..9e5a46a79d 100644 --- a/src/ov_SC04_009/ov_SC04_009.c +++ b/src/ov_SC04_009/ov_SC04_009.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_009/nonmatchings/ov_SC04_009", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017EDA0[]; + s16 idx = D_8017EDA0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80195C60, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_009/nonmatchings/ov_SC04_009", func_80128CFC); diff --git a/src/ov_SC04_009/ov_SC04_009_after.c b/src/ov_SC04_009/ov_SC04_009_after.c index 3048dc1fbd..52a52a6bfc 100644 --- a/src/ov_SC04_009/ov_SC04_009_after.c +++ b/src/ov_SC04_009/ov_SC04_009_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_009/nonmatchings/ov_SC04_009_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_009/nonmatchings/ov_SC04_009_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_009/ov_SC04_009_jr_8012ACE0.c b/src/ov_SC04_009/ov_SC04_009_jr_8012ACE0.c index f632a1a537..3312516f99 100644 --- a/src/ov_SC04_009/ov_SC04_009_jr_8012ACE0.c +++ b/src/ov_SC04_009/ov_SC04_009_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_009/nonmatchings/ov_SC04_009_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_009/ov_SC04_009_jr_801734BC.c b/src/ov_SC04_009/ov_SC04_009_jr_801734BC.c index ca28d273c5..33c87d0a97 100644 --- a/src/ov_SC04_009/ov_SC04_009_jr_801734BC.c +++ b/src/ov_SC04_009/ov_SC04_009_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_009/nonmatchings/ov_SC04_009_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_009/ov_SC04_009_jr_8017BEBC.c b/src/ov_SC04_009/ov_SC04_009_jr_8017BEBC.c index 3ad749e3bc..69d77de31d 100644 --- a/src/ov_SC04_009/ov_SC04_009_jr_8017BEBC.c +++ b/src/ov_SC04_009/ov_SC04_009_jr_8017BEBC.c @@ -3491,7 +3491,72 @@ void func_8017DBFC(int param_1) INCLUDE_ASM("asm/ov_SC04_009/nonmatchings/ov_SC04_009_jr_8017BEBC", func_8017DCE0); -INCLUDE_ASM("asm/ov_SC04_009/nonmatchings/ov_SC04_009_jr_8017BEBC", func_8017DD4C); + +/* func_8017DD4C — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_8017DD4C; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(void); + +void func_8017DD4C(int param_1) +{ + UVec_8017EA1C_8017DD4C v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + extern void (*D_80194ED0[])(void); diff --git a/src/ov_SC04_010/ov_SC04_010.c b/src/ov_SC04_010/ov_SC04_010.c index 910a777a4e..9a5c2948d8 100644 --- a/src/ov_SC04_010/ov_SC04_010.c +++ b/src/ov_SC04_010/ov_SC04_010.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_010/nonmatchings/ov_SC04_010", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017E44C[]; + s16 idx = D_8017E44C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8018D0EC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_010/nonmatchings/ov_SC04_010", func_80128CFC); diff --git a/src/ov_SC04_010/ov_SC04_010_after.c b/src/ov_SC04_010/ov_SC04_010_after.c index edb352bbc7..62cd191b2a 100644 --- a/src/ov_SC04_010/ov_SC04_010_after.c +++ b/src/ov_SC04_010/ov_SC04_010_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_010/nonmatchings/ov_SC04_010_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_010/nonmatchings/ov_SC04_010_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_010/ov_SC04_010_jr_8012ACE0.c b/src/ov_SC04_010/ov_SC04_010_jr_8012ACE0.c index 5f299df9a5..220f7415c3 100644 --- a/src/ov_SC04_010/ov_SC04_010_jr_8012ACE0.c +++ b/src/ov_SC04_010/ov_SC04_010_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_010/nonmatchings/ov_SC04_010_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_010/ov_SC04_010_jr_801734BC.c b/src/ov_SC04_010/ov_SC04_010_jr_801734BC.c index 1c368a2dc2..f9ec449bfa 100644 --- a/src/ov_SC04_010/ov_SC04_010_jr_801734BC.c +++ b/src/ov_SC04_010/ov_SC04_010_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_010/nonmatchings/ov_SC04_010_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_010/ov_SC04_010_jr_8017BEBC.c b/src/ov_SC04_010/ov_SC04_010_jr_8017BEBC.c index b0be433e19..ce2b1eda72 100644 --- a/src/ov_SC04_010/ov_SC04_010_jr_8017BEBC.c +++ b/src/ov_SC04_010/ov_SC04_010_jr_8017BEBC.c @@ -3473,7 +3473,72 @@ void func_8017DF14(int param_1) INCLUDE_ASM("asm/ov_SC04_010/nonmatchings/ov_SC04_010_jr_8017BEBC", func_8017DFF8); -INCLUDE_ASM("asm/ov_SC04_010/nonmatchings/ov_SC04_010_jr_8017BEBC", func_8017E064); + +/* func_8017E064 — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_8017E064; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(void); + +void func_8017E064(int param_1) +{ + UVec_8017EA1C_8017E064 v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + diff --git a/src/ov_SC04_011/ov_SC04_011.c b/src/ov_SC04_011/ov_SC04_011.c index 5a8e7b5c34..a2af412927 100644 --- a/src/ov_SC04_011/ov_SC04_011.c +++ b/src/ov_SC04_011/ov_SC04_011.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801906DC[]; + s16 idx = D_801906DC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801EC688, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011", func_80128CFC); diff --git a/src/ov_SC04_011/ov_SC04_011_after.c b/src/ov_SC04_011/ov_SC04_011_after.c index 80a9f4fd57..b122603a62 100644 --- a/src/ov_SC04_011/ov_SC04_011_after.c +++ b/src/ov_SC04_011/ov_SC04_011_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_011/ov_SC04_011_jr_8012ACE0.c b/src/ov_SC04_011/ov_SC04_011_jr_8012ACE0.c index 5dabdf9882..d00a8d375c 100644 --- a/src/ov_SC04_011/ov_SC04_011_jr_8012ACE0.c +++ b/src/ov_SC04_011/ov_SC04_011_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_011/ov_SC04_011_jr_801734BC.c b/src/ov_SC04_011/ov_SC04_011_jr_801734BC.c index 06dac9e44a..6e047c97bd 100644 --- a/src/ov_SC04_011/ov_SC04_011_jr_801734BC.c +++ b/src/ov_SC04_011/ov_SC04_011_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_011/ov_SC04_011_jr_8017AE2C.c b/src/ov_SC04_011/ov_SC04_011_jr_8017AE2C.c index 997a732180..6903007920 100644 --- a/src/ov_SC04_011/ov_SC04_011_jr_8017AE2C.c +++ b/src/ov_SC04_011/ov_SC04_011_jr_8017AE2C.c @@ -3356,7 +3356,47 @@ void func_8017BF84(int param_1) } -INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017AE2C", func_8017BFE0); + +/* Entity record touched by func_8017BFE0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017BFE0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017BFE0; + +extern void func_80147324(s32 arg0); +extern void func_8017C218(int); + +void func_8017BFE0(Ent_8017BFE0_8017BFE0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017BFE0 *))func_8017C218)(param_1); +} + INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017AE2C", func_8017C064); @@ -3484,7 +3524,72 @@ void func_8017C7C4(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017AE2C", func_8017C800); + +/* func_8017C800 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017C800(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + DEFINE_func_8017C8B4() /* dedup: shared engine-core @0x8017C8B4 (src/shared) */ diff --git a/src/ov_SC04_011/ov_SC04_011_jr_8017D494.c b/src/ov_SC04_011/ov_SC04_011_jr_8017D494.c index 81a32b6163..327dc2b4a5 100644 --- a/src/ov_SC04_011/ov_SC04_011_jr_8017D494.c +++ b/src/ov_SC04_011/ov_SC04_011_jr_8017D494.c @@ -4603,7 +4603,72 @@ void func_8018D318(int param_1) INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017D494", func_8018D3FC); -INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017D494", func_8018D468); + +/* func_8018D468 — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_8018D468; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(u8*); + +void func_8018D468(int param_1) +{ + UVec_8017EA1C_8018D468 v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017D494", func_8018D554); @@ -4658,7 +4723,53 @@ void func_8018E010(void) { } -INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017D494", func_8018E034); + +/* func_8018E034 — cookbook §71 (sibling-first). + * func_8018E0D4 is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_8018E0D4(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_8018E1F0 (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_8018E034; + +extern void func_8018E0D4(s32 arg0, s32 arg1, s32 arg2); +extern void func_8018E1F0(s32 arg0, Rec_8018A6A4_8018E034 *arg1, s32 arg2, s32 arg3); + +void func_8018E034(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_8018E034 sp10; + s32 i; + s32 ang; + + func_8018E0D4(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_8018E1F0(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + extern s16 D_801F1414; @@ -4690,7 +4801,57 @@ INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017D494", func_8018E2C INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017D494", func_8018E300); -INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017D494", func_8018E34C); + +/* func_8018E34C — 16-entry table walk, stride 0xE, over D_801F141C. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801F141C; s16 *p = &D_801F141C; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_8018E428(s32 arg0); + +void func_8018E34C(void) { + + extern s16 D_801F141C; + s16 *p = &D_801F141C; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_8018E428(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC04_011/nonmatchings/ov_SC04_011_jr_8017D494", func_8018E428); diff --git a/src/ov_SC04_012/ov_SC04_012.c b/src/ov_SC04_012/ov_SC04_012.c index 892f8cdae8..aacb899fb8 100644 --- a/src/ov_SC04_012/ov_SC04_012.c +++ b/src/ov_SC04_012/ov_SC04_012.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_012/nonmatchings/ov_SC04_012", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017E8B0[]; + s16 idx = D_8017E8B0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8018F7CC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_012/nonmatchings/ov_SC04_012", func_80128CFC); diff --git a/src/ov_SC04_012/ov_SC04_012_after.c b/src/ov_SC04_012/ov_SC04_012_after.c index 62c7c8f9f1..b007fc1680 100644 --- a/src/ov_SC04_012/ov_SC04_012_after.c +++ b/src/ov_SC04_012/ov_SC04_012_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_012/nonmatchings/ov_SC04_012_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_012/nonmatchings/ov_SC04_012_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_012/ov_SC04_012_jr_8012ACE0.c b/src/ov_SC04_012/ov_SC04_012_jr_8012ACE0.c index e6c51733fb..a8ba476b2c 100644 --- a/src/ov_SC04_012/ov_SC04_012_jr_8012ACE0.c +++ b/src/ov_SC04_012/ov_SC04_012_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_012/nonmatchings/ov_SC04_012_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_012/ov_SC04_012_jr_801734BC.c b/src/ov_SC04_012/ov_SC04_012_jr_801734BC.c index 3bb7987316..48fb50b2a0 100644 --- a/src/ov_SC04_012/ov_SC04_012_jr_801734BC.c +++ b/src/ov_SC04_012/ov_SC04_012_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_012/nonmatchings/ov_SC04_012_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_012/ov_SC04_012_jr_8017AE2C.c b/src/ov_SC04_012/ov_SC04_012_jr_8017AE2C.c index c48e657ba3..fe0ae85dcf 100644 --- a/src/ov_SC04_012/ov_SC04_012_jr_8017AE2C.c +++ b/src/ov_SC04_012/ov_SC04_012_jr_8017AE2C.c @@ -4144,7 +4144,72 @@ void func_8017E378(int param_1) INCLUDE_ASM("asm/ov_SC04_012/nonmatchings/ov_SC04_012_jr_8017AE2C", func_8017E45C); -INCLUDE_ASM("asm/ov_SC04_012/nonmatchings/ov_SC04_012_jr_8017AE2C", func_8017E4C8); + +/* func_8017E4C8 — per-frame update for the effect entity that func_8017E8CC + * initialises (its GPU primitive lives at +0x20). Advance the spin angle at + * +0x2C by 0x40, take rsin(angle)/256 as the Z component of a stack vector, + * rotate that vector by the primitive's own angle at p+0x12, then re-derive + * the draw position words at +6/+0xA/+0xE, grow the size counter at +0x2E + * (mirrored into the primitive's w/h at p+0x18/p+0x1A), fade the RGB triple + * at p+0x24..0x26 by 4 per frame, and retire the entity via func_801292C8 + * once the shared lifetime check func_80146E98 reports done. + * + * Matching notes (cookbook §S1/§S4 in gcc-2.7.2-map/sched.md): the three + * position statements and the +0x2E statement all tie at sched priority 1, + * so their SOURCE ORDER is the schedule. The target's order is + * 0x6, 0xE, 0xA, 0x2E — writing them in field order (0x6, 0xA, 0xE, 0x2E) + * costs 12 mismatches because the 0x30 load, not the 0x2E load, wins the + * load-delay filler slot after the first group. `siz` must be an explicit + * temporary (a re-read of +0x2E in the p+0x1A statement re-groups the whole + * block, 26+ mismatches). + */ + +typedef struct { + unsigned short vx, vy, vz, pad; +} UVec_8017EA1C_8017E4C8; + +extern s32 func_8004787C(s32 a0); +extern void func_800139C8(s32 a0, void *a1, void *a2); +extern s32 func_80146E98(s32 a0); +extern void func_801292C8(void); + +void func_8017E4C8(int param_1) +{ + UVec_8017EA1C_8017E4C8 v; + int p; + short ang; + int siz; + int wid; + int col; + + p = *(int *)(param_1 + 0x20); + ang = *(unsigned short *)(param_1 + 0x2c) + 0x40; + *(unsigned short *)(param_1 + 0x2c) = ang; + v.vz = func_8004787C(ang) / 256; + v.vy = 0; + v.vx = 0; + func_800139C8(*(short *)(p + 0x12), &v, &v); + + *(unsigned short *)(param_1 + 6) = *(unsigned short *)(param_1 + 0x12) + v.vx; + *(unsigned short *)(param_1 + 0xe) = *(unsigned short *)(param_1 + 0x1a) + v.vz; + *(unsigned short *)(param_1 + 0xa) = *(unsigned short *)(param_1 + 0xa) - *(unsigned short *)(param_1 + 0x30); + siz = *(unsigned short *)(param_1 + 0x2e) + 0x10; + *(unsigned short *)(param_1 + 0x2e) = siz; + + wid = *(unsigned short *)(p + 0x1a) + siz; + *(unsigned short *)(p + 0x1a) = wid; + *(unsigned short *)(p + 0x18) = wid; + + col = *(unsigned char *)(p + 0x26) - 4; + *(unsigned char *)(p + 0x26) = col; + *(unsigned char *)(p + 0x25) = col; + *(unsigned char *)(p + 0x24) = col; + + if (func_80146E98(param_1) != 0) { + ((void (*)(int))func_801292C8)(param_1); + } +} + diff --git a/src/ov_SC04_015/ov_SC04_015.c b/src/ov_SC04_015/ov_SC04_015.c index a762772ed7..86d95de59c 100644 --- a/src/ov_SC04_015/ov_SC04_015.c +++ b/src/ov_SC04_015/ov_SC04_015.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_015/nonmatchings/ov_SC04_015", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801847E8[]; + s16 idx = D_801847E8[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C6464, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_015/nonmatchings/ov_SC04_015", func_80128CFC); diff --git a/src/ov_SC04_015/ov_SC04_015_after.c b/src/ov_SC04_015/ov_SC04_015_after.c index b34304b826..fcfbab2c81 100644 --- a/src/ov_SC04_015/ov_SC04_015_after.c +++ b/src/ov_SC04_015/ov_SC04_015_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_015/nonmatchings/ov_SC04_015_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_015/nonmatchings/ov_SC04_015_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_015/ov_SC04_015_jr_8012ACE0.c b/src/ov_SC04_015/ov_SC04_015_jr_8012ACE0.c index 3dc063cb4d..ca08d388c9 100644 --- a/src/ov_SC04_015/ov_SC04_015_jr_8012ACE0.c +++ b/src/ov_SC04_015/ov_SC04_015_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_015/nonmatchings/ov_SC04_015_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_015/ov_SC04_015_jr_801734BC.c b/src/ov_SC04_015/ov_SC04_015_jr_801734BC.c index 8681e2e59c..0478fcea51 100644 --- a/src/ov_SC04_015/ov_SC04_015_jr_801734BC.c +++ b/src/ov_SC04_015/ov_SC04_015_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_015/nonmatchings/ov_SC04_015_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_016/ov_SC04_016.c b/src/ov_SC04_016/ov_SC04_016.c index 041bb85287..048b4c67c8 100644 --- a/src/ov_SC04_016/ov_SC04_016.c +++ b/src/ov_SC04_016/ov_SC04_016.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_016/nonmatchings/ov_SC04_016", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801802AC[]; + s16 idx = D_801802AC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A461C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_016/nonmatchings/ov_SC04_016", func_80128CFC); diff --git a/src/ov_SC04_016/ov_SC04_016_after.c b/src/ov_SC04_016/ov_SC04_016_after.c index fd2a42d1e1..f122ae3565 100644 --- a/src/ov_SC04_016/ov_SC04_016_after.c +++ b/src/ov_SC04_016/ov_SC04_016_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_016/nonmatchings/ov_SC04_016_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_016/nonmatchings/ov_SC04_016_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_016/ov_SC04_016_jr_8012ACE0.c b/src/ov_SC04_016/ov_SC04_016_jr_8012ACE0.c index 99b8c7b3f0..b366260509 100644 --- a/src/ov_SC04_016/ov_SC04_016_jr_8012ACE0.c +++ b/src/ov_SC04_016/ov_SC04_016_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_016/nonmatchings/ov_SC04_016_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_016/ov_SC04_016_jr_801734BC.c b/src/ov_SC04_016/ov_SC04_016_jr_801734BC.c index a68012eec4..c61329e759 100644 --- a/src/ov_SC04_016/ov_SC04_016_jr_801734BC.c +++ b/src/ov_SC04_016/ov_SC04_016_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_016/nonmatchings/ov_SC04_016_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_016/ov_SC04_016_jr_8017BEBC.c b/src/ov_SC04_016/ov_SC04_016_jr_8017BEBC.c index 434e1dbf60..ce7d5778d6 100644 --- a/src/ov_SC04_016/ov_SC04_016_jr_8017BEBC.c +++ b/src/ov_SC04_016/ov_SC04_016_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3240,7 +3239,32 @@ void func_8017D010(void *a0) { } -INCLUDE_ASM("asm/ov_SC04_016/nonmatchings/ov_SC04_016_jr_8017BEBC", func_8017D04C); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D04C; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D0EC(s32*); + +void func_8017D04C(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80183A60[]; + extern Blk8_80126940_8017D04C D_80126940; + Blk8_80126940_8017D04C sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80183A60[t]; + } + sp10 = D_80126940; + ((void (*)(s32, s16 *))func_8017D0EC)(a0, sp10.v); +} + void func_8017D0EC(s32 *a0) { *(s32 *)((s32)a0 + 0x3C) = 0x18C; diff --git a/src/ov_SC04_018/ov_SC04_018.c b/src/ov_SC04_018/ov_SC04_018.c index d85708cb9d..8d9c23ad34 100644 --- a/src/ov_SC04_018/ov_SC04_018.c +++ b/src/ov_SC04_018/ov_SC04_018.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_018/nonmatchings/ov_SC04_018", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018D4C4[]; + s16 idx = D_8018D4C4[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801E4434, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_018/nonmatchings/ov_SC04_018", func_80128CFC); diff --git a/src/ov_SC04_018/ov_SC04_018_after.c b/src/ov_SC04_018/ov_SC04_018_after.c index cbd08745ce..86587f62e9 100644 --- a/src/ov_SC04_018/ov_SC04_018_after.c +++ b/src/ov_SC04_018/ov_SC04_018_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_018/nonmatchings/ov_SC04_018_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_018/nonmatchings/ov_SC04_018_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_018/ov_SC04_018_jr_8012ACE0.c b/src/ov_SC04_018/ov_SC04_018_jr_8012ACE0.c index e7f80551bd..ca9d3ca898 100644 --- a/src/ov_SC04_018/ov_SC04_018_jr_8012ACE0.c +++ b/src/ov_SC04_018/ov_SC04_018_jr_8012ACE0.c @@ -329,7 +329,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_018/nonmatchings/ov_SC04_018_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_018/ov_SC04_018_jr_801734BC.c b/src/ov_SC04_018/ov_SC04_018_jr_801734BC.c index ecd2f0560a..9644fb1ff9 100644 --- a/src/ov_SC04_018/ov_SC04_018_jr_801734BC.c +++ b/src/ov_SC04_018/ov_SC04_018_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_018/nonmatchings/ov_SC04_018_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_019/ov_SC04_019.c b/src/ov_SC04_019/ov_SC04_019.c index e54184f2b0..5bd45bd13e 100644 --- a/src/ov_SC04_019/ov_SC04_019.c +++ b/src/ov_SC04_019/ov_SC04_019.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_019/nonmatchings/ov_SC04_019", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018D4C4[]; + s16 idx = D_8018D4C4[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801E4434, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_019/nonmatchings/ov_SC04_019", func_80128CFC); diff --git a/src/ov_SC04_019/ov_SC04_019_after.c b/src/ov_SC04_019/ov_SC04_019_after.c index d3bd747f15..12e87f786a 100644 --- a/src/ov_SC04_019/ov_SC04_019_after.c +++ b/src/ov_SC04_019/ov_SC04_019_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_019/nonmatchings/ov_SC04_019_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_019/nonmatchings/ov_SC04_019_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_019/ov_SC04_019_jr_8012ACE0.c b/src/ov_SC04_019/ov_SC04_019_jr_8012ACE0.c index 4800ad8181..96c039cffa 100644 --- a/src/ov_SC04_019/ov_SC04_019_jr_8012ACE0.c +++ b/src/ov_SC04_019/ov_SC04_019_jr_8012ACE0.c @@ -329,7 +329,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_019/nonmatchings/ov_SC04_019_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_019/ov_SC04_019_jr_801734BC.c b/src/ov_SC04_019/ov_SC04_019_jr_801734BC.c index d578be3986..a8c7b3f508 100644 --- a/src/ov_SC04_019/ov_SC04_019_jr_801734BC.c +++ b/src/ov_SC04_019/ov_SC04_019_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_019/nonmatchings/ov_SC04_019_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_020/ov_SC04_020.c b/src/ov_SC04_020/ov_SC04_020.c index 2fa06395fd..1f638281c1 100644 --- a/src/ov_SC04_020/ov_SC04_020.c +++ b/src/ov_SC04_020/ov_SC04_020.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_020/nonmatchings/ov_SC04_020", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801835FC[]; + s16 idx = D_801835FC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B9E5C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_020/nonmatchings/ov_SC04_020", func_80128CFC); diff --git a/src/ov_SC04_020/ov_SC04_020_after.c b/src/ov_SC04_020/ov_SC04_020_after.c index ad9febe388..d4d9d2e33e 100644 --- a/src/ov_SC04_020/ov_SC04_020_after.c +++ b/src/ov_SC04_020/ov_SC04_020_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_020/nonmatchings/ov_SC04_020_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_020/nonmatchings/ov_SC04_020_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_020/ov_SC04_020_jr_8012ACE0.c b/src/ov_SC04_020/ov_SC04_020_jr_8012ACE0.c index 0f2b187fbe..b4ffd13106 100644 --- a/src/ov_SC04_020/ov_SC04_020_jr_8012ACE0.c +++ b/src/ov_SC04_020/ov_SC04_020_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_020/nonmatchings/ov_SC04_020_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_020/ov_SC04_020_jr_801734BC.c b/src/ov_SC04_020/ov_SC04_020_jr_801734BC.c index 1e98af655e..021b15fb7b 100644 --- a/src/ov_SC04_020/ov_SC04_020_jr_801734BC.c +++ b/src/ov_SC04_020/ov_SC04_020_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_020/nonmatchings/ov_SC04_020_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC04_021/ov_SC04_021.c b/src/ov_SC04_021/ov_SC04_021.c index a91f7648e7..ddba561af8 100644 --- a/src/ov_SC04_021/ov_SC04_021.c +++ b/src/ov_SC04_021/ov_SC04_021.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_021/nonmatchings/ov_SC04_021", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017F528[]; + s16 idx = D_8017F528[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8018D4F8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC04_021/nonmatchings/ov_SC04_021", func_80128CFC); diff --git a/src/ov_SC04_021/ov_SC04_021_after.c b/src/ov_SC04_021/ov_SC04_021_after.c index 75ad610cfe..c28409cb57 100644 --- a/src/ov_SC04_021/ov_SC04_021_after.c +++ b/src/ov_SC04_021/ov_SC04_021_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC04_021/nonmatchings/ov_SC04_021_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_021/nonmatchings/ov_SC04_021_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC04_021/ov_SC04_021_jr_8012ACE0.c b/src/ov_SC04_021/ov_SC04_021_jr_8012ACE0.c index 6add4197a4..bd9bb2453a 100644 --- a/src/ov_SC04_021/ov_SC04_021_jr_8012ACE0.c +++ b/src/ov_SC04_021/ov_SC04_021_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC04_021/nonmatchings/ov_SC04_021_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC04_021/ov_SC04_021_jr_801734BC.c b/src/ov_SC04_021/ov_SC04_021_jr_801734BC.c index 11f97b1fc1..a2b6dae7af 100644 --- a/src/ov_SC04_021/ov_SC04_021_jr_801734BC.c +++ b/src/ov_SC04_021/ov_SC04_021_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC04_021/nonmatchings/ov_SC04_021_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_000/ov_SC05_000.c b/src/ov_SC05_000/ov_SC05_000.c index 09e3f2bcb0..c477346ff9 100644 --- a/src/ov_SC05_000/ov_SC05_000.c +++ b/src/ov_SC05_000/ov_SC05_000.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_000/nonmatchings/ov_SC05_000", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017E53C[]; + s16 idx = D_8017E53C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80198648, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_000/nonmatchings/ov_SC05_000", func_80128CFC); diff --git a/src/ov_SC05_000/ov_SC05_000_after.c b/src/ov_SC05_000/ov_SC05_000_after.c index 06cf4c3c2f..08606231ab 100644 --- a/src/ov_SC05_000/ov_SC05_000_after.c +++ b/src/ov_SC05_000/ov_SC05_000_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_000/nonmatchings/ov_SC05_000_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_000/nonmatchings/ov_SC05_000_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_000/ov_SC05_000_jr_8012ACE0.c b/src/ov_SC05_000/ov_SC05_000_jr_8012ACE0.c index ee15eb8d7b..7ceb083375 100644 --- a/src/ov_SC05_000/ov_SC05_000_jr_8012ACE0.c +++ b/src/ov_SC05_000/ov_SC05_000_jr_8012ACE0.c @@ -329,7 +329,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_000/nonmatchings/ov_SC05_000_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_000/ov_SC05_000_jr_801734BC.c b/src/ov_SC05_000/ov_SC05_000_jr_801734BC.c index 79dd887eba..26b5b0486f 100644 --- a/src/ov_SC05_000/ov_SC05_000_jr_801734BC.c +++ b/src/ov_SC05_000/ov_SC05_000_jr_801734BC.c @@ -3170,7 +3170,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_000/nonmatchings/ov_SC05_000_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_001/ov_SC05_001.c b/src/ov_SC05_001/ov_SC05_001.c index a083a21980..a110cad855 100644 --- a/src/ov_SC05_001/ov_SC05_001.c +++ b/src/ov_SC05_001/ov_SC05_001.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_001/nonmatchings/ov_SC05_001", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80185D18[]; + s16 idx = D_80185D18[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B35FC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_001/nonmatchings/ov_SC05_001", func_80128CFC); diff --git a/src/ov_SC05_001/ov_SC05_001_after.c b/src/ov_SC05_001/ov_SC05_001_after.c index 315ae004ea..6eefe42c30 100644 --- a/src/ov_SC05_001/ov_SC05_001_after.c +++ b/src/ov_SC05_001/ov_SC05_001_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_001/nonmatchings/ov_SC05_001_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_001/nonmatchings/ov_SC05_001_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_001/ov_SC05_001_jr_8012ACE0.c b/src/ov_SC05_001/ov_SC05_001_jr_8012ACE0.c index aa78b0ce6c..2dc0b6e1f3 100644 --- a/src/ov_SC05_001/ov_SC05_001_jr_8012ACE0.c +++ b/src/ov_SC05_001/ov_SC05_001_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_001/nonmatchings/ov_SC05_001_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_001/ov_SC05_001_jr_801734BC.c b/src/ov_SC05_001/ov_SC05_001_jr_801734BC.c index 33c19690fe..70f97b330e 100644 --- a/src/ov_SC05_001/ov_SC05_001_jr_801734BC.c +++ b/src/ov_SC05_001/ov_SC05_001_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_001/nonmatchings/ov_SC05_001_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_001/ov_SC05_001_jr_8017BEBC.c b/src/ov_SC05_001/ov_SC05_001_jr_8017BEBC.c index 92751640be..bf741f4e4e 100644 --- a/src/ov_SC05_001/ov_SC05_001_jr_8017BEBC.c +++ b/src/ov_SC05_001/ov_SC05_001_jr_8017BEBC.c @@ -3212,7 +3212,47 @@ void func_8017CE64(int param_1) } -INCLUDE_ASM("asm/ov_SC05_001/nonmatchings/ov_SC05_001_jr_8017BEBC", func_8017CEC0); + +/* Entity record touched by func_8017CEC0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017CEC0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017CEC0; + +extern void func_80147324(s32 arg0); +extern void func_8017D0F8(int); + +void func_8017CEC0(Ent_8017BFE0_8017CEC0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017CEC0 *))func_8017D0F8)(param_1); +} + INCLUDE_ASM("asm/ov_SC05_001/nonmatchings/ov_SC05_001_jr_8017BEBC", func_8017CF44); @@ -3377,7 +3417,72 @@ void func_8017D6A4(void *a0) { } -INCLUDE_ASM("asm/ov_SC05_001/nonmatchings/ov_SC05_001_jr_8017BEBC", func_8017D6E0); + +/* func_8017D6E0 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D6E0(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC05_002/ov_SC05_002.c b/src/ov_SC05_002/ov_SC05_002.c index 9804481865..228345b40a 100644 --- a/src/ov_SC05_002/ov_SC05_002.c +++ b/src/ov_SC05_002/ov_SC05_002.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_002/nonmatchings/ov_SC05_002", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801804D8[]; + s16 idx = D_801804D8[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019D9A8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_002/nonmatchings/ov_SC05_002", func_80128CFC); diff --git a/src/ov_SC05_002/ov_SC05_002_after.c b/src/ov_SC05_002/ov_SC05_002_after.c index f455bcc7b4..0f4e8dea48 100644 --- a/src/ov_SC05_002/ov_SC05_002_after.c +++ b/src/ov_SC05_002/ov_SC05_002_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_002/nonmatchings/ov_SC05_002_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_002/nonmatchings/ov_SC05_002_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_002/ov_SC05_002_jr_8012ACE0.c b/src/ov_SC05_002/ov_SC05_002_jr_8012ACE0.c index 0ad789eabb..294d6b97b4 100644 --- a/src/ov_SC05_002/ov_SC05_002_jr_8012ACE0.c +++ b/src/ov_SC05_002/ov_SC05_002_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_002/nonmatchings/ov_SC05_002_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_002/ov_SC05_002_jr_801734BC.c b/src/ov_SC05_002/ov_SC05_002_jr_801734BC.c index b4ac6799e6..cc015df045 100644 --- a/src/ov_SC05_002/ov_SC05_002_jr_801734BC.c +++ b/src/ov_SC05_002/ov_SC05_002_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_002/nonmatchings/ov_SC05_002_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_002/ov_SC05_002_jr_8017BEBC.c b/src/ov_SC05_002/ov_SC05_002_jr_8017BEBC.c index 72e0a6521a..3b911ff8f9 100644 --- a/src/ov_SC05_002/ov_SC05_002_jr_8017BEBC.c +++ b/src/ov_SC05_002/ov_SC05_002_jr_8017BEBC.c @@ -3426,7 +3426,31 @@ void func_8017E1A0(void *a0) { } -INCLUDE_ASM("asm/ov_SC05_002/nonmatchings/ov_SC05_002_jr_8017BEBC", func_8017E1DC); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017E1DC; + +extern u16 func_80148800(s32 *a0); +extern void func_8017E27C(s32 param_1, s16 *param_2); + +void func_8017E1DC(s32 a0) { + + extern s16 D_8018412C[]; + extern Blk8_80126940_8017E1DC D_80126940; + Blk8_80126940_8017E1DC sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_8018412C[t]; + } + sp10 = D_80126940; + func_8017E27C(a0, sp10.v); +} + // @class: schedule diff --git a/src/ov_SC05_003/ov_SC05_003.c b/src/ov_SC05_003/ov_SC05_003.c index 7f3539139b..52be814cfc 100644 --- a/src/ov_SC05_003/ov_SC05_003.c +++ b/src/ov_SC05_003/ov_SC05_003.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_003/nonmatchings/ov_SC05_003", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80182810[]; + s16 idx = D_80182810[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801AA4A4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_003/nonmatchings/ov_SC05_003", func_80128CFC); diff --git a/src/ov_SC05_003/ov_SC05_003_after.c b/src/ov_SC05_003/ov_SC05_003_after.c index e39bc311f8..cfc3938ccc 100644 --- a/src/ov_SC05_003/ov_SC05_003_after.c +++ b/src/ov_SC05_003/ov_SC05_003_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_003/nonmatchings/ov_SC05_003_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_003/nonmatchings/ov_SC05_003_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_003/ov_SC05_003_jr_8012ACE0.c b/src/ov_SC05_003/ov_SC05_003_jr_8012ACE0.c index 251cc17e00..13f46973ef 100644 --- a/src/ov_SC05_003/ov_SC05_003_jr_8012ACE0.c +++ b/src/ov_SC05_003/ov_SC05_003_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_003/nonmatchings/ov_SC05_003_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_003/ov_SC05_003_jr_801734BC.c b/src/ov_SC05_003/ov_SC05_003_jr_801734BC.c index 5c8408e993..ad792c39f4 100644 --- a/src/ov_SC05_003/ov_SC05_003_jr_801734BC.c +++ b/src/ov_SC05_003/ov_SC05_003_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_003/nonmatchings/ov_SC05_003_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_004/ov_SC05_004.c b/src/ov_SC05_004/ov_SC05_004.c index 65baacf662..7fe0329f2b 100644 --- a/src/ov_SC05_004/ov_SC05_004.c +++ b/src/ov_SC05_004/ov_SC05_004.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_004/nonmatchings/ov_SC05_004", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018191C[]; + s16 idx = D_8018191C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019CA98, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_004/nonmatchings/ov_SC05_004", func_80128CFC); diff --git a/src/ov_SC05_004/ov_SC05_004_after.c b/src/ov_SC05_004/ov_SC05_004_after.c index 2f56dd2eed..b92e8b9d0a 100644 --- a/src/ov_SC05_004/ov_SC05_004_after.c +++ b/src/ov_SC05_004/ov_SC05_004_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_004/nonmatchings/ov_SC05_004_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_004/nonmatchings/ov_SC05_004_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_004/ov_SC05_004_jr_8012ACE0.c b/src/ov_SC05_004/ov_SC05_004_jr_8012ACE0.c index 34de4859aa..55921b15bd 100644 --- a/src/ov_SC05_004/ov_SC05_004_jr_8012ACE0.c +++ b/src/ov_SC05_004/ov_SC05_004_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_004/nonmatchings/ov_SC05_004_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_004/ov_SC05_004_jr_801734BC.c b/src/ov_SC05_004/ov_SC05_004_jr_801734BC.c index bb209a083c..088cc196e3 100644 --- a/src/ov_SC05_004/ov_SC05_004_jr_801734BC.c +++ b/src/ov_SC05_004/ov_SC05_004_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_004/nonmatchings/ov_SC05_004_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_005/ov_SC05_005.c b/src/ov_SC05_005/ov_SC05_005.c index 2edb43d312..70406a91cb 100644 --- a/src/ov_SC05_005/ov_SC05_005.c +++ b/src/ov_SC05_005/ov_SC05_005.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_005/nonmatchings/ov_SC05_005", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801826F0[]; + s16 idx = D_801826F0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801AF780, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_005/nonmatchings/ov_SC05_005", func_80128CFC); diff --git a/src/ov_SC05_005/ov_SC05_005_after.c b/src/ov_SC05_005/ov_SC05_005_after.c index 5d9aa79cdc..3f3e270543 100644 --- a/src/ov_SC05_005/ov_SC05_005_after.c +++ b/src/ov_SC05_005/ov_SC05_005_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_005/nonmatchings/ov_SC05_005_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_005/nonmatchings/ov_SC05_005_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_005/ov_SC05_005_jr_8012ACE0.c b/src/ov_SC05_005/ov_SC05_005_jr_8012ACE0.c index e15bb5adab..99008c9c9d 100644 --- a/src/ov_SC05_005/ov_SC05_005_jr_8012ACE0.c +++ b/src/ov_SC05_005/ov_SC05_005_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_005/nonmatchings/ov_SC05_005_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_005/ov_SC05_005_jr_801734BC.c b/src/ov_SC05_005/ov_SC05_005_jr_801734BC.c index 1278a3e048..6b7a4d5e65 100644 --- a/src/ov_SC05_005/ov_SC05_005_jr_801734BC.c +++ b/src/ov_SC05_005/ov_SC05_005_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_005/nonmatchings/ov_SC05_005_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_005/ov_SC05_005_jr_8017AE2C.c b/src/ov_SC05_005/ov_SC05_005_jr_8017AE2C.c index ba46a1efb0..d5b494729a 100644 --- a/src/ov_SC05_005/ov_SC05_005_jr_8017AE2C.c +++ b/src/ov_SC05_005/ov_SC05_005_jr_8017AE2C.c @@ -3356,7 +3356,47 @@ void func_8017BF84(int param_1) } -INCLUDE_ASM("asm/ov_SC05_005/nonmatchings/ov_SC05_005_jr_8017AE2C", func_8017BFE0); + +/* Entity record touched by func_8017BFE0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017BFE0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017BFE0; + +extern void func_80147324(s32 arg0); +extern void func_8017C218(int); + +void func_8017BFE0(Ent_8017BFE0_8017BFE0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017BFE0 *))func_8017C218)(param_1); +} + INCLUDE_ASM("asm/ov_SC05_005/nonmatchings/ov_SC05_005_jr_8017AE2C", func_8017C064); @@ -3484,7 +3524,72 @@ void func_8017C7C4(void *a0) { } -INCLUDE_ASM("asm/ov_SC05_005/nonmatchings/ov_SC05_005_jr_8017AE2C", func_8017C800); + +/* func_8017C800 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017C800(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + DEFINE_func_8017C8B4() /* dedup: shared engine-core @0x8017C8B4 (src/shared) */ diff --git a/src/ov_SC05_006/ov_SC05_006.c b/src/ov_SC05_006/ov_SC05_006.c index 2e2b619868..899d64984f 100644 --- a/src/ov_SC05_006/ov_SC05_006.c +++ b/src/ov_SC05_006/ov_SC05_006.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_006/nonmatchings/ov_SC05_006", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017F710[]; + s16 idx = D_8017F710[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8018D8D0, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_006/nonmatchings/ov_SC05_006", func_80128CFC); diff --git a/src/ov_SC05_006/ov_SC05_006_after.c b/src/ov_SC05_006/ov_SC05_006_after.c index bb82220e2b..64ed09fbf7 100644 --- a/src/ov_SC05_006/ov_SC05_006_after.c +++ b/src/ov_SC05_006/ov_SC05_006_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_006/nonmatchings/ov_SC05_006_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_006/nonmatchings/ov_SC05_006_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_006/ov_SC05_006_jr_8012ACE0.c b/src/ov_SC05_006/ov_SC05_006_jr_8012ACE0.c index 8b067d8198..1c2d0dd60c 100644 --- a/src/ov_SC05_006/ov_SC05_006_jr_8012ACE0.c +++ b/src/ov_SC05_006/ov_SC05_006_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_006/nonmatchings/ov_SC05_006_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_006/ov_SC05_006_jr_801734BC.c b/src/ov_SC05_006/ov_SC05_006_jr_801734BC.c index 21f7b1ab2f..bf5b91ebe3 100644 --- a/src/ov_SC05_006/ov_SC05_006_jr_801734BC.c +++ b/src/ov_SC05_006/ov_SC05_006_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_006/nonmatchings/ov_SC05_006_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_006/ov_SC05_006_jr_8017BEBC.c b/src/ov_SC05_006/ov_SC05_006_jr_8017BEBC.c index afd392103b..0ab4fad16b 100644 --- a/src/ov_SC05_006/ov_SC05_006_jr_8017BEBC.c +++ b/src/ov_SC05_006/ov_SC05_006_jr_8017BEBC.c @@ -3213,7 +3213,47 @@ void func_8017CE64(int param_1) } -INCLUDE_ASM("asm/ov_SC05_006/nonmatchings/ov_SC05_006_jr_8017BEBC", func_8017CEC0); + +/* Entity record touched by func_8017CEC0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017CEC0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017CEC0; + +extern void func_80147324(s32 arg0); +extern void func_8017D0F8(int); + +void func_8017CEC0(Ent_8017BFE0_8017CEC0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017CEC0 *))func_8017D0F8)(param_1); +} + INCLUDE_ASM("asm/ov_SC05_006/nonmatchings/ov_SC05_006_jr_8017BEBC", func_8017CF44); @@ -3378,7 +3418,72 @@ void func_8017D6A4(void *a0) { } -INCLUDE_ASM("asm/ov_SC05_006/nonmatchings/ov_SC05_006_jr_8017BEBC", func_8017D6E0); + +/* func_8017D6E0 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_8017D6E0(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); diff --git a/src/ov_SC05_007/ov_SC05_007.c b/src/ov_SC05_007/ov_SC05_007.c index 5ff7ea38e2..598b3588c2 100644 --- a/src/ov_SC05_007/ov_SC05_007.c +++ b/src/ov_SC05_007/ov_SC05_007.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_007/nonmatchings/ov_SC05_007", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80180D0C[]; + s16 idx = D_80180D0C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019A8A8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_007/nonmatchings/ov_SC05_007", func_80128CFC); diff --git a/src/ov_SC05_007/ov_SC05_007_after.c b/src/ov_SC05_007/ov_SC05_007_after.c index f3e878b650..8b4a2abffd 100644 --- a/src/ov_SC05_007/ov_SC05_007_after.c +++ b/src/ov_SC05_007/ov_SC05_007_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_007/nonmatchings/ov_SC05_007_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_007/nonmatchings/ov_SC05_007_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_007/ov_SC05_007_jr_8012ACE0.c b/src/ov_SC05_007/ov_SC05_007_jr_8012ACE0.c index 896afc7d13..d2e57a3037 100644 --- a/src/ov_SC05_007/ov_SC05_007_jr_8012ACE0.c +++ b/src/ov_SC05_007/ov_SC05_007_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_007/nonmatchings/ov_SC05_007_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_007/ov_SC05_007_jr_801734BC.c b/src/ov_SC05_007/ov_SC05_007_jr_801734BC.c index afd7e62cbf..48ceb597ae 100644 --- a/src/ov_SC05_007/ov_SC05_007_jr_801734BC.c +++ b/src/ov_SC05_007/ov_SC05_007_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_007/nonmatchings/ov_SC05_007_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_008/ov_SC05_008.c b/src/ov_SC05_008/ov_SC05_008.c index fc7dd51b0f..8560c18f7b 100644 --- a/src/ov_SC05_008/ov_SC05_008.c +++ b/src/ov_SC05_008/ov_SC05_008.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_008/nonmatchings/ov_SC05_008", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80182C64[]; + s16 idx = D_80182C64[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019EBDC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_008/nonmatchings/ov_SC05_008", func_80128CFC); diff --git a/src/ov_SC05_008/ov_SC05_008_after.c b/src/ov_SC05_008/ov_SC05_008_after.c index dd43a22477..72690cdcee 100644 --- a/src/ov_SC05_008/ov_SC05_008_after.c +++ b/src/ov_SC05_008/ov_SC05_008_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_008/nonmatchings/ov_SC05_008_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_008/nonmatchings/ov_SC05_008_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_008/ov_SC05_008_jr_8012ACE0.c b/src/ov_SC05_008/ov_SC05_008_jr_8012ACE0.c index cba73b2354..a7edccad04 100644 --- a/src/ov_SC05_008/ov_SC05_008_jr_8012ACE0.c +++ b/src/ov_SC05_008/ov_SC05_008_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_008/nonmatchings/ov_SC05_008_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_008/ov_SC05_008_jr_801734BC.c b/src/ov_SC05_008/ov_SC05_008_jr_801734BC.c index 8ef870b68b..458272b354 100644 --- a/src/ov_SC05_008/ov_SC05_008_jr_801734BC.c +++ b/src/ov_SC05_008/ov_SC05_008_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_008/nonmatchings/ov_SC05_008_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_009/ov_SC05_009.c b/src/ov_SC05_009/ov_SC05_009.c index 9f4bce058d..bd4ea55a67 100644 --- a/src/ov_SC05_009/ov_SC05_009.c +++ b/src/ov_SC05_009/ov_SC05_009.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_009/nonmatchings/ov_SC05_009", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017ED74[]; + s16 idx = D_8017ED74[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801945F0, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_009/nonmatchings/ov_SC05_009", func_80128CFC); diff --git a/src/ov_SC05_009/ov_SC05_009_after.c b/src/ov_SC05_009/ov_SC05_009_after.c index 2a8b6452b8..8d18cbcefd 100644 --- a/src/ov_SC05_009/ov_SC05_009_after.c +++ b/src/ov_SC05_009/ov_SC05_009_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_009/nonmatchings/ov_SC05_009_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_009/nonmatchings/ov_SC05_009_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_009/ov_SC05_009_jr_8012ACE0.c b/src/ov_SC05_009/ov_SC05_009_jr_8012ACE0.c index 2d492f6ed9..cc8e594514 100644 --- a/src/ov_SC05_009/ov_SC05_009_jr_8012ACE0.c +++ b/src/ov_SC05_009/ov_SC05_009_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_009/nonmatchings/ov_SC05_009_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_009/ov_SC05_009_jr_801734BC.c b/src/ov_SC05_009/ov_SC05_009_jr_801734BC.c index dff4393958..9530dab197 100644 --- a/src/ov_SC05_009/ov_SC05_009_jr_801734BC.c +++ b/src/ov_SC05_009/ov_SC05_009_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_009/nonmatchings/ov_SC05_009_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_009/ov_SC05_009_jr_8017BEBC.c b/src/ov_SC05_009/ov_SC05_009_jr_8017BEBC.c index 4154071bfe..0b198fa3e7 100644 --- a/src/ov_SC05_009/ov_SC05_009_jr_8017BEBC.c +++ b/src/ov_SC05_009/ov_SC05_009_jr_8017BEBC.c @@ -3273,11 +3273,69 @@ void func_8017D1D4(void *a0) { } -INCLUDE_ASM("asm/ov_SC05_009/nonmatchings/ov_SC05_009_jr_8017BEBC", func_8017D210); -INCLUDE_ASM("asm/ov_SC05_009/nonmatchings/ov_SC05_009_jr_8017BEBC", func_8017D2B0); +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D210; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D340(s32 param_1, s16 *param_2); + +void func_8017D210(s32 a0) { + + extern s16 D_80182550[]; + extern Blk8_80126940_8017D210 D_80126940; + Blk8_80126940_8017D210 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80182550[t]; + } + sp10 = D_80126940; + func_8017D340(a0, sp10.v); +} + + + +/* 8-byte, alignment-1 blob: the target copies it with lwl/lwr + swl/swr, + * which is gcc's emit_block_move for align < 4. */ +typedef struct { + char b[8]; +} Blob8_8018A47C_8017D2B0; + +extern void func_8017D340(s32, s16*); + +void func_8017D2B0(s32 a0) { + + extern Blob8_8018A47C_8017D2B0 D_80126940; + Blob8_8018A47C_8017D2B0 tmp; + + tmp = D_80126940; + ((void (*)(s32, Blob8_8018A47C_8017D2B0 *))func_8017D340)(a0, &tmp); +} + + + +/* 8-byte, alignment-1 blob: the target copies it with lwl/lwr + swl/swr, + * which is gcc's emit_block_move for align < 4. */ +typedef struct { + char b[8]; +} Blob8_8018A47C_8017D2F8; + +extern void func_8017D4D8(s32, s16*); + +void func_8017D2F8(s32 a0) { + + extern Blob8_8018A47C_8017D2F8 D_80126940; + Blob8_8018A47C_8017D2F8 tmp; + + tmp = D_80126940; + ((void (*)(s32, Blob8_8018A47C_8017D2F8 *))func_8017D4D8)(a0, &tmp); +} -INCLUDE_ASM("asm/ov_SC05_009/nonmatchings/ov_SC05_009_jr_8017BEBC", func_8017D2F8); // @class: schedule diff --git a/src/ov_SC05_010/ov_SC05_010.c b/src/ov_SC05_010/ov_SC05_010.c index 4e265bff02..4c09c46dca 100644 --- a/src/ov_SC05_010/ov_SC05_010.c +++ b/src/ov_SC05_010/ov_SC05_010.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_010/nonmatchings/ov_SC05_010", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80188C50[]; + s16 idx = D_80188C50[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C4824, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_010/nonmatchings/ov_SC05_010", func_80128CFC); diff --git a/src/ov_SC05_010/ov_SC05_010_after.c b/src/ov_SC05_010/ov_SC05_010_after.c index caaac82721..5d41bb628e 100644 --- a/src/ov_SC05_010/ov_SC05_010_after.c +++ b/src/ov_SC05_010/ov_SC05_010_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_010/nonmatchings/ov_SC05_010_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_010/nonmatchings/ov_SC05_010_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_010/ov_SC05_010_jr_8012ACE0.c b/src/ov_SC05_010/ov_SC05_010_jr_8012ACE0.c index 0483ffccc1..b77ece8fcd 100644 --- a/src/ov_SC05_010/ov_SC05_010_jr_8012ACE0.c +++ b/src/ov_SC05_010/ov_SC05_010_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_010/nonmatchings/ov_SC05_010_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_010/ov_SC05_010_jr_801734BC.c b/src/ov_SC05_010/ov_SC05_010_jr_801734BC.c index 50eaf3fdb0..b82da90bc0 100644 --- a/src/ov_SC05_010/ov_SC05_010_jr_801734BC.c +++ b/src/ov_SC05_010/ov_SC05_010_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_010/nonmatchings/ov_SC05_010_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_010/ov_SC05_010_jr_8017C8D0.c b/src/ov_SC05_010/ov_SC05_010_jr_8017C8D0.c index e5323c094b..12057efc50 100644 --- a/src/ov_SC05_010/ov_SC05_010_jr_8017C8D0.c +++ b/src/ov_SC05_010/ov_SC05_010_jr_8017C8D0.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3442,7 +3441,32 @@ void func_8017E9D4(void *a0) { } -INCLUDE_ASM("asm/ov_SC05_010/nonmatchings/ov_SC05_010_jr_8017C8D0", func_8017EA10); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017EA10; + +extern u16 func_80148800(s32 *a0); +extern void func_8017EAE4(s32 param_1, s16 *param_2); + +void func_8017EA10(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80192284[]; + extern Blk8_80126940_8017EA10 D_80126940; + Blk8_80126940_8017EA10 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80192284[t]; + } + sp10 = D_80126940; + func_8017EAE4(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC05_010/nonmatchings/ov_SC05_010_jr_8017C8D0", func_8017EAB0); diff --git a/src/ov_SC05_011/ov_SC05_011.c b/src/ov_SC05_011/ov_SC05_011.c index b1dc7bd13c..5c41f1b134 100644 --- a/src/ov_SC05_011/ov_SC05_011.c +++ b/src/ov_SC05_011/ov_SC05_011.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_011/nonmatchings/ov_SC05_011", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017DFC8[]; + s16 idx = D_8017DFC8[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019AB88, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_011/nonmatchings/ov_SC05_011", func_80128CFC); diff --git a/src/ov_SC05_011/ov_SC05_011_after.c b/src/ov_SC05_011/ov_SC05_011_after.c index 6741210aa2..a821ba6d81 100644 --- a/src/ov_SC05_011/ov_SC05_011_after.c +++ b/src/ov_SC05_011/ov_SC05_011_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_011/nonmatchings/ov_SC05_011_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_011/nonmatchings/ov_SC05_011_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_011/ov_SC05_011_jr_8012ACE0.c b/src/ov_SC05_011/ov_SC05_011_jr_8012ACE0.c index 325e73640a..b055714b4a 100644 --- a/src/ov_SC05_011/ov_SC05_011_jr_8012ACE0.c +++ b/src/ov_SC05_011/ov_SC05_011_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_011/nonmatchings/ov_SC05_011_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_011/ov_SC05_011_jr_801734BC.c b/src/ov_SC05_011/ov_SC05_011_jr_801734BC.c index 1fadfe4357..948b829b29 100644 --- a/src/ov_SC05_011/ov_SC05_011_jr_801734BC.c +++ b/src/ov_SC05_011/ov_SC05_011_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_011/nonmatchings/ov_SC05_011_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_011/ov_SC05_011_jr_8017BEBC.c b/src/ov_SC05_011/ov_SC05_011_jr_8017BEBC.c index 15638cce75..76fa08e5a3 100644 --- a/src/ov_SC05_011/ov_SC05_011_jr_8017BEBC.c +++ b/src/ov_SC05_011/ov_SC05_011_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3240,7 +3239,32 @@ void func_8017D010(void *a0) { } -INCLUDE_ASM("asm/ov_SC05_011/nonmatchings/ov_SC05_011_jr_8017BEBC", func_8017D04C); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D04C; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D0EC(s32 param_1, s16 *param_2); + +void func_8017D04C(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_8018177C[]; + extern Blk8_80126940_8017D04C D_80126940; + Blk8_80126940_8017D04C sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_8018177C[t]; + } + sp10 = D_80126940; + func_8017D0EC(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC05_011/nonmatchings/ov_SC05_011_jr_8017BEBC", func_8017D0EC); diff --git a/src/ov_SC05_017/ov_SC05_017.c b/src/ov_SC05_017/ov_SC05_017.c index 9ea54b702c..b3f704c241 100644 --- a/src/ov_SC05_017/ov_SC05_017.c +++ b/src/ov_SC05_017/ov_SC05_017.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_017/nonmatchings/ov_SC05_017", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018D488[]; + s16 idx = D_8018D488[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801EA270, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_017/nonmatchings/ov_SC05_017", func_80128CFC); diff --git a/src/ov_SC05_017/ov_SC05_017_after.c b/src/ov_SC05_017/ov_SC05_017_after.c index 5e8d59d86d..11134db9ae 100644 --- a/src/ov_SC05_017/ov_SC05_017_after.c +++ b/src/ov_SC05_017/ov_SC05_017_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_017/nonmatchings/ov_SC05_017_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_017/nonmatchings/ov_SC05_017_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_017/ov_SC05_017_jr_8012ACE0.c b/src/ov_SC05_017/ov_SC05_017_jr_8012ACE0.c index e9aee66f44..97cf780d0d 100644 --- a/src/ov_SC05_017/ov_SC05_017_jr_8012ACE0.c +++ b/src/ov_SC05_017/ov_SC05_017_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_017/nonmatchings/ov_SC05_017_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_017/ov_SC05_017_jr_801734BC.c b/src/ov_SC05_017/ov_SC05_017_jr_801734BC.c index 375ceacbc5..f61429ade9 100644 --- a/src/ov_SC05_017/ov_SC05_017_jr_801734BC.c +++ b/src/ov_SC05_017/ov_SC05_017_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_017/nonmatchings/ov_SC05_017_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_018/ov_SC05_018.c b/src/ov_SC05_018/ov_SC05_018.c index 55b53c3fe3..2ddff624a8 100644 --- a/src/ov_SC05_018/ov_SC05_018.c +++ b/src/ov_SC05_018/ov_SC05_018.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_018/nonmatchings/ov_SC05_018", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80186BE4[]; + s16 idx = D_80186BE4[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801E3DE4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_018/nonmatchings/ov_SC05_018", func_80128CFC); diff --git a/src/ov_SC05_018/ov_SC05_018_after.c b/src/ov_SC05_018/ov_SC05_018_after.c index baa18017f9..e847fcb410 100644 --- a/src/ov_SC05_018/ov_SC05_018_after.c +++ b/src/ov_SC05_018/ov_SC05_018_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_018/nonmatchings/ov_SC05_018_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_018/nonmatchings/ov_SC05_018_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_018/ov_SC05_018_jr_8012ACE0.c b/src/ov_SC05_018/ov_SC05_018_jr_8012ACE0.c index 3068b8081f..e1df7141bc 100644 --- a/src/ov_SC05_018/ov_SC05_018_jr_8012ACE0.c +++ b/src/ov_SC05_018/ov_SC05_018_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_018/nonmatchings/ov_SC05_018_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_018/ov_SC05_018_jr_801734BC.c b/src/ov_SC05_018/ov_SC05_018_jr_801734BC.c index 6c7fc97aea..36ac00b9c1 100644 --- a/src/ov_SC05_018/ov_SC05_018_jr_801734BC.c +++ b/src/ov_SC05_018/ov_SC05_018_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_018/nonmatchings/ov_SC05_018_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC05_019/ov_SC05_019.c b/src/ov_SC05_019/ov_SC05_019.c index 4f8c478800..7d1588f0b1 100644 --- a/src/ov_SC05_019/ov_SC05_019.c +++ b/src/ov_SC05_019/ov_SC05_019.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_019/nonmatchings/ov_SC05_019", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017F528[]; + s16 idx = D_8017F528[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8018D4F8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC05_019/nonmatchings/ov_SC05_019", func_80128CFC); diff --git a/src/ov_SC05_019/ov_SC05_019_after.c b/src/ov_SC05_019/ov_SC05_019_after.c index c2dd4a5cb5..446ed7b22a 100644 --- a/src/ov_SC05_019/ov_SC05_019_after.c +++ b/src/ov_SC05_019/ov_SC05_019_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC05_019/nonmatchings/ov_SC05_019_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_019/nonmatchings/ov_SC05_019_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC05_019/ov_SC05_019_jr_8012ACE0.c b/src/ov_SC05_019/ov_SC05_019_jr_8012ACE0.c index c33d484bf1..56d1e4c913 100644 --- a/src/ov_SC05_019/ov_SC05_019_jr_8012ACE0.c +++ b/src/ov_SC05_019/ov_SC05_019_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC05_019/nonmatchings/ov_SC05_019_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC05_019/ov_SC05_019_jr_801734BC.c b/src/ov_SC05_019/ov_SC05_019_jr_801734BC.c index 581abe7892..d42dcfaa09 100644 --- a/src/ov_SC05_019/ov_SC05_019_jr_801734BC.c +++ b/src/ov_SC05_019/ov_SC05_019_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC05_019/nonmatchings/ov_SC05_019_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_000/ov_SC06_000.c b/src/ov_SC06_000/ov_SC06_000.c index 671cc76aec..03e49ac38b 100644 --- a/src/ov_SC06_000/ov_SC06_000.c +++ b/src/ov_SC06_000/ov_SC06_000.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80188538[]; + s16 idx = D_80188538[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801AC170, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000", func_80128CFC); diff --git a/src/ov_SC06_000/ov_SC06_000_after.c b/src/ov_SC06_000/ov_SC06_000_after.c index f017593a2f..4cf8247c74 100644 --- a/src/ov_SC06_000/ov_SC06_000_after.c +++ b/src/ov_SC06_000/ov_SC06_000_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_000/ov_SC06_000_jr_8012ACE0.c b/src/ov_SC06_000/ov_SC06_000_jr_8012ACE0.c index 4e8442c0e6..203b555314 100644 --- a/src/ov_SC06_000/ov_SC06_000_jr_8012ACE0.c +++ b/src/ov_SC06_000/ov_SC06_000_jr_8012ACE0.c @@ -329,7 +329,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_000/ov_SC06_000_jr_801734BC.c b/src/ov_SC06_000/ov_SC06_000_jr_801734BC.c index a829c5ea0d..d0a666153e 100644 --- a/src/ov_SC06_000/ov_SC06_000_jr_801734BC.c +++ b/src/ov_SC06_000/ov_SC06_000_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c b/src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c index b4e6f5ce76..7c92f46d0c 100644 --- a/src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c +++ b/src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c @@ -3467,7 +3467,67 @@ INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_8017D80 INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_8017D890); -INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_8017D900); + +/* func_8017D900 — fade the 4-byte colour quad at D_801AE668 one step toward 0 + * (func_80012F74 = "step a value toward a target"), splat the byte over the + * three sibling bytes, mirror the whole quad into the three following quads, + * then tear the entity down once the byte reaches 0. + * + * §71 sibling-first: DEFINE_func_801685EC() (engine_core.h L8520) is the same + * `if ( == 0) ((void (*)(s32))func_80146C3C)(arg0);` teardown tail. + * In-TU sibling func_8017D678 shows D_801AE669/D_801AE66A are SEPARATE u8 + * globals (each gets its own lui/%lo sb) while D_801AE668's address lives in a + * callee-saved register. + * + * @class: schedule (LENGTH-DRIFT/-1) + * @stuck: none — MATCH 50/50 (match_one AND rtu_match), iteration 2. + * THE CRACK (one edit): the TRAILING reload `if (*p == 0)` was being hoisted by + * sched2 up past the third block move, where the swl/swr pair covered its load + * delay — costing exactly the one `nop` the target keeps (49 vs 50 ins, + * LENGTH-DRIFT/-1). A second zero-byte `__asm__("")` fence between the last + * struct assignment and the `if` pins the lbu after the copies and the load-delay + * nop reappears. Lesson: an inline block move (swl/swr) is a fat delay-slot + * SPONGE — any following narrow load will be sucked up into it unless fenced. + * The first fence (after the chained byte stores) is what keeps the block moves + * from being interleaved with them. + * Other levers already in this draft, all load-bearing: + * - `u8 *p = &D_801AE668;` (§20) — one address register ($s0, callee-saved + * across the jal) serves the lbu, the sb and all three block-move sources. + * - chained assignment `D_801AE669 = D_801AE66A = *p = f(...)` gives the + * target's store order 880, 882, 881 (right-to-left after the *p store). + * - the 4×u8 struct (align 1) is what makes the assignment expand to inline + * lwl/lwr + swl/swr instead of a `jal memcpy` (cf. §38). + */ + +typedef struct { + u8 b0, b1, b2, b3; +} Quad_801EA880_8017D900; /* align 1 => movstrsi expands to lwl/lwr + swl/swr */ + + +extern s32 func_80012F74(s32 a0, s32 a1, s32 a2, s32 a3); +extern void func_80146C3C(void); + +void func_8017D900(s32 arg0) { + + extern u8 D_801AE668; + extern u8 D_801AE669; + extern u8 D_801AE66A; + extern u8 D_801AE66C; + extern u8 D_801AE670; + extern u8 D_801AE674; + u8 *p = &D_801AE668; + + D_801AE669 = D_801AE66A = *p = func_80012F74(*p, 0, 10, 1); + __asm__(""); + *(Quad_801EA880_8017D900 *)&D_801AE66C = *(Quad_801EA880_8017D900 *)p; + *(Quad_801EA880_8017D900 *)&D_801AE670 = *(Quad_801EA880_8017D900 *)p; + *(Quad_801EA880_8017D900 *)&D_801AE674 = *(Quad_801EA880_8017D900 *)p; + __asm__(""); + if (*p == 0) { + ((void (*)(s32))func_80146C3C)(arg0); + } +} + INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_8017D9C8); @@ -4233,7 +4293,47 @@ void func_8017FF54(int param_1) } -INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_8017FFB0); + +/* Entity record touched by func_8017FFB0 (offsets read straight off the asm): + * 0x02 u16 frame/state counter (lhu / sh) + * 0x1C s32 tick counter (lw / sw), signed compare against 0x20 + * 0x2A u16 y-ish delta, decremented by 0x10 (lhu / sh) + * 0x2C u16 sound id passed to func_80147324 (lhu) + * 0x30 s32 suppress flag + */ +typedef struct Ent_8017BFE0_8017FFB0 { + u8 pad00[2]; /* 0x00 */ + u16 f02; /* 0x02 */ + u8 pad04[0x18];/* 0x04 */ + s32 f1c; /* 0x1C */ + u8 pad20[0xA]; /* 0x20 */ + u16 f2a; /* 0x2A */ + u16 f2c; /* 0x2C */ + u8 pad2e[2]; /* 0x2E */ + s32 f30; /* 0x30 */ +} Ent_8017BFE0_8017FFB0; + +extern void func_80147324(s32 arg0); +extern void func_801801E8(int); + +void func_8017FFB0(Ent_8017BFE0_8017FFB0 *param_1) +{ + s32 t; + + t = param_1->f1c; + param_1->f1c = t + 1; + if (t < 0x20) { + param_1->f2a = param_1->f2a - 0x10; + } else { + if (param_1->f30 == 0) { + func_80147324(param_1->f2c); + } + param_1->f1c = 0; + param_1->f02 = param_1->f02 + 1; + } + ((void (*)(Ent_8017BFE0_8017FFB0 *))func_801801E8)(param_1); +} + INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_80180034); @@ -4399,7 +4499,72 @@ void func_80180794(void *a0) { } -INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_801807D0); + +/* func_801807D0 — spawn/scatter tick for the +0x34 sub-object (state word @0x2). + * MATCH (45 ins), match_one + rtu_match. Four levers, in the order they were found: + * + * 1. §71 sibling-first — same entity shape as func_8017C610 / func_8017C69C in this + * TU: sub-object pointer @0x34 read BEFORE the call (it lives in $s1 across the + * jal), state word @0x2 bumped last. §3-T4: `beqz $v1,else` => `if (p->f2C) {..}`. + * ONE rand() feeds three fields; the raw low 6 bits use a bare `andi` (no extend) + * while the >>12 / >>6 uses share one `sll $x,16` — that shared sign-extend is + * what forces `r` to be a `short` local rather than an int. + * + * 2. §5a CROSS-JUMP — both arms end in `sh ?,0xA($s0)`; gcc tail-merged them (23 off). + * They only stay separate because the loaded halfword lands in a DIFFERENT hard + * reg per arm, which needs (a) the load to be its own statement at the TOP of each + * arm and (b) a SEPARATE temp per arm (t / t2) — one shared temp is one pseudo, + * gets one register in both arms, and re-merges. 23 -> 10 -> 6. + * + * 3. +0x16 is SIGNED: the target materialises -0x20 as `addiu $v0,$zero,-0x20`, not + * `ori 0xffe0`, so that store must go through an s16. + * + * 4. §49 BIRTHING BOOST (the last 6 -> 2 -> 0). Residual was two ALU insns swapped + * with identical registers; source statement order does NOT flip it, because + * sched1's `adjust_priority`/`birthing_insn_p` hands every SET(REG,..) whose dest + * has REG_N_SETS==1 a 0x7f000001 priority, so it sinks to just before its consumer + * and fixes the .greg LUID order that sched2's tie-break then reads. + * THE DIAL: give the offending insn's dest a SECOND set so it loses the boost — + * here one `u16 d` reused by both tail statements. It must be a THIRD temp, not + * `c` itself: writing `c = c + 1;` also un-boosts c's LOAD, which then starves to + * the front of the block and swaps the two `lhu`s instead. Boost the loads, starve + * the arithmetic. */ + +extern int rand(void); + +void func_801807D0(void *a0) +{ + s32 p; + s32 obj; + short r; + u16 t; + u16 t2; + u16 e; + u16 c; + u16 d; + + p = (s32)a0; + obj = *(s32 *)(p + 0x34); + r = rand(); + *(u16 *)(p + 0x06) = *(u16 *)(obj + 0x06) + ((r & 0x3F) - 0x20); + if (*(s32 *)(p + 0x2C) != 0) { + t = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = 0x20; + *(u16 *)(p + 0x0A) = t - 0x140; + } else { + t2 = *(u16 *)(obj + 0x0A); + *(s16 *)(p + 0x16) = -0x20; + *(u16 *)(p + 0x0A) = t2; + } + e = *(u16 *)(obj + 0x0E); + c = *(u16 *)(p + 0x02); + *(s32 *)(p + 0x30) = (r >> 12) & 3; + d = ((r >> 6) & 0x3F) - 0x20; + *(u16 *)(p + 0x0E) = e + d; + d = c + 1; + *(u16 *)(p + 0x02) = d; +} + extern void func_800D22E4(s32 a0); extern void func_80146C3C(void); @@ -5387,7 +5552,53 @@ void func_80186758(void) { } -INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_8018677C); + +/* func_8018677C — cookbook §71 (sibling-first). + * func_8018681C is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_8018681C(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_80186938 (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_8018677C; + +extern void func_8018681C(s32 arg0, s32 arg1, s32 arg2); +extern void func_80186938(s32 arg0, Rec_8018A6A4_8018677C *arg1, s32 arg2, s32 arg3); + +void func_8018677C(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_8018677C sp10; + s32 i; + s32 ang; + + func_8018681C(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_80186938(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + extern s16 D_801B1EF4; @@ -5420,7 +5631,57 @@ INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_80186A0 INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_80186A48); -INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_80186A94); + +/* func_80186A94 — 16-entry table walk, stride 0xE, over D_801B1EFC. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801B1EFC; s16 *p = &D_801B1EFC; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_80186B70(s32 arg0); + +void func_80186A94(void) { + + extern s16 D_801B1EFC; + s16 *p = &D_801B1EFC; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_80186B70(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_80186B70); @@ -5483,7 +5744,67 @@ INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_8018775 INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_80187798); -INCLUDE_ASM("asm/ov_SC06_000/nonmatchings/ov_SC06_000_jr_8017AE2C", func_801878A8); + +extern void func_8001D074(s32 a0, s32 a1); +extern void func_8001CD04(s32 a0, s32 a1); + +typedef struct Obj_8018A550_801878A8 { + s32 f0; /* 0x00 */ + u32 f4; /* 0x04 */ + s32 f8; /* 0x08 */ + s32 fC; /* 0x0C */ + s32 f10; /* 0x10 */ + s32 f14; /* 0x14 */ + s16 f18; /* 0x18 */ + s16 f1A; /* 0x1A */ + s16 f1C; /* 0x1C */ + s16 f1E; /* 0x1E */ +} Obj_8018A550_801878A8; + +typedef struct Rec_8018A550_801878A8 { + u16 f0; /* 0x00 */ + u16 f2; /* 0x02 */ + s16 f4; /* 0x04 */ + s16 f6; /* 0x06 */ + s32 f8; /* 0x08 */ + s32 fC; /* 0x0C */ +} Rec_8018A550_801878A8; + +typedef struct Ctl_8018A550_801878A8 { + s32 f0; /* 0x00 */ + s16 ids[8]; /* 0x04 */ + Obj_8018A550_801878A8 *slots[8]; /* 0x14 */ +} Ctl_8018A550_801878A8; + +void func_801878A8(Ctl_8018A550_801878A8 *ctl, Rec_8018A550_801878A8 *rec) +{ + s32 i; + Obj_8018A550_801878A8 *m; + s16 v; + u16 t; + + do { + for (i = 0; i < 8; i++) { + if (ctl->slots[i] == 0) { + break; + } + } + m = (Obj_8018A550_801878A8 *)((s32 (*)(s32, s32))func_8001D074)(0x7E, 0x100); + if (m != 0) { + ((void (*)(Obj_8018A550_801878A8 *, s32))func_8001CD04)(m, rec->fC); + m->f4 |= 0xF0000000; + v = rec->f6; + m->f1C = v; + m->f1A = v; + m->f18 = v; + ctl->slots[i] = m; + ctl->ids[i] = rec->f4; + } + t = rec->f0; + rec++; + } while (t != 0xFF); +} + diff --git a/src/ov_SC06_006/ov_SC06_006.c b/src/ov_SC06_006/ov_SC06_006.c index c60ca08955..5eb55086e4 100644 --- a/src/ov_SC06_006/ov_SC06_006.c +++ b/src/ov_SC06_006/ov_SC06_006.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_006/nonmatchings/ov_SC06_006", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018205C[]; + s16 idx = D_8018205C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801F5A78, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_006/nonmatchings/ov_SC06_006", func_80128CFC); diff --git a/src/ov_SC06_006/ov_SC06_006_after.c b/src/ov_SC06_006/ov_SC06_006_after.c index c0d727a83e..6738e1a9bc 100644 --- a/src/ov_SC06_006/ov_SC06_006_after.c +++ b/src/ov_SC06_006/ov_SC06_006_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_006/nonmatchings/ov_SC06_006_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_006/nonmatchings/ov_SC06_006_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_006/ov_SC06_006_jr_8012ACE0.c b/src/ov_SC06_006/ov_SC06_006_jr_8012ACE0.c index cb6a8c6f80..39f74fb798 100644 --- a/src/ov_SC06_006/ov_SC06_006_jr_8012ACE0.c +++ b/src/ov_SC06_006/ov_SC06_006_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_006/nonmatchings/ov_SC06_006_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_006/ov_SC06_006_jr_801734BC.c b/src/ov_SC06_006/ov_SC06_006_jr_801734BC.c index 20460cd8d9..b6c941a245 100644 --- a/src/ov_SC06_006/ov_SC06_006_jr_801734BC.c +++ b/src/ov_SC06_006/ov_SC06_006_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_006/nonmatchings/ov_SC06_006_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_006/ov_SC06_006_jr_8017BEBC.c b/src/ov_SC06_006/ov_SC06_006_jr_8017BEBC.c index 92fe66f3ed..5e6ec96edd 100644 --- a/src/ov_SC06_006/ov_SC06_006_jr_8017BEBC.c +++ b/src/ov_SC06_006/ov_SC06_006_jr_8017BEBC.c @@ -3260,7 +3260,32 @@ void func_8017D19C(void *a0) { } -INCLUDE_ASM("asm/ov_SC06_006/nonmatchings/ov_SC06_006_jr_8017BEBC", func_8017D1D8); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D1D8; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D278(s32 param_1, s16 *param_2); + +void func_8017D1D8(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80185814[]; + extern Blk8_80126940_8017D1D8 D_80126940; + Blk8_80126940_8017D1D8 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80185814[t]; + } + sp10 = D_80126940; + func_8017D278(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC06_006/nonmatchings/ov_SC06_006_jr_8017BEBC", func_8017D278); diff --git a/src/ov_SC06_008/ov_SC06_008.c b/src/ov_SC06_008/ov_SC06_008.c index 6aad7d6a3f..e4ba80f40f 100644 --- a/src/ov_SC06_008/ov_SC06_008.c +++ b/src/ov_SC06_008/ov_SC06_008.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80185AC4[]; + s16 idx = D_80185AC4[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A7B50, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008", func_80128CFC); diff --git a/src/ov_SC06_008/ov_SC06_008_after.c b/src/ov_SC06_008/ov_SC06_008_after.c index c507f5fb88..61c879d34a 100644 --- a/src/ov_SC06_008/ov_SC06_008_after.c +++ b/src/ov_SC06_008/ov_SC06_008_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_008/ov_SC06_008_jr_8012ACE0.c b/src/ov_SC06_008/ov_SC06_008_jr_8012ACE0.c index a0f32237d4..a12a956506 100644 --- a/src/ov_SC06_008/ov_SC06_008_jr_8012ACE0.c +++ b/src/ov_SC06_008/ov_SC06_008_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_008/ov_SC06_008_jr_801734BC.c b/src/ov_SC06_008/ov_SC06_008_jr_801734BC.c index b80269d10c..bc25288140 100644 --- a/src/ov_SC06_008/ov_SC06_008_jr_801734BC.c +++ b/src/ov_SC06_008/ov_SC06_008_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_010/ov_SC06_010.c b/src/ov_SC06_010/ov_SC06_010.c index 6e3e829c59..0ce33e1a3f 100644 --- a/src/ov_SC06_010/ov_SC06_010.c +++ b/src/ov_SC06_010/ov_SC06_010.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_010/nonmatchings/ov_SC06_010", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80186CA0[]; + s16 idx = D_80186CA0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801AFBA4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_010/nonmatchings/ov_SC06_010", func_80128CFC); diff --git a/src/ov_SC06_010/ov_SC06_010_after.c b/src/ov_SC06_010/ov_SC06_010_after.c index c415c4fd47..a878fb1da0 100644 --- a/src/ov_SC06_010/ov_SC06_010_after.c +++ b/src/ov_SC06_010/ov_SC06_010_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_010/nonmatchings/ov_SC06_010_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_010/nonmatchings/ov_SC06_010_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_010/ov_SC06_010_jr_8012ACE0.c b/src/ov_SC06_010/ov_SC06_010_jr_8012ACE0.c index 40ac9d8d55..99a5fd4470 100644 --- a/src/ov_SC06_010/ov_SC06_010_jr_8012ACE0.c +++ b/src/ov_SC06_010/ov_SC06_010_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_010/nonmatchings/ov_SC06_010_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_010/ov_SC06_010_jr_801734BC.c b/src/ov_SC06_010/ov_SC06_010_jr_801734BC.c index d03e72d412..d6c51ca90c 100644 --- a/src/ov_SC06_010/ov_SC06_010_jr_801734BC.c +++ b/src/ov_SC06_010/ov_SC06_010_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_010/nonmatchings/ov_SC06_010_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_011/ov_SC06_011.c b/src/ov_SC06_011/ov_SC06_011.c index 4a281f592b..2f820d91a3 100644 --- a/src/ov_SC06_011/ov_SC06_011.c +++ b/src/ov_SC06_011/ov_SC06_011.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80180700[]; + s16 idx = D_80180700[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A9704, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011", func_80128CFC); diff --git a/src/ov_SC06_011/ov_SC06_011_after.c b/src/ov_SC06_011/ov_SC06_011_after.c index 5112a7f542..b710bba798 100644 --- a/src/ov_SC06_011/ov_SC06_011_after.c +++ b/src/ov_SC06_011/ov_SC06_011_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_011/ov_SC06_011_jr_8012ACE0.c b/src/ov_SC06_011/ov_SC06_011_jr_8012ACE0.c index 7f0da6d12c..30f567c69a 100644 --- a/src/ov_SC06_011/ov_SC06_011_jr_8012ACE0.c +++ b/src/ov_SC06_011/ov_SC06_011_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_011/ov_SC06_011_jr_801734BC.c b/src/ov_SC06_011/ov_SC06_011_jr_801734BC.c index f41da06294..ca31d2a5ba 100644 --- a/src/ov_SC06_011/ov_SC06_011_jr_801734BC.c +++ b/src/ov_SC06_011/ov_SC06_011_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_011/ov_SC06_011_jr_8017BEBC.c b/src/ov_SC06_011/ov_SC06_011_jr_8017BEBC.c index 5bae96f4a1..bfbbeb8989 100644 --- a/src/ov_SC06_011/ov_SC06_011_jr_8017BEBC.c +++ b/src/ov_SC06_011/ov_SC06_011_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3289,15 +3288,140 @@ void func_8017D594(void *a0) { } -INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011_jr_8017BEBC", func_8017D5D0); -INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011_jr_8017BEBC", func_8017D670); +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D5D0; -INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011_jr_8017BEBC", func_8017D710); +extern u16 func_80148800(s32 *a0); +extern void func_8017D8F0(s32 param_1, s16 *param_2); -INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011_jr_8017BEBC", func_8017D7B0); +void func_8017D5D0(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80184104[]; + extern Blk8_80126940_8017D5D0 D_80126940; + Blk8_80126940_8017D5D0 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80184104[t]; + } + sp10 = D_80126940; + func_8017D8F0(a0, sp10.v); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D670; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D8F0(s32 param_1, s16 *param_2); + +void func_8017D670(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80184108[]; + extern Blk8_80126940_8017D670 D_80126940; + Blk8_80126940_8017D670 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80184108[t]; + } + sp10 = D_80126940; + func_8017D8F0(a0, sp10.v); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D710; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D8F0(s32 param_1, s16 *param_2); + +void func_8017D710(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_8018410C[]; + extern Blk8_80126940_8017D710 D_80126940; + Blk8_80126940_8017D710 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_8018410C[t]; + } + sp10 = D_80126940; + func_8017D8F0(a0, sp10.v); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D7B0; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D8F0(s32 param_1, s16 *param_2); + +void func_8017D7B0(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80184110[]; + extern Blk8_80126940_8017D7B0 D_80126940; + Blk8_80126940_8017D7B0 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80184110[t]; + } + sp10 = D_80126940; + func_8017D8F0(a0, sp10.v); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D850; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D8F0(s32 param_1, s16 *param_2); + +void func_8017D850(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80184114[]; + extern Blk8_80126940_8017D850 D_80126940; + Blk8_80126940_8017D850 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80184114[t]; + } + sp10 = D_80126940; + func_8017D8F0(a0, sp10.v); +} -INCLUDE_ASM("asm/ov_SC06_011/nonmatchings/ov_SC06_011_jr_8017BEBC", func_8017D850); // @class: schedule diff --git a/src/ov_SC06_013/ov_SC06_013.c b/src/ov_SC06_013/ov_SC06_013.c index 69d8a1e345..5735450974 100644 --- a/src/ov_SC06_013/ov_SC06_013.c +++ b/src/ov_SC06_013/ov_SC06_013.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_013/nonmatchings/ov_SC06_013", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017EE7C[]; + s16 idx = D_8017EE7C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801985D8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_013/nonmatchings/ov_SC06_013", func_80128CFC); diff --git a/src/ov_SC06_013/ov_SC06_013_after.c b/src/ov_SC06_013/ov_SC06_013_after.c index dbf252ac56..dae47c91fa 100644 --- a/src/ov_SC06_013/ov_SC06_013_after.c +++ b/src/ov_SC06_013/ov_SC06_013_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_013/nonmatchings/ov_SC06_013_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_013/nonmatchings/ov_SC06_013_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_013/ov_SC06_013_jr_8012ACE0.c b/src/ov_SC06_013/ov_SC06_013_jr_8012ACE0.c index e18a948adf..9811631f1f 100644 --- a/src/ov_SC06_013/ov_SC06_013_jr_8012ACE0.c +++ b/src/ov_SC06_013/ov_SC06_013_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_013/nonmatchings/ov_SC06_013_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_013/ov_SC06_013_jr_801734BC.c b/src/ov_SC06_013/ov_SC06_013_jr_801734BC.c index 9795d881d3..92794191d6 100644 --- a/src/ov_SC06_013/ov_SC06_013_jr_801734BC.c +++ b/src/ov_SC06_013/ov_SC06_013_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_013/nonmatchings/ov_SC06_013_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_013/ov_SC06_013_jr_8017BEBC.c b/src/ov_SC06_013/ov_SC06_013_jr_8017BEBC.c index 7908dc4f64..0c67c9f386 100644 --- a/src/ov_SC06_013/ov_SC06_013_jr_8017BEBC.c +++ b/src/ov_SC06_013/ov_SC06_013_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3259,9 +3258,59 @@ void func_8017D220(void *a0) { } -INCLUDE_ASM("asm/ov_SC06_013/nonmatchings/ov_SC06_013_jr_8017BEBC", func_8017D25C); -INCLUDE_ASM("asm/ov_SC06_013/nonmatchings/ov_SC06_013_jr_8017BEBC", func_8017D2FC); +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D25C; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D39C(s32 param_1, s16 *param_2); + +void func_8017D25C(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_801826E4[]; + extern Blk8_80126940_8017D25C D_80126940; + Blk8_80126940_8017D25C sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_801826E4[t]; + } + sp10 = D_80126940; + func_8017D39C(a0, sp10.v); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D2FC; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D39C(s32 param_1, s16 *param_2); + +void func_8017D2FC(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_801826E8[]; + extern Blk8_80126940_8017D2FC D_80126940; + Blk8_80126940_8017D2FC sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_801826E8[t]; + } + sp10 = D_80126940; + func_8017D39C(a0, sp10.v); +} + // @class: schedule diff --git a/src/ov_SC06_014/ov_SC06_014.c b/src/ov_SC06_014/ov_SC06_014.c index f78fce9bc2..dd24e93fbb 100644 --- a/src/ov_SC06_014/ov_SC06_014.c +++ b/src/ov_SC06_014/ov_SC06_014.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_014/nonmatchings/ov_SC06_014", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801801E0[]; + s16 idx = D_801801E0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019EFC8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_014/nonmatchings/ov_SC06_014", func_80128CFC); diff --git a/src/ov_SC06_014/ov_SC06_014_after.c b/src/ov_SC06_014/ov_SC06_014_after.c index 09ba9ecc55..11ffc37b7a 100644 --- a/src/ov_SC06_014/ov_SC06_014_after.c +++ b/src/ov_SC06_014/ov_SC06_014_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_014/nonmatchings/ov_SC06_014_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_014/nonmatchings/ov_SC06_014_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_014/ov_SC06_014_jr_8012ACE0.c b/src/ov_SC06_014/ov_SC06_014_jr_8012ACE0.c index 15758ece2e..791bf7bbc2 100644 --- a/src/ov_SC06_014/ov_SC06_014_jr_8012ACE0.c +++ b/src/ov_SC06_014/ov_SC06_014_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_014/nonmatchings/ov_SC06_014_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_014/ov_SC06_014_jr_801734BC.c b/src/ov_SC06_014/ov_SC06_014_jr_801734BC.c index 027fe6f00b..0ba8267f88 100644 --- a/src/ov_SC06_014/ov_SC06_014_jr_801734BC.c +++ b/src/ov_SC06_014/ov_SC06_014_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_014/nonmatchings/ov_SC06_014_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_014/ov_SC06_014_jr_8017BEBC.c b/src/ov_SC06_014/ov_SC06_014_jr_8017BEBC.c index a00727f466..b363238dfd 100644 --- a/src/ov_SC06_014/ov_SC06_014_jr_8017BEBC.c +++ b/src/ov_SC06_014/ov_SC06_014_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3414,9 +3413,59 @@ void func_8017D5F8(void *a0) { } -INCLUDE_ASM("asm/ov_SC06_014/nonmatchings/ov_SC06_014_jr_8017BEBC", func_8017D634); -INCLUDE_ASM("asm/ov_SC06_014/nonmatchings/ov_SC06_014_jr_8017BEBC", func_8017D6D4); +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D634; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D774(s32 param_1, s16 *param_2); + +void func_8017D634(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80183AC0[]; + extern Blk8_80126940_8017D634 D_80126940; + Blk8_80126940_8017D634 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80183AC0[t]; + } + sp10 = D_80126940; + func_8017D774(a0, sp10.v); +} + + + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D6D4; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D774(s32 param_1, s16 *param_2); + +void func_8017D6D4(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80183AC4[]; + extern Blk8_80126940_8017D6D4 D_80126940; + Blk8_80126940_8017D6D4 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80183AC4[t]; + } + sp10 = D_80126940; + func_8017D774(a0, sp10.v); +} + // @class: schedule diff --git a/src/ov_SC06_015/ov_SC06_015.c b/src/ov_SC06_015/ov_SC06_015.c index 06ac4a2fbf..4012007ade 100644 --- a/src/ov_SC06_015/ov_SC06_015.c +++ b/src/ov_SC06_015/ov_SC06_015.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_015/nonmatchings/ov_SC06_015", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017ED38[]; + s16 idx = D_8017ED38[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801923A8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_015/nonmatchings/ov_SC06_015", func_80128CFC); diff --git a/src/ov_SC06_015/ov_SC06_015_after.c b/src/ov_SC06_015/ov_SC06_015_after.c index d3f07c9c0b..055969c03c 100644 --- a/src/ov_SC06_015/ov_SC06_015_after.c +++ b/src/ov_SC06_015/ov_SC06_015_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_015/nonmatchings/ov_SC06_015_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_015/nonmatchings/ov_SC06_015_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_015/ov_SC06_015_jr_8012ACE0.c b/src/ov_SC06_015/ov_SC06_015_jr_8012ACE0.c index 76cc4c2924..0c8e786b5a 100644 --- a/src/ov_SC06_015/ov_SC06_015_jr_8012ACE0.c +++ b/src/ov_SC06_015/ov_SC06_015_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_015/nonmatchings/ov_SC06_015_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_015/ov_SC06_015_jr_801734BC.c b/src/ov_SC06_015/ov_SC06_015_jr_801734BC.c index 6c2f607dee..6c074c414d 100644 --- a/src/ov_SC06_015/ov_SC06_015_jr_801734BC.c +++ b/src/ov_SC06_015/ov_SC06_015_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_015/nonmatchings/ov_SC06_015_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_015/ov_SC06_015_jr_8017BEBC.c b/src/ov_SC06_015/ov_SC06_015_jr_8017BEBC.c index 585f5f5458..693e6dd81f 100644 --- a/src/ov_SC06_015/ov_SC06_015_jr_8017BEBC.c +++ b/src/ov_SC06_015/ov_SC06_015_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3418,7 +3417,32 @@ void func_8017D554(void *a0) { } -INCLUDE_ASM("asm/ov_SC06_015/nonmatchings/ov_SC06_015_jr_8017BEBC", func_8017D590); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D590; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D630(s32 param_1, s16 *param_2); + +void func_8017D590(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80182574[]; + extern Blk8_80126940_8017D590 D_80126940; + Blk8_80126940_8017D590 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80182574[t]; + } + sp10 = D_80126940; + func_8017D630(a0, sp10.v); +} + // @class: schedule diff --git a/src/ov_SC06_016/ov_SC06_016.c b/src/ov_SC06_016/ov_SC06_016.c index 0a7465acdc..49c54f585a 100644 --- a/src/ov_SC06_016/ov_SC06_016.c +++ b/src/ov_SC06_016/ov_SC06_016.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80185148[]; + s16 idx = D_80185148[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019CFF0, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016", func_80128CFC); diff --git a/src/ov_SC06_016/ov_SC06_016_after.c b/src/ov_SC06_016/ov_SC06_016_after.c index 7f86b513de..6ace827049 100644 --- a/src/ov_SC06_016/ov_SC06_016_after.c +++ b/src/ov_SC06_016/ov_SC06_016_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_016/ov_SC06_016_jr_8012ACE0.c b/src/ov_SC06_016/ov_SC06_016_jr_8012ACE0.c index ec6dea231d..db7580be0b 100644 --- a/src/ov_SC06_016/ov_SC06_016_jr_8012ACE0.c +++ b/src/ov_SC06_016/ov_SC06_016_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_016/ov_SC06_016_jr_801734BC.c b/src/ov_SC06_016/ov_SC06_016_jr_801734BC.c index b2546e280d..c4d762a992 100644 --- a/src/ov_SC06_016/ov_SC06_016_jr_801734BC.c +++ b/src/ov_SC06_016/ov_SC06_016_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_016/ov_SC06_016_jr_8017C8D0.c b/src/ov_SC06_016/ov_SC06_016_jr_8017C8D0.c index b0c5811682..d42b0c4721 100644 --- a/src/ov_SC06_016/ov_SC06_016_jr_8017C8D0.c +++ b/src/ov_SC06_016/ov_SC06_016_jr_8017C8D0.c @@ -3513,7 +3513,52 @@ INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_jr_8017C8D0", func_8018089 INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_jr_8017C8D0", func_80180BF0); -INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_jr_8017C8D0", func_80180D24); + +/* func_80180D24 — ov_SC04_011 (split ov_SC04_011_jr_8017D494), 49 ins, MATCH. + * + * Two byte-load-bearing levers (both cookbook-indexed): + * 1. PARAM WIDTH (§43/§3-T3): arg3 must be a PROTOTYPED `s16`. An `s32` param with an + * explicit `(s16)` cast at the use site gives the same sll/sra but LOSES the + * `addu $s1,$s2,$zero` copy that the target fills the func_80135888 delay slot with + * (48 ins vs 49). The declared-narrow param makes gcc keep the incoming SImode arg + * ($s2, sign-extended at the int use) AND a separate HImode variable pseudo ($s1, + * stored with `sh`) — two live pseudos, hence the copy. + * 2. RET-0 PLACEMENT (§3-T4 / the shared-ret0 note): `if (c != 0) { body; return 1; } + * return 0;` puts the return-0 block FIRST (bnez-to-body + `j` epilogue with + * `move v0,zero` in the delay slot). The early-return form `if (c == 0) return 0; + * body; return 1;` is NOT equivalent here — gcc sinks the ret-0 block to the tail and + * emits `beqz` instead. Byte-measured: `== 0` early-return = 13 mismatches, `!= 0` + * with a trailing `return 0` = MATCH. (`goto ret0;` + trailing `ret0: return 0;` + * also matches.) + */ + +typedef struct { u16 x, y, z, w; } Pt_80187940_80180D24; /* 8-byte out-param scratch */ + +extern void func_8012F14C(s32); /* TU-canonical decl; called through a cast (fleet house style) */ +extern void func_8012F568(); +extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3); + +s32 func_80180D24(s32 arg0, s32 arg1, s32 arg2, s16 arg3) +{ + + extern s32 *D_80126B78; + extern s32 *D_80126B90; + extern s16 D_80126B9A; + extern u8 D_801152A8[]; + Pt_80187940_80180D24 a; + Pt_80187940_80180D24 b; + + ((void (*)(s32, s32, void *))func_8012F14C)(*(s32 *)(arg0 + 0x20) + 0x54, arg1, &a); + ((void (*)(s32, s32, void *))func_8012F14C)(*(s32 *)(arg0 + 0x20) + 0x54, arg2, &b); + + if (func_80135888((s32)D_80126B78, (s32)D_80126B90, (s32)&a, (s32)&b) != 0) { + func_8012F568(1, 0x4201, arg3, 0x5a, &b, D_801152A8); + D_80126B9A = arg3; + return 1; + } + return 0; +} + extern void (*D_801890B4[])(void); @@ -3814,7 +3859,53 @@ void func_80183D5C(void) { } -INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_jr_8017C8D0", func_80183D80); + +/* func_80183D80 — cookbook §71 (sibling-first). + * func_80183E20 is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_80183E20(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_80183F3C (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_80183D80; + +extern void func_80183E20(s32 arg0, s32 arg1, s32 arg2); +extern void func_80183F3C(s32 arg0, Rec_8018A6A4_80183D80 *arg1, s32 arg2, s32 arg3); + +void func_80183D80(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_80183D80 sp10; + s32 i; + s32 ang; + + func_80183E20(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_80183F3C(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + extern s16 D_801A0014; @@ -3845,7 +3936,57 @@ INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_jr_8017C8D0", func_8018401 INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_jr_8017C8D0", func_8018404C); -INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_jr_8017C8D0", func_80184098); + +/* func_80184098 — 16-entry table walk, stride 0xE, over D_801A001C. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801A001C; s16 *p = &D_801A001C; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_80184174(s32 arg0); + +void func_80184098(void) { + + extern s16 D_801A001C; + s16 *p = &D_801A001C; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_80184174(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC06_016/nonmatchings/ov_SC06_016_jr_8017C8D0", func_80184174); diff --git a/src/ov_SC06_018/ov_SC06_018.c b/src/ov_SC06_018/ov_SC06_018.c index 136df1c6f8..3ebcfe448a 100644 --- a/src/ov_SC06_018/ov_SC06_018.c +++ b/src/ov_SC06_018/ov_SC06_018.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80193884[]; + s16 idx = D_80193884[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801D2880, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018", func_80128CFC); diff --git a/src/ov_SC06_018/ov_SC06_018_after.c b/src/ov_SC06_018/ov_SC06_018_after.c index f1b4715830..6912e073f6 100644 --- a/src/ov_SC06_018/ov_SC06_018_after.c +++ b/src/ov_SC06_018/ov_SC06_018_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_018/ov_SC06_018_jr_8012ACE0.c b/src/ov_SC06_018/ov_SC06_018_jr_8012ACE0.c index d481aebb50..4122c237b7 100644 --- a/src/ov_SC06_018/ov_SC06_018_jr_8012ACE0.c +++ b/src/ov_SC06_018/ov_SC06_018_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_018/ov_SC06_018_jr_801734BC.c b/src/ov_SC06_018/ov_SC06_018_jr_801734BC.c index 57c779f2ba..61dccd7e64 100644 --- a/src/ov_SC06_018/ov_SC06_018_jr_801734BC.c +++ b/src/ov_SC06_018/ov_SC06_018_jr_801734BC.c @@ -3232,7 +3232,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c b/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c index 17393bb320..bbf8b576b8 100644 --- a/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c +++ b/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c @@ -5506,7 +5506,55 @@ INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_8018BC4 INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_8018BCC4); -INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_8018BFA8); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8018BFA8; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0x4 are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8018BFA8(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8018BFA8 t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0x4) - *(s16 *)(from + 0x4); + dx = *(s16 *)(to + 0x0) - *(s16 *)(from + 0x0); + dy = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8018BFA8 *)out = t; + return out; +} + INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_8018C090); diff --git a/src/ov_SC06_020/ov_SC06_020.c b/src/ov_SC06_020/ov_SC06_020.c index 4631181c14..68f0878e69 100644 --- a/src/ov_SC06_020/ov_SC06_020.c +++ b/src/ov_SC06_020/ov_SC06_020.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_020/nonmatchings/ov_SC06_020", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018530C[]; + s16 idx = D_8018530C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B8168, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_020/nonmatchings/ov_SC06_020", func_80128CFC); diff --git a/src/ov_SC06_020/ov_SC06_020_after.c b/src/ov_SC06_020/ov_SC06_020_after.c index 561c68bddd..1102fdef57 100644 --- a/src/ov_SC06_020/ov_SC06_020_after.c +++ b/src/ov_SC06_020/ov_SC06_020_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_020/nonmatchings/ov_SC06_020_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_020/nonmatchings/ov_SC06_020_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_020/ov_SC06_020_jr_8012ACE0.c b/src/ov_SC06_020/ov_SC06_020_jr_8012ACE0.c index 2dffcd876c..a075bd723e 100644 --- a/src/ov_SC06_020/ov_SC06_020_jr_8012ACE0.c +++ b/src/ov_SC06_020/ov_SC06_020_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_020/nonmatchings/ov_SC06_020_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_020/ov_SC06_020_jr_801734BC.c b/src/ov_SC06_020/ov_SC06_020_jr_801734BC.c index 875e2816fd..8270319b92 100644 --- a/src/ov_SC06_020/ov_SC06_020_jr_801734BC.c +++ b/src/ov_SC06_020/ov_SC06_020_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_020/nonmatchings/ov_SC06_020_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_020/ov_SC06_020_jr_8017C24C.c b/src/ov_SC06_020/ov_SC06_020_jr_8017C24C.c index 7bdfbc6979..189c2e5521 100644 --- a/src/ov_SC06_020/ov_SC06_020_jr_8017C24C.c +++ b/src/ov_SC06_020/ov_SC06_020_jr_8017C24C.c @@ -611,7 +611,6 @@ extern s32 func_8014E83C(s32 arg0, s16 * arg1, s16 * arg2); extern void func_8014E934(s32 _arg0); extern s32 func_8014EA4C(void *a0, void *a1, void *a2, s32 a3); extern s32 func_8014E98C(void *a0); -extern u16 D_800B99DA; extern s32 D_801150D8; extern s16 D_801152AA; extern u8 D_80126720[]; @@ -3621,7 +3620,109 @@ INCLUDE_ASM("asm/ov_SC06_020/nonmatchings/ov_SC06_020_jr_8017C24C", func_8017F93 INCLUDE_ASM("asm/ov_SC06_020/nonmatchings/ov_SC06_020_jr_8017C24C", func_8017FAB4); -INCLUDE_ASM("asm/ov_SC06_020/nonmatchings/ov_SC06_020_jr_8017C24C", func_8017FAFC); + +typedef struct { + u8 pad0[6]; + u16 f6; /* 0x06 -> D_80126B5E */ + u8 pad8[2]; + u16 fa; /* 0x0A -> D_80126B62 */ + u8 padc[2]; + u16 fe; /* 0x0E -> D_80126B66 */ +} StructB58_8017FAFC; + +/* holds a pointer value */ + +extern int rand(void); +extern s32 func_8012BEE8(s32 a0); +extern void func_8012B0B4(unsigned int *p, int a1, int a2); +extern s32 func_8012B744(void *a0, void *a1); +extern s32 func_8012B608(s32 a0, s32 a1, s32 a2); +extern void func_8012B178(s32 a0, s32 a1); +extern s32 func_801817CC(s32 a0); +extern void func_80181954(s32 a0); +extern void func_8012F14C(s32 a0); +extern void func_801834F0(s32, void*, void*, s32); +extern void func_8018348C(s32, void*, s32, s32, s32, s32); +extern s32 func_80013478(s32 a0, s32 a1); + +void func_8017FAFC(s32 param_1) { + + extern u16 D_800B99DA; + extern u8 D_8019E9B4; + /* [T51] scoped in from file scope: a file-scope decl of these symbols constrains every + LATER function in this TU, which blocks a byte-true decl of a different type. + Declaration-only move (cookbook §103); the whole-binary byte-gate is the arbiter. */ + extern s32 *D_80126B78; + u8 auStack_38[8]; + s16 sp20[3]; + u8 auStack_28[8]; + register StructB58_8017FAFC *b58 __asm__("$20") = &(*(StructB58_8017FAFC *)&D_80126B58); /* $s4 */ + short *psVar7 = (short *)(param_1 + 0xec); + s32 sVar1; + s32 r_b608; + + if (func_8012BEE8(param_1) != 0) { + register unsigned int *p28 __asm__("$21") = (unsigned int *)auStack_28; /* $s5 */ + s32 r0 = rand(); + s32 coord; + s32 s2v; + s32 r3; + s32 tmp; + + coord = r0 % 0x400; + sVar1 = *(s16 *)((*(s32 *)&(*(s32 *)&D_80126B78)) + 0x12); + s2v = sVar1 + 0x800; + if ((rand() & 1) == 0) { + coord = s2v - coord; + } else { + s32 c = coord; /* fresh pseudo so gcc keeps s2v first in the addu (§10 A1) */ + coord = s2v + c; + } + + func_8012B0B4(p28, coord, rand() % 0x200 + 0x200); + + tmp = *(s32 *)auStack_28; + psVar7[0] = b58->f6 + tmp; + psVar7[1] = b58->fa; + psVar7[2] = b58->fe + (tmp >> 16); + + r3 = rand(); + *(s32 *)(param_1 + 0x1c) = 0x80; + *(s16 *)(param_1 + 0x100) = r3 % 9 + 8; + } + + if ((*(u32 *)(param_1 + 0xe0) & 0x40) == 0) { + *(u32 *)(param_1 + 0xe8) = func_8012B744((void *)(param_1 + 4), psVar7); + } + + r_b608 = func_8012B608((s32)*(s16 *)(*(s32 *)(param_1 + 0x20) + 0x12), + *(s32 *)(param_1 + 0xe8), + (s32)*(s16 *)(param_1 + 0x100)); + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) = + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) + r_b608; + func_8012B178(param_1, 0xfffa0000); + + *(u32 *)(param_1 + 0xe0) &= 0xffffffbf; + if (func_801817CC(param_1) == 0) { + func_80181954(param_1); + sp20[1] = 0; + sp20[0] = 0; + sp20[2] = -0x100; + ((void (*)(s32, s32, s32))func_8012F14C)(*(s32 *)(param_1 + 0x20) + 0x34, + (s32)sp20, (s32)psVar7); + } + + if (((u32)D_800B99DA % 0x28 == 0) && ((*(u32 *)(param_1 + 0xe0) & 0x80) == 0)) { + ((void (*)(s32, s32, s32, s32))func_801834F0)(param_1, (s32)&D_8019E9B4, (s32)auStack_38, 0xb); + ((void (*)(s32, s32, s32, s32, s32, s32))func_8018348C)(param_1, (s32)auStack_38, 0x282, 1, 0, 0); + *(u32 *)(param_1 + 0xe0) |= 0x80; + } + + if (func_80013478(param_1 + 4, (s32)psVar7) < 0x400) { + *(s32 *)(param_1 + 0x1c) = 0; + } +} + INCLUDE_ASM("asm/ov_SC06_020/nonmatchings/ov_SC06_020_jr_8017C24C", func_8017FD9C); diff --git a/src/ov_SC06_022/ov_SC06_022.c b/src/ov_SC06_022/ov_SC06_022.c index 3386344f3b..1a71ba9b5c 100644 --- a/src/ov_SC06_022/ov_SC06_022.c +++ b/src/ov_SC06_022/ov_SC06_022.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_022/nonmatchings/ov_SC06_022", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018D5C8[]; + s16 idx = D_8018D5C8[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801DF978, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_022/nonmatchings/ov_SC06_022", func_80128CFC); diff --git a/src/ov_SC06_022/ov_SC06_022_after.c b/src/ov_SC06_022/ov_SC06_022_after.c index f3a2c76b63..ada99e5506 100644 --- a/src/ov_SC06_022/ov_SC06_022_after.c +++ b/src/ov_SC06_022/ov_SC06_022_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_022/nonmatchings/ov_SC06_022_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_022/nonmatchings/ov_SC06_022_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_022/ov_SC06_022_jr_8012ACE0.c b/src/ov_SC06_022/ov_SC06_022_jr_8012ACE0.c index 28c002c6b1..e8c4b519e8 100644 --- a/src/ov_SC06_022/ov_SC06_022_jr_8012ACE0.c +++ b/src/ov_SC06_022/ov_SC06_022_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_022/nonmatchings/ov_SC06_022_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_022/ov_SC06_022_jr_801734BC.c b/src/ov_SC06_022/ov_SC06_022_jr_801734BC.c index c954861199..669144d71c 100644 --- a/src/ov_SC06_022/ov_SC06_022_jr_801734BC.c +++ b/src/ov_SC06_022/ov_SC06_022_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_022/nonmatchings/ov_SC06_022_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_022/ov_SC06_022_jr_8017BEBC.c b/src/ov_SC06_022/ov_SC06_022_jr_8017BEBC.c index 93a80675a8..71eeccbd7c 100644 --- a/src/ov_SC06_022/ov_SC06_022_jr_8017BEBC.c +++ b/src/ov_SC06_022/ov_SC06_022_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -611,7 +610,6 @@ extern s32 func_8014E83C(s32 arg0, s16 * arg1, s16 * arg2); extern void func_8014E934(s32 _arg0); extern s32 func_8014EA4C(void *a0, void *a1, void *a2, s32 a3); extern s32 func_8014E98C(void *a0); -extern u16 D_800B99DA; extern s32 D_801150D8; extern s16 D_801152AA; extern u8 D_80126720[]; @@ -3991,7 +3989,110 @@ INCLUDE_ASM("asm/ov_SC06_022/nonmatchings/ov_SC06_022_jr_8017BEBC", func_8018386 INCLUDE_ASM("asm/ov_SC06_022/nonmatchings/ov_SC06_022_jr_8017BEBC", func_801839D8); -INCLUDE_ASM("asm/ov_SC06_022/nonmatchings/ov_SC06_022_jr_8017BEBC", func_80183A20); + +typedef struct { + u8 pad0[6]; + u16 f6; /* 0x06 -> D_80126B5E */ + u8 pad8[2]; + u16 fa; /* 0x0A -> D_80126B62 */ + u8 padc[2]; + u16 fe; /* 0x0E -> D_80126B66 */ +} StructB58_80183A20; + +/* holds a pointer value */ + +extern int rand(void); +extern s32 func_8012BEE8(s32 a0); +extern void func_8012B0B4(unsigned int *p, int a1, int a2); +extern s32 func_8012B744(void *a0, void *a1); +extern s32 func_8012B608(s32 a0, s32 a1, s32 a2); +extern void func_8012B178(s32 a0, s32 a1); +extern s32 func_801856F0(s32 a0); +extern void func_80185878(s32 a0); +extern void func_8012F14C(s32 a0); +extern void func_80187414(s32, void*, void*, s32); +extern void func_801873B0(s32, void*, s32, s32, s32, s32); +extern s32 func_80013478(s32 a0, s32 a1); + +void func_80183A20(s32 param_1) { + + extern s32 D_80126B58; + extern u16 D_800B99DA; + extern u8 D_801BD0DC; + /* [T51] scoped in from file scope: a file-scope decl of these symbols constrains every + LATER function in this TU, which blocks a byte-true decl of a different type. + Declaration-only move (cookbook §103); the whole-binary byte-gate is the arbiter. */ + extern s32 *D_80126B78; + u8 auStack_38[8]; + s16 sp20[3]; + u8 auStack_28[8]; + register StructB58_80183A20 *b58 __asm__("$20") = &(*(StructB58_80183A20 *)&D_80126B58); /* $s4 */ + short *psVar7 = (short *)(param_1 + 0xec); + s32 sVar1; + s32 r_b608; + + if (func_8012BEE8(param_1) != 0) { + register unsigned int *p28 __asm__("$21") = (unsigned int *)auStack_28; /* $s5 */ + s32 r0 = rand(); + s32 coord; + s32 s2v; + s32 r3; + s32 tmp; + + coord = r0 % 0x400; + sVar1 = *(s16 *)((*(s32 *)&(*(s32 *)&D_80126B78)) + 0x12); + s2v = sVar1 + 0x800; + if ((rand() & 1) == 0) { + coord = s2v - coord; + } else { + s32 c = coord; /* fresh pseudo so gcc keeps s2v first in the addu (§10 A1) */ + coord = s2v + c; + } + + func_8012B0B4(p28, coord, rand() % 0x200 + 0x200); + + tmp = *(s32 *)auStack_28; + psVar7[0] = b58->f6 + tmp; + psVar7[1] = b58->fa; + psVar7[2] = b58->fe + (tmp >> 16); + + r3 = rand(); + *(s32 *)(param_1 + 0x1c) = 0x80; + *(s16 *)(param_1 + 0x100) = r3 % 9 + 8; + } + + if ((*(u32 *)(param_1 + 0xe0) & 0x40) == 0) { + *(u32 *)(param_1 + 0xe8) = func_8012B744((void *)(param_1 + 4), psVar7); + } + + r_b608 = func_8012B608((s32)*(s16 *)(*(s32 *)(param_1 + 0x20) + 0x12), + *(s32 *)(param_1 + 0xe8), + (s32)*(s16 *)(param_1 + 0x100)); + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) = + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) + r_b608; + func_8012B178(param_1, 0xfffa0000); + + *(u32 *)(param_1 + 0xe0) &= 0xffffffbf; + if (func_801856F0(param_1) == 0) { + func_80185878(param_1); + sp20[1] = 0; + sp20[0] = 0; + sp20[2] = -0x100; + ((void (*)(s32, s32, s32))func_8012F14C)(*(s32 *)(param_1 + 0x20) + 0x34, + (s32)sp20, (s32)psVar7); + } + + if (((u32)D_800B99DA % 0x28 == 0) && ((*(u32 *)(param_1 + 0xe0) & 0x80) == 0)) { + ((void (*)(s32, s32, s32, s32))func_80187414)(param_1, (s32)&D_801BD0DC, (s32)auStack_38, 0xb); + ((void (*)(s32, s32, s32, s32, s32, s32))func_801873B0)(param_1, (s32)auStack_38, 0x282, 1, 0, 0); + *(u32 *)(param_1 + 0xe0) |= 0x80; + } + + if (func_80013478(param_1 + 4, (s32)psVar7) < 0x400) { + *(s32 *)(param_1 + 0x1c) = 0; + } +} + INCLUDE_ASM("asm/ov_SC06_022/nonmatchings/ov_SC06_022_jr_8017BEBC", func_80183CC0); diff --git a/src/ov_SC06_024/ov_SC06_024.c b/src/ov_SC06_024/ov_SC06_024.c index 44b31614b4..185b0ab7af 100644 --- a/src/ov_SC06_024/ov_SC06_024.c +++ b/src/ov_SC06_024/ov_SC06_024.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_024/nonmatchings/ov_SC06_024", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018FAA0[]; + s16 idx = D_8018FAA0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801DEABC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_024/nonmatchings/ov_SC06_024", func_80128CFC); diff --git a/src/ov_SC06_024/ov_SC06_024_after.c b/src/ov_SC06_024/ov_SC06_024_after.c index 60f9e87c8c..8da7eb1f55 100644 --- a/src/ov_SC06_024/ov_SC06_024_after.c +++ b/src/ov_SC06_024/ov_SC06_024_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_024/nonmatchings/ov_SC06_024_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_024/nonmatchings/ov_SC06_024_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_024/ov_SC06_024_jr_8012ACE0.c b/src/ov_SC06_024/ov_SC06_024_jr_8012ACE0.c index 2f0b13c0dd..40e7896280 100644 --- a/src/ov_SC06_024/ov_SC06_024_jr_8012ACE0.c +++ b/src/ov_SC06_024/ov_SC06_024_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_024/nonmatchings/ov_SC06_024_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_024/ov_SC06_024_jr_801734BC.c b/src/ov_SC06_024/ov_SC06_024_jr_801734BC.c index 747a119078..e70fcb4ddc 100644 --- a/src/ov_SC06_024/ov_SC06_024_jr_801734BC.c +++ b/src/ov_SC06_024/ov_SC06_024_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_024/nonmatchings/ov_SC06_024_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_024/ov_SC06_024_jr_8017BEBC.c b/src/ov_SC06_024/ov_SC06_024_jr_8017BEBC.c index 9fe34da8fd..12cb2a5748 100644 --- a/src/ov_SC06_024/ov_SC06_024_jr_8017BEBC.c +++ b/src/ov_SC06_024/ov_SC06_024_jr_8017BEBC.c @@ -4341,7 +4341,110 @@ INCLUDE_ASM("asm/ov_SC06_024/nonmatchings/ov_SC06_024_jr_8017BEBC", func_80185D3 INCLUDE_ASM("asm/ov_SC06_024/nonmatchings/ov_SC06_024_jr_8017BEBC", func_80185EB0); -INCLUDE_ASM("asm/ov_SC06_024/nonmatchings/ov_SC06_024_jr_8017BEBC", func_80185EF8); + +typedef struct { + u8 pad0[6]; + u16 f6; /* 0x06 -> D_80126B5E */ + u8 pad8[2]; + u16 fa; /* 0x0A -> D_80126B62 */ + u8 padc[2]; + u16 fe; /* 0x0E -> D_80126B66 */ +} StructB58_80185EF8; + +/* holds a pointer value */ + +extern int rand(void); +extern s32 func_8012BEE8(s32 a0); +extern void func_8012B0B4(unsigned int *p, int a1, int a2); +extern s32 func_8012B744(void *a0, void *a1); +extern s32 func_8012B608(s32 a0, s32 a1, s32 a2); +extern void func_8012B178(s32 a0, s32 a1); +extern s32 func_80187BC8(s32 a0); +extern void func_80187D50(s32 a0); +extern void func_8012F14C(s32 a0); +extern void func_801898EC(s32, void*, void*, s32); +extern void func_80189888(s32, void*, s32, s32, s32, s32); +extern s32 func_80013478(s32 a0, s32 a1); + +void func_80185EF8(s32 param_1) { + + extern s32 D_80126B58; + extern u16 D_800B99DA; + extern u8 D_801BC220; + /* [T51] scoped in from file scope: a file-scope decl of these symbols constrains every + LATER function in this TU, which blocks a byte-true decl of a different type. + Declaration-only move (cookbook §103); the whole-binary byte-gate is the arbiter. */ + extern s32 *D_80126B78; + u8 auStack_38[8]; + s16 sp20[3]; + u8 auStack_28[8]; + register StructB58_80185EF8 *b58 __asm__("$20") = &(*(StructB58_80185EF8 *)&D_80126B58); /* $s4 */ + short *psVar7 = (short *)(param_1 + 0xec); + s32 sVar1; + s32 r_b608; + + if (func_8012BEE8(param_1) != 0) { + register unsigned int *p28 __asm__("$21") = (unsigned int *)auStack_28; /* $s5 */ + s32 r0 = rand(); + s32 coord; + s32 s2v; + s32 r3; + s32 tmp; + + coord = r0 % 0x400; + sVar1 = *(s16 *)((*(s32 *)&(*(s32 *)&D_80126B78)) + 0x12); + s2v = sVar1 + 0x800; + if ((rand() & 1) == 0) { + coord = s2v - coord; + } else { + s32 c = coord; /* fresh pseudo so gcc keeps s2v first in the addu (§10 A1) */ + coord = s2v + c; + } + + func_8012B0B4(p28, coord, rand() % 0x200 + 0x200); + + tmp = *(s32 *)auStack_28; + psVar7[0] = b58->f6 + tmp; + psVar7[1] = b58->fa; + psVar7[2] = b58->fe + (tmp >> 16); + + r3 = rand(); + *(s32 *)(param_1 + 0x1c) = 0x80; + *(s16 *)(param_1 + 0x100) = r3 % 9 + 8; + } + + if ((*(u32 *)(param_1 + 0xe0) & 0x40) == 0) { + *(u32 *)(param_1 + 0xe8) = func_8012B744((void *)(param_1 + 4), psVar7); + } + + r_b608 = func_8012B608((s32)*(s16 *)(*(s32 *)(param_1 + 0x20) + 0x12), + *(s32 *)(param_1 + 0xe8), + (s32)*(s16 *)(param_1 + 0x100)); + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) = + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) + r_b608; + func_8012B178(param_1, 0xfffa0000); + + *(u32 *)(param_1 + 0xe0) &= 0xffffffbf; + if (func_80187BC8(param_1) == 0) { + func_80187D50(param_1); + sp20[1] = 0; + sp20[0] = 0; + sp20[2] = -0x100; + ((void (*)(s32, s32, s32))func_8012F14C)(*(s32 *)(param_1 + 0x20) + 0x34, + (s32)sp20, (s32)psVar7); + } + + if (((u32)D_800B99DA % 0x28 == 0) && ((*(u32 *)(param_1 + 0xe0) & 0x80) == 0)) { + ((void (*)(s32, s32, s32, s32))func_801898EC)(param_1, (s32)&D_801BC220, (s32)auStack_38, 0xb); + ((void (*)(s32, s32, s32, s32, s32, s32))func_80189888)(param_1, (s32)auStack_38, 0x282, 1, 0, 0); + *(u32 *)(param_1 + 0xe0) |= 0x80; + } + + if (func_80013478(param_1 + 4, (s32)psVar7) < 0x400) { + *(s32 *)(param_1 + 0x1c) = 0; + } +} + INCLUDE_ASM("asm/ov_SC06_024/nonmatchings/ov_SC06_024_jr_8017BEBC", func_80186198); diff --git a/src/ov_SC06_025/ov_SC06_025.c b/src/ov_SC06_025/ov_SC06_025.c index 0d4732f1c2..662e89eb7f 100644 --- a/src/ov_SC06_025/ov_SC06_025.c +++ b/src/ov_SC06_025/ov_SC06_025.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_025/nonmatchings/ov_SC06_025", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80184F44[]; + s16 idx = D_80184F44[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801AEDDC, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_025/nonmatchings/ov_SC06_025", func_80128CFC); diff --git a/src/ov_SC06_025/ov_SC06_025_after.c b/src/ov_SC06_025/ov_SC06_025_after.c index 2b80e533dd..c430076d8d 100644 --- a/src/ov_SC06_025/ov_SC06_025_after.c +++ b/src/ov_SC06_025/ov_SC06_025_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_025/nonmatchings/ov_SC06_025_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_025/nonmatchings/ov_SC06_025_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_025/ov_SC06_025_jr_8012ACE0.c b/src/ov_SC06_025/ov_SC06_025_jr_8012ACE0.c index 924818e366..c415603f4e 100644 --- a/src/ov_SC06_025/ov_SC06_025_jr_8012ACE0.c +++ b/src/ov_SC06_025/ov_SC06_025_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_025/nonmatchings/ov_SC06_025_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_025/ov_SC06_025_jr_801734BC.c b/src/ov_SC06_025/ov_SC06_025_jr_801734BC.c index 9438a648aa..c0b49e2339 100644 --- a/src/ov_SC06_025/ov_SC06_025_jr_801734BC.c +++ b/src/ov_SC06_025/ov_SC06_025_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_025/nonmatchings/ov_SC06_025_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_027/ov_SC06_027.c b/src/ov_SC06_027/ov_SC06_027.c index 54d688cd66..82b1e203f4 100644 --- a/src/ov_SC06_027/ov_SC06_027.c +++ b/src/ov_SC06_027/ov_SC06_027.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_027/nonmatchings/ov_SC06_027", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017E284[]; + s16 idx = D_8017E284[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8019AE18, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_027/nonmatchings/ov_SC06_027", func_80128CFC); diff --git a/src/ov_SC06_027/ov_SC06_027_after.c b/src/ov_SC06_027/ov_SC06_027_after.c index e02fef756a..1ac29aed87 100644 --- a/src/ov_SC06_027/ov_SC06_027_after.c +++ b/src/ov_SC06_027/ov_SC06_027_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_027/nonmatchings/ov_SC06_027_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_027/nonmatchings/ov_SC06_027_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_027/ov_SC06_027_jr_8012ACE0.c b/src/ov_SC06_027/ov_SC06_027_jr_8012ACE0.c index f5eaf03d65..5b10d6d991 100644 --- a/src/ov_SC06_027/ov_SC06_027_jr_8012ACE0.c +++ b/src/ov_SC06_027/ov_SC06_027_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_027/nonmatchings/ov_SC06_027_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_027/ov_SC06_027_jr_801734BC.c b/src/ov_SC06_027/ov_SC06_027_jr_801734BC.c index 6e86b837a9..ad663cdb46 100644 --- a/src/ov_SC06_027/ov_SC06_027_jr_801734BC.c +++ b/src/ov_SC06_027/ov_SC06_027_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_027/nonmatchings/ov_SC06_027_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_029/ov_SC06_029.c b/src/ov_SC06_029/ov_SC06_029.c index c702cf748c..bd6d133b2c 100644 --- a/src/ov_SC06_029/ov_SC06_029.c +++ b/src/ov_SC06_029/ov_SC06_029.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_029/nonmatchings/ov_SC06_029", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018C818[]; + s16 idx = D_8018C818[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801DA494, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_029/nonmatchings/ov_SC06_029", func_80128CFC); diff --git a/src/ov_SC06_029/ov_SC06_029_after.c b/src/ov_SC06_029/ov_SC06_029_after.c index 1972e93ec1..1371f9c817 100644 --- a/src/ov_SC06_029/ov_SC06_029_after.c +++ b/src/ov_SC06_029/ov_SC06_029_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_029/nonmatchings/ov_SC06_029_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_029/nonmatchings/ov_SC06_029_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_029/ov_SC06_029_jr_8012ACE0.c b/src/ov_SC06_029/ov_SC06_029_jr_8012ACE0.c index 755995d6a4..fec59f5dfe 100644 --- a/src/ov_SC06_029/ov_SC06_029_jr_8012ACE0.c +++ b/src/ov_SC06_029/ov_SC06_029_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_029/nonmatchings/ov_SC06_029_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_029/ov_SC06_029_jr_801734BC.c b/src/ov_SC06_029/ov_SC06_029_jr_801734BC.c index 02c4057dd7..00a025e78b 100644 --- a/src/ov_SC06_029/ov_SC06_029_jr_801734BC.c +++ b/src/ov_SC06_029/ov_SC06_029_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_029/nonmatchings/ov_SC06_029_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_030/ov_SC06_030.c b/src/ov_SC06_030/ov_SC06_030.c index 46ab890d83..928018bad0 100644 --- a/src/ov_SC06_030/ov_SC06_030.c +++ b/src/ov_SC06_030/ov_SC06_030.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_030/nonmatchings/ov_SC06_030", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80182108[]; + s16 idx = D_80182108[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801B77F8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_030/nonmatchings/ov_SC06_030", func_80128CFC); diff --git a/src/ov_SC06_030/ov_SC06_030_after.c b/src/ov_SC06_030/ov_SC06_030_after.c index b48553fb5f..b45259be1e 100644 --- a/src/ov_SC06_030/ov_SC06_030_after.c +++ b/src/ov_SC06_030/ov_SC06_030_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_030/nonmatchings/ov_SC06_030_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_030/nonmatchings/ov_SC06_030_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_030/ov_SC06_030_jr_8012ACE0.c b/src/ov_SC06_030/ov_SC06_030_jr_8012ACE0.c index 63f47e2912..f1ada30e80 100644 --- a/src/ov_SC06_030/ov_SC06_030_jr_8012ACE0.c +++ b/src/ov_SC06_030/ov_SC06_030_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_030/nonmatchings/ov_SC06_030_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_030/ov_SC06_030_jr_801734BC.c b/src/ov_SC06_030/ov_SC06_030_jr_801734BC.c index 04f2c6a1f4..864b740774 100644 --- a/src/ov_SC06_030/ov_SC06_030_jr_801734BC.c +++ b/src/ov_SC06_030/ov_SC06_030_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_030/nonmatchings/ov_SC06_030_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_032/ov_SC06_032.c b/src/ov_SC06_032/ov_SC06_032.c index 723fc17bb3..4c7e2251ba 100644 --- a/src/ov_SC06_032/ov_SC06_032.c +++ b/src/ov_SC06_032/ov_SC06_032.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801935D4[]; + s16 idx = D_801935D4[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801CDE54, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032", func_80128CFC); diff --git a/src/ov_SC06_032/ov_SC06_032_after.c b/src/ov_SC06_032/ov_SC06_032_after.c index 4599286914..f45f92eef1 100644 --- a/src/ov_SC06_032/ov_SC06_032_after.c +++ b/src/ov_SC06_032/ov_SC06_032_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_032/ov_SC06_032_jr_8012ACE0.c b/src/ov_SC06_032/ov_SC06_032_jr_8012ACE0.c index a901c4a65f..d3be9890f7 100644 --- a/src/ov_SC06_032/ov_SC06_032_jr_8012ACE0.c +++ b/src/ov_SC06_032/ov_SC06_032_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_032/ov_SC06_032_jr_801734BC.c b/src/ov_SC06_032/ov_SC06_032_jr_801734BC.c index 40d02f0954..9db52a7cbb 100644 --- a/src/ov_SC06_032/ov_SC06_032_jr_801734BC.c +++ b/src/ov_SC06_032/ov_SC06_032_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_032/ov_SC06_032_jr_8017C24C.c b/src/ov_SC06_032/ov_SC06_032_jr_8017C24C.c index 9b7ae8629f..78dfd28229 100644 --- a/src/ov_SC06_032/ov_SC06_032_jr_8017C24C.c +++ b/src/ov_SC06_032/ov_SC06_032_jr_8017C24C.c @@ -3964,7 +3964,110 @@ INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8017C24C", func_8018057 INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8017C24C", func_801806E8); -INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8017C24C", func_80180730); + +typedef struct { + u8 pad0[6]; + u16 f6; /* 0x06 -> D_80126B5E */ + u8 pad8[2]; + u16 fa; /* 0x0A -> D_80126B62 */ + u8 padc[2]; + u16 fe; /* 0x0E -> D_80126B66 */ +} StructB58_80180730; + +/* holds a pointer value */ + +extern int rand(void); +extern s32 func_8012BEE8(s32 a0); +extern void func_8012B0B4(unsigned int *p, int a1, int a2); +extern s32 func_8012B744(void *a0, void *a1); +extern s32 func_8012B608(s32 a0, s32 a1, s32 a2); +extern void func_8012B178(s32 a0, s32 a1); +extern s32 func_80182400(s32 a0); +extern void func_80182588(s32 a0); +extern void func_8012F14C(s32 a0); +extern void func_80184124(s32, void*, void*, s32); +extern void func_801840C0(s32, void*, s32, s32, s32, s32); +extern s32 func_80013478(s32 a0, s32 a1); + +void func_80180730(s32 param_1) { + + extern s32 D_80126B58; + extern u16 D_800B99DA; + extern u8 D_801A6614; + /* [T51] scoped in from file scope: a file-scope decl of these symbols constrains every + LATER function in this TU, which blocks a byte-true decl of a different type. + Declaration-only move (cookbook §103); the whole-binary byte-gate is the arbiter. */ + extern s32 *D_80126B78; + u8 auStack_38[8]; + s16 sp20[3]; + u8 auStack_28[8]; + register StructB58_80180730 *b58 __asm__("$20") = &(*(StructB58_80180730 *)&D_80126B58); /* $s4 */ + short *psVar7 = (short *)(param_1 + 0xec); + s32 sVar1; + s32 r_b608; + + if (func_8012BEE8(param_1) != 0) { + register unsigned int *p28 __asm__("$21") = (unsigned int *)auStack_28; /* $s5 */ + s32 r0 = rand(); + s32 coord; + s32 s2v; + s32 r3; + s32 tmp; + + coord = r0 % 0x400; + sVar1 = *(s16 *)((*(s32 *)&(*(s32 *)&D_80126B78)) + 0x12); + s2v = sVar1 + 0x800; + if ((rand() & 1) == 0) { + coord = s2v - coord; + } else { + s32 c = coord; /* fresh pseudo so gcc keeps s2v first in the addu (§10 A1) */ + coord = s2v + c; + } + + func_8012B0B4(p28, coord, rand() % 0x200 + 0x200); + + tmp = *(s32 *)auStack_28; + psVar7[0] = b58->f6 + tmp; + psVar7[1] = b58->fa; + psVar7[2] = b58->fe + (tmp >> 16); + + r3 = rand(); + *(s32 *)(param_1 + 0x1c) = 0x80; + *(s16 *)(param_1 + 0x100) = r3 % 9 + 8; + } + + if ((*(u32 *)(param_1 + 0xe0) & 0x40) == 0) { + *(u32 *)(param_1 + 0xe8) = func_8012B744((void *)(param_1 + 4), psVar7); + } + + r_b608 = func_8012B608((s32)*(s16 *)(*(s32 *)(param_1 + 0x20) + 0x12), + *(s32 *)(param_1 + 0xe8), + (s32)*(s16 *)(param_1 + 0x100)); + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) = + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) + r_b608; + func_8012B178(param_1, 0xfffa0000); + + *(u32 *)(param_1 + 0xe0) &= 0xffffffbf; + if (func_80182400(param_1) == 0) { + func_80182588(param_1); + sp20[1] = 0; + sp20[0] = 0; + sp20[2] = -0x100; + ((void (*)(s32, s32, s32))func_8012F14C)(*(s32 *)(param_1 + 0x20) + 0x34, + (s32)sp20, (s32)psVar7); + } + + if (((u32)D_800B99DA % 0x28 == 0) && ((*(u32 *)(param_1 + 0xe0) & 0x80) == 0)) { + ((void (*)(s32, s32, s32, s32))func_80184124)(param_1, (s32)&D_801A6614, (s32)auStack_38, 0xb); + ((void (*)(s32, s32, s32, s32, s32, s32))func_801840C0)(param_1, (s32)auStack_38, 0x282, 1, 0, 0); + *(u32 *)(param_1 + 0xe0) |= 0x80; + } + + if (func_80013478(param_1 + 4, (s32)psVar7) < 0x400) { + *(s32 *)(param_1 + 0x1c) = 0; + } +} + INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8017C24C", func_801809D0); @@ -4698,7 +4801,55 @@ INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8017C24C", func_80186E1 INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8017C24C", func_80186E9C); -INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8017C24C", func_80187180); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_80187180; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0x4 are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_80187180(s32 out, s32 from, s32 to) { + Ang2_8012B77C_80187180 t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0x4) - *(s16 *)(from + 0x4); + dx = *(s16 *)(to + 0x0) - *(s16 *)(from + 0x0); + dy = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_80187180 *)out = t; + return out; +} + INCLUDE_ASM("asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8017C24C", func_80187268); diff --git a/src/ov_SC06_033/ov_SC06_033.c b/src/ov_SC06_033/ov_SC06_033.c index e311a8bb1b..daa4cbb352 100644 --- a/src/ov_SC06_033/ov_SC06_033.c +++ b/src/ov_SC06_033/ov_SC06_033.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_033/nonmatchings/ov_SC06_033", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80191AE4[]; + s16 idx = D_80191AE4[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801CDF08, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC06_033/nonmatchings/ov_SC06_033", func_80128CFC); diff --git a/src/ov_SC06_033/ov_SC06_033_after.c b/src/ov_SC06_033/ov_SC06_033_after.c index 17373538c8..45b6886518 100644 --- a/src/ov_SC06_033/ov_SC06_033_after.c +++ b/src/ov_SC06_033/ov_SC06_033_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC06_033/nonmatchings/ov_SC06_033_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_033/nonmatchings/ov_SC06_033_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC06_033/ov_SC06_033_jr_8012ACE0.c b/src/ov_SC06_033/ov_SC06_033_jr_8012ACE0.c index ad3e5aa9e3..7ad34c64ae 100644 --- a/src/ov_SC06_033/ov_SC06_033_jr_8012ACE0.c +++ b/src/ov_SC06_033/ov_SC06_033_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC06_033/nonmatchings/ov_SC06_033_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC06_033/ov_SC06_033_jr_801734BC.c b/src/ov_SC06_033/ov_SC06_033_jr_801734BC.c index f072a136ab..db1fc773ef 100644 --- a/src/ov_SC06_033/ov_SC06_033_jr_801734BC.c +++ b/src/ov_SC06_033/ov_SC06_033_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC06_033/nonmatchings/ov_SC06_033_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC06_033/ov_SC06_033_jr_8017C24C.c b/src/ov_SC06_033/ov_SC06_033_jr_8017C24C.c index bcfa4e2555..361091954b 100644 --- a/src/ov_SC06_033/ov_SC06_033_jr_8017C24C.c +++ b/src/ov_SC06_033/ov_SC06_033_jr_8017C24C.c @@ -4565,7 +4565,110 @@ INCLUDE_ASM("asm/ov_SC06_033/nonmatchings/ov_SC06_033_jr_8017C24C", func_8018425 INCLUDE_ASM("asm/ov_SC06_033/nonmatchings/ov_SC06_033_jr_8017C24C", func_801843CC); -INCLUDE_ASM("asm/ov_SC06_033/nonmatchings/ov_SC06_033_jr_8017C24C", func_80184414); + +typedef struct { + u8 pad0[6]; + u16 f6; /* 0x06 -> D_80126B5E */ + u8 pad8[2]; + u16 fa; /* 0x0A -> D_80126B62 */ + u8 padc[2]; + u16 fe; /* 0x0E -> D_80126B66 */ +} StructB58_80184414; + +/* holds a pointer value */ + +extern int rand(void); +extern s32 func_8012BEE8(s32 a0); +extern void func_8012B0B4(unsigned int *p, int a1, int a2); +extern s32 func_8012B744(void *a0, void *a1); +extern s32 func_8012B608(s32 a0, s32 a1, s32 a2); +extern void func_8012B178(s32 a0, s32 a1); +extern s32 func_801860E4(s32 a0); +extern void func_8018626C(s32 a0); +extern void func_8012F14C(s32 a0); +extern void func_80187E08(s32, void*, void*, s32); +extern void func_80187DA4(s32, void*, s32, s32, s32, s32); +extern s32 func_80013478(s32 a0, s32 a1); + +void func_80184414(s32 param_1) { + + extern s32 D_80126B58; + extern u16 D_800B99DA; + extern u8 D_801AF9A8; + /* [T51] scoped in from file scope: a file-scope decl of these symbols constrains every + LATER function in this TU, which blocks a byte-true decl of a different type. + Declaration-only move (cookbook §103); the whole-binary byte-gate is the arbiter. */ + extern s32 *D_80126B78; + u8 auStack_38[8]; + s16 sp20[3]; + u8 auStack_28[8]; + register StructB58_80184414 *b58 __asm__("$20") = &(*(StructB58_80184414 *)&D_80126B58); /* $s4 */ + short *psVar7 = (short *)(param_1 + 0xec); + s32 sVar1; + s32 r_b608; + + if (func_8012BEE8(param_1) != 0) { + register unsigned int *p28 __asm__("$21") = (unsigned int *)auStack_28; /* $s5 */ + s32 r0 = rand(); + s32 coord; + s32 s2v; + s32 r3; + s32 tmp; + + coord = r0 % 0x400; + sVar1 = *(s16 *)((*(s32 *)&(*(s32 *)&D_80126B78)) + 0x12); + s2v = sVar1 + 0x800; + if ((rand() & 1) == 0) { + coord = s2v - coord; + } else { + s32 c = coord; /* fresh pseudo so gcc keeps s2v first in the addu (§10 A1) */ + coord = s2v + c; + } + + func_8012B0B4(p28, coord, rand() % 0x200 + 0x200); + + tmp = *(s32 *)auStack_28; + psVar7[0] = b58->f6 + tmp; + psVar7[1] = b58->fa; + psVar7[2] = b58->fe + (tmp >> 16); + + r3 = rand(); + *(s32 *)(param_1 + 0x1c) = 0x80; + *(s16 *)(param_1 + 0x100) = r3 % 9 + 8; + } + + if ((*(u32 *)(param_1 + 0xe0) & 0x40) == 0) { + *(u32 *)(param_1 + 0xe8) = func_8012B744((void *)(param_1 + 4), psVar7); + } + + r_b608 = func_8012B608((s32)*(s16 *)(*(s32 *)(param_1 + 0x20) + 0x12), + *(s32 *)(param_1 + 0xe8), + (s32)*(s16 *)(param_1 + 0x100)); + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) = + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) + r_b608; + func_8012B178(param_1, 0xfffa0000); + + *(u32 *)(param_1 + 0xe0) &= 0xffffffbf; + if (func_801860E4(param_1) == 0) { + func_8018626C(param_1); + sp20[1] = 0; + sp20[0] = 0; + sp20[2] = -0x100; + ((void (*)(s32, s32, s32))func_8012F14C)(*(s32 *)(param_1 + 0x20) + 0x34, + (s32)sp20, (s32)psVar7); + } + + if (((u32)D_800B99DA % 0x28 == 0) && ((*(u32 *)(param_1 + 0xe0) & 0x80) == 0)) { + ((void (*)(s32, s32, s32, s32))func_80187E08)(param_1, (s32)&D_801AF9A8, (s32)auStack_38, 0xb); + ((void (*)(s32, s32, s32, s32, s32, s32))func_80187DA4)(param_1, (s32)auStack_38, 0x282, 1, 0, 0); + *(u32 *)(param_1 + 0xe0) |= 0x80; + } + + if (func_80013478(param_1 + 4, (s32)psVar7) < 0x400) { + *(s32 *)(param_1 + 0x1c) = 0; + } +} + INCLUDE_ASM("asm/ov_SC06_033/nonmatchings/ov_SC06_033_jr_8017C24C", func_801846B4); diff --git a/src/ov_SC07_000/ov_SC07_000.c b/src/ov_SC07_000/ov_SC07_000.c index 18f4e059fb..d5108bd914 100644 --- a/src/ov_SC07_000/ov_SC07_000.c +++ b/src/ov_SC07_000/ov_SC07_000.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_000/nonmatchings/ov_SC07_000", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018292C[]; + s16 idx = D_8018292C[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801CD564, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC07_000/nonmatchings/ov_SC07_000", func_80128CFC); diff --git a/src/ov_SC07_000/ov_SC07_000_after.c b/src/ov_SC07_000/ov_SC07_000_after.c index 5dadb31305..3b0ae8929f 100644 --- a/src/ov_SC07_000/ov_SC07_000_after.c +++ b/src/ov_SC07_000/ov_SC07_000_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC07_000/nonmatchings/ov_SC07_000_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_000/nonmatchings/ov_SC07_000_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC07_000/ov_SC07_000_jr_8012ACE0.c b/src/ov_SC07_000/ov_SC07_000_jr_8012ACE0.c index f32473fca1..f0c460a056 100644 --- a/src/ov_SC07_000/ov_SC07_000_jr_8012ACE0.c +++ b/src/ov_SC07_000/ov_SC07_000_jr_8012ACE0.c @@ -329,7 +329,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_000/nonmatchings/ov_SC07_000_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC07_000/ov_SC07_000_jr_801734BC.c b/src/ov_SC07_000/ov_SC07_000_jr_801734BC.c index d08df346c8..805a3111f3 100644 --- a/src/ov_SC07_000/ov_SC07_000_jr_801734BC.c +++ b/src/ov_SC07_000/ov_SC07_000_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC07_000/nonmatchings/ov_SC07_000_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC07_000/ov_SC07_000_jr_8017BEBC.c b/src/ov_SC07_000/ov_SC07_000_jr_8017BEBC.c index 98bbbc7a4e..6dd3e4ecd2 100644 --- a/src/ov_SC07_000/ov_SC07_000_jr_8017BEBC.c +++ b/src/ov_SC07_000/ov_SC07_000_jr_8017BEBC.c @@ -3682,7 +3682,53 @@ void func_80181790(void) { } -INCLUDE_ASM("asm/ov_SC07_000/nonmatchings/ov_SC07_000_jr_8017BEBC", func_801817B4); + +/* func_801817B4 — cookbook §71 (sibling-first). + * func_80181854 is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_80181854(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_80181970 (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_801817B4; + +extern void func_80181854(s32 arg0, s32 arg1, s32 arg2); +extern void func_80181970(s32 arg0, Rec_8018A6A4_801817B4 *arg1, s32 arg2, s32 arg3); + +void func_801817B4(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_801817B4 sp10; + s32 i; + s32 ang; + + func_80181854(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_80181970(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + extern s16 D_801D0A7C; @@ -3713,7 +3759,57 @@ INCLUDE_ASM("asm/ov_SC07_000/nonmatchings/ov_SC07_000_jr_8017BEBC", func_80181A4 INCLUDE_ASM("asm/ov_SC07_000/nonmatchings/ov_SC07_000_jr_8017BEBC", func_80181A80); -INCLUDE_ASM("asm/ov_SC07_000/nonmatchings/ov_SC07_000_jr_8017BEBC", func_80181ACC); + +/* func_80181ACC — 16-entry table walk, stride 0xE, over D_801D0A84. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_801D0A84; s16 *p = &D_801D0A84; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_80181BA8(s32 arg0); + +void func_80181ACC(void) { + + extern s16 D_801D0A84; + s16 *p = &D_801D0A84; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_80181BA8(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC07_000/nonmatchings/ov_SC07_000_jr_8017BEBC", func_80181BA8); diff --git a/src/ov_SC07_001/ov_SC07_001.c b/src/ov_SC07_001/ov_SC07_001.c index b13a52a4e8..fbf02b3f57 100644 --- a/src/ov_SC07_001/ov_SC07_001.c +++ b/src/ov_SC07_001/ov_SC07_001.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_001/nonmatchings/ov_SC07_001", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801817DC[]; + s16 idx = D_801817DC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A8700, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC07_001/nonmatchings/ov_SC07_001", func_80128CFC); diff --git a/src/ov_SC07_001/ov_SC07_001_after.c b/src/ov_SC07_001/ov_SC07_001_after.c index 3e39299db1..2b11e2e9ef 100644 --- a/src/ov_SC07_001/ov_SC07_001_after.c +++ b/src/ov_SC07_001/ov_SC07_001_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC07_001/nonmatchings/ov_SC07_001_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_001/nonmatchings/ov_SC07_001_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC07_001/ov_SC07_001_jr_8012ACE0.c b/src/ov_SC07_001/ov_SC07_001_jr_8012ACE0.c index 644a041aef..9bca4a5e9e 100644 --- a/src/ov_SC07_001/ov_SC07_001_jr_8012ACE0.c +++ b/src/ov_SC07_001/ov_SC07_001_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_001/nonmatchings/ov_SC07_001_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC07_001/ov_SC07_001_jr_801734BC.c b/src/ov_SC07_001/ov_SC07_001_jr_801734BC.c index ca9ee60ab9..a22998628e 100644 --- a/src/ov_SC07_001/ov_SC07_001_jr_801734BC.c +++ b/src/ov_SC07_001/ov_SC07_001_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC07_001/nonmatchings/ov_SC07_001_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC07_002/ov_SC07_002.c b/src/ov_SC07_002/ov_SC07_002.c index 8c7ad38ca3..d8d8395990 100644 --- a/src/ov_SC07_002/ov_SC07_002.c +++ b/src/ov_SC07_002/ov_SC07_002.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80186A98[]; + s16 idx = D_80186A98[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801990E8, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002", func_80128CFC); diff --git a/src/ov_SC07_002/ov_SC07_002_after.c b/src/ov_SC07_002/ov_SC07_002_after.c index f34c65e078..d81292e88c 100644 --- a/src/ov_SC07_002/ov_SC07_002_after.c +++ b/src/ov_SC07_002/ov_SC07_002_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC07_002/ov_SC07_002_jr_8012ACE0.c b/src/ov_SC07_002/ov_SC07_002_jr_8012ACE0.c index bb0dccac8d..b41325a97f 100644 --- a/src/ov_SC07_002/ov_SC07_002_jr_8012ACE0.c +++ b/src/ov_SC07_002/ov_SC07_002_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC07_002/ov_SC07_002_jr_801734BC.c b/src/ov_SC07_002/ov_SC07_002_jr_801734BC.c index 9ecbee3ff4..43498fcfb5 100644 --- a/src/ov_SC07_002/ov_SC07_002_jr_801734BC.c +++ b/src/ov_SC07_002/ov_SC07_002_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC07_002/ov_SC07_002_jr_8017C8D0.c b/src/ov_SC07_002/ov_SC07_002_jr_8017C8D0.c index 53a453f931..244bf4e2e4 100644 --- a/src/ov_SC07_002/ov_SC07_002_jr_8017C8D0.c +++ b/src/ov_SC07_002/ov_SC07_002_jr_8017C8D0.c @@ -3714,7 +3714,53 @@ void func_80184594(void) { } -INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002_jr_8017C8D0", func_801845B8); + +/* func_801845B8 — cookbook §71 (sibling-first). + * func_80184658 is ALREADY MATCHED in the same TU + * (src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c L4221) as a 3-arg + * `void func_80184658(s32, s32, s32)`, so the untouched $a3 at the first + * jal is just the incoming arg3 living on, not a 4th argument. + * func_80184774 (asm, same TU) reads its 2nd arg as lhu+0 / lhu+2 / lh+4 / + * lh+6 => the sp+0x10 local is a 4 x s16 record. + * + * Two levers took it 32 -> 2 -> 0 (match_one MATCH, rtu_match MATCH): + * 1. LENGTH-DRIFT (-2, cookbook §78): writing `sp10.unk2 = i * 0x100` + * leaves gcc-2.7.2 recomputing `sll v0,s1,8` instead of building the + * strength-reduced giv, so only s0..s3 get saved and the frame is two + * instructions short. An EXPLICIT accumulator (`ang += 0x100`) forces + * the second callee-saved register ($s2) and restores sw/lw $s4. + * 2. REGALLOC-PERM $s1>$s2 (cookbook §3-T2, source order drives emission): + * `ang = 0;` on its own line before the loop emits the $s2 zero-init + * FIRST. Folding it into the for-init (`for (i = 0, ang = 0; ...)`) + * puts $s1's zero-init first, which is the target order. + */ + +typedef struct { + s16 unk0; + s16 unk2; + s16 unk4; + s16 unk6; +} Rec_8018A6A4_801845B8; + +extern void func_80184658(s32 arg0, s32 arg1, s32 arg2); +extern void func_80184774(s32 arg0, Rec_8018A6A4_801845B8 *arg1, s32 arg2, s32 arg3); + +void func_801845B8(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { + Rec_8018A6A4_801845B8 sp10; + s32 i; + s32 ang; + + func_80184658(arg0, 0x1000, 0); + sp10.unk0 = *(u16 *)(arg3 + 0x0); + sp10.unk4 = *(u16 *)(arg3 + 0x2); + sp10.unk6 = 1; + for (i = 0, ang = 0; i < 16; i++) { + sp10.unk2 = ang; + func_80184774(i, &sp10, arg1, arg2); + ang += 0x100; + } +} + extern s16 D_8019FE7C; @@ -3745,7 +3791,57 @@ INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002_jr_8017C8D0", func_8018484 INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002_jr_8017C8D0", func_80184884); -INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002_jr_8017C8D0", func_801848D0); + +/* func_801848D0 — 16-entry table walk, stride 0xE, over D_8019FE84. + * §71 sibling: func_8018A680 (same TU, L4199) already matched the + * `extern s16 D_8019FE84; s16 *p = &D_8019FE84; p = (s16*)((s32)p+0xe)` + * shape over the very same array — copy that walker verbatim. + * + * Two induction registers in the target ($s1 = base+0, $s0 = base+4) are NOT + * two source pointers: $s1 is the user pointer (the biv, used for the +0 + * accesses) and $s0 is loop.c's single COMBINED address giv for the + * {+4, +9, +13} group (offsets 0/5/9 off $s0). Declaring a second pointer + * splits that group and costs a third register (iter 1: 53 mismatches). + */ + +extern void func_801849AC(s32 arg0); + +void func_801848D0(void) { + + extern s16 D_8019FE84; + s16 *p = &D_8019FE84; + s32 i = 0; + s16 t; + + do { + if (*(u16 *)p != 0) { + func_801849AC(i); + switch (*(u8 *)((s32)p + 9)) { + case 1: + if (*(s16 *)((s32)p + 4) < *(u8 *)((s32)p + 13)) { + *(s16 *)((s32)p + 4) = *(s16 *)((s32)p + 4) + 8; + } else { + *(u8 *)((s32)p + 9) = 0; + } + break; + case 2: + t = *(s16 *)((s32)p + 4); + if (t != 0) { + t -= 0x10; + *(s16 *)((s32)p + 4) = t; + if (t > 0) { + break; + } + } + *p = 0; + break; + } + } + i++; + p = (s16 *)((s32)p + 0xe); + } while (i < 0x10); +} + INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002_jr_8017C8D0", func_801849AC); diff --git a/src/ov_SC07_006/ov_SC07_006.c b/src/ov_SC07_006/ov_SC07_006.c index f0089380bf..6b8f02decc 100644 --- a/src/ov_SC07_006/ov_SC07_006.c +++ b/src/ov_SC07_006/ov_SC07_006.c @@ -411,7 +411,28 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128c14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_006/nonmatchings/ov_SC07_006", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8018A6BC[]; + extern s32 D_801F3B6C; + s16 idx = D_8018A6BC[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801F3B6C, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC07_006/nonmatchings/ov_SC07_006", func_80128CFC); diff --git a/src/ov_SC07_006/ov_SC07_006_jr_80140608.c b/src/ov_SC07_006/ov_SC07_006_jr_80140608.c index 7976723fae..185665c9c0 100644 --- a/src/ov_SC07_006/ov_SC07_006_jr_80140608.c +++ b/src/ov_SC07_006/ov_SC07_006_jr_80140608.c @@ -3139,7 +3139,84 @@ INCLUDE_ASM("asm/ov_SC07_006/nonmatchings/ov_SC07_006_jr_80140608", func_80146A6 DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146ab4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_006/nonmatchings/ov_SC07_006_jr_80140608", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146b9c (src/shared) */ diff --git a/src/ov_SC07_006/ov_SC07_006_jr_8016AE5C.c b/src/ov_SC07_006/ov_SC07_006_jr_8016AE5C.c index a79ef24acd..b582e38d00 100644 --- a/src/ov_SC07_006/ov_SC07_006_jr_8016AE5C.c +++ b/src/ov_SC07_006/ov_SC07_006_jr_8016AE5C.c @@ -4404,7 +4404,61 @@ void func_8016E728(u8 *a0) { DEFINE_func_8016E778() /* dedup: shared engine-core @0x8016e778 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_006/nonmatchings/ov_SC07_006_jr_8016AE5C", func_8016E7C8); +extern s32 func_80017DC4(void *a0, void *a1); + +// @class: regalloc-order +// @stuck: none — MATCH (74 ins); register pin $s2 forces &prim into a saved reg (§17) + + /* 0x08 */ + /* 0x20 */ + +typedef struct { + SVECTOR v[4]; /* 0x00 */ + s32 f0, f1, f2, f3, f4, f5; /* 0x20..0x37 */ + u8 f6; /* 0x38 */ + u8 pad[7]; /* -> 0x40 */ +} Prim_8016E7C8_8016E7C8; + + +void func_8016E7C8(int param_1, short *param_2, unsigned int *param_3) +{ + extern void func_8004914C(void *a0); + extern void func_800491AC(void *a0); + extern void RotTransSV(s32, s32, void*); + extern void func_80016ED4(void *a0); + extern SVECTOR D_8018D758[4]; + extern s32 D_8018D778; + extern s32 D_8018D780; + extern s32 D_8018D788; + extern s32 D_8018D790; + + Prim_8016E7C8_8016E7C8 prim; + MATRIX_c2 m; + SVECTOR tmp; + register Prim_8016E7C8_8016E7C8 *pp __asm__("$18"); /* $s2 — force &prim into a saved reg */ + + ((void (*)(void *, void *))func_80017DC4)(param_2, &m); + m.t[0] = *(short *)(param_1 + 6); + m.t[1] = *(short *)(param_1 + 10); + m.t[2] = *(short *)(param_1 + 14); + func_8004914C(&m); + func_800491AC(&m); + pp = &prim; + ((void (*)(void *, void *, void *))RotTransSV)(&D_8018D758[0], pp, &tmp); + ((void (*)(void *, void *, void *))RotTransSV)(&D_8018D758[1], &prim.v[1], &tmp); + ((void (*)(void *, void *, void *))RotTransSV)(&D_8018D758[2], &prim.v[2], &tmp); + ((void (*)(void *, void *, void *))RotTransSV)(&D_8018D758[3], &prim.v[3], &tmp); + prim.v[0].vz = 3; + prim.f5 = 0x50000000; + prim.f0 = D_8018D778; + prim.f1 = D_8018D780; + prim.f2 = D_8018D788; + prim.f3 = D_8018D790; + prim.f4 = *param_3; + prim.f6 = 0x27; + func_80016ED4(pp); +} + DEFINE_func_8016E8F0() /* dedup: shared engine-core @0x8016e8f0 (src/shared) */ diff --git a/src/ov_SC07_006/ov_SC07_006_jr_8017BEBC.c b/src/ov_SC07_006/ov_SC07_006_jr_8017BEBC.c index ef4b141e7b..f0325e3d25 100644 --- a/src/ov_SC07_006/ov_SC07_006_jr_8017BEBC.c +++ b/src/ov_SC07_006/ov_SC07_006_jr_8017BEBC.c @@ -159,7 +159,6 @@ extern void func_8012A018(s32 a0, s32 a1); extern u16 D_80126B5E; extern u16 D_80126B62; extern u16 D_80126B66; -extern s16 D_80126940; extern s16 D_80126942; extern s16 D_80126944; extern void *memcpy(void *, const void *, unsigned int); @@ -227,7 +226,6 @@ extern void func_8012AD80(s32 a0); extern void func_8012ADE4(u8 *a0); extern s32 *D_80126B78; extern s32 *D_80126B90; -extern s32 D_80126B58; extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3); extern s32 func_80013478(s32 a0, s32 a1); extern s32 func_8012AE00(s32 a0); @@ -3768,7 +3766,32 @@ void func_8017D0F4(void *a0) { } -INCLUDE_ASM("asm/ov_SC07_006/nonmatchings/ov_SC07_006_jr_8017BEBC", func_8017D130); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D130; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D4E4(s32 param_1, s16 *param_2); + +void func_8017D130(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_8018DF0C[]; + extern Blk8_80126940_8017D130 D_80126940; + Blk8_80126940_8017D130 sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_8018DF0C[t]; + } + sp10 = D_80126940; + func_8017D4E4(a0, sp10.v); +} + INCLUDE_ASM("asm/ov_SC07_006/nonmatchings/ov_SC07_006_jr_8017BEBC", func_8017D1D0); diff --git a/src/ov_SC07_007/ov_SC07_007.c b/src/ov_SC07_007/ov_SC07_007.c index 428fd5658c..9f708b38c9 100644 --- a/src/ov_SC07_007/ov_SC07_007.c +++ b/src/ov_SC07_007/ov_SC07_007.c @@ -411,7 +411,28 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128c14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_007/nonmatchings/ov_SC07_007", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_801831E0[]; + extern s32 D_801C5348; + s16 idx = D_801831E0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801C5348, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC07_007/nonmatchings/ov_SC07_007", func_80128CFC); @@ -1067,7 +1088,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012b70c (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012b744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_007/nonmatchings/ov_SC07_007", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012b864 (src/shared) */ diff --git a/src/ov_SC07_007/ov_SC07_007_jr_80140608.c b/src/ov_SC07_007/ov_SC07_007_jr_80140608.c index 511baaeaf0..8de4456e41 100644 --- a/src/ov_SC07_007/ov_SC07_007_jr_80140608.c +++ b/src/ov_SC07_007/ov_SC07_007_jr_80140608.c @@ -3097,7 +3097,84 @@ INCLUDE_ASM("asm/ov_SC07_007/nonmatchings/ov_SC07_007_jr_80140608", func_80146A6 DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146ab4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_007/nonmatchings/ov_SC07_007_jr_80140608", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146b9c (src/shared) */ diff --git a/src/ov_SC07_007/ov_SC07_007_jr_8016AE5C.c b/src/ov_SC07_007/ov_SC07_007_jr_8016AE5C.c index 5327b54f0f..d988ce7d9e 100644 --- a/src/ov_SC07_007/ov_SC07_007_jr_8016AE5C.c +++ b/src/ov_SC07_007/ov_SC07_007_jr_8016AE5C.c @@ -4392,7 +4392,61 @@ void func_8016E728(u8 *a0) { DEFINE_func_8016E778() /* dedup: shared engine-core @0x8016e778 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_007/nonmatchings/ov_SC07_007_jr_8016AE5C", func_8016E7C8); +extern s32 func_80017DC4(void *a0, void *a1); + +// @class: regalloc-order +// @stuck: none — MATCH (74 ins); register pin $s2 forces &prim into a saved reg (§17) + + /* 0x08 */ + /* 0x20 */ + +typedef struct { + SVECTOR v[4]; /* 0x00 */ + s32 f0, f1, f2, f3, f4, f5; /* 0x20..0x37 */ + u8 f6; /* 0x38 */ + u8 pad[7]; /* -> 0x40 */ +} Prim_8016E7C8_8016E7C8; + + +void func_8016E7C8(int param_1, short *param_2, unsigned int *param_3) +{ + extern void func_8004914C(void *a0); + extern void func_800491AC(void *a0); + extern void RotTransSV(s32, s32, void*); + extern void func_80016ED4(void *a0); + extern SVECTOR D_8018627C[4]; + extern s32 D_8018629C; + extern s32 D_801862A4; + extern s32 D_801862AC; + extern s32 D_801862B4; + + Prim_8016E7C8_8016E7C8 prim; + MATRIX_c2 m; + SVECTOR tmp; + register Prim_8016E7C8_8016E7C8 *pp __asm__("$18"); /* $s2 — force &prim into a saved reg */ + + ((void (*)(void *, void *))func_80017DC4)(param_2, &m); + m.t[0] = *(short *)(param_1 + 6); + m.t[1] = *(short *)(param_1 + 10); + m.t[2] = *(short *)(param_1 + 14); + func_8004914C(&m); + func_800491AC(&m); + pp = &prim; + ((void (*)(void *, void *, void *))RotTransSV)(&D_8018627C[0], pp, &tmp); + ((void (*)(void *, void *, void *))RotTransSV)(&D_8018627C[1], &prim.v[1], &tmp); + ((void (*)(void *, void *, void *))RotTransSV)(&D_8018627C[2], &prim.v[2], &tmp); + ((void (*)(void *, void *, void *))RotTransSV)(&D_8018627C[3], &prim.v[3], &tmp); + prim.v[0].vz = 3; + prim.f5 = 0x50000000; + prim.f0 = D_8018629C; + prim.f1 = D_801862A4; + prim.f2 = D_801862AC; + prim.f3 = D_801862B4; + prim.f4 = *param_3; + prim.f6 = 0x27; + func_80016ED4(pp); +} + DEFINE_func_8016E8F0() /* dedup: shared engine-core @0x8016e8f0 (src/shared) */ diff --git a/src/ov_SC07_007/ov_SC07_007_jr_80171B4C.c b/src/ov_SC07_007/ov_SC07_007_jr_80171B4C.c index 4c7544c7df..e19d8af0bc 100644 --- a/src/ov_SC07_007/ov_SC07_007_jr_80171B4C.c +++ b/src/ov_SC07_007/ov_SC07_007_jr_80171B4C.c @@ -4254,7 +4254,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC07_007/nonmatchings/ov_SC07_007_jr_80171B4C", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // KEY FINDINGS (reusable): // * Base MUST be `s32`, and the index expr written OFFSET-FIRST (`((p<<16)>>14) + st + 0x18`) — a `u8*` base diff --git a/src/ov_SC07_008/ov_SC07_008.c b/src/ov_SC07_008/ov_SC07_008.c index 4d330feef0..b479da92d4 100644 --- a/src/ov_SC07_008/ov_SC07_008.c +++ b/src/ov_SC07_008/ov_SC07_008.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_008/nonmatchings/ov_SC07_008", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017D5B0[]; + s16 idx = D_8017D5B0[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_80194138, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC07_008/nonmatchings/ov_SC07_008", func_80128CFC); diff --git a/src/ov_SC07_008/ov_SC07_008_after.c b/src/ov_SC07_008/ov_SC07_008_after.c index 6c7e8002ac..d254df2599 100644 --- a/src/ov_SC07_008/ov_SC07_008_after.c +++ b/src/ov_SC07_008/ov_SC07_008_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC07_008/nonmatchings/ov_SC07_008_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_008/nonmatchings/ov_SC07_008_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC07_008/ov_SC07_008_jr_8012ACE0.c b/src/ov_SC07_008/ov_SC07_008_jr_8012ACE0.c index c3d8ca888e..be76339028 100644 --- a/src/ov_SC07_008/ov_SC07_008_jr_8012ACE0.c +++ b/src/ov_SC07_008/ov_SC07_008_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_008/nonmatchings/ov_SC07_008_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC07_008/ov_SC07_008_jr_801734BC.c b/src/ov_SC07_008/ov_SC07_008_jr_801734BC.c index abbf92a56c..313b4e2369 100644 --- a/src/ov_SC07_008/ov_SC07_008_jr_801734BC.c +++ b/src/ov_SC07_008/ov_SC07_008_jr_801734BC.c @@ -3171,7 +3171,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC07_008/nonmatchings/ov_SC07_008_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC07_008/ov_SC07_008_jr_8017BEBC.c b/src/ov_SC07_008/ov_SC07_008_jr_8017BEBC.c index a0b64b322e..1e80ef486e 100644 --- a/src/ov_SC07_008/ov_SC07_008_jr_8017BEBC.c +++ b/src/ov_SC07_008/ov_SC07_008_jr_8017BEBC.c @@ -52,7 +52,6 @@ extern s32 func_80165A50(s32); extern void func_80029514(s32); extern u8 D_800AF630[]; extern u8 D_80078EC0; -extern s32 D_80126B58; extern s32 func_80028FBC(void); extern s32 func_80029000(void); extern s32 func_80028D9C(void); @@ -3248,7 +3247,32 @@ void func_8017D040(void *a0) { } -INCLUDE_ASM("asm/ov_SC07_008/nonmatchings/ov_SC07_008_jr_8017BEBC", func_8017D07C); + +/* 8 bytes, align 2 -> lwl/lwr/swl/swr copy (cookbook §48-C2) */ +typedef struct { + s16 v[4]; +} Blk8_80126940_8017D07C; + +extern u16 func_80148800(s32 *a0); +extern void func_8017D11C(s32 param_1, s16 *param_2); + +void func_8017D07C(s32 a0) { + + extern s32 D_80126B58; + extern s16 D_80180D74[]; + extern Blk8_80126940_8017D07C D_80126940; + Blk8_80126940_8017D07C sp10; + u8 t; + + if (func_80148800(&D_80126B58) & 3) { + t = (*(u8 *)(a0 + 5) + 1) & 1; + *(u8 *)(a0 + 5) = t; + *(s32 *)(a0 + 0x14) = D_80180D74[t]; + } + sp10 = D_80126940; + func_8017D11C(a0, sp10.v); +} + // @class: schedule diff --git a/src/ov_SC07_009/ov_SC07_009.c b/src/ov_SC07_009/ov_SC07_009.c index 508a7d75b5..c35f382c13 100644 --- a/src/ov_SC07_009/ov_SC07_009.c +++ b/src/ov_SC07_009/ov_SC07_009.c @@ -387,7 +387,27 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128C14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_009/nonmatchings/ov_SC07_009", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017E054[]; + s16 idx = D_8017E054[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A17C4, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC07_009/nonmatchings/ov_SC07_009", func_80128CFC); diff --git a/src/ov_SC07_009/ov_SC07_009_after.c b/src/ov_SC07_009/ov_SC07_009_after.c index 785b80a617..9e8600ad5b 100644 --- a/src/ov_SC07_009/ov_SC07_009_after.c +++ b/src/ov_SC07_009/ov_SC07_009_after.c @@ -481,7 +481,84 @@ INCLUDE_ASM("asm/ov_SC07_009/nonmatchings/ov_SC07_009_after", func_80146A6C); DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146AB4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_009/nonmatchings/ov_SC07_009_after", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146B9C (src/shared) */ diff --git a/src/ov_SC07_009/ov_SC07_009_jr_8012ACE0.c b/src/ov_SC07_009/ov_SC07_009_jr_8012ACE0.c index 1f6e622196..cc78843eb7 100644 --- a/src/ov_SC07_009/ov_SC07_009_jr_8012ACE0.c +++ b/src/ov_SC07_009/ov_SC07_009_jr_8012ACE0.c @@ -327,7 +327,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012B70C (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012B744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_009/nonmatchings/ov_SC07_009_jr_8012ACE0", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012B864 (src/shared) */ diff --git a/src/ov_SC07_009/ov_SC07_009_jr_801734BC.c b/src/ov_SC07_009/ov_SC07_009_jr_801734BC.c index b85dcde233..66cf0d4fae 100644 --- a/src/ov_SC07_009/ov_SC07_009_jr_801734BC.c +++ b/src/ov_SC07_009/ov_SC07_009_jr_801734BC.c @@ -3172,7 +3172,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC07_009/nonmatchings/ov_SC07_009_jr_801734BC", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // @class: regalloc-order diff --git a/src/ov_SC07_010/ov_SC07_010.c b/src/ov_SC07_010/ov_SC07_010.c index de6a4e42db..04db0b9327 100644 --- a/src/ov_SC07_010/ov_SC07_010.c +++ b/src/ov_SC07_010/ov_SC07_010.c @@ -411,7 +411,28 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128c14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_010/nonmatchings/ov_SC07_010", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_80182270[]; + extern s32 D_801A5828; + s16 idx = D_80182270[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_801A5828, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC07_010/nonmatchings/ov_SC07_010", func_80128CFC); @@ -1067,7 +1088,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012b70c (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012b744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_010/nonmatchings/ov_SC07_010", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012b864 (src/shared) */ diff --git a/src/ov_SC07_010/ov_SC07_010_jr_80140608.c b/src/ov_SC07_010/ov_SC07_010_jr_80140608.c index b20bbd9f45..15fc66dc2b 100644 --- a/src/ov_SC07_010/ov_SC07_010_jr_80140608.c +++ b/src/ov_SC07_010/ov_SC07_010_jr_80140608.c @@ -2356,7 +2356,84 @@ INCLUDE_ASM("asm/ov_SC07_010/nonmatchings/ov_SC07_010_jr_80140608", func_80146A6 DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146ab4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_010/nonmatchings/ov_SC07_010_jr_80140608", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146b9c (src/shared) */ diff --git a/src/ov_SC07_010/ov_SC07_010_jr_8016AE5C.c b/src/ov_SC07_010/ov_SC07_010_jr_8016AE5C.c index 9b017bca1b..3d3651cc03 100644 --- a/src/ov_SC07_010/ov_SC07_010_jr_8016AE5C.c +++ b/src/ov_SC07_010/ov_SC07_010_jr_8016AE5C.c @@ -3841,7 +3841,61 @@ void func_8016E728(u8 *a0) { DEFINE_func_8016E778() /* dedup: shared engine-core @0x8016e778 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_010/nonmatchings/ov_SC07_010_jr_8016AE5C", func_8016E7C8); +extern s32 func_80017DC4(void *a0, void *a1); + +// @class: regalloc-order +// @stuck: none — MATCH (74 ins); register pin $s2 forces &prim into a saved reg (§17) + + /* 0x08 */ + /* 0x20 */ + +typedef struct { + SVECTOR v[4]; /* 0x00 */ + s32 f0, f1, f2, f3, f4, f5; /* 0x20..0x37 */ + u8 f6; /* 0x38 */ + u8 pad[7]; /* -> 0x40 */ +} Prim_8016E7C8_8016E7C8; + + +void func_8016E7C8(int param_1, short *param_2, unsigned int *param_3) +{ + extern void func_8004914C(void *a0); + extern void func_800491AC(void *a0); + extern void RotTransSV(void *a0, void *a1, void *a2); + extern void func_80016ED4(void *a0); + extern SVECTOR D_8018530C[4]; + extern s32 D_8018532C; + extern s32 D_80185334; + extern s32 D_8018533C; + extern s32 D_80185344; + + Prim_8016E7C8_8016E7C8 prim; + MATRIX_c2 m; + SVECTOR tmp; + register Prim_8016E7C8_8016E7C8 *pp __asm__("$18"); /* $s2 — force &prim into a saved reg */ + + ((void (*)(void *, void *))func_80017DC4)(param_2, &m); + m.t[0] = *(short *)(param_1 + 6); + m.t[1] = *(short *)(param_1 + 10); + m.t[2] = *(short *)(param_1 + 14); + func_8004914C(&m); + func_800491AC(&m); + pp = &prim; + RotTransSV(&D_8018530C[0], pp, &tmp); + RotTransSV(&D_8018530C[1], &prim.v[1], &tmp); + RotTransSV(&D_8018530C[2], &prim.v[2], &tmp); + RotTransSV(&D_8018530C[3], &prim.v[3], &tmp); + prim.v[0].vz = 3; + prim.f5 = 0x50000000; + prim.f0 = D_8018532C; + prim.f1 = D_80185334; + prim.f2 = D_8018533C; + prim.f3 = D_80185344; + prim.f4 = *param_3; + prim.f6 = 0x27; + func_80016ED4(pp); +} + DEFINE_func_8016E8F0() /* dedup: shared engine-core @0x8016e8f0 (src/shared) */ diff --git a/src/ov_SC07_010/ov_SC07_010_jr_80171B4C.c b/src/ov_SC07_010/ov_SC07_010_jr_80171B4C.c index 32ec2867c9..ed1ff1d8fa 100644 --- a/src/ov_SC07_010/ov_SC07_010_jr_80171B4C.c +++ b/src/ov_SC07_010/ov_SC07_010_jr_80171B4C.c @@ -3701,7 +3701,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC07_010/nonmatchings/ov_SC07_010_jr_80171B4C", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // KEY FINDINGS (reusable): // * Base MUST be `s32`, and the index expr written OFFSET-FIRST (`((p<<16)>>14) + st + 0x18`) — a `u8*` base diff --git a/src/ov_SC07_010/ov_SC07_010_jr_8017AE2C.c b/src/ov_SC07_010/ov_SC07_010_jr_8017AE2C.c index 900068a877..bb0304f8ee 100644 --- a/src/ov_SC07_010/ov_SC07_010_jr_8017AE2C.c +++ b/src/ov_SC07_010/ov_SC07_010_jr_8017AE2C.c @@ -3651,7 +3651,24 @@ void func_8017DE68(void *a0) { } -INCLUDE_ASM("asm/ov_SC07_010/nonmatchings/ov_SC07_010_jr_8017AE2C", func_8017DEA4); + +/* 8-byte, alignment-1 blob: the target copies it with lwl/lwr + swl/swr, + * which is gcc's emit_block_move for align < 4. */ +typedef struct { + char b[8]; +} Blob8_8018A47C_8017DEA4; + +extern void func_8017DEEC(s32, s16*); + +void func_8017DEA4(s32 a0) { + + extern Blob8_8018A47C_8017DEA4 D_801274E8; + Blob8_8018A47C_8017DEA4 tmp; + + tmp = D_801274E8; + ((void (*)(s32, Blob8_8018A47C_8017DEA4 *))func_8017DEEC)(a0, &tmp); +} + // @class: schedule diff --git a/src/ov_SC07_011/ov_SC07_011.c b/src/ov_SC07_011/ov_SC07_011.c index 843f15b4b8..1ea8c42b4a 100644 --- a/src/ov_SC07_011/ov_SC07_011.c +++ b/src/ov_SC07_011/ov_SC07_011.c @@ -411,7 +411,28 @@ void func_80128AF4(void) { DEFINE_func_80128C14() /* dedup: shared engine-core @0x80128c14 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_011/nonmatchings/ov_SC07_011", func_80128C98); + +typedef struct { + s32 word0; + s32 word4; +} CdFileLoc_80128C98; + +extern CdFileLoc_80128C98 cdFileLocTable[]; +extern void func_8001ABBC(s32 a0, s32 a1, void *a2, s32 a3, s32 a4); + +s32 func_80128C98(s32 arg0) { + + extern s16 D_8017E930[]; + extern s32 D_8018DEF0; + s16 idx = D_8017E930[arg0]; + + if (idx >= 0) { + func_8001ABBC(0, 0, (u8 *)&cdFileLocTable[idx], D_8018DEF0, 0); + } else { + return 1; + } +} + INCLUDE_ASM("asm/ov_SC07_011/nonmatchings/ov_SC07_011", func_80128CFC); @@ -1067,7 +1088,55 @@ DEFINE_func_8012B70C() /* dedup: shared engine-core @0x8012b70c (src/shared) */ DEFINE_func_8012B744() /* dedup: shared engine-core @0x8012b744 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_011/nonmatchings/ov_SC07_011", func_8012B77C); + +extern s32 ratan2(s32 a0, s32 a1); +extern s32 func_80047948(s32 a0); /* rsin-like: angle (0..0xFFF) -> 1.12 fixed */ +extern s32 func_8004787C(s32 a0); /* rcos-like: angle (0..0xFFF) -> 1.12 fixed */ + +/* The 4-byte destination is a PACKED PAIR of angles held entirely in ONE saved register + * ($s4) across all three calls — that is what produces the target's + * andi $s4,$s4,0xFFFF (read of the still-uninitialized local, hoisted into the prologue) + * ... or $s4,$s4,ang<<16 -> t.hi = yaw + * ... and $s4,$s4,0xFFFF0000 / or $s4,$s4,ang&0xFFFF -> t.lo = pitch + * A `struct { s16 lo, hi; }` has align 2 -> BLKmode-ish handling: gcc spills it to the stack + * and stores it with lwl/lwr + swl/swr (54 ins, 53 mismatched). Two 16-bit BITFIELDS in a + * u32 container give the SImode, align-4 struct gcc keeps in a register. */ +typedef struct { + u32 lo : 16; + u32 hi : 16; +} Ang2_8012B77C_8012B77C; + +/* a0 = destination packed-angle word, a1 = "from" entity, a2 = "to" entity. + * Both entities carry 16.16 fixed-point x/y/z at +0/+4/+8; the s16 reads at +2/+6/+0xA are + * the integer halves. Returns the destination pointer — the return value is REAL: without it + * gcc stores with `sw $s4,0($s3)` (57 ins) instead of the target's + * addu $v0,$s3,$zero ; sw $s4,0($v0) (the return-value copy that the store's base coalesces onto). + * The flattened `dz` reuse at the end is also load-bearing: making the (dz*sin + dx*cos)>>12 + * temp its OWN variable gives it $a1 for the whole chain; reusing `dz` extends that allocno so + * it lands in $s5 exactly as the target does (`sra $s5,$v0,12` / `negu $a1,$s5`), and it also + * demotes dz's priority so the saved-reg order comes out $s3=out, $s4=t, $s5=dz. */ +s32 func_8012B77C(s32 out, s32 from, s32 to) { + Ang2_8012B77C_8012B77C t; + s32 dx, dy, dz; + s32 ang; + s32 r1, r2; + + dz = *(s16 *)(to + 0xA) - *(s16 *)(from + 0xA); + dx = *(s16 *)(to + 0x2) - *(s16 *)(from + 0x2); + dy = *(s16 *)(to + 0x6) - *(s16 *)(from + 0x6); + + ang = (ratan2(-dz, dx) - 0x400) & 0xFFF; + t.hi = ang; + + r1 = func_80047948(ang); + r2 = func_8004787C(ang); + dz = (dz * r1 + dx * r2) >> 12; + t.lo = ratan2(dy, -dz); + + *(Ang2_8012B77C_8012B77C *)out = t; + return out; +} + DEFINE_func_8012B864() /* dedup: shared engine-core @0x8012b864 (src/shared) */ diff --git a/src/ov_SC07_011/ov_SC07_011_jr_80140608.c b/src/ov_SC07_011/ov_SC07_011_jr_80140608.c index 5d3648f6fb..118939bb0c 100644 --- a/src/ov_SC07_011/ov_SC07_011_jr_80140608.c +++ b/src/ov_SC07_011/ov_SC07_011_jr_80140608.c @@ -3099,7 +3099,84 @@ INCLUDE_ASM("asm/ov_SC07_011/nonmatchings/ov_SC07_011_jr_80140608", func_80146A6 DEFINE_func_80146AB4() /* dedup: shared engine-core @0x80146ab4 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_011/nonmatchings/ov_SC07_011_jr_80140608", func_80146AFC); +extern s32 func_80146B9C(void * arg0); + +/* func_80146AFC — ASCENDING twin of the byte-proven DEFINE_func_80146B9C() + * in src/shared/engine_core.h (cookbook §71: find the already-matched sibling first). + * Same 0x58-stride slot table (base D_8011D030), same 7-store copy body in the same + * order, same $a2/$a1 giv pair. 80146B9C walks DOWN; this one walks UP, so the guard + * is `p < end`, end = p + 0xA50 (30 slots x 0x58). + * + * DECAY ROOT CAUSE (this redraft): the stored backlog draft had been rewritten to + * `void func_80146AFC(...)`, which drops BOTH `return 0` paths' `addu $v0,$zero,$zero` + * and the hit path's `j .L80146B94` => LENGTH-DRIFT -2 (38 vs 40) plus $v0/$v1 regalloc + * drift on the final lw/sw pair. Restoring the s32 return type (the fleet spelling the + * banked sibling func_80146B9C already uses) restores MATCH at 40/40. + * + * RECONCILE (2026-08-01) — the whole-binary gate failed with + * ov_SC01_077_after.c:592: conflicting types for `D_8011D030' (previous decl :564) + * TWO file-scope collisions were present; both are fixed HERE, with NO edit to + * src/shared/engine_core.h and NO change to the generated code (re-verified MATCH + * after each step): + * + * 1. D_8011D030 (the reported one). DEFINE_func_801469C8() emits + * `extern s32 D_8011D030;` at FILE scope (engine_core.h:10811, above the + * `s32 func_801469C8(...) {` line), and this TU expands that macro at :564 — + + extern s32 D_8011D030; + * i.e. before the splice point :570. The draft's `extern u16` therefore + * redeclared it incompatibly at :592. Conformed to the TU's `extern s32`. + * Codegen-neutral: the sole use is `(u8 *)&D_8011D030`, an address-of, so the + * declared object type never reaches a load/store width (cookbook §20). + * + * 2. func_80146AFC ITSELF (latent, would have surfaced next). DEFINE_func_8014C010() + * (:13510) and DEFINE_func_8014AD30() (:13524) each emit a file-scope + * `extern void func_80146AFC(void *a0);`, and this TU expands them at :1386 and + * :1541 — after the splice — so an `s32 func_80146AFC` definition collides on the + * RETURN axis. Fixed with the §37/§124 ASM-LABEL ALIAS: the C identifier is + * aF80146AFC, the emitted label is func_80146AFC, so the canonical void decl and + * this s32 definition never share a namespace. Callers discard the result, so the + * void-typed call sites stay codegen-identical. + * + * Both were reproduced and then cleared against the real cpp+cc1-2.7.2 pair using a + * synthetic copy of this TU's declaration environment (.run/uc2/_recon_probe_80146AFC.c): + * the pre-reconcile spelling emits exactly the gate's error pair; the spelling below + * compiles clean. + * + * ORACLE: tools/match_one.py func_80146AFC --c .run/uc2/func_80146AFC.c + * --asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_after -> MATCH (40 ins) + */ + + +s32 aF80146AFC(void *arg0) __asm__("func_80146AFC"); + +s32 aF80146AFC(void *arg0) +{ + register u8 *p __asm__("$6"); + register u8 *q __asm__("$5"); + u8 *end; + p = (u8 *)&D_8011D030; + end = p + 0xA50; + if ((u32)p < (u32)end) { + q = p + 0x30; + do { + if (*(u16 *)p == 0) { + *(s32 *)(q + 0x4) = *(s32 *)((u8 *)arg0 + 0x8); + *(s16 *)p = *(u16 *)((u8 *)arg0 + 0x0); + *(s16 *)(q - 0x2A) = *(u16 *)((u8 *)arg0 + 0x2); + *(s16 *)(q - 0x26) = *(u16 *)((u8 *)arg0 + 0x4); + *(s16 *)(q - 0x22) = *(u16 *)((u8 *)arg0 + 0x6); + *(s32 *)(q - 0x4) = *(s32 *)((u8 *)arg0 + 0xC); + *(s32 *)(q + 0x0) = *(s32 *)((u8 *)arg0 + 0x10); + return (s32)p; + } + p += 0x58; + q += 0x58; + } while ((u32)p < (u32)end); + } + return 0; +} + DEFINE_func_80146B9C() /* dedup: shared engine-core @0x80146b9c (src/shared) */ diff --git a/src/ov_SC07_011/ov_SC07_011_jr_8016AE5C.c b/src/ov_SC07_011/ov_SC07_011_jr_8016AE5C.c index 00d7b6b71d..2ed50da68a 100644 --- a/src/ov_SC07_011/ov_SC07_011_jr_8016AE5C.c +++ b/src/ov_SC07_011/ov_SC07_011_jr_8016AE5C.c @@ -4392,7 +4392,61 @@ void func_8016E728(u8 *a0) { DEFINE_func_8016E778() /* dedup: shared engine-core @0x8016e778 (src/shared) */ -INCLUDE_ASM("asm/ov_SC07_011/nonmatchings/ov_SC07_011_jr_8016AE5C", func_8016E7C8); +extern s32 func_80017DC4(void *a0, void *a1); + +// @class: regalloc-order +// @stuck: none — MATCH (74 ins); register pin $s2 forces &prim into a saved reg (§17) + + /* 0x08 */ + /* 0x20 */ + +typedef struct { + SVECTOR v[4]; /* 0x00 */ + s32 f0, f1, f2, f3, f4, f5; /* 0x20..0x37 */ + u8 f6; /* 0x38 */ + u8 pad[7]; /* -> 0x40 */ +} Prim_8016E7C8_8016E7C8; + + +void func_8016E7C8(int param_1, short *param_2, unsigned int *param_3) +{ + extern void func_8004914C(void *a0); + extern void func_800491AC(void *a0); + extern void RotTransSV(s32, s32, void*); + extern void func_80016ED4(void *a0); + extern SVECTOR D_801819CC[4]; + extern s32 D_801819EC; + extern s32 D_801819F4; + extern s32 D_801819FC; + extern s32 D_80181A04; + + Prim_8016E7C8_8016E7C8 prim; + MATRIX_c2 m; + SVECTOR tmp; + register Prim_8016E7C8_8016E7C8 *pp __asm__("$18"); /* $s2 — force &prim into a saved reg */ + + ((void (*)(void *, void *))func_80017DC4)(param_2, &m); + m.t[0] = *(short *)(param_1 + 6); + m.t[1] = *(short *)(param_1 + 10); + m.t[2] = *(short *)(param_1 + 14); + func_8004914C(&m); + func_800491AC(&m); + pp = &prim; + ((void (*)(void *, void *, void *))RotTransSV)(&D_801819CC[0], pp, &tmp); + ((void (*)(void *, void *, void *))RotTransSV)(&D_801819CC[1], &prim.v[1], &tmp); + ((void (*)(void *, void *, void *))RotTransSV)(&D_801819CC[2], &prim.v[2], &tmp); + ((void (*)(void *, void *, void *))RotTransSV)(&D_801819CC[3], &prim.v[3], &tmp); + prim.v[0].vz = 3; + prim.f5 = 0x50000000; + prim.f0 = D_801819EC; + prim.f1 = D_801819F4; + prim.f2 = D_801819FC; + prim.f3 = D_80181A04; + prim.f4 = *param_3; + prim.f6 = 0x27; + func_80016ED4(pp); +} + DEFINE_func_8016E8F0() /* dedup: shared engine-core @0x8016e8f0 (src/shared) */ diff --git a/src/ov_SC07_011/ov_SC07_011_jr_80171B4C.c b/src/ov_SC07_011/ov_SC07_011_jr_80171B4C.c index 44985655cd..dd5e97cba6 100644 --- a/src/ov_SC07_011/ov_SC07_011_jr_80171B4C.c +++ b/src/ov_SC07_011/ov_SC07_011_jr_80171B4C.c @@ -4255,7 +4255,80 @@ void func_80175DA8(param_1) } -INCLUDE_ASM("asm/ov_SC07_011/nonmatchings/ov_SC07_011_jr_80171B4C", func_80176144); + +/* func_80176144 — RECONCILED variant of .run/uc/func_80176144.c + * + * GATE BLOCKER (whole-binary build, NOT match_one): + * src/ov_SC01_077/ov_SC01_077_jr_801734BC.c:3476: conflicting types for `D_800AF634' + * || previous declaration at :3296 + * + * ROOT CAUSE — a HOISTED file-scope typedef, not a bad signature: + * That TU hoists, at FILE scope, for func_80175DA8: + * :3295 typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; + * :3296 extern S_AF634_80176144 D_800AF634[]; + * :3297 extern S_AF634_80176144 D_800AF638[]; + * The stored draft re-declares the SAME struct shape as a BLOCK-scope typedef + * (rule D — it must travel to the 137 sibling overlays, which have no such + * preamble). A block-scope `typedef struct {...} S_AF634_80176144;` is a DISTINCT type + * from the file-scope one (C has no structural typing), so the block-scope + * `extern S_AF634_80176144 D_800AF634[];` re-declares the symbol incompatibly with the + * in-scope file-scope decl -> hard error. + * Note the earlier block-scope copies in the same TU (:3080 func_80175820, + * :3123 func_801759D8) do NOT error: they precede :3296, so no file-scope decl + * of D_800AF634 is in scope there. Anything AFTER :3296 collides. Our + * definition lands at :3476. That is why only this one fired. + * + * FIX — §37/§124 ASM-LABEL ALIAS applied to the DATA symbols (cookbook §2516: + * "asm-label alias for sibling-decl signedness/proto conflicts ... beats + * reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc"): + * the two objects are reached through PRIVATE C identifiers aAF634 / aAF638 + * carrying __asm__("D_800AF634") / __asm__("D_800AF638"). The emitted + * %hi/%lo relocations are against the same symbols, so codegen is unchanged, + * while the C names can never collide with ANY sibling TU's declaration — + * whether hoisted, block-scope, or absent. No header edit; no src/ edit. + * Strictly better than deleting the local decls (which would bind this + * exemplar to the one TU that happens to hoist them). + * + * The s32 parameter + explicit (s16) narrowing is retained from the stored draft + * (canonical decl in engine_core.h:18985/:4587 is `void func_80176144(s32)`; + * the K&R short param would itself be a conflicting-types error). The (s16) + * narrowing IS the entry `sll $s0,$a0,16 / sra $s0,$s0,16` pair. + * + * Verified: python3 tools/match_one.py func_80176144 --c .run/uc2/func_80176144.c + * --asm-subdir ov_SC01_077/nonmatchings/ov_SC01_077_jr_801734BC -> MATCH (53 ins) + */ + +void func_80176144(s32 a0) +{ + typedef struct { s32 g0; s32 pad[2]; } S_AF634_80176144; /* size 0x0C */ + /* §37 asm-label alias: private C names, canonical relocations. */ + extern S_AF634_80176144 aAF634[] __asm__("D_800AF634"); + extern S_AF634_80176144 aAF638[] __asm__("D_800AF638"); + + extern u8 D_8011F7A8; + extern s16 D_8011F7BC; + extern s16 D_8011F7BE; + + extern s32 func_80178004(s32 a0, s32 a1, s32 a2); + + u32 *slot; + u32 *p; + s16 param_1 = (s16)a0; + + p = (u32 *)(aAF638[param_1].g0 + aAF634[param_1].g0 * 4); + slot = (u32 *)(param_1 * 4 + (s32)&D_8011F7A8); + slot[14] = (u32)p; + /* §5a zero-byte sched fence: without it sched1 hoists the two %hi/lhu global + argument loads above the `sw` of slot[14] (16 mismatches, 0 length drift). */ + __asm__(""); + p = (u32 *)func_80178004((s32)p, + (s16)((*(u16 *)&D_8011F7BC) - 0x17), + (s16)((*(u16 *)&D_8011F7BE) + 0x65)); + slot[16] = (u32)p - 0x14; + p += 5; + aAF634[param_1].g0 += ((s32)p - (s32)slot[14]) >> 2; +} + // KEY FINDINGS (reusable): // * Base MUST be `s32`, and the index expr written OFFSET-FIRST (`((p<<16)>>14) + st + 0x18`) — a `u8*` base diff --git a/src/ov_SC07_011/ov_SC07_011_jr_8017BEBC.c b/src/ov_SC07_011/ov_SC07_011_jr_8017BEBC.c index f24135d77f..27d6589292 100644 --- a/src/ov_SC07_011/ov_SC07_011_jr_8017BEBC.c +++ b/src/ov_SC07_011/ov_SC07_011_jr_8017BEBC.c @@ -159,7 +159,6 @@ extern void func_8012A018(s32 a0, s32 a1); extern u16 D_80126B5E; extern u16 D_80126B62; extern u16 D_80126B66; -extern s16 D_80126940; extern s16 D_80126942; extern s16 D_80126944; extern void *memcpy(void *, const void *, unsigned int); @@ -4018,7 +4017,24 @@ void func_8017D930(void *a0) { } -INCLUDE_ASM("asm/ov_SC07_011/nonmatchings/ov_SC07_011_jr_8017BEBC", func_8017D96C); + +/* 8-byte, alignment-1 blob: the target copies it with lwl/lwr + swl/swr, + * which is gcc's emit_block_move for align < 4. */ +typedef struct { + char b[8]; +} Blob8_8018A47C_8017D96C; + +extern void func_8017D9B4(s32, s16*); + +void func_8017D96C(s32 a0) { + + extern Blob8_8018A47C_8017D96C D_80126940; + Blob8_8018A47C_8017D96C tmp; + + tmp = D_80126940; + ((void (*)(s32, Blob8_8018A47C_8017D96C *))func_8017D9B4)(a0, &tmp); +} + diff --git a/tools/family_remap.py b/tools/family_remap.py index e16483eef5..0175fddbc3 100644 --- a/tools/family_remap.py +++ b/tools/family_remap.py @@ -610,7 +610,41 @@ def _carry_macros(lines, start, end, unit_text): return carried -def _def_head_at(ln, paren_idx): +_TD_CLOSE = re.compile(r'^\}\s*[A-Za-z_]\w*\s*(?:\[[^\]]*\])?\s*;') + + +def _typedef_block_start(lines, j, limit=400): + """Index of the `typedef` line OPENING the multi-line typedef whose CLOSING line is `lines[j]` + (`} Ang2_8012B77C;`), else None — Phase-30 S6b, defect D5. + + extract_unit's preamble backscan reads one line at a time, so a multi-line typedef presents its + CLOSING line first: `}` is not one of the accepted prefixes, the walk stops, and the type never + travels. The sibling then gets `Ang2_8012B77C undeclared` — MEASURED as 17 zero-crack families / + 24,332 templatable ins, including the 275-member `func_80128C98` (`CdFileLoc`). The old note here + said such functions "route through the engine_types.h lift"; that lift is a separate, heavier + mechanism (a fleet-shared header edit, blast-radius T2) and it was never run for these, so in + practice the class was simply dropped. Carrying the block is blast-radius T0 (draft-only) and + `harvest_verify` already removes a typedef the sibling TU also provides + (`cdecl.strip_provided_typedefs`), so a duplicate cannot break the sibling. + + Only a block that literally BEGINS with `typedef` is carried: a plain struct VARIABLE (`struct + {…} someGlobal;`) closes identically but defining it in the sibling would be a duplicate global.""" + if not _TD_CLOSE.match(lines[j].lstrip()): + return None + depth = 0 + for k in range(j, max(-1, j - limit), -1): + depth += lines[k].count('}') - lines[k].count('{') + if depth == 0: + if re.match(r'^\s*typedef\b', lines[k]): + return k + # brace-on-its-own-line form: `typedef struct` / `{` / … / `} Foo;` + if lines[k].strip() == '{' and k and re.match(r'^\s*typedef\b', lines[k - 1]): + return k - 1 + return None + return None + + +def _def_head_at(ln, paren_idx, more=()): """Does the `func_…(` occurrence whose '(' is at `paren_idx` head a DEFINITION on this line? The old test was "the line does not end in `;`", which is wrong whenever a line holds BOTH a @@ -623,22 +657,39 @@ def _def_head_at(ln, paren_idx): the real definition seven lines below, and every sibling got `redefinition of func_80155FF8`. The correct question is what follows the parameter list: `;` is a declaration, `{` (or end of - line, i.e. the brace-on-its-own-line form) is a definition.""" + line, i.e. the brace-on-its-own-line form) is a definition. + + `more` = the following source lines, so the question can still be answered when the parameter list + WRAPS. The old fallback answered "param list continues past this line -> an ANSI definition", which + is false for a wrapped multi-line DECLARATION (Phase-30 S6a, defect D2): + + extern void func_801466F0(s32 a0, s32 a1, s32 a2, s32 a3, + s32 sp5, s32 sp6, s32 sp7, s32 sp8); + + ov_SC01_077_after.c:457 is exactly that, and it was accepted as a definition head — so extract_unit + returned a 16-line fragment containing NO function body (a neighbouring `DEFINE_func_*()`, an + `#include`, and a comment whose `{ u16, … }` example closed the forward brace scan). Every sibling + of that family failed, and the family read as a 0/137 compiler wall (§110/R35). With `more`, the + list closes on the continuation line and the same `;` vs `{` test gives the right answer.""" depth = 0 - for i in range(paren_idx, len(ln)): - if ln[i] == '(': - depth += 1 - elif ln[i] == ')': - depth -= 1 - if depth == 0: - rest = ln[i + 1:].strip() - rest = re.sub(r'^(/\*.*?\*/|//.*)\s*', '', rest) - if rest == '' or rest.startswith('{'): - return True - if rest.startswith(';'): - return False - return '{' in rest - return True # param list continues past this line -> an ANSI definition + for seg in (ln[paren_idx:],) + tuple(more): + for i, ch in enumerate(seg): + if ch == '(': + depth += 1 + elif ch == ')': + depth -= 1 + if depth == 0: + rest = seg[i + 1:].strip() + rest = re.sub(r'^(/\*.*?\*/|//.*)\s*', '', rest) + if rest == '' or rest.startswith('{'): + return True + if rest.startswith(';'): + return False + return '{' in rest + # The parameter list never closed. Given lookahead that means malformed/unknown input, and + # "unknown" must not be reported as a definition (D2). With no lookahead we genuinely cannot + # tell, so keep the historical answer for any caller not yet passing `more`. + return not more def _foreign_defs(unit_text, addr): @@ -650,7 +701,8 @@ def _foreign_defs(unit_text, addr): since a macro instantiation defines nothing the sibling does not already have.""" self_sym = f"func_{addr:08X}".lower() out = [] - for ln in cdecl._mask(unit_text).split("\n"): + _mlines = cdecl._mask(unit_text).split("\n") + for _li, ln in enumerate(_mlines): for m in re.finditer(r'\bfunc_[0-9A-Fa-f]{8}\s*\(', ln): name = m.group(0).split("(")[0].strip() if name.lower() == self_sym: @@ -662,8 +714,10 @@ def _foreign_defs(unit_text, addr): pre_tail = ln[:m.start()].rsplit(';', 1)[-1] if not re.fullmatch(r'\s*[A-Za-z_][\w \*]*', pre_tail): continue - if not _def_head_at(ln, ln.index('(', m.start())): # a declaration, not a def - continue + # Lookahead (D2): a WRAPPED declaration continues past its line, so without `more` this + # test used to answer "definition" and _foreign_defs would refuse a perfectly good unit. + if not _def_head_at(ln, ln.index('(', m.start()), _mlines[_li + 1:_li + 9]): + continue # a declaration, not a def if name not in out: out.append(name) return out @@ -707,7 +761,12 @@ def extract_unit(ov, addr): unit so the sibling still emits the func_ symbol.""" plain = re.compile(rf'^\s*[A-Za-z_][\w \*]*\bfunc_{addr:08X}\s*\(', re.I) for cf in sorted(glob.glob(f"src/{ov}/{ov}*.c")): - lines = open(cf).read().split("\n") + _raw = open(cf).read() + lines = _raw.split("\n") + # Length- AND line-preserving comment/string blank-out (R33: cdecl._mask is the ONE masking + # oracle). Used for the forward brace scan below, so a `{ u16, … }` inside a documentation + # comment can never close a function body (Phase-30 S6a, the D2 post-mortem). + masked = cdecl._mask(_raw).split("\n") alias_ident, alias_ln = _alias_decl_for(lines, addr) # RE-DERIVE per file: `pat` must never leak an earlier file's alias into a later one. pat = (re.compile(rf'^\s*[A-Za-z_][\w \*]*\b{re.escape(alias_ident)}\s*\(', re.I) @@ -726,21 +785,30 @@ def extract_unit(ov, addr): code = re.sub(r'(/\*.*?\*/|//.*)\s*$', '', ln).rstrip() _m = pat.search(ln) if _m and "INCLUDE_ASM" not in ln and not code.endswith(";") \ - and _def_head_at(ln, ln.index('(', _m.end() - 1)): + and _def_head_at(ln, ln.index('(', _m.end() - 1), lines[i + 1:i + 9]): j = i - 1 - # Grab the fn's own preceding decls: externs, comments, AND single-line typedefs + # Grab the fn's own preceding decls: externs, comments, single-line typedefs # (Phase-26 §8: jr-function bodies define local `typedef struct {…} Foo_;` that - # must template with the body, else the sibling sees `Foo undeclared`. Multi-line - # typedefs aren't carried — those functions route through the engine_types.h lift). + # must template with the body, else the sibling sees `Foo undeclared`) — AND, since + # Phase-30 S6b (D5), MULTI-LINE typedefs, via `_typedef_block_start` (the old note + # here said they "route through the engine_types.h lift"; measured, they routed + # nowhere — 17 families / 24,332 ins were simply dropped). # STOP at a machine-generated FILE-SCOPE decl layer (the §8b carried layer that # jr_isolate_all prepends to an isolated region, or the Phase-17 canonical-sig layer): # those belong to the FILE, not to the first function under them. Absorbing one makes # the unit drag ~140 unrelated externs into every sibling — several naming types the # sibling's TU lacks — and the whole family gate-fails (Phase 26 session 6). while j >= 0 and (lines[j].strip() == "" or j == alias_ln or - lines[j].lstrip().startswith(("extern", "//", "/*", "*", "typedef"))): + lines[j].lstrip().startswith(("extern", "//", "/*", "*", "typedef")) or + _typedef_block_start(lines, j) is not None): if _DECL_LAYER_END.search(lines[j]): break + # D5: a multi-line typedef closes with `} Foo;`. Jump to its `typedef` line so the + # WHOLE block is carried, then keep walking above it. + _tds = _typedef_block_start(lines, j) + if _tds is not None: + j = _tds - 1 + continue # A LINE THAT STARTS WITH `extern` CAN STILL HOLD A DEFINITION (Phase 29 T65). # ov_SC01_077_jr_80154C24.c:1346 is # extern void func_80156044(int, int); int func_80155FF8(int, int) { __asm__ … } @@ -750,14 +818,34 @@ def extract_unit(ov, addr): # via its shared DEFINE_ macro got `redefinition of func_80155FF8`. 137 members, # booked as a compile failure. A pure declaration never contains `{`; a single-line # `typedef struct {…} Foo;` legitimately does, and is still carried. - if "{" in lines[j] and not lines[j].lstrip().startswith("typedef"): + # + # …AND NEITHER DOES A COMMENT (Phase-30 S6a, defect D1). The guard fired on any + # DOCUMENTATION line that merely mentions a brace — `* => { u16, u16, s32 }` — so + # the carry stopped in the MIDDLE of a block comment and the sibling received a + # dangling ` * …` fragment plus an unmatched `*/`: `parse error before 'the'`. + # Comment text cannot hold a definition, so exempt it. (A `/*…*/ int f() {` line + # is code with a leading comment, so only an UNCLOSED `/*` counts as comment-only.) + _ls = lines[j].lstrip() + _comment_only = _ls.startswith(("*", "//")) or (_ls.startswith("/*") and "*/" not in lines[j]) + if "{" in lines[j] and not _ls.startswith("typedef") and not _comment_only: break j -= 1 start = j + 1 + # R32 BACKSTOP for D1: never hand a sibling a DANGLING comment fragment. If the carried + # preamble opens inside a block comment (a `*/` with no `/*` before it) the backscan was + # truncated by something we have not accounted for — drop the fragment and say so, rather + # than emit ` * …` lines as code and let 137 siblings fail as a phantom "wall". + _pre = "\n".join(lines[start:i]) + _close = _pre.find("*/") + if _close != -1 and (_pre.find("/*") == -1 or _pre.find("/*") > _close): + _drop = _pre[:_close + 2].count("\n") + 1 + print(f"[extract_unit] func_{addr:08X} in {ov}: carried preamble opened INSIDE a " + f"block comment — dropping {_drop} dangling line(s) (D1 backstop)") + start = min(start + _drop, i) depth, started, end = 0, False, i for k in range(i, len(lines)): - depth += lines[k].count("{") - lines[k].count("}") - if "{" in lines[k]: + depth += masked[k].count("{") - masked[k].count("}") + if "{" in masked[k]: started = True if started and depth <= 0: end = k