Files
BFM-decomp/docs/gcc-2.7.2-map/README.md
T

104 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.