wcc+w6c+w6c_ww: tuple slot layout SSoT — checker size = cgen slot stride (C-t0)

The checker computed TY_TUPLE size as the packed element-size sum
((u32,u32) = 8B) while every cgen cursor-transport site strode 8B
slots (16B). 16B tuples were blind to the split (slot == packed);
packed tuples hit it everywhere: cstage let-receive keyed on sz 16/32
missed sz 8 and dropped word 1, the cgfn param receive spilled
8B/element into a packed-sized local (saved-BP clobber, SIGSEGV), and
mixed (u32,f64)/(u32,str) shapes missed the receive arms entirely.

Slot layout is now the SSoT (user-ratified): the flip lives in the two
checkers' N_TTUPLE size computation only (check.c, check.ww
tupleelemslot + stamp); cgen's packed-keyed walks (t.N read, #235 len
arm, over-cap sret send/receive pair) align onto the slot stride, and
the wwstage t.N read gains the natural-width load (tnodeloadop) to
byte-id with cstage's fldloadop. ttupleelem.offset re-stamped
slot-cumulative (no consumers yet). The #242/#243 eightbyte-share
loud-stop dissolves by construction (no two narrows ever share an
eightbyte) — 940's eightbyte_share row graduates to a runtime
round-trip. Hare-layout divergence documented at both checker sites;
re-alignment is task #60. #32 send skew and #33 wwstage literal-let
receive are separate commits on this base.

941_tuple_slot_layout_run pins the matrix: 4 packed rows fail at the
parent (8/21 checks), 3 neutral anchors prove 16B/32B emission
untouched.
This commit is contained in:
2026-06-04 18:20:07 +09:00
parent 0139652180
commit fdfc2ce318
9 changed files with 500 additions and 106 deletions

View File

@@ -629,7 +629,30 @@ resolve_type(Checker *c, Node *n)
if (!require_sized(c, tp->type, e->pos, "a tuple member"))
continue;
if (tp->type && tp->type->align > al) al = tp->type->align;
if (tp->type) sz += tp->type->size;
/* Slot layout is the tuple SSoT (tuple arc C-t0,
* user-ratified): every element occupies the stride
* cgen's cursor transport actually writes — a
* str/slice its header, everything else (narrow
* scalars included) one 8B eightbyte. ww-internal ABI
* only (tuples never cross extern); size((u32,u32))=16
* is observable via size() and diverges from Hare
* (harec type_store.c:533-580 anonymous-struct rule)
* AND from ww's own structs (which pack narrow fields
* post-fldloadop) — that internal inconsistency is
* what task #60 eventually fixes; re-open before any
* serialization/FFI/density use. Pre-C-t0 this summed
* packed element sizes while cgen strode 8B slots —
* the checker-says-8/cgen-does-16 split behind the
* packed-tuple miscompile family (#32/#33/#48). */
if (tp->type) {
Type *eu = tp->type->kind == TY_NAMED
? tp->type->under : tp->type;
if (eu && (eu->kind == TY_STR
|| eu->kind == TY_SLICE))
sz += eu->size;
else if (eu == NULL || eu->kind != TY_VOID)
sz += 8; /* sizelint-ok: the slot IS the 8B eightbyte */
}
if (head == NULL) head = tp;
else tail->next = tp;
tail = tp;