diff --git a/src/md_SC03_076/md_SC03_076.c b/src/md_SC03_076/md_SC03_076.c index 1d5707d2ce..97b990f4fe 100644 --- a/src/md_SC03_076/md_SC03_076.c +++ b/src/md_SC03_076/md_SC03_076.c @@ -120,7 +120,130 @@ INCLUDE_ASM("asm/md_SC03_076/nonmatchings/md_SC03_076", func_801EFBB4); INCLUDE_ASM("asm/md_SC03_076/nonmatchings/md_SC03_076", func_801F0210); -INCLUDE_ASM("asm/md_SC03_076/nonmatchings/md_SC03_076", func_801F03C0); + typedef struct { s8 c[8]; } Blk8_8012C890_8017C348_801F03C0; +typedef struct { s16 m[3][3]; s32 t[3]; } MTX_C974_801F03C0; + +/* func_801F03C0 (ov_MAIN_012 / jr_801789AC) — 188 ins, byte-exact vs + * asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_801789AC/func_801F03C0.s + * + * Sprite/quad draw dispatcher: builds an OT chain for one "part list" entry. + * + * Idioms that were load-bearing here (feed these back into the cookbook): + * 1) `dim`/`dim2`/`dim3` are DELIBERATE copies of `flag`. The target keeps + * `flag` in $s7 and copies it into $s6 in each loop preheader and into $s0 + * for the tail. A plain `x = flag;` written in the same basic block as its + * use is killed by cse; it survives only when a multi-pred label separates + * def from use. So: the loop-1 copy is written at the END of the outer + * body (loop.c hoists it into the preheader), the loop-2 copy is written in + * the preheader itself, and the tail copy needs a hard-register pin + * (`register s32 dim3 __asm__("$16")`) because nothing separates it from + * its uses. Same shape as the matched sibling func_8013FAF8 (ov_SC06_008), + * which also needed a pin for exactly this call pair. + * 2) `bp = sp18;` exists only to fix the ORDER of the two loop-1 preheader + * insns. loop.c emits hoisted invariants in body order; writing the + * sp18-relative store address as an explicit pointer makes `addiu $s5,$sp,0x18` + * the FIRST movable, so the `dim` copy lands after it (as in the target). + * 3) The `do { } while (0)` around the loop-1 call is a REGISTER-ALLOCATION + * lever, not dead syntax. flow.c weights REG_N_REFS by loop_depth; the + * extra (never-iterating) loop note gives `ot` 18 weighted refs instead of + * 16, which raises its global-alloc priority above `s` (21 refs / 159 insns) + * and lands the a0/a1 params in $s2/$s3 exactly as the target does. + * `mode` is hoisted out of the wrapper so `dim` does NOT get the same +1 + * (that would swap $s5/$s6 between `bp` and `dim`). + * 4) Low half of sp60[0] uses `& 0xFFFF`, NOT a (u16) cast: the mask keeps the + * operands in SImode so both halves load with `lh`; a (u16) cast makes + * gcc-2.7.2 emit `lhu`. + */ + + +extern s32 func_80024054(u8 *, u8 *); +extern s32 func_800D2650(s32, u8 *, s16, s16, s32, s32); +extern s32 func_800D27DC(s32, s32, void *, s16, s32); +extern s32 func_800D29F8(s32, s32, void *, s16, s32); +extern s32 func_801F06B0(s32, s16, s16, s16, s32 *); + +s32 func_801F03C0(s32 ot, u8 *s, s16 c) { + + extern u16 D_8011511A; + extern u8 D_801F341C[]; + extern s32 *D_801F3394[]; + u8 sp18[72]; + s32 sp60[5]; + s32 sp78[8]; + s32 flag; + s32 dim; + s32 dim2; + register s32 dim3 __asm__("$16"); + s32 t; + s16 i; + s16 k; + s32 *p; + u8 *bp; + s16 *q; + s32 r; + s32 mode; + + if (c == 0) { + flag = 0; + } else { + flag = -(D_8011511A != c) & 0xFF; + } + + t = *(s32 *)(s + 0x14); + if (t < 0) { + func_80024054((u8 *)t, sp18); + ot = func_800D2650(ot, sp18, *(s16 *)(s + 0x10), *(s16 *)(s + 0x12), 1, + flag ? 0x585858 : 0x808080); + } else { + p = D_801F3394[t]; + for (k = 0; k < D_801F341C[*(s32 *)(s + 0x14)]; k++) { + bp = sp18; + dim = flag; + for (i = 0; i < 5; i++) { + if (i == 0) { + sp60[0] = (((s16 *)p)[0] + *(s16 *)(s + 0x10)) & 0xFFFF | + ((((s16 *)p)[1] + *(s16 *)(s + 0x12)) << 16); + } else { + *(s32 *)(bp + 0x48 + i * 4) = p[i]; + } + } + mode = dim ? 3 : 2; + do { + ot = func_800D27DC(mode, ot, sp60, 1, 0); + } while (0); + p += 5; + } + } + + i = 0; + q = *(s16 **)(s + 0x18); + dim2 = flag; + for (;;) { + r = func_801F06B0(*(s32 *)(s + 0x1C), *(s16 *)s, c, i++, sp78); + if (r == 0) { + break; + } + if (r < 0) { + func_80024054((u8 *)r, sp18); + if (dim2 != 0) { + sp78[0] = 0x585858; + } + ot = func_800D2650(ot, sp18, q[0], q[1], 1, sp78[0]); + } else { + p = D_801F3394[r]; + *p = (u16)q[0] | (q[1] << 16); + ot = func_800D27DC(dim2 ? 3 : 2, ot, p, 1, 0); + } + q += 2; + } + + dim3 = flag; + return func_800D29F8(dim3, + func_800D27DC(dim3 != 0, ot, (void *)*(s32 *)(s + 4), + *(s16 *)(s + 0xC), 0), + (void *)*(s32 *)(s + 8), *(s16 *)(s + 0xE), 0); +} + INCLUDE_ASM("asm/md_SC03_076/nonmatchings/md_SC03_076", func_801F06B0); diff --git a/src/md_SC03_135/md_SC03_135.c b/src/md_SC03_135/md_SC03_135.c index 96d975a4df..cd3b9d6bf4 100644 --- a/src/md_SC03_135/md_SC03_135.c +++ b/src/md_SC03_135/md_SC03_135.c @@ -120,7 +120,130 @@ INCLUDE_ASM("asm/md_SC03_135/nonmatchings/md_SC03_135", func_801E2D34); INCLUDE_ASM("asm/md_SC03_135/nonmatchings/md_SC03_135", func_801E3390); -INCLUDE_ASM("asm/md_SC03_135/nonmatchings/md_SC03_135", func_801E3540); + typedef struct { s8 c[8]; } Blk8_8012C890_8017C348_801E3540; +typedef struct { s16 m[3][3]; s32 t[3]; } MTX_C974_801E3540; + +/* func_801E3540 (ov_MAIN_012 / jr_801789AC) — 188 ins, byte-exact vs + * asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_801789AC/func_801E3540.s + * + * Sprite/quad draw dispatcher: builds an OT chain for one "part list" entry. + * + * Idioms that were load-bearing here (feed these back into the cookbook): + * 1) `dim`/`dim2`/`dim3` are DELIBERATE copies of `flag`. The target keeps + * `flag` in $s7 and copies it into $s6 in each loop preheader and into $s0 + * for the tail. A plain `x = flag;` written in the same basic block as its + * use is killed by cse; it survives only when a multi-pred label separates + * def from use. So: the loop-1 copy is written at the END of the outer + * body (loop.c hoists it into the preheader), the loop-2 copy is written in + * the preheader itself, and the tail copy needs a hard-register pin + * (`register s32 dim3 __asm__("$16")`) because nothing separates it from + * its uses. Same shape as the matched sibling func_8013FAF8 (ov_SC06_008), + * which also needed a pin for exactly this call pair. + * 2) `bp = sp18;` exists only to fix the ORDER of the two loop-1 preheader + * insns. loop.c emits hoisted invariants in body order; writing the + * sp18-relative store address as an explicit pointer makes `addiu $s5,$sp,0x18` + * the FIRST movable, so the `dim` copy lands after it (as in the target). + * 3) The `do { } while (0)` around the loop-1 call is a REGISTER-ALLOCATION + * lever, not dead syntax. flow.c weights REG_N_REFS by loop_depth; the + * extra (never-iterating) loop note gives `ot` 18 weighted refs instead of + * 16, which raises its global-alloc priority above `s` (21 refs / 159 insns) + * and lands the a0/a1 params in $s2/$s3 exactly as the target does. + * `mode` is hoisted out of the wrapper so `dim` does NOT get the same +1 + * (that would swap $s5/$s6 between `bp` and `dim`). + * 4) Low half of sp60[0] uses `& 0xFFFF`, NOT a (u16) cast: the mask keeps the + * operands in SImode so both halves load with `lh`; a (u16) cast makes + * gcc-2.7.2 emit `lhu`. + */ + + +extern s32 func_80024054(u8 *, u8 *); +extern s32 func_800D2650(s32, u8 *, s16, s16, s32, s32); +extern s32 func_800D27DC(s32, s32, void *, s16, s32); +extern s32 func_800D29F8(s32, s32, void *, s16, s32); +extern s32 func_801E3830(s32, s16, s16, s16, s32 *); + +s32 func_801E3540(s32 ot, u8 *s, s16 c) { + + extern u16 D_8011511A; + extern u8 D_801E6584[]; + extern s32 *D_801E64FC[]; + u8 sp18[72]; + s32 sp60[5]; + s32 sp78[8]; + s32 flag; + s32 dim; + s32 dim2; + register s32 dim3 __asm__("$16"); + s32 t; + s16 i; + s16 k; + s32 *p; + u8 *bp; + s16 *q; + s32 r; + s32 mode; + + if (c == 0) { + flag = 0; + } else { + flag = -(D_8011511A != c) & 0xFF; + } + + t = *(s32 *)(s + 0x14); + if (t < 0) { + func_80024054((u8 *)t, sp18); + ot = func_800D2650(ot, sp18, *(s16 *)(s + 0x10), *(s16 *)(s + 0x12), 1, + flag ? 0x585858 : 0x808080); + } else { + p = D_801E64FC[t]; + for (k = 0; k < D_801E6584[*(s32 *)(s + 0x14)]; k++) { + bp = sp18; + dim = flag; + for (i = 0; i < 5; i++) { + if (i == 0) { + sp60[0] = (((s16 *)p)[0] + *(s16 *)(s + 0x10)) & 0xFFFF | + ((((s16 *)p)[1] + *(s16 *)(s + 0x12)) << 16); + } else { + *(s32 *)(bp + 0x48 + i * 4) = p[i]; + } + } + mode = dim ? 3 : 2; + do { + ot = func_800D27DC(mode, ot, sp60, 1, 0); + } while (0); + p += 5; + } + } + + i = 0; + q = *(s16 **)(s + 0x18); + dim2 = flag; + for (;;) { + r = func_801E3830(*(s32 *)(s + 0x1C), *(s16 *)s, c, i++, sp78); + if (r == 0) { + break; + } + if (r < 0) { + func_80024054((u8 *)r, sp18); + if (dim2 != 0) { + sp78[0] = 0x585858; + } + ot = func_800D2650(ot, sp18, q[0], q[1], 1, sp78[0]); + } else { + p = D_801E64FC[r]; + *p = (u16)q[0] | (q[1] << 16); + ot = func_800D27DC(dim2 ? 3 : 2, ot, p, 1, 0); + } + q += 2; + } + + dim3 = flag; + return func_800D29F8(dim3, + func_800D27DC(dim3 != 0, ot, (void *)*(s32 *)(s + 4), + *(s16 *)(s + 0xC), 0), + (void *)*(s32 *)(s + 8), *(s16 *)(s + 0xE), 0); +} + INCLUDE_ASM("asm/md_SC03_135/nonmatchings/md_SC03_135", func_801E3830); diff --git a/src/md_SC04_027/md_SC04_027.c b/src/md_SC04_027/md_SC04_027.c index 67f41b3ad6..78270a1202 100644 --- a/src/md_SC04_027/md_SC04_027.c +++ b/src/md_SC04_027/md_SC04_027.c @@ -120,7 +120,130 @@ INCLUDE_ASM("asm/md_SC04_027/nonmatchings/md_SC04_027", func_801E8274); INCLUDE_ASM("asm/md_SC04_027/nonmatchings/md_SC04_027", func_801E88D0); -INCLUDE_ASM("asm/md_SC04_027/nonmatchings/md_SC04_027", func_801E8A80); + typedef struct { s8 c[8]; } Blk8_8012C890_8017C348_801E8A80; +typedef struct { s16 m[3][3]; s32 t[3]; } MTX_C974_801E8A80; + +/* func_801E8A80 (ov_MAIN_012 / jr_801789AC) — 188 ins, byte-exact vs + * asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_801789AC/func_801E8A80.s + * + * Sprite/quad draw dispatcher: builds an OT chain for one "part list" entry. + * + * Idioms that were load-bearing here (feed these back into the cookbook): + * 1) `dim`/`dim2`/`dim3` are DELIBERATE copies of `flag`. The target keeps + * `flag` in $s7 and copies it into $s6 in each loop preheader and into $s0 + * for the tail. A plain `x = flag;` written in the same basic block as its + * use is killed by cse; it survives only when a multi-pred label separates + * def from use. So: the loop-1 copy is written at the END of the outer + * body (loop.c hoists it into the preheader), the loop-2 copy is written in + * the preheader itself, and the tail copy needs a hard-register pin + * (`register s32 dim3 __asm__("$16")`) because nothing separates it from + * its uses. Same shape as the matched sibling func_8013FAF8 (ov_SC06_008), + * which also needed a pin for exactly this call pair. + * 2) `bp = sp18;` exists only to fix the ORDER of the two loop-1 preheader + * insns. loop.c emits hoisted invariants in body order; writing the + * sp18-relative store address as an explicit pointer makes `addiu $s5,$sp,0x18` + * the FIRST movable, so the `dim` copy lands after it (as in the target). + * 3) The `do { } while (0)` around the loop-1 call is a REGISTER-ALLOCATION + * lever, not dead syntax. flow.c weights REG_N_REFS by loop_depth; the + * extra (never-iterating) loop note gives `ot` 18 weighted refs instead of + * 16, which raises its global-alloc priority above `s` (21 refs / 159 insns) + * and lands the a0/a1 params in $s2/$s3 exactly as the target does. + * `mode` is hoisted out of the wrapper so `dim` does NOT get the same +1 + * (that would swap $s5/$s6 between `bp` and `dim`). + * 4) Low half of sp60[0] uses `& 0xFFFF`, NOT a (u16) cast: the mask keeps the + * operands in SImode so both halves load with `lh`; a (u16) cast makes + * gcc-2.7.2 emit `lhu`. + */ + + +extern s32 func_80024054(u8 *, u8 *); +extern s32 func_800D2650(s32, u8 *, s16, s16, s32, s32); +extern s32 func_800D27DC(s32, s32, void *, s16, s32); +extern s32 func_800D29F8(s32, s32, void *, s16, s32); +extern s32 func_801E8D70(s32, s16, s16, s16, s32 *); + +s32 func_801E8A80(s32 ot, u8 *s, s16 c) { + + extern u16 D_8011511A; + extern u8 D_801EBAEC[]; + extern s32 *D_801EBA64[]; + u8 sp18[72]; + s32 sp60[5]; + s32 sp78[8]; + s32 flag; + s32 dim; + s32 dim2; + register s32 dim3 __asm__("$16"); + s32 t; + s16 i; + s16 k; + s32 *p; + u8 *bp; + s16 *q; + s32 r; + s32 mode; + + if (c == 0) { + flag = 0; + } else { + flag = -(D_8011511A != c) & 0xFF; + } + + t = *(s32 *)(s + 0x14); + if (t < 0) { + func_80024054((u8 *)t, sp18); + ot = func_800D2650(ot, sp18, *(s16 *)(s + 0x10), *(s16 *)(s + 0x12), 1, + flag ? 0x585858 : 0x808080); + } else { + p = D_801EBA64[t]; + for (k = 0; k < D_801EBAEC[*(s32 *)(s + 0x14)]; k++) { + bp = sp18; + dim = flag; + for (i = 0; i < 5; i++) { + if (i == 0) { + sp60[0] = (((s16 *)p)[0] + *(s16 *)(s + 0x10)) & 0xFFFF | + ((((s16 *)p)[1] + *(s16 *)(s + 0x12)) << 16); + } else { + *(s32 *)(bp + 0x48 + i * 4) = p[i]; + } + } + mode = dim ? 3 : 2; + do { + ot = func_800D27DC(mode, ot, sp60, 1, 0); + } while (0); + p += 5; + } + } + + i = 0; + q = *(s16 **)(s + 0x18); + dim2 = flag; + for (;;) { + r = func_801E8D70(*(s32 *)(s + 0x1C), *(s16 *)s, c, i++, sp78); + if (r == 0) { + break; + } + if (r < 0) { + func_80024054((u8 *)r, sp18); + if (dim2 != 0) { + sp78[0] = 0x585858; + } + ot = func_800D2650(ot, sp18, q[0], q[1], 1, sp78[0]); + } else { + p = D_801EBA64[r]; + *p = (u16)q[0] | (q[1] << 16); + ot = func_800D27DC(dim2 ? 3 : 2, ot, p, 1, 0); + } + q += 2; + } + + dim3 = flag; + return func_800D29F8(dim3, + func_800D27DC(dim3 != 0, ot, (void *)*(s32 *)(s + 4), + *(s16 *)(s + 0xC), 0), + (void *)*(s32 *)(s + 8), *(s16 *)(s + 0xE), 0); +} + INCLUDE_ASM("asm/md_SC04_027/nonmatchings/md_SC04_027", func_801E8D70); diff --git a/src/md_SC05_026/md_SC05_026.c b/src/md_SC05_026/md_SC05_026.c index e71733df08..ed79def435 100644 --- a/src/md_SC05_026/md_SC05_026.c +++ b/src/md_SC05_026/md_SC05_026.c @@ -120,7 +120,130 @@ INCLUDE_ASM("asm/md_SC05_026/nonmatchings/md_SC05_026", func_801EE0D4); INCLUDE_ASM("asm/md_SC05_026/nonmatchings/md_SC05_026", func_801EE730); -INCLUDE_ASM("asm/md_SC05_026/nonmatchings/md_SC05_026", func_801EE8E0); + typedef struct { s8 c[8]; } Blk8_8012C890_8017C348_801EE8E0; +typedef struct { s16 m[3][3]; s32 t[3]; } MTX_C974_801EE8E0; + +/* func_801EE8E0 (ov_MAIN_012 / jr_801789AC) — 188 ins, byte-exact vs + * asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_801789AC/func_801EE8E0.s + * + * Sprite/quad draw dispatcher: builds an OT chain for one "part list" entry. + * + * Idioms that were load-bearing here (feed these back into the cookbook): + * 1) `dim`/`dim2`/`dim3` are DELIBERATE copies of `flag`. The target keeps + * `flag` in $s7 and copies it into $s6 in each loop preheader and into $s0 + * for the tail. A plain `x = flag;` written in the same basic block as its + * use is killed by cse; it survives only when a multi-pred label separates + * def from use. So: the loop-1 copy is written at the END of the outer + * body (loop.c hoists it into the preheader), the loop-2 copy is written in + * the preheader itself, and the tail copy needs a hard-register pin + * (`register s32 dim3 __asm__("$16")`) because nothing separates it from + * its uses. Same shape as the matched sibling func_8013FAF8 (ov_SC06_008), + * which also needed a pin for exactly this call pair. + * 2) `bp = sp18;` exists only to fix the ORDER of the two loop-1 preheader + * insns. loop.c emits hoisted invariants in body order; writing the + * sp18-relative store address as an explicit pointer makes `addiu $s5,$sp,0x18` + * the FIRST movable, so the `dim` copy lands after it (as in the target). + * 3) The `do { } while (0)` around the loop-1 call is a REGISTER-ALLOCATION + * lever, not dead syntax. flow.c weights REG_N_REFS by loop_depth; the + * extra (never-iterating) loop note gives `ot` 18 weighted refs instead of + * 16, which raises its global-alloc priority above `s` (21 refs / 159 insns) + * and lands the a0/a1 params in $s2/$s3 exactly as the target does. + * `mode` is hoisted out of the wrapper so `dim` does NOT get the same +1 + * (that would swap $s5/$s6 between `bp` and `dim`). + * 4) Low half of sp60[0] uses `& 0xFFFF`, NOT a (u16) cast: the mask keeps the + * operands in SImode so both halves load with `lh`; a (u16) cast makes + * gcc-2.7.2 emit `lhu`. + */ + + +extern s32 func_80024054(u8 *, u8 *); +extern s32 func_800D2650(s32, u8 *, s16, s16, s32, s32); +extern s32 func_800D27DC(s32, s32, void *, s16, s32); +extern s32 func_800D29F8(s32, s32, void *, s16, s32); +extern s32 func_801EEBD0(s32, s16, s16, s16, s32 *); + +s32 func_801EE8E0(s32 ot, u8 *s, s16 c) { + + extern u16 D_8011511A; + extern u8 D_801F1974[]; + extern s32 *D_801F18EC[]; + u8 sp18[72]; + s32 sp60[5]; + s32 sp78[8]; + s32 flag; + s32 dim; + s32 dim2; + register s32 dim3 __asm__("$16"); + s32 t; + s16 i; + s16 k; + s32 *p; + u8 *bp; + s16 *q; + s32 r; + s32 mode; + + if (c == 0) { + flag = 0; + } else { + flag = -(D_8011511A != c) & 0xFF; + } + + t = *(s32 *)(s + 0x14); + if (t < 0) { + func_80024054((u8 *)t, sp18); + ot = func_800D2650(ot, sp18, *(s16 *)(s + 0x10), *(s16 *)(s + 0x12), 1, + flag ? 0x585858 : 0x808080); + } else { + p = D_801F18EC[t]; + for (k = 0; k < D_801F1974[*(s32 *)(s + 0x14)]; k++) { + bp = sp18; + dim = flag; + for (i = 0; i < 5; i++) { + if (i == 0) { + sp60[0] = (((s16 *)p)[0] + *(s16 *)(s + 0x10)) & 0xFFFF | + ((((s16 *)p)[1] + *(s16 *)(s + 0x12)) << 16); + } else { + *(s32 *)(bp + 0x48 + i * 4) = p[i]; + } + } + mode = dim ? 3 : 2; + do { + ot = func_800D27DC(mode, ot, sp60, 1, 0); + } while (0); + p += 5; + } + } + + i = 0; + q = *(s16 **)(s + 0x18); + dim2 = flag; + for (;;) { + r = func_801EEBD0(*(s32 *)(s + 0x1C), *(s16 *)s, c, i++, sp78); + if (r == 0) { + break; + } + if (r < 0) { + func_80024054((u8 *)r, sp18); + if (dim2 != 0) { + sp78[0] = 0x585858; + } + ot = func_800D2650(ot, sp18, q[0], q[1], 1, sp78[0]); + } else { + p = D_801F18EC[r]; + *p = (u16)q[0] | (q[1] << 16); + ot = func_800D27DC(dim2 ? 3 : 2, ot, p, 1, 0); + } + q += 2; + } + + dim3 = flag; + return func_800D29F8(dim3, + func_800D27DC(dim3 != 0, ot, (void *)*(s32 *)(s + 4), + *(s16 *)(s + 0xC), 0), + (void *)*(s32 *)(s + 8), *(s16 *)(s + 0xE), 0); +} + INCLUDE_ASM("asm/md_SC05_026/nonmatchings/md_SC05_026", func_801EEBD0); diff --git a/tools/scope_data_externs.py b/tools/scope_data_externs.py index 68c749975e..bcc81f71eb 100644 --- a/tools/scope_data_externs.py +++ b/tools/scope_data_externs.py @@ -50,9 +50,13 @@ CLI (diagnostics): --func func_8015AE2C [--out fixed.c] """ import argparse +import os import re import sys +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import cdecl # noqa: E402 — the ONE masking oracle (§134/R33) + # a col-0 (file-scope) `extern ...;` on one line. Leading whitespace => block scope, which is what we # emit and never need to re-place. FILE_EXTERN_RE = re.compile(r'^extern\b[^;{}\n]*;', re.M) @@ -79,11 +83,28 @@ def _body_open_brace(body, func): the brace on the signature line, the ANSI form with the brace on its own line, AND the K&R form whose param decls sit between the signature and the `{`). The first cut of this used `^\s*\{\s*$` — own-line braces only — and silently no-op'd on every ANSI draft (the same silent-skip disease as the four - catalogued in §40/§8d; caught because the h_seq re-sweep banked 0/780).""" - sig = re.search(rf'^[^\n]*\b{re.escape(func)}\s*\(', body, re.M) + catalogued in §40/§8d; caught because the h_seq re-sweep banked 0/780). + + BOTH SCANS RUN ON `cdecl._mask`ed TEXT (P30 S48, byte-witnessed). A crack agent's draft opens with + a header comment that NAMES the function and quotes C at it: + + /* func_801EE8E0 (ov_MAIN_012 / jr_801789AC) — 188 ins, byte-exact vs … + * 3) The `do { } while (0)` around the loop-1 call is a REGISTER-ALLOCATION lever … + + Unmasked, `sig` matched the COMMENT's first line and `find('{')` then found the comment's + `do {`, so every carried `extern` was spliced INTO THE COMMENT — silently commented out. The + gate reported `'D_8011511A' undeclared` and the sweep classified it CC1-FAIL, i.e. it read as a + property of the SIBLING (all 4 members of the family failed identically) when it was a property + of the EXEMPLAR'S PROSE. Every richly-commented agent draft is a carrier; the trigger is any + brace inside the header comment. Same §134 class as `_mask_cpp_directives` and the wrapped-decl + scans — mask first, then index the ORIGINAL by the masked offsets.""" + masked = cdecl._mask(body) + if len(masked) != len(body): # R32: the length invariant is what makes offsets portable + return None # refuse rather than mis-place a decl into live code + sig = re.search(rf'^[^\n]*\b{re.escape(func)}\s*\(', masked, re.M) if not sig: return None - i = body.find('{', sig.end()) + i = masked.find('{', sig.end()) if i < 0: return None j = body.find('\n', i)