feat(phase-26): h_seq family sweep — 2192 member-matches banked via remap_hseq

This commit is contained in:
Drew T
2026-08-01 12:07:54 -06:00
parent 53a374ed21
commit 9d346f1afa
959 changed files with 111589 additions and 2481 deletions
+118 -2
View File
@@ -2279,7 +2279,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2994,7 +3068,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -994,7 +994,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1904,9 +2039,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1290,13 +1290,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1807,7 +1807,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_80180304[])();
if (*(s16 *)&D_801270C0 != 3) {
D_80180304[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3290,7 +3290,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3576,7 +3627,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_801816C0[];
extern unsigned short D_801816C2[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_801816C0[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_801816C2[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3594,7 +3668,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_801816F0;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_801816F0)[param_2]);
}
}
}
// @class: struct
@@ -5928,7 +6053,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3885,7 +3883,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4249,7 +4303,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4299,7 +4374,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_000/nonmatchings/ov_SC01_000_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_80182138[])(void);
+118 -2
View File
@@ -2279,7 +2279,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2994,7 +3068,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1289,13 +1289,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1827,7 +1827,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_80184F54[])();
if (*(s16 *)&D_801270C0 != 3) {
D_80184F54[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3287,7 +3287,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3573,7 +3624,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_80186310[];
extern unsigned short D_80186312[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_80186310[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_80186312[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3591,7 +3665,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_80186340;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_80186340)[param_2]);
}
}
}
// @class: struct
@@ -5926,7 +6051,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3883,7 +3881,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4247,7 +4301,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4297,7 +4372,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_001/nonmatchings/ov_SC01_001_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_80186D88[])(void);
+118 -2
View File
@@ -2281,7 +2281,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2996,7 +3070,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1289,13 +1289,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1811,7 +1811,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_80180918[])();
if (*(s16 *)&D_801270C0 != 3) {
D_80180918[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3289,7 +3289,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3575,7 +3626,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_80181CD4[];
extern unsigned short D_80181CD6[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_80181CD4[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_80181CD6[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3593,7 +3667,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_80181D04;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_80181D04)[param_2]);
}
}
}
// @class: struct
@@ -5928,7 +6053,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3883,7 +3881,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4247,7 +4301,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4297,7 +4372,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_004/nonmatchings/ov_SC01_004_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_8018274C[])(void);
+118 -2
View File
@@ -2282,7 +2282,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2997,7 +3071,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -978,7 +978,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1888,9 +2023,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1290,13 +1290,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1812,7 +1812,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_80183AAC[])();
if (*(s16 *)&D_801270C0 != 3) {
D_80183AAC[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1344,7 +1344,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3290,7 +3290,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3576,7 +3627,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_80184E68[];
extern unsigned short D_80184E6A[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_80184E68[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_80184E6A[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3594,7 +3668,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_80184E98;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_80184E98)[param_2]);
}
}
}
// @class: struct
@@ -5929,7 +6054,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -470,12 +470,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3884,7 +3882,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4247,7 +4301,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4297,7 +4372,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_005/nonmatchings/ov_SC01_005_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_801858E0[])(void);
+118 -2
View File
@@ -2282,7 +2282,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2997,7 +3071,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -978,7 +978,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1888,9 +2023,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1290,13 +1290,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1812,7 +1812,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_80183AAC[])();
if (*(s16 *)&D_801270C0 != 3) {
D_80183AAC[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1344,7 +1344,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3290,7 +3290,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3576,7 +3627,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_80184E68[];
extern unsigned short D_80184E6A[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_80184E68[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_80184E6A[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3594,7 +3668,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_80184E98;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_80184E98)[param_2]);
}
}
}
// @class: struct
@@ -5929,7 +6054,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -470,12 +470,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3884,7 +3882,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4247,7 +4301,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4297,7 +4372,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_006/nonmatchings/ov_SC01_006_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_801858E0[])(void);
+118 -2
View File
@@ -2281,7 +2281,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2996,7 +3070,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1289,13 +1289,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1811,7 +1811,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_80180E8C[])();
if (*(s16 *)&D_801270C0 != 3) {
D_80180E8C[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3289,7 +3289,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3575,7 +3626,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_80182248[];
extern unsigned short D_8018224A[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_80182248[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_8018224A[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3593,7 +3667,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_80182278;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_80182278)[param_2]);
}
}
}
// @class: struct
@@ -5928,7 +6053,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3883,7 +3881,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4246,7 +4300,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4296,7 +4371,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_008/nonmatchings/ov_SC01_008_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_80182CC0[])(void);
+118 -2
View File
@@ -2281,7 +2281,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2996,7 +3070,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1289,13 +1289,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1811,7 +1811,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_80184074[])();
if (*(s16 *)&D_801270C0 != 3) {
D_80184074[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3289,7 +3289,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3575,7 +3626,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_80185430[];
extern unsigned short D_80185432[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_80185430[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_80185432[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3593,7 +3667,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_80185460;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_80185460)[param_2]);
}
}
}
// @class: struct
@@ -5928,7 +6053,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3883,7 +3881,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4246,7 +4300,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4296,7 +4371,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_009/nonmatchings/ov_SC01_009_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_80185EA8[])(void);
+118 -2
View File
@@ -2281,7 +2281,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2996,7 +3070,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1289,13 +1289,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1812,7 +1812,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_8017FCF4[])();
if (*(s16 *)&D_801270C0 != 3) {
D_8017FCF4[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3289,7 +3289,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3575,7 +3626,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_801810B0[];
extern unsigned short D_801810B2[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_801810B0[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_801810B2[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3593,7 +3667,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_801810E0;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_801810E0)[param_2]);
}
}
}
// @class: struct
@@ -5928,7 +6053,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3883,7 +3881,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4246,7 +4300,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4296,7 +4371,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_074/nonmatchings/ov_SC01_074_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_80181B28[])(void);
+118 -2
View File
@@ -2281,7 +2281,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2996,7 +3070,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1289,13 +1289,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1828,7 +1828,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_80184C54[])();
if (*(s16 *)&D_801270C0 != 3) {
D_80184C54[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3289,7 +3289,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3575,7 +3626,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_80186010[];
extern unsigned short D_80186012[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_80186010[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_80186012[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3593,7 +3667,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_80186040;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_80186040)[param_2]);
}
}
}
// @class: struct
@@ -5928,7 +6053,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3883,7 +3881,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4246,7 +4300,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4296,7 +4371,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_080/nonmatchings/ov_SC01_080_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_80186A88[])(void);
+118 -2
View File
@@ -2281,7 +2281,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2996,7 +3070,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1289,13 +1289,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1812,7 +1812,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_80187F48[])();
if (*(s16 *)&D_801270C0 != 3) {
D_80187F48[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3288,7 +3288,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3574,7 +3625,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_80189304[];
extern unsigned short D_80189306[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_80189304[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_80189306[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3592,7 +3666,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_80189334;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_80189334)[param_2]);
}
}
}
// @class: struct
@@ -5927,7 +6052,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3884,7 +3882,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4247,7 +4301,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4297,7 +4372,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC01_084/nonmatchings/ov_SC01_084_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_80189D7C[])(void);
+118 -2
View File
@@ -2281,7 +2281,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2996,7 +3070,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1289,13 +1289,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1827,7 +1827,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_8018C2F8[])();
if (*(s16 *)&D_801270C0 != 3) {
D_8018C2F8[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3287,7 +3287,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3573,7 +3624,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_8018D6B4[];
extern unsigned short D_8018D6B6[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_8018D6B4[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_8018D6B6[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3591,7 +3665,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_8018D6E4;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_8018D6E4)[param_2]);
}
}
}
// @class: struct
@@ -5926,7 +6051,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3881,7 +3879,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4244,7 +4298,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4294,7 +4369,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_8018E12C[])(void);
+118 -2
View File
@@ -2281,7 +2281,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2996,7 +3070,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1289,13 +1289,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1827,7 +1827,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_8018C2F8[])();
if (*(s16 *)&D_801270C0 != 3) {
D_8018C2F8[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3287,7 +3287,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3573,7 +3624,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_8018D6B4[];
extern unsigned short D_8018D6B6[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_8018D6B4[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_8018D6B6[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3591,7 +3665,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_8018D6E4;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_8018D6E4)[param_2]);
}
}
}
// @class: struct
@@ -5926,7 +6051,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3881,7 +3879,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4244,7 +4298,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4294,7 +4369,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_003/nonmatchings/ov_SC02_003_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_8018E12C[])(void);
+118 -2
View File
@@ -2281,7 +2281,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2996,7 +3070,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1289,13 +1289,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1812,7 +1812,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_8017F3D8[])();
if (*(s16 *)&D_801270C0 != 3) {
D_8017F3D8[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3289,7 +3289,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3575,7 +3626,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_80180794[];
extern unsigned short D_80180796[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_80180794[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_80180796[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3593,7 +3667,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_801807C4;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_801807C4)[param_2]);
}
}
}
// @class: struct
@@ -5928,7 +6053,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3883,7 +3881,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4246,7 +4300,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4296,7 +4371,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_004/nonmatchings/ov_SC02_004_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_8018120C[])(void);
+118 -2
View File
@@ -2281,7 +2281,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2996,7 +3070,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */
+127 -2
View File
@@ -1289,13 +1289,138 @@ DEFINE_func_801372B0() /* dedup: shared engine-core @0x801372B0 (src/shared) */
DEFINE_func_801375EC() /* dedup: shared engine-core @0x801375EC (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_80135D20", func_80137614);
extern void func_801375EC(s32 a0, s16 a1);
// @class: schedule (arg-copy placement) — PIN-FREE
// match_one: MATCH (26 ins). rtu: MATCH (26 ins) with NO //@EDIT and NO header edit.
//
// ---- RECONCILE 2026-08-01 (uc2 -> uc3) ---------------------------------------------------
// GATE ERROR was:
// jr_80135D20.c:1412 conflicting types for func_80137614 || :1362 previous declaration
// :1362 is `DEFINE_func_801375EC()`, whose expansion (src/shared/engine_core.h:2819) carries
// extern void func_80137614(s32 a0, s32 a1, s32 a2);
// and it is instantiated two lines ABOVE this function's INCLUDE_ASM splice point (:1364).
// :1412 is this draft's own definition. So the conflicting symbol is func_80137614 ITSELF
// and the axis is the §73 RETURN type: the shared header says `void`, the target ends
// `addu $v0, $s0, $zero` and callers in other overlays consume the result
// (ov_SC03_099_jr_80178D40.c already declares it `extern s32 func_80137614(s32,s32,s32)`),
// so the definition MUST stay s32. Re-voiding the definition is the decay loop: gcc-2.7.2
// silently drops the $v0 set and you get 25/26 ins, class LENGTH-DRIFT/-1.
//
// ESCAPE USED: §37/§124 ASM-LABEL ALIAS (escape #2). The definition is given a distinct C
// identifier `aF80137614` with __asm__("func_80137614"), so it never collides with the
// header's `extern void func_80137614` while still emitting the canonical symbol. Zero
// header edits, zero TU edits, blast radius 0 — this replaces uc2's //@EDIT §65b de-macroize
// of DEFINE_func_801375EC, which would have had to be repeated at all 138 sweep sites.
// The TU already uses this exact idiom 60-odd lines below
// (`void *aF801376E8(int a0, int a1) __asm__("func_801376E8");`), so it travels to siblings.
// The in-TU call from func_801375EC still binds to the header's extern declaration and
// resolves to the same symbol at link time; func_801375EC's own 10 instructions are unchanged.
//
// ---- CODEGEN (unchanged from uc2 — do not touch) -----------------------------------------
// Residual before the lever: 4 mismatched, the (sw $sN / addu $sN,$aX) prologue PAIRS mirrored —
// target births $s2<-a2 then $s3<-a1; the naive draft births $s3<-a1 then $s2<-a2 (parm order),
// and drags `sw $s3` above `sw $s2` with it. Register ASSIGNMENT was already right in both, so
// this is NOT a regalloc problem. Measured INERT: body statement order, extra plain locals,
// K&R parm-declaration order (incl. declaring a2 before a1 in the K&R decl block).
//
// LEVER — cookbook §67 (arg-copy PLACEMENT). One zero-instruction launder of the a1 parameter
// pins WHERE its entry copy materialises; a2's copy then takes the earlier slot and the register
// saves fall back into ascending order. DIRECTION MATTERS and is the opposite of the intuition:
// laundering a2 (the copy that must move EARLIER) is inert — launder the copy that must land
// LATER. §67 rule 1 respected: the laundered local is NOT pinned. A pinned variant
// (register s32 __asm__("$18") / __asm__("$19") on a2/a1) also MATCHes, but pins are strictly
// worse for the ×138 family sweep (§42e/§86 pin guard), so the pin-free single launder is banked.
//
// Shape copied from the matched next-door sibling DEFINE_func_8013767C() (engine_core.h),
// which is this function minus the 0xD8 mask and the +0x1C halfword store.
extern s32 func_801399A8(void);
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
s32 aF80137614(s32 a0, s32 a1, s32 a2) __asm__("func_80137614");
s32 aF80137614(s32 a0, s32 a1, s32 a2)
{
s32 v1, s0;
__asm__("" : "=r"(v1) : "0"(a1));
s0 = func_801399A8();
if (s0 != 0) {
func_801377B4(a0, a2 & 0xD8, s0);
*(s16 *)(s0 + 0x1C) = v1;
}
return s0;
}
DEFINE_func_8013767C() /* dedup: shared engine-core @0x8013767C (src/shared) */
DEFINE_func_801376C8() /* dedup: shared engine-core @0x801376C8 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_80135D20", func_801376E8);
/* @class: plumbing (globals-around-two-calls)
* @stuck: none — MATCH (51 ins).
*
* RECONCILE (§37/§124 ASM-LABEL ALIAS) — no TU / header edit required.
* Gate error: ov_SC01_077_jr_80135D20.c:1415: conflicting types for `func_801376E8'
* || previous declaration at :1368
* :1368 is DEFINE_func_801376C8(), the shared engine-core macro that carries
* `extern void func_801376E8(int a0, int a1);` — a VOID return. The target's last
* pre-epilogue instruction is `addu $v0, $s1, $zero`, i.e. it RETURNS &D_801269F0,
* so the definition MUST be non-void; a `void` definition makes gcc-2.7.2 merely warn
* and DROP the returned value, killing that instruction (LENGTH-DRIFT/-1, 50 ins).
* The conflict is on func_801376E8 ITSELF and is a pure RETURN-type disagreement
* (params already agree: int,int), so the §37/§124 alias applies verbatim:
* define under the C name aF801376E8 with __asm__("func_801376E8") so the C-level
* declaration never collides, while the emitted symbol is still func_801376E8.
* Codegen is untouched — an asm label renames the symbol, nothing else.
* (The earlier draft's `//@EDIT` widening of the shared extern to `void *` is a
* T2 fleet-shared edit; the alias is T0 draft-only. Cookbook §124: fix the reader,
* not the source.)
*
* Byte levers (unchanged from the passing draft):
* - `obj` local holding (s32)&D_801269F0: the address is CSEd ONCE into $s1 and reused
* for both jal args and the return (same idiom as the neighbouring func_80137B80).
* - D_80126A24 is s16 (`lh`) but D_80126A26 is u16 (`lhu`) with an explicit (s16) cast
* at the use site: gcc combines the cast's `sll 16; sra 16` with the `>>1` into
* `sll 16; sra 17`, which is exactly what the target emits. A plain s16 D_80126A26
* would give `lh; sra 1` instead.
* - D_80126A14 as u16[2] (`lhu` loads, `%lo(D_80126A14 + 0x2)` for element 1).
*/
extern void func_801377B4(s32 a0, s32 a1, s32 a2);
extern void func_80139BE0(s32 a0);
void *aF801376E8(int a0, int a1) __asm__("func_801376E8");
void *aF801376E8(int a0, int a1)
{
extern s32 D_801269F0;
extern u8 D_801269FD;
extern u16 D_80126A14[];
extern s16 D_80126A1C;
extern s16 D_80126A20;
extern s16 D_80126A22;
extern s16 D_80126A24;
extern u16 D_80126A26;
u16 *p = (u16 *)a1;
s32 obj = (s32)&D_801269F0;
func_801377B4(a0, 0x6200, obj);
D_80126A1C = 0x1C;
D_801269FD = 0;
if (p != 0) {
D_80126A14[0] = p[0];
D_80126A14[1] = p[1];
}
func_80139BE0(obj);
D_80126A20 = (D_80126A14[0] + 0x28) - ((D_80126A24 + 0x28) >> 1);
D_80126A22 = D_80126A14[1] - ((s16)D_80126A26 >> 1);
return (void *)obj;
}
DEFINE_func_801377B4() /* dedup: shared engine-core @0x801377B4 (src/shared) */
+22 -1
View File
@@ -1812,7 +1812,28 @@ void func_801429C4(int param_1)
}
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_80140608", func_80142A10);
// @class: struct
// @stuck: none — MATCH (array-of-fnptr %lo-fold + signed-halfword guard)
// @reconcile: func_80142A80 is DEFINED later in this TU as `void func_80142A80(void)`.
// The uc2 draft declared it `extern void func_80142A80(int)` -> conflicting types.
// Escape §17a-1/§20: conform the declaration to the TU's, cast at the use site
// (codegen-neutral: the argument still lands in $a0).
extern void func_80142A80(void);
void func_80142A10(int param_1)
{
extern void (*D_80191FDC[])();
if (*(s16 *)&D_801270C0 != 3) {
D_80191FDC[*(u16 *)(param_1 + 2)]();
if (*(s16 *)(param_1 + 0xFC) != 0) {
((void (*)(int))func_80142A80)(param_1);
}
}
}
// @class: struct
+56 -1
View File
@@ -1343,7 +1343,62 @@ DEFINE_func_801564B0() /* dedup: shared engine-core @0x801564B0 (src/shared) */
DEFINE_func_801565C0() /* dedup: shared engine-core @0x801565C0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_80154C24", func_80156600);
// @class: MATCH (18 ins) — match_one, asm-subdir asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_80154C24
//
// RECONCILE (uc2 -> uc3). The body is UNCHANGED and still MATCHes; only the declaration
// environment moved.
//
// Gate error: `conflicting types for func_80156600 || previous declaration`. The conflicting
// symbol is func_80156600 ITSELF. ov_SC01_077_jr_80154C24.c:1747 instantiates
// DEFINE_func_80157EA4(), whose macro body (src/shared/engine_core.h:11395) carries
// extern s32 func_80156600(void *a0);
// and calls it at engine_core.h:11409 as `v1 = (s32 *)func_80156600(a0);`.
// The byte-true body is NULLARY — the target zeroes $a0 at entry and uses it as the loop
// counter — so `s32 (void)` vs the header's `s32 (void *)` is a PARAM/ARITY disagreement on
// our own definition. Neither declaration can be changed: the header decl is fleet-shared
// (137 siblings instantiate the same macro), and adding a phantom `void *` parameter to the
// definition perturbs the $a0 allocation.
//
// Escape: §37/§124 ASM-LABEL ALIAS. The definition is given the private C name aF80156600
// and the assembler label "func_80156600", so it never collides with the canonical
// declaration while still emitting the required symbol for the macro's call site. Zero
// header edits, zero codegen change (verified: cc1 on the real spliced TU is diagnostic-free,
// and match_one still prints MATCH). This declaration MUST travel with the body.
//
// Everything else is as in uc2: externs at BLOCK scope (rule D — keeps the bank travellable to
// the 137 siblings; the sibling func_80156670 declares the same two symbols at function scope
// in the same TU at :1427/:1432), and D_80126AF0 typed as plain u8[] because the body only
// ever does pointer arithmetic on it (+8/entry) — the file-scope `extern S8 D_80126AF0[];`
// form needs engine_types.h, which common.h does not pull in.
//
// Codegen shape: a counter in $a0, a byte cursor $a1 walking D_80126AF0 by 8, a word cursor
// $v1 walking D_801151E0 by 4; the `addu $v0,$a1,$zero` return value sits in the bnez delay
// slot, and the loop fallthrough re-zeroes $v0 for the not-found return.
s32 aF80156600(void) __asm__("func_80156600");
s32 aF80156600(void)
{
extern u8 D_80126AF0[];
extern s32 D_801151E0[];
s32 i;
u8 *p;
s32 *q;
i = 0;
p = &D_80126AF0[0];
q = &D_801151E0[0];
do {
if (*q & 1) {
return (s32)p;
}
p += 8;
i += 1;
q += 1;
} while ((u32)i < 3);
return 0;
}
DEFINE_func_80156648() /* dedup: shared engine-core @0x80156648 (src/shared) */
+144 -4
View File
@@ -3287,7 +3287,58 @@ DEFINE_func_80161278() /* dedup: shared engine-core @0x80161278 (src/shared) */
DEFINE_func_801612B8() /* dedup: shared engine-core @0x801612B8 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_8015C32C", func_8016130C);
extern void func_80161240(void *a0);
extern s32 func_801612B8(void * a0, s32 a1);
#define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
#define SHB(x) __asm__("" : "=r"(x) : "0"(x))
extern void func_801599A4(void*);
extern void func_8015BDD0(s32*);
extern void func_8015BF48(s32*);
/* REDRAFT (decay axis: RETURN TYPE). The stored draft had been flipped to
* `void` to fit the fleet header decl in src/shared/engine_core.h, while the
* body still `return 1; / return 0;`. gcc-2.7.2 silently drops the $v0 sets in
* that situation, costing the three `addiu $v0, $zero, 1` / `addu $v0,$zero,$zero`
* instructions the ASM plainly has. Restored to s32 (§109/§85 — the single call
* site `func_8016130C(a0, func_801612B8(a0, 1));` discards the result, so the
* void->s32 widen is caller-neutral and must be fixed on the HEADER side). */
/* RECONCILE (§37/§124 asm-label alias — zero header touch).
* Gate error: jr_8015C32C.c:3501 conflicting types for `func_8016130C'
* :3479 previous declaration.
* TU line 3479 is `DEFINE_func_80161240()`, whose expansion (engine_core.h:3781)
* declares `extern void func_8016130C(void *a0, s32 a1);` — a RETURN-TYPE
* disagreement with this draft's required `s32`. The third line the gate quoted
* (:5228 "location of previous definition") is unrelated noise: it is the
* pre-existing `#define SHB(x)` redefinition *warning* between TU lines 5227 and
* 5538, present with or without this draft.
* Fix: the C identifier becomes aF8016130C, so it never collides with the
* canonical `void func_8016130C` declaration, while the GNU asm label makes the
* EMITTED symbol `func_8016130C`. The macro's caller func_80161240 keeps calling
* the `extern void` spelling and is byte-unaffected (it discards the return).
* Codegen for this function is untouched — match_one still MATCH.
* (Alternative, house style, NOT taken here per the no-header-edit rule: widen
* src/shared/engine_core.h:3781 to `extern s32 func_8016130C(void *a0, s32 a1);`
* and rename back to the plain name — byte-identical either way.) */
s32 aF8016130C(void *a0, s32 a1) __asm__("func_8016130C");
s32 aF8016130C(void *a0, s32 a1)
{
if ((a1 == 0) || (a1 == 0x8000)) {
func_801599A4(a0);
((void (*)(void *))func_8015BDD0)(a0);
return 1;
}
if ((a1 & 0x4000) != 0) {
func_801599A4(a0);
((void (*)(void *))func_8015BF48)(a0);
return 1;
}
return 0;
}
// @class: schedule
@@ -3573,7 +3624,30 @@ DEFINE_func_80161B84() /* dedup: shared engine-core @0x80161B84 (src/shared) */
DEFINE_func_80161BE0() /* dedup: shared engine-core @0x80161BE0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_8015C32C", func_80161C24);
extern void func_80147324();
/* RECONCILE (§17a-1/§20): the TU already declares
* extern void func_80161C24(s32, s32); (jr_8015C32C.c:1474 / :1417)
* so the definition must use (int, int); the unsigned semantics of param_2
* are restored by a cast at each use (codegen-neutral: sltiu + index math). */
void func_80161C24(int param_1, int param_2)
{
extern unsigned short D_80193398[];
extern unsigned short D_8019339A[];
if ((unsigned int)param_2 < 8) {
if (*(u8 *)(param_1 + 0xDA) != 0) {
func_80147324(D_80193398[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 0;
} else {
func_80147324(D_8019339A[(unsigned int)param_2 * 2]);
*(u8 *)(param_1 + 0xDA) = 1;
}
}
}
// @class: struct
@@ -3591,7 +3665,58 @@ void func_80161C98(int param_1, u32 param_2)
}
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_8015C32C", func_80161CD0);
// @class: plumbing
// @stuck: none — MATCH (20 ins)
// DECAY AXIS: return type. The stored draft declared `s32 func_80161CD0(...)` with no
// return statement. That kept $v0 live-out at the epilogue, so gcc-2.7.2's delayed-branch
// pass refused to speculatively fill the second `beqz $v0` delay slot from the fall-through
// with `sll $v0, $s0, 1` — costing one extra nop (21 vs 20 ins) and shifting both branch
// displacements. Declaring the function `void` makes $v0 dead at the return and the fill
// happens. Same return-type axis as the wave, opposite direction (s32 -> void).
// param_2 must be UNSIGNED: the guard assembles as `sltiu $v0, $s0, 0x8`.
//
// RECONCILE (§37/§124 asm-label alias) — the ONLY change vs the uc2 draft; the body is
// byte-identical and untouched.
// The real TU src/ov_SC01_077/ov_SC01_077_jr_8015C32C.c already carries the m2c canonical
// declaration
// :23 extern s32 func_80161CD0(s32 a0, s32 a1); /* match-first, arity 2 */
// :1207 extern s32 func_80161CD0(s32 a0, s32 a1);
// so a plain `void func_80161CD0(int, unsigned int)` definition dies with
// conflicting types for `func_80161CD0' / previous declaration ... (rtu_match CC1 FAIL).
// This is the RETURN axis (s32 vs void) plus the param-2 signedness axis, and BOTH spellings
// are load-bearing for the 20-instruction codegen — conforming the definition to the
// declaration (escape #1) would perturb bytes, so it is not available here.
// The alias fixes it at T0: the C identifier is aF80161CD0 (no declaration to collide with)
// while the EMITTED SYMBOL is func_80161CD0. In-TU callers keep using the `extern s32`
// spelling and are byte-unaffected (they discard the return). Zero tracked files touched;
// no header edit is even possible/needed — grep shows func_80161CD0 has NO declaration in
// include/ or src/shared/, the conflict is purely TU-local m2c boilerplate.
// Exactly the pattern already banked at src/ov_SC03_099/ov_SC03_099_jr_8015C32C.c:3503
// for the sibling func_8016191C.
//
// NOTE on the third gate diagnostic (`:5223 note: location of previous definition`): that is
// a RED HERRING, unrelated to this function. It is the pre-existing CPP note paired with
// `:5533 warning: "SHB" redefined` — the TU defines the SHB scheduling-barrier macro twice
// (post-splice :5222 with __volatile__, :5533 without). It is a warning, present with or
// without this draft, and it does not fail cc1.
extern int func_800CF8B4();
extern void func_80147324(int arg0);
void aF80161CD0(int param_1, unsigned int param_2) __asm__("func_80161CD0");
void aF80161CD0(int param_1, unsigned int param_2)
{
extern unsigned short D_801933C8;
if (param_2 < 8) {
if (func_800CF8B4() != 0) {
func_80147324((&D_801933C8)[param_2]);
}
}
}
// @class: struct
@@ -5926,7 +6051,22 @@ void func_80168AA8(void *a0) {
DEFINE_func_80168AE4() /* dedup: shared engine-core @0x80168AE4 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_8015C32C", func_80168B70);
extern void func_80168BDC(s32 a0, s32 a1, s32 a2, s32 a3);
/* Conform to the TU's canonical decl (jr_8015C32C.c:5546 `extern void func_80146C3C(void);`)
* and cast at the use site — same escape the TU already uses at :6388. Codegen-neutral. */
extern void func_80146C3C(void);
void func_80168B70(s32 a0) {
s32 *p = (s32 *)a0;
if (--p[0x1C / 4] != -1) {
func_80168BDC(a0, 9, 3, 1);
} else {
func_80168BDC(a0, 9, 2, 1);
((void (*)(s32))func_80146C3C)(a0);
}
}
DEFINE_func_80168BDC() /* dedup: shared engine-core @0x80168BDC (src/shared) */
+113 -5
View File
@@ -469,12 +469,10 @@ extern void func_8014B768(s32 a0, s32 a1);
extern void func_8014B944(s32 a0, s32 a1, s32 a2);
extern s32 D_80078EA4;
extern u16 D_80078EB2;
extern s16 D_80078EB4;
extern void func_8014BB0C(void);
extern void func_8014BB24(s32 a0, s32 a1, s32 a2);
extern void func_8014BC0C(s32 a0, s32 a1);
extern void func_8014BC44(s32 a0, s32 a1);
extern u8 D_800B9A17;
extern void func_8014BCC0(s32 a0, s32 a1);
extern u16 D_80078EB6;
extern s32 func_8014BCEC(s32 a0, s32 a1);
@@ -3885,7 +3883,63 @@ s32 func_8016F0AC()
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_8016AB6C", func_8016F0E4);
/* RECONCILE NOTE (uc3) — the body is byte-unchanged from uc2; only the declaration
* environment moved. The gate error was
* jr_8016AB6C.c:4183 conflicting types for func_8016F0E4 || :4089 previous declaration
* :4089 was THIS definition; :4183 is the `extern void func_8016F0E4(void);` carried inside
* DEFINE_func_8016F4C4() (src/shared/engine_core.h:22579), which the host TU instantiates at
* ov_SC01_077_jr_8016AB6C.c:4136 — i.e. AFTER the definition, so it is a hard error, not the
* mere warning produced by the earlier block-scope decl in func_8016F0AC (TU:4047).
* Byte-true signature is `void (u8 *)`; the fleet canon is `void (void)` — a PARAM/ARITY
* disagreement on func_8016F0E4 ITSELF.
*
* ESCAPE TAKEN: §37/§124 ASM-LABEL ALIAS (escape 2, T0 draft-only, zero tracked-file edits).
* The C identifier is aF8016F0E4 so this TU declares func_8016F0E4 exactly once (the macro's
* own `extern void`), while the emitted SYMBOL is func_8016F0E4. Both existing callers already
* launder through a cast or take no args, so neither is perturbed:
* - func_8016F0AC (TU:4047-4049) casts: ((void (*)(void *))func_8016F0E4)(&D_80126B58);
* - DEFINE_func_8016F4C4 calls func_8016F0E4() with 0 args against its own (void) prototype.
* cc1-proven: preprocess+compile of the real TU with this body spliced in is free of any
* func_8016F0E4 diagnostic (the pre-existing unrelated warnings in the TU are unchanged).
*
* This SUPERSEDES uc2's //@EDIT de-macroize plan (§65b) and its T2 engine_core.h alternative
* (§75c) — neither is needed; nothing outside this unit changes, so the bank travels to the
* 137 siblings as a plain unit (carry the alias DECLARATION line with it — §124 trap 2).
*/
extern void func_8017196C(s32 *a0, s8 a1); /* == DEFINE_func_8017196C's own signature */
extern void func_80147060(u8 *a0);
extern void func_801511A8(u8 *a0);
extern void func_80148634(void *a0);
// @class: plumbing
// @stuck: none — MATCH (26 ins).
// Levers: (1) §42b read-global &-cast — the TU declares D_80078EB4 as s16 but the target
// loads it with `lhu`; the bare `D_80078EB4 != 0` gives `lh` (probed: closeness 1, WIDTH
// lh!=lhu), so read it as *(u16 *)&D_80078EB4. (2) both 0x1F8/0x1FC stores are s32 `sw`,
// emitted before the first jal (the 0x1FC one lands in the delay slot by sched2 — free).
// (3) the param needs no laundering: it is copied to $s0 at entry and the first call's
// `move $a0,$s0` is deleted because $a0 already holds it — plain `u8 *p` reproduces this.
// (4) §37/§124 asm-label alias — see the RECONCILE NOTE above; codegen-neutral (symbol only).
void aF8016F0E4(u8 *p) __asm__("func_8016F0E4");
void aF8016F0E4(u8 *p) {
extern s16 D_80078EB4; /* fleet-canonical spelling; see the &-cast below */
extern u8 D_800B9A17;
*(s32 *)(p + 0x1F8) = 0;
*(s32 *)(p + 0x1FC) = 0;
func_8017196C((s32 *)p, 0);
func_80147060(p);
func_801511A8(p);
if (*(u16 *)&D_80078EB4 != 0) {
D_800B9A17 = 1;
}
func_80148634(p);
}
DEFINE_func_8016F14C() /* dedup: shared engine-core @0x8016F14C (src/shared) */
@@ -4248,7 +4302,28 @@ void func_80170810(void *a0) {
DEFINE_func_8017084C() /* dedup: shared engine-core @0x8017084C (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_8016AB6C", func_801708B0);
extern void func_801484B0(s32 a0, s32 a1);
extern void func_80149350(s32 arg0);
extern s32 func_8014C168(s32*, s32);
extern void func_80171928(void *a0);
void func_801708B0(void* a0)
{
extern void *D_8011F738;
u16 sp10[4];
u16 sp18[4];
short *r;
func_801484B0((s32)&sp10, (s32)&sp18);
((void (*)(s32, void *, void *))func_80149350)((s32)a0, &sp10, &sp10);
r = (short *)((s32 (*)(s32, s32))func_8014C168)((s32)a0, (*(s32 *)&D_8011F738));
r[3] = sp10[0];
r[5] = sp10[1];
r[7] = sp10[2];
func_80171928((void *)a0);
}
DEFINE_func_80170928() /* dedup: shared engine-core @0x80170928 (src/shared) */
@@ -4298,7 +4373,40 @@ void func_80170C74(void *a0) {
DEFINE_func_80170CB0() /* dedup: shared engine-core @0x80170CB0 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_005/nonmatchings/ov_SC02_005_jr_8016AB6C", func_80170CF0);
extern void func_801718AC(void *a0);
void func_80170CF0(void* a0)
{
extern void *D_8011F738;
extern s32 D_8011F73C;
extern s32 D_8011F740;
s32 v1;
void *p;
((void (*)(s32))D_8011F738)(a0);
v1 = *(u8 *)(a0 + 0x217);
if (v1 == 1) {
goto case_1;
}
if (v1 <= 1) {
goto done;
}
if (v1 == 2) {
goto case_2;
}
goto done;
case_1:
p = (*(void * *)&D_8011F73C);
goto call;
case_2:
p = (*(void * *)&D_8011F740);
call:
func_801718AC(p);
done:
;
}
extern void (*D_80193E10[])(void);
+118 -2
View File
@@ -2281,7 +2281,81 @@ DEFINE_func_8014E48C() /* dedup: shared engine-core @0x8014E48C (src/shared) */
DEFINE_func_8014E514() /* dedup: shared engine-core @0x8014E514 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_after", func_8014E5B4);
// — the guard makes $v1, CSE turns the in-body `e = p + 0x6480` into a copy of it, and
// regalloc does not coalesce (gcc-2.7.2 has no coalescing, regalloc.md K8). The back edge
// then uses the register ($s5), NOT a rematerialised %hi/%lo(D_80126720) as in
// func_8014CF04 — so do NOT reuse that sibling's absolute-bound half here.
//
// (2) TWO INDUCTION VARIABLES, secondary base +0xE. `q = p + 0xE` carries every access except
// the two that use the entry pointer itself (`*(u16 *)p` and `*(u8 **)(a0+0x17C) = p`):
// offsets -0x8 / 0x0 / 0x12 / 0x4A / 0x4E off q == 0x6 / 0xE / 0x20 / 0x58 / 0x5C off p.
// A single-pointer spelling is NOT equivalent: gcc emits ONE base and the function comes
// out 56 ins (verified). The negative displacement is the tell that the second pointer is
// in the source, not a compiler-made giv.
//
// (3) REGISTER PINS ($16/$17) — the one non-obvious lever, and it is a genuine density
// knife-edge (regalloc.md K2 / §RC-15). Unpinned, the .lreg reads
// p: 9 refs / 24 insns -> floor_log2(9)*9/24 = 1.125
// q: 8 refs / 22 insns -> floor_log2(8)*8/22 = 1.091
// so p wins $s0 by ~3% and the whole function comes out with p/q SWAPPED (17 mismatches,
// every one of them a bare $s0<->$s1 rename). The target wants q in $s0. Decl-order swap
// does nothing (ties are not what decides it — p genuinely out-scores q). Rather than
// hunt a +1-ref anchor (§RC-11 `#APP` would sit next to three delay slots that maspsx
// fills: the `beqz $a1` slot, the `jal` slot and the `bnez` slot), pin both:
// register u8 *p __asm__("$17"); register u8 *q __asm__("$16");
// Both are callee-saved, so the live-across-`jal` range is §42e/§74-safe by construction
// (the ov_SC03_099 func_8014D820 caveat only applies to caller-saved pins). Everything
// else falls out naturally: a0->$s2, a1->$s3, a2->$s4, e->$s5.
//
// (4) `t = *(s32 *)(q + 0x4A)` is loaded ONCE and reused as arg1 of func_80135888 — that is
// why `lw $a1, 0x4A($s0)` sits at the zero-test rather than at the call.
//
// The func_80135888 decl below is byte-compatible with the one this TU already carries at
// ov_SC01_077_after.c:2303, so it is not a second conflict axis.
extern s32 func_80135888(s32 a0, s32 a1, s32 a2, s32 a3);
/* §37/§124 asm-label alias: the fleet canon declares this `extern void` (engine_core.h:13392,
* inside DEFINE_func_8014E48C()); the byte-true body must return s32. Aliasing the C name
* sidesteps the RETURN-axis conflict with no header edit. This line MUST travel with the body. */
s32 aF8014E5B4(s32 a0, void *a1, void *a2) __asm__("func_8014E5B4");
s32 aF8014E5B4(s32 a0, void *a1, void *a2)
{
extern u8 D_801202A0[];
register u8 *p __asm__("$17");
register u8 *q __asm__("$16");
u8 *e;
s32 t;
p = D_801202A0;
if (p < p + 0x6480) {
e = p + 0x6480;
q = p + 0xE;
loop:
if (*(u16 *)p != 0) {
if ((*(u16 *)(q + 0x4E) & 0x40) != 0) {
t = *(s32 *)(q + 0x4A);
if (t != 0) {
if (func_80135888(*(s32 *)(q + 0x12), t, (s32)a1, (s32)a2) != 0) {
*(u8 **)(a0 + 0x17C) = p;
*(u16 *)(a0 + 6) = *(u16 *)(q - 8);
*(u16 *)(a0 + 0xE) = *(u16 *)q;
return 1;
}
}
}
}
p += 0x10C;
q += 0x10C;
if (p < e) {
goto loop;
}
}
return 0;
}
extern void func_8014E6F8(struct SubE6F8 *a0);
@@ -2996,7 +3070,49 @@ DEFINE_func_80151238() /* dedup: shared engine-core @0x80151238 (src/shared) */
DEFINE_func_8015126C() /* dedup: shared engine-core @0x8015126C (src/shared) */
INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_after", func_80151664);
/* func_80151664 — INTEGRATE lane.
* Fleet canon (src/shared/engine_core.h:2924, inside DEFINE_func_8015410C()) declares
* extern void func_80151664(void);
* so a `void func_80151664(s32 a0)` definition is `conflicting types` in every TU that
* expands that macro (ov_SC01_077_after.c:3910 does). Cookbook §73 PARAMS axis / §42:
* keep the canonical (void) signature and read the incoming argument through a $a0 pin.
* The decl below is reproduced verbatim so this file compiles the real conflict. */
extern void func_80151664(void);
extern void func_80154A74(s32 a0, s32 a1);
extern void func_801553C0(s32 a0);
extern void func_801470AC(s32 *a0);
extern void func_801472B4(void *a0);
extern void func_801477E8(s32 *a0, s32 a1);
extern void func_80153C18(); /* fleet canon: K&R empty prototype (engine_core.h:75, :1682 defines it (void));
* a prototyped (s32) decl is `conflicting types` in this TU. Arg still
* passes in $a0 under default promotions -> codegen unchanged. */
void func_80151664(void) {
register s32 a0v __asm__("$4");
s32 s0;
s32 v1;
s0 = a0v;
func_80154A74(s0, 0x11);
func_801553C0(s0);
func_801470AC((s32 *)s0);
func_801472B4((void *)s0);
v1 = *(s32 *)(s0 + 0x20);
*(s16 *)(s0 + 0x3E) = 0;
*(s16 *)(s0 + 0x40) = 0;
*(s16 *)(s0 + 0x42) = 0;
*(s8 *)(s0 + 0xDD) = 0;
*(s16 *)(s0 + 0x3C) = *(u16 *)(s0 + 0x3C) & 0xFFFE;
*(s16 *)(v1 + 0x10) = 0;
*(s16 *)(s0 + 0x60) = 0x1000;
*(s16 *)(s0 + 0x62) = 0x1000;
*(s16 *)(s0 + 0x64) = 0x1000;
func_801477E8((s32 *)s0, 0);
func_80153C18(s0);
}
DEFINE_func_801516F0() /* dedup: shared engine-core @0x801516F0 (src/shared) */
+234 -3
View File
@@ -986,7 +986,142 @@ DEFINE_func_8012EF34() /* dedup: shared engine-core @0x8012EF34 (src/shared) */
DEFINE_func_8012EF70() /* dedup: shared engine-core @0x8012EF70 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8012ACE0", func_8012EFB8);
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_rtps() __asm__ volatile ("nop;nop;rtps")
#define gte_stsxy(r0) __asm__ volatile ( \
"swc2 $14, 0( %0 )" \
: \
: "r"( r0 ) \
: "memory" )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
#define gte_SetRotMatrix(r0) __asm__ volatile ( \
"lw $12, 0( %0 );" \
"lw $13, 4( %0 );" \
"ctc2 $12, $0;" \
"ctc2 $13, $1;" \
"lw $12, 8( %0 );" \
"lw $13, 12( %0 );" \
"lw $14, 16( %0 );" \
"ctc2 $12, $2;" \
"ctc2 $13, $3;" \
"ctc2 $14, $4" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_SetTransMatrix(r0) __asm__ volatile ( \
"lw $12, 20( %0 );" \
"lw $13, 24( %0 );" \
"ctc2 $12, $5;" \
"lw $14, 28( %0 );" \
"ctc2 $13, $6;" \
"ctc2 $14, $7" \
: \
: "r"( r0 ) \
: "$12", "$13", "$14" )
#define gte_ldv0(r0) __asm__ volatile ( \
"lwc2 $0, 0( %0 );" \
"lwc2 $1, 4( %0 )" \
: \
: "r"( r0 ) )
#define gte_stflg(r0) __asm__ volatile ( \
"cfc2 $12, $31;" \
"nop;" \
"sw $12, 0( %0 )" \
: \
: "r"( r0 ) \
: "$12", "memory" )
/* §37/§124 asm-label alias: the fleet canon declares this `extern void
* func_8012EFB8(s32 a0);` inside the DEFINE_func_* macros in
* src/shared/engine_core.h (the one at src/ov_SC01_077/ov_SC01_077_jr_8012ACE0.c:1169
* comes from DEFINE_func_8012EF70()). The byte-true body returns s32 and takes
* TWO pointers, so it conflicts on BOTH the return axis and the arity axis.
* Aliasing the C name sidesteps both with no header edit and no codegen change.
* This declaration MUST travel with the body. */
s32 aF8012EFB8(void *param_1, void *param_2) __asm__("func_8012EFB8");
s32 aF8012EFB8(param_1, param_2)
void *param_1;
void *param_2;
{
extern u8 D_800AF648;
s32 *m;
s32 flag;
m = (s32 *)&D_800AF648;
gte_SetRotMatrix(m);
gte_SetTransMatrix(m);
gte_ldv0(param_1);
gte_rtps();
gte_stsxy(param_2);
gte_stflg(&flag);
return flag;
}
// @class: other
@@ -1896,9 +2031,105 @@ void func_80131B14() {
DEFINE_func_80131C78() /* dedup: shared engine-core @0x80131C78 (src/shared) */
INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8012ACE0", func_80131CA8);
INCLUDE_ASM("asm/ov_SC02_011/nonmatchings/ov_SC02_011_jr_8012ACE0", func_80131CF4);
/* func_80131CA8 — RECONCILE (§37/§124 asm-label alias)
*
* Declaration-environment conflict, NOT a body problem:
* The TU's DEFINE_func_80131C78() expansion (jr_8012ACE0.c L2232) and the later
* DEFINE_func_80131D68() expansion (L2250) each emit the canonical
* extern void func_80131CA8(int a0, int a1);
* (src/shared/engine_core.h, e.g. L1961/L4131). The byte-correct body is
* `s32 f(int)` — it disagrees on BOTH the return axis (s32 vs void) and the
* arity axis (1 vs 2), so it collides with the macro-emitted declaration on
* either side of the slot. Escape 1 (conform + cast at use) cannot apply: the
* conflict is on the DEFINED symbol itself.
*
* Fix: define under the C name aF80131CA8 with __asm__("func_80131CA8") so the
* C-level name never meets the canonical declaration, while the emitted symbol
* is unchanged. Codegen-neutral — match_one still prints MATCH (19/19).
* This declaration MUST travel with the body.
*
* func_80131CF4 is declared here 1-arg s32, matching the engine_core canonical
* at engine_core.h L6563; it does not collide anywhere in this TU (verified by
* a full preprocess+cc1 of the spliced TU: diagnostic-free apart from
* pre-existing warnings).
*/
extern s32 func_80131CF4(s32 a0);
s32 aF80131CA8(int a0) __asm__("func_80131CA8");
s32 aF80131CA8(int a0)
{
s32 (*fp)(int) = (s32 (*)(int))func_80131CF4(*(s32 *)((u8 *)a0 + 0xBC));
if (fp != 0) {
fp(a0);
return 1;
}
return 0;
}
/* func_80131CF4 — table lookup: walk (key, value) pairs; key 0xD chains to the
* next table via value; key == wanted returns value; key 0 terminates.
*
* The __asm__ inside the body is a matching pin, not logic. It does two things
* gcc-2.7.2 -O2 needs in order to reproduce the target's preheader exactly:
* 1. "0"(0xD) forces the 0xD compare constant to be materialised HERE
* (`addiu $v1,$zero,0xD`) instead of being loop-hoisted, which places it
* AFTER the preheader load and drops the load-delay nop at the loop head.
* 2. the "memory" clobber stops CSE folding the preheader re-read of a0[0]
* into the guard's read (that CSE costs the second `lw $v0,0x0($a0)`).
* The asm body is empty, so it emits no instruction of its own.
*
* RECONCILE (§37/§124 asm-label alias) — the gate error was
* jr_8012ACE0.c:2248 conflicting types for func_80131CF4 || :2164 previous declaration
* :2164 is `DEFINE_func_80131AC8()`, whose expansion (src/shared/engine_core.h:6563)
* carries the STALE 1-arg engine-core canonical `extern s32 func_80131CF4(s32 a0);`.
* That prototype is wrong for this function (the TU's own call sites at L1780/L1903/
* L2147 all declare and call the real 2-arg form `int func_80131CF4(int, int)`), but
* it is file-visible before the splice point, so a file-scope definition with the true
* signature is a hard `conflicting types` (arity AND param type). Conforming the
* definition to the 1-arg prototype is impossible without changing codegen, and the
* §42 `register s32 a1 __asm__("$5")` route would still leave the param-type mismatch
* on a0 (s32 vs s32*). So the definition is given a different C identifier and pinned
* to the real symbol with an asm label: no declaration ever collides, the emitted
* label is still `func_80131CF4`, and the callers' `jal func_80131CF4` binds to it.
* Zero header edits; body byte-identical (match_one: MATCH, 29 ins).
*/
s32 aF80131CF4(s32 *a0, s32 a1) __asm__("func_80131CF4");
s32 aF80131CF4(s32 *a0, s32 a1) {
s32 v0;
s32 k;
if (a0 == 0) {
return 0;
}
goto enter;
found:
return a0[1];
enter:
if (a0[0] == 0) {
return 0;
}
__asm__ __volatile__("" : "=r"(k) : "0"(0xD) : "memory");
v0 = a0[0];
do {
if (v0 == k) {
a0 = (s32 *)a0[1];
} else {
if (v0 == a1) {
goto found;
}
a0 = (s32 *)((u8 *)a0 + 8);
}
v0 = a0[0];
} while (v0 != 0);
return 0;
}
DEFINE_func_80131D68() /* dedup: shared engine-core @0x80131D68 (src/shared) */

Some files were not shown because too many files have changed in this diff Show More