From ce8f7629ae3a965baf60bd98e0cafe1cf76e7259 Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Tue, 28 Jul 2026 12:43:06 -0600 Subject: [PATCH] =?UTF-8?q?docs(phase-29):=20T35=20=E2=80=94=20the=20last?= =?UTF-8?q?=204=20codegen-map=20files=20audited=20vs=20real=20gcc-2.7.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scope enumerated before acting: cse_expr.md, loop.md, sched.md (full pass — T33 landed only a partial), t7g-giant-harvest.md. 35 agents (9 derive + 26 adversarial refute), 2.48M subagent tokens. 308 findings: 174 CONFIRMED / 99 LINE-DRIFT / 26 REFUTED raised -> 20 UPHELD, 6 OVERTURNED / 9 unverifiable. cse_expr.md had the highest error density (17 refuted of 74); loop.md the lowest (3 of 96) thanks to its pre-existing caveat table. 12 FABRICATED (vs 0 last audit) — DIAGNOSED, not waved through: the agents pasted MAP text into the source_quote field instead of compiler source. All 12 are CONFIRMED-status and none underpins an upheld refutation, so nothing was deleted on bad evidence — but they are UNVERIFIED, they sit in loop.md's biv-elimination area, and loop.md now records that as an open gap rather than a pass (R32). Headline corrections: - cse_expr: THE 1000-INSN CSE FLUSH DOES NOT EXIST IN 2.7.2 (added in 2.8.1; grep num_insns -> no hits). It drove THREE places — §1's killer table, §6's giant tell, §7's "shift +-insns across the 1000 boundary" lever. A lever aimed at a counter our compiler lacks, in exactly the giants this map serves. All struck. - cse_expr: §2's "kill THE class reg" is singular and wrong. The audit BYTE-REPRODUCED T31's wall on the pinned cc1: expand_block_move (mips.c:2350-2351) copy_addr_to_reg's BOTH aggregate addresses. Two byte-proven remedies recorded, with the caveat that field-by-field copy is closed when the target's own bytes need the block move (func_80132F40's case). - cse_expr: assign_temp absent in 2.7.2 and no /s reset on slot reuse (recycled slots INHERIT /s); no BUILT_IN_MEMSET; §6's "recompute after a join is never a residual" false at -O2. - sched: S7's EPILOGUE half false (no live define_expand "epilogue" on MIPS) — re-scoped not deleted; insn_cost is DEP-KIND-BLIND so restoring /s anti edges is not free. - loop: "no memory load is EVER hoisted from a loop containing a call" FALSE — invariant_p checks RTX_UNCHANGING_P first; byte-proven that a const int* load hoists to the preheader. Call args are emitted LEFT-to-right, not right-to-left. Remaining: matching-cookbook.md (~52 citations, MIXED provenance) — but a DIFFERENT risk profile, since its idioms are byte-proven and citations are explanation, so a targeted citation sweep is proportionate rather than a full audit. Not done; flagged. Docs-only: no src/ or config/ touched, R22 not re-run and not claimed. --- docs/gcc-2.7.2-map/cse_expr.md | 88 ++++++++++++++++++++++--- docs/gcc-2.7.2-map/loop.md | 33 ++++++++-- docs/gcc-2.7.2-map/sched.md | 13 +++- docs/gcc-2.7.2-map/t7g-giant-harvest.md | 7 ++ phase-ends/CURRENT_PHASE.md | 63 ++++++++++++++++++ 5 files changed, 188 insertions(+), 16 deletions(-) diff --git a/docs/gcc-2.7.2-map/cse_expr.md b/docs/gcc-2.7.2-map/cse_expr.md index bfadb7eeee..fbef360086 100644 --- a/docs/gcc-2.7.2-map/cse_expr.md +++ b/docs/gcc-2.7.2-map/cse_expr.md @@ -1,7 +1,8 @@ # gcc-2.7.2 residual→C-lever map: CSE + expression emission + `/s` aliasing + stack layout **Pass-group:** `cse.c` (8989) + `expr.c` (12077) + `function.c` (6321), with targeted reads of `calls.c` / `stmt.c` / `local-alloc.c` / `sched.c` where they consume this group's decisions. -All source cites are `tools/reference/gcc-papermario/:`. All byte-proofs ran through +All source cites are `tools/reference/gcc-papermario/:` — **[A23] which is gcc 2.8.1, NOT +our 2.7.2; see the audit block below before following any line number.** All byte-proofs ran through `tools/match_one.py` (pinned triple, relocation-masked byte equality). Proof C files: `.run/gccmap/proofs/`. Date: 2026-07-02, Phase 23. @@ -9,6 +10,71 @@ All source cites are `tools/reference/gcc-papermario/:`. All byte-pr Phase 20). Both canonical stub exemplars now MATCH** (`func_80149374` 23 ins, `func_801493D0` 23 ins — reach-134 fns, ready for whole-binary integration). Lever = §2 below. +> ## ⚠️ SOURCE-VERSION AUDIT (Phase 29 SESSION-23, 2026-07-28) — THIS FILE HAD THE MOST ERRORS +> The cites above say `gcc-papermario`, **which is gcc 2.8.1, not our 2.7.2** (vanilla 2.7.2 is at +> `tools/reference/gcc-2.7.2/`). All 74 claims here were re-derived against the real source by +> parallel agents, each REFUTED claim then adversarially re-checked by an independent agent told to +> uphold the map by default. **17 REFUTED raised; the highest error density of any map file.** +> Line numbers drift −20 to −220 (cse.c), −960 to −1180 (expr.c), −230 to −520 (function.c) — enough +> to land inside a different function. **`grep -n '^sym ('` before citing.** +> +> ### [A23-1] THE 1000-INSN CSE FLUSH DOES NOT EXIST IN gcc 2.7.2 — it is 2.8.1-only +> `grep -n num_insns tools/reference/gcc-2.7.2/cse.c` → **no hits**; no `flush_hash_table`, no +> "quadratic", no "Perhaps for 2.9" anywhere in the 8,779-line file. It was added in 2.8.1 +> (`gcc-papermario/cse.c:8621-8644`). **In our compiler a CSE class NEVER expires by instruction +> count.** This invalidates THREE places below — §1's table row, §6's "long straight-line giant" +> tell, and §7's "check `num_insns` distance / shift ±insns across the 1000 boundary" bullet — i.e. +> **a lever aimed at a counter our compiler does not have, in exactly the giants this map is +> consulted for.** All three are struck inline. +> +> ### [A23-2] §2's "kill THE class reg" is SINGULAR AND WRONG — and this is why §2 can fail +> A CSE class routinely holds **several** registers, and the extra ones have **no C-level name**, so +> the output-only asm kill can only ever name one of them. Byte-reproduced with the pinned cc1 during +> the audit: adding one line `v[1] = v[0];` to a working case defeats the recipe completely (working: +> frame 56 / 2 saved regs / `addiu` remat at site 2 → broken: frame 64 / 3 saved regs / `addu +> $16,$sp,16` hoist / both sites `move $aN,$16`). **Mechanism:** `config/mips/mips.c:2350-2351` +> (`expand_block_move`) calls `copy_addr_to_reg` on **BOTH** aggregate addresses, creating +> `(set (reg:SI 77) (plus:SI (reg:SI 30 $fp) 16))`; cse substitutes reg 77 into the FIRST call's +> arg-load, so by the time the asm kill fires it invalidates a register **already out of the chain** +> and reg 77 sails on into `$16`. +> **Two remedies, both byte-proven in the audit:** (a) spell the aggregate copy **field-by-field** +> (returns to frame 56 / 2 regs / remat), or (b) force a **real join CODE_LABEL** between the block +> move and the calls. **Caveat before reaching for (a):** if the TARGET's own bytes contain the +> unaligned `lwl/lwr…swl/swr` block move, spelling it field-by-field changes bytes you need — in that +> case the s32/remat route is simply closed and you should keep the narrower-typed draft. +> *(This is the documented explanation of a live 47→40-mismatch wall hit the same day on +> `func_80132F40`; ladder preserved at `.run/near6/f132F40_v1..v6.c`.)* +> +> ### The other upheld corrections (each struck or annotated at its site) +> - **§1's "complete list" of class killers is NOT complete** (upheld narrowly — the word "complete" +> fails). Notably a **volatile SET's dest is invalidated** via `do_not_record` (`cse.c:7110-7114`), +> which is the source line for §2's own lever — as written, §1 says that lever cannot exist. +> - **§4a: `assign_temp` does not exist in gcc 2.7.2** (added in 2.8; `grep -rn assign_temp` → 0 hits) +> and **2.7.2's `assign_stack_temp` does NO `/s` reset**, so a **RECYCLED slot INHERITS `/s` and +> `RTX_UNCHANGING_P` from its previous occupant** — the opposite of what §4a claims, and it +> interacts directly with §5's own slot-recycling text. +> - **There is NO `BUILT_IN_MEMSET`/`BZERO` in 2.7.2's `expand_builtin`.** `memset` is always an +> ordinary library CALL (which flushes the whole cse memory table), never an inline `/s` BLKmode +> block move. The "memcpy/memset/strcpy" trio is really **memcpy/strcpy** sharing one path. +> - **§6's "recompute right after a join is NORMAL — never a residual" is FALSE at -O2**, where +> `flag_cse_follow_jumps` and `flag_cse_skip_blocks` are both set (`toplev.c:3389-3390`) and +> `cse_end_of_basic_block` extends the table across a join (TAKEN `cse.c:8118`, AROUND `:8150`). +> As written, that row would have blocked §H.1's own antidote. +> - **§5's "`frame_offset` starts at 0 (= sp+0x10 at runtime)"** — only the parenthetical is wrong. +> `STARTING_FRAME_OFFSET` is `current_function_outgoing_args_size`, which is **0 for a leaf with no +> calls**, so a leaf's first local sits at **sp+0**, not sp+0x10. The rest of the claim stands. +> - **§H's "no bank (5 permuter-shaped clusters)" verdict is SUPERSEDED** — byte-refuted the same day: +> 4 of the 5 clusters proved steerable from C (`func_80176734` 217 → **13**, count exact 371/371). +> Only two coupled ties survive. §H's own two mechanisms both CONFIRMED, with one correction: the +> diamond antidote's barrier-preceded label is the **ELSE** label, not the merge label (the merge +> label works because it is neither followable nor skip-block-able, so `new_basic_block()` +> (`cse.c:8430`) clears the table). +> - **§H's `update_equiv_regs` live-length doubling is exactly ×2 on global priority** +> (`local-alloc.c:1064`, and `allocno_live_length` is the DENOMINATOR — `global.c:594-597`); the +> rest of the informal "~×4" comes from the `floor_log2(n_refs)*n_refs` numerator. It applies only +> to pseudos carrying a REG_EQUIV note, and `CONSTANT_P` (`rtl.h:237-240`) **excludes a bare PLUS** +> — so a frame address never qualifies (same correction as `regalloc.md` RC-7). + --- ## §0 The diagnostic loop: RTL dumps from the pinned cc1 @@ -24,9 +90,11 @@ cd wd && /tools/bin/gcc-2.7.2-psx/cc1 -quiet -O2 -G0 -mips1 -mcpu=3000 -mg -msoft-float -fgnu-linker -da t.i -o t.s ``` -Reading the dumps: pseudos start ≈ reg 70 (MIPS: 0-31 GPR, 32-63 FPR, 64-66 hi/lo/fpsw, -67-70 virtuals). `(reg:SI 69)` in `.rtl` = **virtual-stack-vars** (frame base, = first local's -address). In `.cse` and later, frame addresses appear as `(plus (reg 30 $fp) k)` — `$fp` is +Reading the dumps: ~~pseudos start ≈ reg 70 (MIPS: 0-31 GPR, 32-63 FPR, 64-66 hi/lo/fpsw, +67-70 virtuals).~~ **[A23] corrected — `FIRST_PSEUDO_REGISTER` is 68** (`config/mips/mips.h:1179`), +so the four virtuals are **68-71** and **the first pseudo is 72**, not ~70. (The headline +`(reg:SI 69)` below is still right: virtual-stack-vars is the 2nd virtual.) `(reg:SI 69)` in `.rtl` += **virtual-stack-vars** (frame base, = first local's address). In `.cse` and later, frame addresses appear as `(plus (reg 30 $fp) k)` — `$fp` is eliminated to `$sp` only at reload, so grep for `$fp` pre-reload, `sp` post. Triage rule: - residual visible in `.cse` → this file, §1-§3 below; - appears first in `.lreg/.greg` → regalloc (pins / §30 recipes); @@ -49,7 +117,7 @@ not reuse that value" reduces to whether the class was still valid at the second | CALL_INSN | `invalidate_memory(everything)`: ALL `MEM` entries die (non-const calls) | `cse.c:7409-7415` | | memory store | selective MEM-entry kill via `note_mem_written` — see §4 aliasing table | `cse.c:7709`, `1732` | | CODE_LABEL | **total flush** (`new_basic_block`) — every class dies at every label | `cse.c:797, 8614` | -| 1000 insns | **total flush** mid-block ("extreme quadratic behavior" kludge) | `cse.c:8626` | +| ~~1000 insns~~ | ~~**total flush** mid-block ("extreme quadratic behavior" kludge)~~ **[A23-1] DOES NOT EXIST IN 2.7.2** — 2.8.1-only; no `num_insns` in our `cse.c`. A class never expires by insn count. | ~~`cse.c:8626`~~ | | volatile asm | **NOTHING** (no reg-class invalidation; a `"memory"` clobber kills only MEM entries via BLKmode→`all=1`) | `cse.c:6340-6355` | Consequences you will see in diffs: @@ -268,7 +336,7 @@ internal offsets AND changes `/s` (stmt.c:3646 gives the array home `/s`) and IV | frame ±8, or a local's offset out of decl order | §5 slot recycling / 8-rounding | reproduce/eliminate the compiler temp; reorder decls | | every array sits 8-aligned with padding gaps | §5 BLKmode rounding | expected — don't fight it, mimic with decl order | | value recomputed right after a branch join/label | §1 label flush | NORMAL — never a residual; don't add CSE-defeating hacks | -| long straight-line giant: early value suddenly recomputed mid-function | §1 1000-insn flush | expected in giants; position-dependent — see §7 | +| long straight-line giant: early value suddenly recomputed mid-function | ~~§1 1000-insn flush~~ **[A23-1] NOT the flush (absent in 2.7.2)** — look for a label/join, a volatile, or a call flushing the memory table instead | ~~expected in giants; position-dependent — see §7~~ **re-triage against §1's real killer list** | | `lui` above a branch, `ori` duplicated in delay slot + taken path | dbr/reorg territory (delay-slot stealing), NOT cse | route to jump/sched pass-group | --- @@ -284,10 +352,14 @@ internal offsets AND changes `/s` (stmt.c:3646 gives the array home `/s`) and IV - **§5 layout: STEERABLE** via decl order/typing/temp reproduction; INTRINSIC only in that you cannot place two 8-BLKmode objects at 4-mod-8 offsets — that's evidence the original source had different object boundaries, not a permuter case. -- **§1 1000-insn flush: INTRINSIC-ish** — you cannot move the counter from C; if a giant's +- ~~**§1 1000-insn flush: INTRINSIC-ish** — you cannot move the counter from C; if a giant's residual is a reuse/recompute flip exactly once mid-function, check `num_insns` distance; restructuring that shifts ±insns across the 1000 boundary is the only (fragile) lever. - Document any confirmed case before hand-grinding. + Document any confirmed case before hand-grinding.~~ + **[A23-1] DELETED — the counter does not exist in gcc 2.7.2** (`grep -n num_insns cse.c` → no hits; + added in 2.8.1). Do NOT spend a giant's budget measuring distance to a 1000-insn boundary. A + once-mid-function reuse/recompute flip in OUR compiler is a label/join (§1 + the -O2 + follow-jumps/skip-blocks behaviour), a volatile, or a call — all of which ARE steerable. - **`func_80132784` (400 ins, `asm/ov_SC01_077/nonmatchings/ov_SC01_077_a/`)** — the draft (`.run/backlog_drafts/func_80132784.c`, stuck 240/400) is MULTI-CLASS, in this order: (1) §5: single `u8 buf[0xC0]` vs target's separate 8-aligned locals (target arg addresses diff --git a/docs/gcc-2.7.2-map/loop.md b/docs/gcc-2.7.2-map/loop.md index 1543965e1e..a83b51fed8 100644 --- a/docs/gcc-2.7.2-map/loop.md +++ b/docs/gcc-2.7.2-map/loop.md @@ -21,6 +21,16 @@ differences are BEHAVIORAL and bit us immediately: | `combine_givs` order | qsort hook + refined benefit bookkeeping | plain linked-list pair loop (anchor rules below) | | giv increment placement | AUTO_INC logic (moot on MIPS) | always inserted **immediately before the biv increment insn** | +> **[A23] AUDIT OUTCOME (2026-07-28):** all 96 claims in this file were re-derived against +> `tools/reference/gcc-2.7.2/` by parallel agents, each REFUTED claim adversarially re-checked. +> **Only 3 REFUTED were raised — the LOWEST error density of any map file**, which is a direct credit +> to the caveat table above: it already captured the behavioural 2.8.1-vs-2.7.2 deltas. Two upheld +> corrections are marked `[A23]` inline (the "no memory load is EVER hoisted" absolute, and the +> right-to-left call-arg order). **One honest gap:** 12 findings in the biv-elimination / +> `check_dbra_loop` area returned evidence that quoted THIS FILE rather than the compiler source, so +> they are **unverified, not confirmed** — the caveat table's own rows are the ones affected. Re-derive +> them before leaning on a biv-elimination claim. + A vanilla 2.7.2 extraction is at `.run/gccmap/gcc-2.7.2-vanilla-src/` (loop.c, unroll.c, sched.c, cse.c, rtl.h, config/mips). **Recommend promoting it to `tools/reference/` — line refs below are to that tree.** (2.8.1 refs marked "pm:".) @@ -78,9 +88,13 @@ exclusion), `record_giv` (:4341), `combine_givs_p`/`express_from` (:5457/:5419), 6. **Anchor choice**: `bl->giv` is prepend-built during the forward scan, and `combine_givs` (2.7.2 loop.c:5494) takes g1 from the list head first (pass 0 = replaceable g1 only) → **the LAST-emitted DEST_ADDR giv anchors** and all others - become `anchor+delta` offsets. NB call args are expanded right-to-left, so *the - first arg's load is emitted last* — that's why banked func_80150528 anchors at - +0x20 (first call arg) with 0x38/0x3C offsets off it. + become `anchor+delta` offsets. ~~NB call args are expanded right-to-left, so *the + first arg's load is emitted last*~~ — **[A23] FALSE: args are emitted LEFT-TO-RIGHT.** The audit's + RTL dump shows `$a0` at insn 10, `$a1` at 12, `$a2` at 14 (ascending), so the FIRST arg's load is + emitted **first**. The observed fact that banked `func_80150528` anchors at +0x20 (its first call + arg) still holds — but it follows from `record_giv`'s prepend + `combine_givs` taking the list + HEAD (which makes the last-PREPENDED giv the head), NOT from a right-to-left arg order. Do not + reason about arg emission order from this bullet. **C levers (with proofs):** - **Target has biv + ONE derived IV (offset cluster)** → single walked base pointer, @@ -205,9 +219,18 @@ substitution (:735-770), `combine_movables` (:1239), desirability + emission `threshold × savings × lifetime ≥ insn_count` (thresholds L0 — for typical loops this is nearly always true; the interesting blockers are the SAFETY conditions). - **A CALL anywhere in the loop sets `unknown_address_altered`** (`prescan_loop:2201`) - → `invariant_p(MEM) == 0` for every load → **no memory load is EVER hoisted from a + → `invariant_p(MEM) == 0` for ~~every~~ **most** loads. ~~**no memory load is EVER hoisted from a loop containing a call** (proven expC c3: `lw D_SRC` stays in-loop). Don't fight - it with cached locals — match the target's in-loop reloads by NOT caching. + it with cached locals — match the target's in-loop reloads by NOT caching.~~ + **[A23] "EVER" is FALSE — there is a real exception.** `invariant_p`'s `case MEM:` arm + (2.7.2 `loop.c:2760-2775`) checks `RTX_UNCHANGING_P (x)` **before** consulting + `unknown_address_altered` and `break`s — i.e. **read-only items ARE invariant and DO hoist even + with a call in the loop.** Byte-proven during the audit on the pinned cc1: + `int t(const int *p,int n){int s=0,i;for(i=0;i1 (load feeding the just-scheduled consumer) it is **queued `cost` cycles**: one independent insn gets wedged between a load and its consumer whenever one is ready; if none, they stay adjacent. 7. **`adjust_priority:2534` (2.7.2: **2507**) — THE BIRTHING BOOST (pre-reload ONLY, `reload_completed==0`)**: on becoming ready, an insn whose pattern is `SET(REG, …)` — **any REG, pseudo OR hard; CORRECTED 2026-07-28, there is no `>= FIRST_PSEUDO_REGISTER` test in the function** — with the dest live and **`REG_N_SETS(dest)==1`** (`birthing_insn_p:2498`; 2.7.2: **2469**, the `reg_n_sets` test at **2490**) has its priority raised to `max_priority` (≈ the launching insn's) → it wins every tie → **single-set defs sink to just before their first consumer**. Dump tell: `(7f000001)` priorities in the ready list. NB: REG_N_SETS is counted **after cse/flow** — a source-level 2nd assignment that cse copy-propagates or flow dead-store-eliminates does NOT kill the boost (proof: `exp/t5.c`, `exp/t6.c` — both still boosted). 8. Special pins: **bb0 head-skip** (sched.c:3218-3244): the leading run of `pseudo = hard-arg-reg` param copies is excluded from scheduling (stays first, in arg order). **Tail pin** (3313-3360): trailing JUMP/CALL/USE insns stay at bb end (TAIL_PRIORITY). `SCHED_GROUP_P`: a call + its immediately-preceding `USE argreg` insns move as one unit. -9. **sched2 differences**: no boost, no head-skip; hard-reg anti/output webs (scratch reuse) now pin most of sched1's order in place; **nop-moves are deleted** (sched.c:4926); RTL prologue/epilogue saves are now in the pool (see S7). sched2's LUID = sched1's output order → **pre-reload placement persists**. +9. **sched2 differences**: no boost, no head-skip; hard-reg anti/output webs (scratch reuse) now pin most of sched1's order in place; **nop-moves are deleted** (sched.c:4926); RTL prologue ~~/epilogue~~ saves are now in the pool (see S7) — **[A23] PROLOGUE ONLY; the epilogue expander is dead on MIPS in 2.7.2, so epilogue restores never enter sched2's pool.** sched2's LUID = sched1's output order → **pre-reload placement persists**. --- @@ -116,7 +117,13 @@ The scheduler **never moves an insn across a basic-block boundary** (gcc-2.7.2 h ### S6 — "Independent insn separates address-gen from use" / copy placed between ⇒ mechanics of the class rule - **Decision point:** `rank_for_schedule:2428-2452` class 3 > class 1. On MIPS anti/output are ALWAYS class 3 (ADJUST_COST) — only true-data-deps through latency>1 (loads, mul/div) are demoted. Explains the recurring "unrelated move sits between `addiu $x` and `lw …($x)`" target shapes. Steer via which independents are available (statement order). -### S7 — Prologue/epilogue save/restore interleave ⇒ sched2 artifact, body-side STEERABLE +### S7 — Prologue~~/epilogue~~ save~~/restore~~ interleave ⇒ sched2 artifact, body-side STEERABLE +> **[A23] RE-SCOPED, not deleted (audit 2026-07-28).** The **prologue** half is CONFIRMED: the MIPS +> prologue really is RTL, so its saves are in sched2's pool. The **epilogue** half is FALSE for our +> build — `grep -n 'define_expand "epilogue"' config/mips/mips.md` finds only a DEAD entry, and +> `thread_prologue_and_epilogue_insns` (`function.c:5515`) is split by two independent guards +> (`HAVE_prologue` / `HAVE_epilogue`), so the epilogue restores are NOT scheduled RTL here. +> **Do not look for epilogue-restore interleave as a sched2 artifact — it cannot occur.** - MIPS prologue is **RTL**: saves emitted `$ra` down to `$s0` (**descending regno**, `save_restore_insns:5077`), sp-adjust first. sched2 weaves body insns among them under the same rank rules (anti-deps: `sw $sN` must precede the first body write of `$sN`). - Target tell: `sw $s1` far from `sw $ra/$s5/$s4` (pulled by an early body overwrite of `$s1`); a callee-save `sw` in a branch/call delay slot (dbr backward-fill, exp/t2 f2: `bne…; sw $31,20($sp)`). - The saves' RELATIVE order is fixed (descending regno) — if the target shows otherwise it's sched2 weaving, steered by the body insns' priorities/LUIDs, not by any prologue-side lever. diff --git a/docs/gcc-2.7.2-map/t7g-giant-harvest.md b/docs/gcc-2.7.2-map/t7g-giant-harvest.md index cd074b8d4e..bbe66d8261 100644 --- a/docs/gcc-2.7.2-map/t7g-giant-harvest.md +++ b/docs/gcc-2.7.2-map/t7g-giant-harvest.md @@ -1,5 +1,12 @@ # T7 §G — levers harvested this session (formalize into cookbook §36/§31 at batch close, R30) +> **[A23] SOURCE-VERSION AUDIT (2026-07-28).** 30 claims re-derived against `tools/reference/gcc-2.7.2/`; +> 2 REFUTED raised. **Provenance here is MIXED, not uniformly contaminated** — some cites are already +> 2.7.2-correct (e.g. `sched.c:2469` = the true `birthing_insn_p` line) while others came from the +> 2.8.1 `gcc-papermario` tree. So check each citation individually rather than assuming a uniform +> offset. This is a session harvest log, not a primary reference: where it disagrees with +> `sched.md` / `regalloc.md` / `cse_expr.md` (all audited the same day), those files win. + ## TOOL FIX (flywheel) — permuter comment-strip (tools/p16_permute.py make_base_c) A draft's header comment (long, non-ASCII —/§, prose that trips a prep regex) lost its closing `*/` in base.c → `cpp -P -nostdinc` died "unterminated comment" → decomp-permuter no-op'd SILENTLY diff --git a/phase-ends/CURRENT_PHASE.md b/phase-ends/CURRENT_PHASE.md index 07b89e5870..ed3f38a4db 100644 --- a/phase-ends/CURRENT_PHASE.md +++ b/phase-ends/CURRENT_PHASE.md @@ -6842,3 +6842,66 @@ Struck-through text is preserved, never deleted (H5). 2. `func_80176734` at 13/371 — permuter, then the `reg_renumber` gdb oracle. 51,198 ins. **§H's oracle recipe is now audited**, so it is safe to run. 3. **`loop.md` is the last un-audited map file** (`scan_loop` drifts +74). Same two-stage recipe. + +## ✅ T35 — the remaining 4 map files audited: 20 corrections, 6 false alarms caught, 12 flagged unverified + +Drew: "do loop.md too. are there more? do them all if we need to." Enumerated the real scope first +rather than guessing, then ran one wave over everything left: **`cse_expr.md`, `loop.md`, +`sched.md` (full pass — T33 had only landed a partial), `t7g-giant-harvest.md`.** +**35 agents (9 derive + 26 adversarial refute), 2.48M subagent tokens, 25 min.** + +**308 findings: 174 CONFIRMED · 99 LINE-DRIFT · 26 REFUTED raised → 20 upheld / 6 overturned · 9 unverifiable.** + +| file | findings | REFUTED raised | note | +|---|---|---|---| +| `cse_expr.md` | 74 | **17** | highest error density of any map file | +| `sched.md` | 108 | 4 | full claim-by-claim pass (T33 was partial) | +| `loop.md` | 96 | 3 | LOWEST density — credit to its pre-existing caveat table | +| `t7g-giant-harvest.md` | 30 | 2 | MIXED provenance, not uniformly contaminated | + +### ⚠️ 12 FABRICATED — diagnosed, and the diagnosis matters +`tools/verify_map_findings.py` flagged 12 quotes that appear nowhere near their cited line (vs **0** +in the T34 audit). **Cause is NOT invention: the agents pasted MAP text into the `source_quote` +field instead of compiler source** — "single fall-through exit." is in `loop.md`, not `loop.c`. +All 12 are **CONFIRMED**-status and **none underpins an upheld refutation**, so nothing was deleted +on bad evidence. But they are **unverified, not confirmed**, they all sit in loop.md's +biv-elimination / `check_dbra_loop` area, and that is recorded in `loop.md` as an open gap rather +than quietly counted as a pass (R32 — a silent skip is a defect). + +### The headline corrections +- **[cse_expr] THE 1000-INSN CSE FLUSH DOES NOT EXIST IN 2.7.2** — `grep -n num_insns cse.c` → no + hits; added in 2.8.1. It appeared in **three** places: §1's killer table, §6's giant tell, and §7's + "shift ±insns across the 1000 boundary" lever. **A lever aimed at a counter our compiler does not + have, in exactly the giants this map is consulted for.** All three struck. +- **[cse_expr] §2's "kill THE class reg" is singular and wrong** — a CSE class holds SEVERAL regs and + the extras have no C-level name. **The audit byte-reproduced my own T31 wall with the pinned cc1**: + `expand_block_move` (`mips.c:2350-2351`) does `copy_addr_to_reg` on BOTH aggregate addresses, and + cse substitutes that pseudo into the first call's arg-load, so the kill invalidates a register + already out of the chain. Two byte-proven remedies recorded (field-by-field copy; a real join + CODE_LABEL) **with the caveat that (a) is closed when the target's own bytes need the block move** + — which is precisely `func_80132F40`'s case. An independent audit and a live byte-test converged + on the same wrong sentence from opposite directions. +- **[cse_expr] `assign_temp` does not exist in 2.7.2**, and `assign_stack_temp` does NO `/s` reset — + a **recycled slot INHERITS `/s`**, the opposite of §4a. **No `BUILT_IN_MEMSET` either** — memset is + always a library call, so the "memcpy/memset/strcpy" trio is really memcpy/strcpy. +- **[cse_expr] §6's "recompute after a join is NORMAL — never a residual" is false at -O2** (both + `flag_cse_follow_jumps` and `flag_cse_skip_blocks` are set) — as written it would have blocked + §H's own antidote. +- **[sched] S7's EPILOGUE half is false** — MIPS has no live `define_expand "epilogue"`, so epilogue + restores never enter sched2's pool. Re-scoped, not deleted (the prologue half is correct). +- **[sched] `insn_cost` is DEP-KIND-BLIND in 2.7.2** (no `REG_DEP_ANTI` zero-case) → restoring `/s` + anti edges is NOT free; it re-groups downstream stores. +- **[loop] "no memory load is EVER hoisted from a loop containing a call" is FALSE** — + `invariant_p`'s `case MEM:` checks `RTX_UNCHANGING_P` FIRST and breaks. Byte-proven on the pinned + cc1: a `const int *` load lands in the **preheader**. So a const-qualified pointer is a real lever. +- **[loop] call args are emitted LEFT-to-right**, not right-to-left (RTL dump: `$a0` insn 10, `$a1` + 12, `$a2` 14). The `func_80150528` anchor observation still holds but for a different reason. + +### Scope answer for Drew: one more exists, and it is a DIFFERENT risk profile +`matching-cookbook.md` carries ~52 source citations and they ARE behavioural. But it is **mixed +provenance** (`loop.c:5556` is exact in 2.7.2; `expr.c:5535` is wrong — the real `MEM_IN_STRUCT_P` +sites are 4577/4904) and — the key difference — **its idioms are BYTE-PROVEN, with citations attached +as explanation.** A drifted cookbook citation corrupts the *explanation* while the *lever still +works*. Recommended: a **targeted citation sweep**, not a claim-by-claim audit. NOT yet done. + +**Docs-only — no `src/`/`config/` touched, R22 not re-run and not claimed.**