diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md index b2dcba550..02d05352d 100644 --- a/docs/cookbook-index.md +++ b/docs/cookbook-index.md @@ -2,7 +2,7 @@ > **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section. > -> `docs/matching-cookbook.md` is ~716 KB / 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) L32611 - **§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) L33632 -### types, signedness & load/store width (93) +### types, signedness & load/store width (95) - **§3-I1** — Unsigned range check: `(x - lo) < (hi-lo)` → `addiu`+`sltiu` L41 - **§3-I2** — Byte mask forces `andi` even after `lbu` L47 @@ -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) L32114 - **§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) L32164 - **§392** — ★★★ — THE SONNET-WAVE HARVEST (P31 S69): SEVEN TYPE/ORDER LEVERS THAT EACH CLOSED A MATCH L32502 +- **§422** — ★★ — QImode ARITHMETIC VIA `(u8)(x - K)`, AND `flag ^ 1` NEEDS ITS OWN TEMP (P31 S71; byte-proven `resident/func_800D06E8`, 344 ins) L33760 +- **§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`) L33780 ### 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) L33692 - **§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) L33729 -### integration / TU plumbing (76) +### integration / TU plumbing (77) - **§8c** — Splitting a TU means rebuilding its DECLARATION ENVIRONMENT, not moving text (Phase 26 session 6) L456 - **§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) L502 @@ -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) L32835 - **§3-D.** — INTEGRATION IS STILL THE BOTTLENECK, AND THE TU IS THE AUTHORITY L33140 - **§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) L33547 +- **§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`) L33780 -### build graph, splat & the harness (192) +### build graph, splat & the harness (193) - **§4** — Flag/toolchain gotchas L190 - **Build** — mechanism — per-file opt override (splat resegmentation) L307 @@ -1210,6 +1213,7 @@ - **§405** — ★★★ — THE S70 WAVE HARVEST: 130 agents, 113 MATCH, and the laws they brought back L33092 - **§3-A.** — THE ORACLE HAS A HOLE: match_one cannot see a jump table (§405-A) L33098 - **§414** — ★★★ — `parallel_gate` ON `main` IS A FALSE PASS, AND THE RULE WAS ALREADY WRITTEN DOWN (P31 S71) L33510 +- **§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`) L33780 ### 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) L33658 - **§420** — ★★★ — A MULTI-CLUSTER SYMBOL REBASE, AND THE BARE-NAME DEDUP THAT HID THREE QUARTERS OF IT (P31 S71; 4 banked in 57 s) L33692 - **§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) L33729 +- **§422** — ★★ — QImode ARITHMETIC VIA `(u8)(x - K)`, AND `flag ^ 1` NEEDS ITS OWN TEMP (P31 S71; byte-proven `resident/func_800D06E8`, 344 ins) L33760 +- **§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`) L33780 --- @@ -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- | diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index 490318493..af3cf880d 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -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/` 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.