mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-26 13:33:34 -04:00
docs(cookbook): §422 QImode arithmetic + flag^1 temp; §423 the "cause not determined" typedef collision
§422 (resident/func_800D06E8, 344 ins): mips.h has no PROMOTE_MODE, so a u8 local is really QImode - `(u8)(c-3) < 2` gives widen_operand a paradoxical subreg (raw $a0) and combine.c:9246 drops the truncation before the sltiu, while `(u32)(c-3)` re-widens and loses it. And `s1 = (cmp) ^ 1` puts the comparison in the destination pseudo; the flag needs its own temp. §423 (ov_SC03_092/func_8017FA74): match_one closeness 0 + gate reject + "cause not determined" has a checkable cause. harvest_verify splices the draft where the INCLUDE_ASM stub was; a file-scope typedef the TU also defines (five lines below, here) makes gcc-2.7.2 exit 33 on a C89 redefinition, the TU fails, the gate reverts, and nothing names the typedef. Fix is block scope, proven with a three-way control. Mirror of §409 law 2 - together they cover collisions above and below the splice point. Tool trap: a scratch TU copy needs -Isrc/<overlay> or cpp exits 1 on the relative engine_core.h include and EVERY variant passes identically.
This commit is contained in:
+12
-4
@@ -2,7 +2,7 @@
|
||||
|
||||
> **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section.
|
||||
>
|
||||
> `docs/matching-cookbook.md` is ~716 KB / 1089 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
|
||||
> `docs/matching-cookbook.md` is ~716 KB / 1091 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
|
||||
|
||||
**How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win.
|
||||
|
||||
@@ -513,7 +513,7 @@
|
||||
- **§395** — ★★★ — FIVE NARROWING/PLACEMENT LEVERS FROM ONE 91-INSTRUCTION CRACK (P31 S69; byte-proven ov_SC06_018/func_80189E60, warm start 32 off → MATCH 91/91) <sub>L32611</sub>
|
||||
- **§418** — ★★★ — TWO LOOP-STRUCTURE LEVERS: MAKE THE SECOND INDEX A GIV, AND KEEP A TABLE ADDRESS UNFOLDED (P31 S71; byte-proven `ov_SC04_016/func_8017DF8C`, 184 ins, 32 → 0 in seven compiles) <sub>L33632</sub>
|
||||
|
||||
### types, signedness & load/store width (93)
|
||||
### types, signedness & load/store width (95)
|
||||
|
||||
- **§3-I1** — Unsigned range check: `(x - lo) < (hi-lo)` → `addiu`+`sltiu` <sub>L41</sub>
|
||||
- **§3-I2** — Byte mask forces `andi` even after `lbu` <sub>L47</sub>
|
||||
@@ -608,6 +608,8 @@
|
||||
- **§378** — ★★★ — THE **SELF-CALLER CAST**: LET A TU KEEP CALLING THE FUNCTION IT IS ABOUT TO DEFINE (P31 S69; byte-proven ov_SC04_010/func_8017D6CC) <sub>L32114</sub>
|
||||
- **§379** — ★★★ — **MEM_IN_STRUCT_P**: THE SAME LOAD, WRITTEN AS A STRUCT MEMBER, SCHEDULES WHERE A CAST CANNOT (P31 S69; byte-proven main/func_80021284 220 ins and main/func_8002D904 217 ins, found INDEPENDENTLY by two agents) <sub>L32164</sub>
|
||||
- **§392** — ★★★ — THE SONNET-WAVE HARVEST (P31 S69): SEVEN TYPE/ORDER LEVERS THAT EACH CLOSED A MATCH <sub>L32502</sub>
|
||||
- **§422** — ★★ — QImode ARITHMETIC VIA `(u8)(x - K)`, AND `flag ^ 1` NEEDS ITS OWN TEMP (P31 S71; byte-proven `resident/func_800D06E8`, 344 ins) <sub>L33760</sub>
|
||||
- **§423** — ★★★ — "MATCH IN ISOLATION + GATE REJECTS + CAUSE NOT DETERMINED" ⇒ GREP THE TU FOR A FILE-SCOPE TYPEDEF THE DRAFT ALSO CARRIES (P31 S71; byte-proven `ov_SC03_092/func_8017FA74`) <sub>L33780</sub>
|
||||
|
||||
### declarations, prototypes & K&R (114)
|
||||
|
||||
@@ -937,7 +939,7 @@
|
||||
- **§420** — ★★★ — A MULTI-CLUSTER SYMBOL REBASE, AND THE BARE-NAME DEDUP THAT HID THREE QUARTERS OF IT (P31 S71; 4 banked in 57 s) <sub>L33692</sub>
|
||||
- **§421** — ★★★ — A `la $tN` + `addiu` PAIR CAN BE A **RELOAD** ARTIFACT THAT NO C SPELLING REACHES (P31 S71; byte-proven `md_SC07_003/func_801A293C`, 313 ins, 6 → 0) <sub>L33729</sub>
|
||||
|
||||
### integration / TU plumbing (76)
|
||||
### integration / TU plumbing (77)
|
||||
|
||||
- **§8c** — Splitting a TU means rebuilding its DECLARATION ENVIRONMENT, not moving text (Phase 26 session 6) <sub>L456</sub>
|
||||
- **§8d** — Templating a body INTO a TU must not CHANGE its declaration environment — demote the carried data externs (Phase 26 session 8, byte-proven on `func_8015AE2C` ×133) <sub>L502</sub>
|
||||
@@ -1015,8 +1017,9 @@
|
||||
- **§398** — ★★★ — `family_remap` CARRIES THE **SOURCE** TU's DECL ENVIRONMENT INTO A DESTINATION THAT ALREADY OWNS THOSE NAMES (P31 S69; measured 3 banked of 22) <sub>L32835</sub>
|
||||
- **§3-D.** — INTEGRATION IS STILL THE BOTTLENECK, AND THE TU IS THE AUTHORITY <sub>L33140</sub>
|
||||
- **§415** — ★★ — A FILE-SCOPE DECL MAKES gcc-2.7.2 MERGE THE TU'S LATER *BLOCK-SCOPE* EXTERNS INTO IT (P31 S71; byte-proven `ov_SC04_011/func_80180B24`, 215 ins) <sub>L33547</sub>
|
||||
- **§423** — ★★★ — "MATCH IN ISOLATION + GATE REJECTS + CAUSE NOT DETERMINED" ⇒ GREP THE TU FOR A FILE-SCOPE TYPEDEF THE DRAFT ALSO CARRIES (P31 S71; byte-proven `ov_SC03_092/func_8017FA74`) <sub>L33780</sub>
|
||||
|
||||
### build graph, splat & the harness (192)
|
||||
### build graph, splat & the harness (193)
|
||||
|
||||
- **§4** — Flag/toolchain gotchas <sub>L190</sub>
|
||||
- **Build** — mechanism — per-file opt override (splat resegmentation) <sub>L307</sub>
|
||||
@@ -1210,6 +1213,7 @@
|
||||
- **§405** — ★★★ — THE S70 WAVE HARVEST: 130 agents, 113 MATCH, and the laws they brought back <sub>L33092</sub>
|
||||
- **§3-A.** — THE ORACLE HAS A HOLE: match_one cannot see a jump table (§405-A) <sub>L33098</sub>
|
||||
- **§414** — ★★★ — `parallel_gate` ON `main` IS A FALSE PASS, AND THE RULE WAS ALREADY WRITTEN DOWN (P31 S71) <sub>L33510</sub>
|
||||
- **§423** — ★★★ — "MATCH IN ISOLATION + GATE REJECTS + CAUSE NOT DETERMINED" ⇒ GREP THE TU FOR A FILE-SCOPE TYPEDEF THE DRAFT ALSO CARRIES (P31 S71; byte-proven `ov_SC03_092/func_8017FA74`) <sub>L33780</sub>
|
||||
|
||||
### process, measurement & doctrine (132)
|
||||
|
||||
@@ -2766,6 +2770,8 @@
|
||||
- **§419** — ★★★ — WHEN A PIN IS IMPOSSIBLE, WIN THE local-alloc DENSITY CONTEST INSTEAD (P31 S71; byte-proven `ov_SC01_000/func_8017DD04`, 297 ins) <sub>L33658</sub>
|
||||
- **§420** — ★★★ — A MULTI-CLUSTER SYMBOL REBASE, AND THE BARE-NAME DEDUP THAT HID THREE QUARTERS OF IT (P31 S71; 4 banked in 57 s) <sub>L33692</sub>
|
||||
- **§421** — ★★★ — A `la $tN` + `addiu` PAIR CAN BE A **RELOAD** ARTIFACT THAT NO C SPELLING REACHES (P31 S71; byte-proven `md_SC07_003/func_801A293C`, 313 ins, 6 → 0) <sub>L33729</sub>
|
||||
- **§422** — ★★ — QImode ARITHMETIC VIA `(u8)(x - K)`, AND `flag ^ 1` NEEDS ITS OWN TEMP (P31 S71; byte-proven `resident/func_800D06E8`, 344 ins) <sub>L33760</sub>
|
||||
- **§423** — ★★★ — "MATCH IN ISOLATION + GATE REJECTS + CAUSE NOT DETERMINED" ⇒ GREP THE TU FOR A FILE-SCOPE TYPEDEF THE DRAFT ALSO CARRIES (P31 S71; byte-proven `ov_SC03_092/func_8017FA74`) <sub>L33780</sub>
|
||||
|
||||
|
||||
---
|
||||
@@ -3867,3 +3873,5 @@ Notes routinely quote that as a section id. This table resolves it. Grep bait: `
|
||||
| L33658 | §419 | ★★★ — WHEN A PIN IS IMPOSSIBLE, WIN THE local-alloc DENSITY CONTEST INSTEAD (P31 S71; byte |
|
||||
| L33692 | §420 | ★★★ — A MULTI-CLUSTER SYMBOL REBASE, AND THE BARE-NAME DEDUP THAT HID THREE QUARTERS OF IT |
|
||||
| L33729 | §421 | ★★★ — A `la $tN` + `addiu` PAIR CAN BE A **RELOAD** ARTIFACT THAT NO C SPELLING REACHES (P |
|
||||
| L33760 | §422 | ★★ — QImode ARITHMETIC VIA `(u8)(x - K)`, AND `flag ^ 1` NEEDS ITS OWN TEMP (P31 S71; byte |
|
||||
| L33780 | §423 | ★★★ — "MATCH IN ISOLATION + GATE REJECTS + CAUSE NOT DETERMINED" ⇒ GREP THE TU FOR A FILE- |
|
||||
|
||||
@@ -33756,3 +33756,50 @@ had moved it.
|
||||
register belongs to REGALLOC at all.* `$t`-register appearances next to a `la` are the signature of
|
||||
reload scratch, and reload runs after every dial C gives you — the only reach is an asm that puts the
|
||||
instruction there directly.
|
||||
|
||||
## §422 ★★ — QImode ARITHMETIC VIA `(u8)(x - K)`, AND `flag ^ 1` NEEDS ITS OWN TEMP (P31 S71; byte-proven `resident/func_800D06E8`, 344 ins)
|
||||
|
||||
**1. A raw-`$a0` `addiu` on a byte value comes from doing the arithmetic in QImode.**
|
||||
mips.h defines no `PROMOTE_MODE`, so a `u8` local really is QImode. Write the range test in QImode —
|
||||
`(u8)(c - 3) < 2` — and `widen_operand` hands the subtraction a **paradoxical subreg** (the raw
|
||||
`$a0`), after which `combine.c:9246`'s `A - C1` vs `C2` rule drops the truncation before the `sltiu`.
|
||||
Every earlier probe on this function used `(u32)(c - 3)`, which **re-widens** and loses it. The cast
|
||||
is not cosmetic: it selects the mode the arithmetic happens in.
|
||||
|
||||
**2. `s1 = (cmp) ^ 1` puts the comparison in the DESTINATION pseudo.** That is expand-time subtarget
|
||||
reuse, and it produces a `$s1`/`$v0` pair the target does not have. Give the flag its own temp:
|
||||
|
||||
```c
|
||||
t = (u32)(r - 0x64) < 0x1E;
|
||||
s1 = t ^ 1;
|
||||
```
|
||||
|
||||
**Both are one-line respellings that no permuter reaches**, because both change which RTL the
|
||||
expander builds rather than the order of anything.
|
||||
|
||||
## §423 ★★★ — "MATCH IN ISOLATION + GATE REJECTS + CAUSE NOT DETERMINED" ⇒ GREP THE TU FOR A FILE-SCOPE TYPEDEF THE DRAFT ALSO CARRIES (P31 S71; byte-proven `ov_SC03_092/func_8017FA74`)
|
||||
|
||||
**The signature.** `match_one` closeness 0, the whole-binary gate rejects, and the classifier records
|
||||
`CAUSE NOT DETERMINED`. That combination has a specific, checkable cause.
|
||||
|
||||
**The mechanism.** `harvest_verify.py:490` splices by `txt.replace(stub, draft, 1)` — the draft lands
|
||||
exactly where the `INCLUDE_ASM` stub was. If the draft carries a FILE-SCOPE typedef that the TU also
|
||||
defines (here `typedef struct { s32 unk00; s32 unk04; } Tbl8_8017FC44;`, defined **five lines below**
|
||||
the stub), gcc-2.7.2 exits **33** on a C89 typedef redefinition. The whole TU fails, the gate reverts,
|
||||
and nothing in the verdict names the typedef — hence "cause not determined".
|
||||
|
||||
**The check, and the fix.** Grep the destination TU for every file-scope `typedef`/`struct`/`union`
|
||||
name the draft declares. Move the draft's copy to **BLOCK scope**; it is codegen-neutral (a
|
||||
label-normalised diff proves the declaration context changes nothing). Proven three ways here:
|
||||
spliced TU with the old draft = exit 33 `conflicting types for 'Tbl8_8017FC44'`, with the new draft =
|
||||
exit 0, and an unmodified-TU negative control = exit 0.
|
||||
|
||||
**This is the mirror of §409 law 2.** There the collision was with a typedef defined LATER in the TU
|
||||
and the fix was also block scope; here it is with one just below the splice point. Same rule, and
|
||||
between them they cover both directions: **a draft's file-scope type declaration is a hazard wherever
|
||||
the TU defines that name.**
|
||||
|
||||
**TOOL TRAP recorded by the same agent.** A scratch copy of a TU needs `-Isrc/<overlay>` or `cpp`
|
||||
exits 1 on its relative `"../shared/engine_core.h"` — and then **every variant "passes" identically**,
|
||||
which is a silent all-green instrument. Negative-control any TU-splice harness against an unmodified
|
||||
copy before believing a single verdict from it.
|
||||
|
||||
Reference in New Issue
Block a user