Skip to content

cc phase 3: re-admit Cast store RHS (ledger class 2, last class)#606

Open
bboe wants to merge 3 commits into
mainfrom
bboe/cc-naddr-phase3-cast
Open

cc phase 3: re-admit Cast store RHS (ledger class 2, last class)#606
bboe wants to merge 3 commits into
mainfrom
bboe/cc-naddr-phase3-cast

Conversation

@bboe

@bboe bboe commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Phase 3 of the native-Address emission refactor — re-admits the last ledger class (class 2: Cast store RHS). With this, all four store-RHS ledger classes (1/2/3/4) are cashed at .text-size parity. Design + plan + errata on the design-specs branch (2026-06-19-cc-native-address-emission-phase3-plan.md).

The corrected mechanism

Reconnaissance falsified the design's Store.width premise: ir.Store already has a vestigial unused width field, and the readdir +6 was never a width drop — it was a cast-temp spill across address resolution (the same class-1/3/4 anatomy phase 2 erased with the store-RHS sink). A Cast store RHS lowers to ir.Block(Assign(Cast)), which the phase-2 sink couldn't reach. So phase 3 extends the value sink to that Block def shape, mirroring the existing _collect_ir_sunk_index_terms Block handling. Store.width stays vestigial (a removal candidate); narrowing-cast truncation is a separate deferred gap belonging in the cast codegen, not on Store. Full rationale in the design-specs errata.

Commits

  1. sink cast store-RHS Block defs — extend _collect_ir_sunk_store_values / _emit_sunk_store_value / the Block suppression to Block(Assign(Cast)) defs; share the _ast_node_reads_ir_temp walker. Byte-neutral (no Cast admitted yet).
  2. re-admit Cast store RHS — add ast_nodes.Cast to _is_byte_safe_store_rhs. readdir 0-delta (the +6 spill erased by commit 1's sink).
  3. phase-3 close-out — CHANGELOG.

Verification

.text byte gate 0-delta (361 functions, 49 files) at every commit; unit 898 passed; cc_bits 122/122; cc_place golden; asm 50/50; bboefs 6/6; programs bbfs 104/104 + ext2 134/134. Codesorter clean; sorting audit SORTED CLEAN; whole-branch review APPROVED (one finding below).

Known caveat (whole-branch review finding, not gate-visible)

An accumulator-preserving cast store whose value rides AX still reserves an unused frame slotgrow_heap (sub esp 20→24) and strtol (108→112), +4 bytes of stack each. The .text code bytes are identical (the gate can't see it — sub esp, N is encoding-length-neutral), and the slot is correctness-clean (never read). This is a pre-existing slot-allocation pattern (main's release already has gap slots) that Cast admission extends by two sites. Recovering it — excluding ax-riding single-use store-RHS temps from frame allocation, which also helps phase 2's preserve-plan sites — is a tracked follow-up, orthogonal to this re-admission.

🤖 Generated with Claude Code

bboe and others added 3 commits June 19, 2026 00:36
…minals (phase 3)

The Block(Assign(expr=Cast)) def shape — the lowering of a cast store RHS
(p->field = (T)x) — now sinks into its AX-clobbering store terminal exactly
like the Index/BinaryOperation classes, replaying the Cast through
generate_expression at the terminal's post-materialization RHS slot (identity
codegen, no spill/reload). The reads_ir_temp operand guard is shared with the
index-term twin via the new module-level _ast_node_reads_ir_temp helper.
Byte-neutral until Cast is admitted as a byte-safe store RHS (Task 2): no
[Block(Cast); Address; Store] triple exists in the corpus yet, so the
extension collects nothing and the per-function byte gate stays 0-delta.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ledger check: re-admit Cast; readdir must be 0-delta or shrink, nothing
else may change. Measured result: readdir 248 -> 248 (0-delta), and the
per-function byte-size gate reports zero deltas across all 361 functions.

Task 1 (93e038e) extended the store-RHS value sink to the
ir.Block(Assign(Cast)) def shape. This change adds ast_nodes.Cast to the
_is_byte_safe_store_rhs admission tuple, which makes the sink fire on the
chained-member cast store (directory->entry.d_ino = (ino_t)d_ino in
readdir). The store's plan is the AX-clobbering chained-member arm, so the
value sink's preserve=False gate fires and Task 1's Block-Cast sink replays
the cast at the terminal RHS slot -- legacy-parity, no cast-temp spill.

Hand-diff of readdir asm (cc.py --bits 32 --object --per-function-sections)
at the parent commit 93e038e vs HEAD: the readdir .text section bodies are
byte-identical (103 lines, IDENTICAL unified diff). The would-be +6
spill/reload around the address resolution never appears -- the d_ino cast
store stays the legacy inline sequence:

    lea eax, [ebx+12]        ; chained-member base (AX-clobbering)
    mov ebx, eax
    mov esi, edx
    movzx eax, byte [esi+6]  ; (ino_t)d_ino cast load, replayed at RHS slot
    mov byte [ebx+4], al     ; terminal store

No def-spill (mov [ebp-N], eax) then reload (mov eax, [ebp-N]) brackets the
address resolution.

The earlier docstring premise that Cast was excluded because Store.width
was the dropped-width fix is falsified: casts are codegen-identity, the
store width is the lvalue's field width (unchanged by the cast), and the
real regression was a cast-temp spill the Task 1 sink erases. Docstring
updated accordingly.

All four ledger classes are now cashed (class 1 BinaryOperation, class 3
Index, class 4 compound-index in phase 2; class 2 Cast here in phase 3).

Verification:
- tests/test_cc_function_sizes.py: PASS (361 functions, readdir 0-delta)
- tests/unit: 898 passed, 1 xfailed
- pre-commit codesorter: Passed
- tests/test_cc_bits.py: 122 passed, 0 failed
- tests/test_cc_place.py: golden byte-identical (no re-bless)
- tests/test_programs.py (bbfs): 104 passed, 0 failed (ls exercises readdir)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Re-admit Cast store RHS via the cast Block(Assign(Cast)) store-RHS sink;
readdir 0-delta; all four ledger classes now cashed at byte parity.  The
design-specs errata records that the Store.width premise was corrected (the
regression was a cast-temp spill, not a dropped width).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant