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

@@ -6660,9 +6660,17 @@ cgexpr(Cg *c, Node *n, Local *locals)
idx = idx * 10 + (*q - '0');
Tparam *tp = bu->params;
int foff = 0;
/* C-t0: slot stride, twin of the N_DOT
* TY_TUPLE walk. */
while (idx > 0 && tp) {
if (tp->type)
foff += (int)tp->type->size;
Type *su = (tp->type
&& tp->type->kind == TY_NAMED)
? tp->type->under : tp->type;
if (su && (su->kind == TY_STR
|| su->kind == TY_SLICE))
foff += (int)su->size;
else
foff += 8;
tp = tp->next;
idx--;
}
@@ -9504,14 +9512,25 @@ cgexpr(Cg *c, Node *n, Local *locals)
break;
}
}
/* tuple positional field access: t.0, t.1, ... */
/* tuple positional field access: t.0, t.1, ...
* C-t0: slot stride (a str/slice its header, everything else
* one 8B eightbyte) — the layout every cursor transport site
* writes and the checker's TY_TUPLE size now counts. The load
* below keeps the element's NATURAL width (fldloadop). */
if (u && u->kind == TY_TUPLE && n->lhs->kind == N_IDENT && n->str) {
int idx = 0;
for (const char *q = n->str; *q; q++) idx = idx * 10 + (*q - '0');
Tparam *tp = u->params;
int foff = 0;
while (idx > 0 && tp) {
if (tp->type) foff += (int)tp->type->size;
Type *su = (tp->type
&& tp->type->kind == TY_NAMED)
? tp->type->under : tp->type;
if (su && (su->kind == TY_STR
|| su->kind == TY_SLICE))
foff += (int)su->size;
else
foff += 8;
tp = tp->next;
idx--;
}
@@ -11765,7 +11784,11 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
} else
ins2(c, fldstoreop(e->type, esz),
areg(D_AX), amem(D_DX, foff));
foff += esz;
/* C-t0: the sret buffer is slot-laid
* like every tuple home (checker size,
* t.N reader, mlet receive agree); esz
* keeps the store WIDTH natural. */
foff += wide ? esz : 8;
if (pp) pp = pp->next;
}
ins2(c, A_MOVQ, amem(D_BP, cg_sret_arg_off),
@@ -12132,7 +12155,9 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
ins2(c, fldstoreop(t, esz),
areg(D_AX), amem(D_BP, off));
}
foff += esz;
/* C-t0: slot stride — must mirror the
* N_RETURN over-cap SEND's buffer layout. */
foff += wide ? esz : 8;
}
break;
}
@@ -12239,7 +12264,9 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
areg(D_AX), amem(D_BP, off));
}
}
foff += esz;
/* C-t0: slot stride — must mirror the
* N_RETURN over-cap SEND's buffer layout. */
foff += wide ? esz : 8;
if (tp) tp = tp->next;
}
break;