# The gcc-2.7.2 codegen map — pass → residual → C-lever catalogue **What this is.** A catalogue of the pinned compiler's behaviour, organised by optimisation pass: for each residual pattern a near-miss diff can show, the mechanism in the compiler's own source that produces it, and the C-level lever that moves it — each lever **byte-proven** on a named function with the diff before and after. It was written in Phase 23 by four frontier-class agents reading the gcc 2.7.2 passes directly, after six phases in which the same residuals had been called "unsteerable"; it is the artifact that lets a mid-tier agent, or a local model, apply compiler-internal levers without reading 80,000 lines of source. The index and triage table live in the cookbook ([`docs/matching-cookbook.md`](../matching-cookbook.md) §31); the method is chapter 07 of the how-to ([`docs/how-to-ai-decomp/07-compiler-source.md`](../how-to-ai-decomp/07-compiler-source.md)). ## The files | File | Pass group (source files) | Catalogue | Size | |---|---|---|---| | [`sched.md`](sched.md) | scheduling: `sched.c` (sched1 pre-reload / sched2 post-reload) + `reorg.c` (delayed-branch) + the MIPS backend hooks (`config/mips/mips.c`, `mips.h`) | S1–S13 (LUID = source order, the birthing boost in both directions, the load-gap filler, the bb0 head-skip, the reused-temp fence …), D1–D5 (delay-slot content, eligibility, eager steal, thread copies, merged exits); the S11/RC-6 verdict downgrade | 266 lines | | [`regalloc.md`](regalloc.md) | register allocation + reload: `local-alloc.c`, `global.c`, `reload.c`, `reload1.c` (with `flow.c`, `function.c`, `caller-save.c`) | §A the eight knobs everything reduces to; §B RC-1…RC-15 (spill-slot shape = declaration order, wrong value spilled, callee-saved order, coalescing, pin side-effects, pressure lock, remat-vs-spill, reload artifacts, the preference cascade, the 3-qty sort bug, the `$0`-add opaque copy …); §C the tells; §D the triage order; §E the experiment record; §F–§H the later extensions incl. the `reg_renumber`-swap oracle | 286 lines | | [`loop.md`](loop.md) | the loop optimiser: `loop.c` (biv/giv detection, `combine_givs`, strength reduction, hoisting/preheader, biv elimination, reversal) | L1–L8 (IV count/anchor, index-biv elimination, loop reversal, hoisting and the inline limit, final-value compensation, giv-add order, invalid loops, increment position) | 369 lines | | [`cse_expr.md`](cse_expr.md) | common-subexpression elimination + expression emission: `cse.c`, `expr.c`, `function.c` (with `calls.c`, `stmt.c`) | cross-call ADDRESS caching (hoist-vs-remat — the class that blocked the 400-instruction giants), cross-call VALUE CSE (the phantom callee-saved register), the `/s` (`MEM_IN_STRUCT_P`) aliasing model in all four arms and its store-side flush lever, the temp-slot and stack-layout rules | 389 lines | | [`t7g-giant-harvest.md`](t7g-giant-harvest.md) | a Phase-24 session harvest (levers found while cracking the giants; a permuter tool fix) | **a log, not a primary reference**: where it disagrees with the three audited files above, those win | 351 lines | ## How to use it 1. Read the **tell** off the near-miss diff (`match_one` / `rtu_match` output, or the RTL dumps): a temporary in a spill slot = a reload artifact; "every small edit moves 20+ instructions" = a pressure lock → the permuter; a load stuck below a `x = 0` store while offset loads float = the `/s` flag; a phantom seventh callee-saved register held across the function = cross-call CSE; a prologue initialisation in the wrong order = the birthing boost. Each catalogue carries its full tells table. 2. Look up the class's lever in the catalogue, apply it to the C, gate. The condensed triage table: | Pass group | STEERABLE (a byte-proven lever exists) | INTRINSIC → the permuter | |---|---|---| | scheduling | S1 source order; S2 birthing boost (create or kill a sink); S4/5/6 load-gap filler, memory-unit spacing, hazard front-move; S7 prologue saves; D1–D3 delay-slot content / eligibility / eager steal | S3 load/mul chain-priority sink; S11 the LUID⊗allocation knife-edge — **downgraded**: try the S12 reused-temp fence and S13 head-skip escape first | | regalloc / reload | RC-1 spill-slot shape (declaration order); RC-2 wrong value spilled (allocno density); RC-3 callee-saved order; RC-4 coalescing un-tie; RC-5 pin side-effects; RC-7 remat-vs-spill; RC-8 reload artifacts; RC-9 cross-block copy | RC-6 pressure lock (its true form); the local-vs-global allocation tie | | loop | L1 IV count/anchor; L2 index-biv elimination; L3 reversal; L4 hoisting/preheader; L7 invalid loop; L8 increment position | L5 final-value compensation; L6 giv-add order | | cse / expr | cross-call address caching (nested-block pointer + a post-call `volatile` re-set); cross-call value CSE; the `/s` model + store-side flush; stack layout | the 1,000-instruction table flush (giants); `QImode` never gets `/s` | 3. **Before any register lever, read the allocation order** (`tools/alloc_table.py` over the pass dumps) — every `register … __asm__` pin the last functions of the project carried came off byte-identical once the source shape was right; pins are symptoms (R73). **Before any "wall" verdict, name the pass and quote the dump line** (R65), and write the producer census against a NAMED list (R69) — two written proofs of unmatchability were each one producer short. ## The byte-proof method Every lever in these files was validated the same way: compile the exemplar with the pinned triple (`gcc-2.7.2-psx cc1 -O2 -G0 -mips1 -mcpu=3000 -mgas -msoft-float -fgnu-linker` → maspsx `--aspsx-version=2.56 --expand-div` → GNU `as`) and compare relocation-masked bytes to the original with [`tools/match_one.py`](../../tools/match_one.py) (or, in the real translation unit, `rtu_match.py`); the experiment C files and RTL dumps are kept under `.run/gccmap/` (scratch). The instruments that grew around the map: `tools/cc1_dumps_tu.sh` (per-pass RTL dumps from the *real* translation unit — the standalone compile is not faithful on the executable's units; `-dL` for the loop pass), `tools/alloc_table.py` (the global allocator's priorities and hard registers per pseudo), `tools/ghost_census.py` (frame and spill-slot census from the dumps), and the one-second **reproducer battery**: five-line functions that isolate one mechanism, compiled with dumps, before any probe of the 500-instruction function. ## Provenance — read this before following a line number **Two source trees, gitignored under `tools/reference/` (SETUP §5.6):** - **`gcc-2.7.2/`** — the vanilla GNU release, **the real source of the pinned `cc1`**: a subset of 18 `.c` files plus `config/mips/` (`sched.c`, `reorg.c`, `local-alloc.c`, `global.c`, `reload.c`, `reload1.c`, `loop.c`, `cse.c`, `expr.c`, `function.c`, `calls.c`, `stmt.c`, `combine.c`, `toplev.c`, `flow.c`, `expmed.c`, `caller-save.c`, `integrate.c`, `optabs.c`, `varasm.c`, `recog.c`, the headers), staged from `ftp.gnu.org/old-gnu/gcc/gcc-2.7.2.tar.gz` (sha256 `7cd8bce5c3aeec59a72ecc2d3d5123864a817b14cdbd0680b1a969c3bccc5da5`; GPL-2.0). Re-fetch the tarball and copy the files you need; the whole tree is not required. - **`gcc-papermario/`** — `pmret/gcc-papermario` at `a6afc2afbcaf6682930141d526afdc95801fc2fd`, source files at the repository root. **It is gcc 2.8.1, not 2.7.2** — a fact established in Phase 23 after the map had been written against it. The difference is *behavioural* (2.8.1 disables biv-elimination paths that are live in the real 2.7.2 `cc1`) and the line-number drift is large and non-uniform: `combine_regs` +103, `allocate_reload_reg` +377, `choose_reload_regs` +611 — enough to land inside a different function. **The Phase-29 audit (2026-07-28).** All 184 citations and claims of the three primary files were re-derived against the vanilla 2.7.2 source by five parallel agents; every refuted claim then went to an independent agent whose job was to refute the refutation, defaulting to upholding the map. Result: **119 confirmed · 40 line-drift (mechanism intact, number wrong) · 21 raised as refuted, of which 14 were overturned and 7 stand · 4 unverifiable.** The model is overwhelmingly sound — do not delete levers — but a line number may belong to either tree. Each file carries its own audit banner with the specifics (`cse_expr.md` had the most errors; one `sched.md` claim about the birthing boost and register-asm pins was byte-refuted and corrected). **Every citation is tagged with its tree.** `tools/gccmap_cites.py` derives, for every `file.c:NNN` cite in these files, which tree the number belongs to, and writes the tag after the cite: | Tag | Meaning | Count | |---|---|---| | `[2.7.2]` | the cited construct sits at that line in the vanilla 2.7.2 subset — verified against the tree | 79 | | `[2.8.1 pm]` | the cited construct sits at that line in gcc-papermario; the 2.7.2 line differs (re-derive with `grep -n` before citing) | 55 | | `[repo]` | a project file (`src/shared/engine_core.h`), not gcc | 1 | The derivation is from the trees, never typed: quoted source snippets and C identifiers in the citing sentence are searched near the cited line in each tree (function extents for cites inside long bodies; the nearer tree wins, an equal distance means the line is equally valid in 2.7.2); the author's own cues (`papermario …`, `→2.7.2 :NNN`) break ties and fail loudly when they contradict the evidence; the 20 cites the evidence cannot settle (18 with no usable evidence near them, 2 where the two trees tie) carry a human verdict with its reason in [`cite_overrides.tsv`](cite_overrides.tsv). Six known-true cases recorded in the map's own text are the tool's controls (`--controls`, 6/6); `--verify` re-derives every tag; `--check` (textual, in `make tools-health` and CI) refuses an untagged cite or a stale override. 135 cites across the five files. ## Related - Cookbook §31 (the index and triage), §17 (the register-pin toolkit), §30 (the `/s` flag), §34 (the 3-qty sort bug), §501 (the twelve dump-read laws and the two overturned proofs). - [`docs/accelerators.md`](../accelerators.md) A4 — "read the compiler's source once, into a codegen map" (found Phase 23, available from Phase 6). - [`docs/how-to-ai-decomp/07-compiler-source.md`](../how-to-ai-decomp/07-compiler-source.md) — the method for the next project.