wcc_ww/cgen: #62 Layer-2 (ww half) — rhsstructpayload chases the alias chain; widen-store su at entry

The wwstage tagged widen's struct-payload classify was name-keyed:
rhsstructpayload's N_IDENT arm did a bare structlookup on the local's
declared TNAME, so an alias name (ali->base) missed the registered
structinfo and the value fell past the struct arm to the SCALAR widen
arm — word0-only box payload, words 1+ zero-filled. At normal decl
order this was BOTH-WRONG-IDENTICAL with cstage pre-F1 (byte-id YES,
gate-blind; F0 m5b_match1 exit 2/2). Choke-point fix: route the arm
through structlookupchain (the name-domain twin of cstage's
su = type_chase_named, c138605) and return the REGISTERED struct
name so every consumer's re-lookup hits. All three consumers
graduate through the one funnel (proof-grep: rhsstructpayload is the
only struct-payload classifier): cgwidentaggedstorebp's struct arm
(let/assign/match), pushargsrev's widen route (the call-arg twin),
and cgreturn's needswiden (cgenstmt.ww:1022). The variant TAG still
keys on the un-chased stamped type — the member's nominal identity
is the alias (cg_tag_for_variant precedent).

Rider, same store family: cgwidentaggedstorebp now chases the source
classify ONCE at entry (post cast peels, where src is final) —
`su = tichase(src.type_)` replaces the five per-arm chases
(nested-arm su / memread su37 / >32B+cast-guard sf37 / tuple-guard
stu72 / tuple-arm stu, all reading the same src.type_), mirroring
cstage cg_widen_tagged_store's su position. dt entry loop + the
remaining in-function plain chases (castu/ceti/fti/fvt) collapse to
tichase — mechanical, excluded from c1 only because the function was
c2 scope wholesale.

Runtime graduation (banked rows .ai/impl62r_layer2_rows.md):
m5b_match1 (L2-1 norm) + m5_match (L2-2 fwd) cs0/ww2 -> 0/0 byte-id;
L2-4 3-word (last payload word) 0/0; push-twin arg row 0/0; control
m5b_match0 holds 0/0 (ken confirms at verdict). test 944: the four
K_RUN_CS rows flip to K_RUN (both drivers + byte-id), 129/129.

SURFACED, FILED NOT FIXED (task #89): the RETURN-position leg
(`return x` of an alias struct into a (void|ali) fn return) was
both-wrong-identical (cs1/ww1 byte-id) and is now transiently
cs1/ww0 byte-id NO — ww is the runtime-correct side; cstage
cgreturn's own route into the widen misses the alias (F1 c138605
covered store+push only). F1-precedent transient divergence, noted
per the L2 rows file's acceptance clause.

Selfhost byte-id: new w6c_ww on the c1-HEAD five main.combined.ww —
byte-identical to the c1 build's output (the fix is asm-neutral on
the corpus); cs==ww on the regenerated five. make test-unit green
(288). Closes task #62's ww half — fix-landed-pending-gate (#71
precedent). combined.ww regens ride along.
This commit is contained in:
2026-06-05 21:46:36 +09:00
parent f19d0cb14d
commit f7fd3e4850
4 changed files with 122 additions and 131 deletions

View File

@@ -19202,9 +19202,20 @@ fn rhsstructpayload(c: *cgen, src: *node) str = {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
if (tn != nil) { if (tn != nil) {
if (tn.kind == nkind.N_TNAME) { if (tn.kind == nkind.N_TNAME) {
if (structlookup(c, tn.str) != nil) { // #62 Layer-2 (F2 ww half): bare structlookup
return tn.str; // missed an alias name (ali->base), so the
}; // struct value fell to the SCALAR widen arm —
// word0-only box payload, words 1+ zero-filled
// (both-wrong-identical with cstage pre-F1,
// gate-blind). structlookupchain is the name-
// domain twin of cstage's su=type_chase_named
// (cg_widen_tagged_store, c138605); returning
// the REGISTERED name keeps every consumer's
// re-lookup hitting. The variant TAG still
// keys on the un-chased stamped type — the
// member's nominal identity is the alias.
let si: *structinfo = structlookupchain(c, tn);
if (si != nil) { return si.sname; };
}; };
}; };
}; };
@@ -19484,7 +19495,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// (cmd/w6c/cgen.c:1273). resolvetagged's N_TBANG unwrap is already // (cmd/w6c/cgen.c:1273). resolvetagged's N_TBANG unwrap is already
// handled upstream by tinfofornode (check.ww:1203-1210). // handled upstream by tinfofornode (check.ww:1203-1210).
let dt: *tinfo = dst; let dt: *tinfo = dst;
for (dt != nil && dt.kind == tykind.TY_NAMED) { dt = dt.under; }; dt = tichase(dt);
if (dt == nil) { return; }; if (dt == nil) { return; };
if (dt.kind != tykind.TY_TAGGED) { return; }; if (dt.kind != tykind.TY_TAGGED) { return; };
// Nullable fold: one 8B word holding the pointer (or 0 for void). // Nullable fold: one 8B word holding the pointer (or 0 for void).
@@ -19539,9 +19550,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
if (castrhs != nil) { if (castrhs != nil) {
let castt: *tinfo = castrhs.type_: *tinfo; let castt: *tinfo = castrhs.type_: *tinfo;
let castu: *tinfo = castt; let castu: *tinfo = castt;
for (castu != nil && castu.kind == tykind.TY_NAMED) { castu = tichase(castu);
castu = castu.under;
};
if (castu != nil) { if (castu != nil) {
if (castu == dt) { if (castu == dt) {
castisdst = true; castisdst = true;
@@ -19558,6 +19567,13 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
}; };
}; };
}; };
// #62 Layer-2: ONE source-classify chase at entry (post cast peels,
// where src is final) — the per-arm single reads it replaces all
// chased the same src.type_. Mirrors cstage cg_widen_tagged_store's
// `su = type_chase_named(st)` position (c138605). Tag lookups keep
// the un-chased src.type_ (nominal identity is the alias).
let su: *tinfo = src.type_: *tinfo;
su = tichase(su);
// #218: is the source itself a single NESTED variant of dt (its // #218: is the source itself a single NESTED variant of dt (its
// whole tagged type matches one dt variant), rather than a flattened // whole tagged type matches one dt variant), rather than a flattened
// SUBSET whose members spread into dt? If so, the inner tagged value // SUBSET whose members spread into dt? If so, the inner tagged value
@@ -19593,10 +19609,6 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
os.write(2, msg.ptr, msg.len: u64); os.write(2, msg.ptr, msg.len: u64);
os.exit(1); os.exit(1);
}; };
let su: *tinfo = src.type_: *tinfo;
for (su != nil && su.kind == tykind.TY_NAMED) {
su = su.under;
};
let ssz: i32 = su.size: i32; let ssz: i32 = su.size: i32;
emitline("\tXORQ\tAX, AX\n"); emitline("\tXORQ\tAX, AX\n");
let zk: i32 = 0; let zk: i32 = 0;
@@ -19741,11 +19753,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// tag-remap — the mem-based twin of the ident arm above. // tag-remap — the mem-based twin of the ident arm above.
// Mirrors cstage cg_widen_tagged_store's memread arm. // Mirrors cstage cg_widen_tagged_store's memread arm.
if (taggedmemread(c, src)) { if (taggedmemread(c, src)) {
let su37: *tinfo = src.type_: *tinfo; let ssz37: i32 = su.size: i32;
for (su37 != nil && su37.kind == tykind.TY_NAMED) {
su37 = su37.under;
};
let ssz37: i32 = su37.size: i32;
cgexpr(c, src); cgexpr(c, src);
let mk37: i32 = 0; let mk37: i32 = 0;
for (mk37 < ssz37) { for (mk37 < ssz37) {
@@ -19798,12 +19806,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// cg_widen_tagged_store's generic-else bound. Surfaced by // cg_widen_tagged_store's generic-else bound. Surfaced by
// reviewer-37's `let w = *p` probe on a 56B box: cstage loud, // reviewer-37's `let w = *p` probe on a 56B box: cstage loud,
// wwstage silent (rule-10 break). // wwstage silent (rule-10 break).
let sf37: *tinfo = src.type_: *tinfo; if (su != nil && su.kind == tykind.TY_TAGGED
for (sf37 != nil && sf37.kind == tykind.TY_NAMED) { && su.size: i32 > TUPLE_GPCAP * 8) {
sf37 = sf37.under;
};
if (sf37 != nil && sf37.kind == tykind.TY_TAGGED
&& sf37.size: i32 > TUPLE_GPCAP * 8) {
let m37f: str = "#37: >32B tagged source of a non-mem-based kind unwired (rule 7)\n"; let m37f: str = "#37: >32B tagged source of a non-mem-based kind unwired (rule 7)\n";
os.write(2, m37f.ptr, m37f.len: u64); os.write(2, m37f.ptr, m37f.len: u64);
os.exit(1); os.exit(1);
@@ -19812,8 +19816,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// taggedcastpeel (cast to a THIRD union) would fall to the // taggedcastpeel (cast to a THIRD union) would fall to the
// scalar arm below and silently truncate — loud. Mirrors // scalar arm below and silently truncate — loud. Mirrors
// cstage's widen subset-arm cast bound. // cstage's widen subset-arm cast bound.
if (src.kind == nkind.N_CAST && sf37 != nil if (src.kind == nkind.N_CAST && su != nil
&& sf37.kind == tykind.TY_TAGGED && sf37.nullable == 0) { && su.kind == tykind.TY_TAGGED && su.nullable == 0) {
let m35b: str = "#35: tagged cast source shape unwired at the widen subset arm (rule 7)\n"; let m35b: str = "#35: tagged cast source shape unwired at the widen subset arm (rule 7)\n";
os.write(2, m35b.ptr, m35b.len: u64); os.write(2, m35b.ptr, m35b.len: u64);
os.exit(1); os.exit(1);
@@ -19850,12 +19854,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// the word-copy / cursor-receive arms are wired. Mirrors // the word-copy / cursor-receive arms are wired. Mirrors
// cstage cg_widen_tagged_store. // cstage cg_widen_tagged_store.
if (tupsrc == nil) { if (tupsrc == nil) {
let stu72: *tinfo = src.type_: *tinfo; if (su != nil) {
for (stu72 != nil && stu72.kind == tykind.TY_NAMED) { if (su.kind == tykind.TY_TUPLE) {
stu72 = stu72.under;
};
if (stu72 != nil) {
if (stu72.kind == tykind.TY_TUPLE) {
let m72: str = "cgwidentaggedstore: tuple-typed source shape unwired (only the bare/cast tuple literal carries a full payload; see #72)\n"; let m72: str = "cgwidentaggedstore: tuple-typed source shape unwired (only the bare/cast tuple literal carries a full payload; see #72)\n";
os.write(2, m72.ptr, m72.len: u64); os.write(2, m72.ptr, m72.len: u64);
os.exit(1); os.exit(1);
@@ -19864,9 +19864,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
}; };
}; };
if (tupsrc != nil) { if (tupsrc != nil) {
let stu: *tinfo = src.type_: *tinfo; if (su != nil) { if (su.kind == tykind.TY_TUPLE) {
for (stu != nil && stu.kind == tykind.TY_NAMED) { stu = stu.under; };
if (stu != nil) { if (stu.kind == tykind.TY_TUPLE) {
// #242/#241: mirror cstage's loud-stop CONDITION, not its // #242/#241: mirror cstage's loud-stop CONDITION, not its
// -1 mechanism (rule 10, align the RICHER side DOWN). // -1 mechanism (rule 10, align the RICHER side DOWN).
// wwstage types `true`/`false` as bool and a suffix-less `7` // wwstage types `true`/`false` as bool and a suffix-less `7`
@@ -19929,9 +19927,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// tagged-in-tuple-in-union packing is the // tagged-in-tuple-in-union packing is the
// #242/#22b family. Mirrors cstage. // #242/#22b family. Mirrors cstage.
let ceti: *tinfo = ce.type_: *tinfo; let ceti: *tinfo = ce.type_: *tinfo;
for (ceti != nil && ceti.kind == tykind.TY_NAMED) { ceti = tichase(ceti);
ceti = ceti.under;
};
if (ceti != nil && ceti.kind == tykind.TY_TAGGED) { if (ceti != nil && ceti.kind == tykind.TY_TAGGED) {
let m22: str = "cgwidentaggedstore: tagged element in a tuple-in-union payload unwired (see #242/#22b)\n"; let m22: str = "cgwidentaggedstore: tagged element in a tuple-in-union payload unwired (see #242/#22b)\n";
os.write(2, m22.ptr, m22.len: u64); os.write(2, m22.ptr, m22.len: u64);
@@ -20152,13 +20148,13 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
let wantf32: bool = (fkind == 1); let wantf32: bool = (fkind == 1);
let ftag: i32 = -1; let ftag: i32 = -1;
let fti: *tinfo = dt; let fti: *tinfo = dt;
for (fti != nil && fti.kind == tykind.TY_NAMED) { fti = fti.under; }; fti = tichase(fti);
if (fti != nil) { if (fti.kind == tykind.TY_TAGGED) { if (fti != nil) { if (fti.kind == tykind.TY_TAGGED) {
let fp: *tparam = fti.params; let fp: *tparam = fti.params;
let fidx: i32 = 0; let fidx: i32 = 0;
for (fp != nil) { for (fp != nil) {
let fvt: *tinfo = fp.type_; let fvt: *tinfo = fp.type_;
for (fvt != nil && fvt.kind == tykind.TY_NAMED) { fvt = fvt.under; }; fvt = tichase(fvt);
if (fvt != nil) { if (fvt != nil) {
if (typeisfloat(fvt)) { if (typeisfloat(fvt)) {
if (typeisf32(fvt) == wantf32) { ftag = fidx; break; }; if (typeisf32(fvt) == wantf32) { ftag = fidx; break; };

View File

@@ -3130,9 +3130,20 @@ fn rhsstructpayload(c: *cgen, src: *node) str = {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
if (tn != nil) { if (tn != nil) {
if (tn.kind == nkind.N_TNAME) { if (tn.kind == nkind.N_TNAME) {
if (structlookup(c, tn.str) != nil) { // #62 Layer-2 (F2 ww half): bare structlookup
return tn.str; // missed an alias name (ali->base), so the
}; // struct value fell to the SCALAR widen arm —
// word0-only box payload, words 1+ zero-filled
// (both-wrong-identical with cstage pre-F1,
// gate-blind). structlookupchain is the name-
// domain twin of cstage's su=type_chase_named
// (cg_widen_tagged_store, c138605); returning
// the REGISTERED name keeps every consumer's
// re-lookup hitting. The variant TAG still
// keys on the un-chased stamped type — the
// member's nominal identity is the alias.
let si: *structinfo = structlookupchain(c, tn);
if (si != nil) { return si.sname; };
}; };
}; };
}; };
@@ -3412,7 +3423,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// (cmd/w6c/cgen.c:1273). resolvetagged's N_TBANG unwrap is already // (cmd/w6c/cgen.c:1273). resolvetagged's N_TBANG unwrap is already
// handled upstream by tinfofornode (check.ww:1203-1210). // handled upstream by tinfofornode (check.ww:1203-1210).
let dt: *tinfo = dst; let dt: *tinfo = dst;
for (dt != nil && dt.kind == tykind.TY_NAMED) { dt = dt.under; }; dt = tichase(dt);
if (dt == nil) { return; }; if (dt == nil) { return; };
if (dt.kind != tykind.TY_TAGGED) { return; }; if (dt.kind != tykind.TY_TAGGED) { return; };
// Nullable fold: one 8B word holding the pointer (or 0 for void). // Nullable fold: one 8B word holding the pointer (or 0 for void).
@@ -3467,9 +3478,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
if (castrhs != nil) { if (castrhs != nil) {
let castt: *tinfo = castrhs.type_: *tinfo; let castt: *tinfo = castrhs.type_: *tinfo;
let castu: *tinfo = castt; let castu: *tinfo = castt;
for (castu != nil && castu.kind == tykind.TY_NAMED) { castu = tichase(castu);
castu = castu.under;
};
if (castu != nil) { if (castu != nil) {
if (castu == dt) { if (castu == dt) {
castisdst = true; castisdst = true;
@@ -3486,6 +3495,13 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
}; };
}; };
}; };
// #62 Layer-2: ONE source-classify chase at entry (post cast peels,
// where src is final) — the per-arm single reads it replaces all
// chased the same src.type_. Mirrors cstage cg_widen_tagged_store's
// `su = type_chase_named(st)` position (c138605). Tag lookups keep
// the un-chased src.type_ (nominal identity is the alias).
let su: *tinfo = src.type_: *tinfo;
su = tichase(su);
// #218: is the source itself a single NESTED variant of dt (its // #218: is the source itself a single NESTED variant of dt (its
// whole tagged type matches one dt variant), rather than a flattened // whole tagged type matches one dt variant), rather than a flattened
// SUBSET whose members spread into dt? If so, the inner tagged value // SUBSET whose members spread into dt? If so, the inner tagged value
@@ -3521,10 +3537,6 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
os.write(2, msg.ptr, msg.len: u64); os.write(2, msg.ptr, msg.len: u64);
os.exit(1); os.exit(1);
}; };
let su: *tinfo = src.type_: *tinfo;
for (su != nil && su.kind == tykind.TY_NAMED) {
su = su.under;
};
let ssz: i32 = su.size: i32; let ssz: i32 = su.size: i32;
emitline("\tXORQ\tAX, AX\n"); emitline("\tXORQ\tAX, AX\n");
let zk: i32 = 0; let zk: i32 = 0;
@@ -3669,11 +3681,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// tag-remap — the mem-based twin of the ident arm above. // tag-remap — the mem-based twin of the ident arm above.
// Mirrors cstage cg_widen_tagged_store's memread arm. // Mirrors cstage cg_widen_tagged_store's memread arm.
if (taggedmemread(c, src)) { if (taggedmemread(c, src)) {
let su37: *tinfo = src.type_: *tinfo; let ssz37: i32 = su.size: i32;
for (su37 != nil && su37.kind == tykind.TY_NAMED) {
su37 = su37.under;
};
let ssz37: i32 = su37.size: i32;
cgexpr(c, src); cgexpr(c, src);
let mk37: i32 = 0; let mk37: i32 = 0;
for (mk37 < ssz37) { for (mk37 < ssz37) {
@@ -3726,12 +3734,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// cg_widen_tagged_store's generic-else bound. Surfaced by // cg_widen_tagged_store's generic-else bound. Surfaced by
// reviewer-37's `let w = *p` probe on a 56B box: cstage loud, // reviewer-37's `let w = *p` probe on a 56B box: cstage loud,
// wwstage silent (rule-10 break). // wwstage silent (rule-10 break).
let sf37: *tinfo = src.type_: *tinfo; if (su != nil && su.kind == tykind.TY_TAGGED
for (sf37 != nil && sf37.kind == tykind.TY_NAMED) { && su.size: i32 > TUPLE_GPCAP * 8) {
sf37 = sf37.under;
};
if (sf37 != nil && sf37.kind == tykind.TY_TAGGED
&& sf37.size: i32 > TUPLE_GPCAP * 8) {
let m37f: str = "#37: >32B tagged source of a non-mem-based kind unwired (rule 7)\n"; let m37f: str = "#37: >32B tagged source of a non-mem-based kind unwired (rule 7)\n";
os.write(2, m37f.ptr, m37f.len: u64); os.write(2, m37f.ptr, m37f.len: u64);
os.exit(1); os.exit(1);
@@ -3740,8 +3744,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// taggedcastpeel (cast to a THIRD union) would fall to the // taggedcastpeel (cast to a THIRD union) would fall to the
// scalar arm below and silently truncate — loud. Mirrors // scalar arm below and silently truncate — loud. Mirrors
// cstage's widen subset-arm cast bound. // cstage's widen subset-arm cast bound.
if (src.kind == nkind.N_CAST && sf37 != nil if (src.kind == nkind.N_CAST && su != nil
&& sf37.kind == tykind.TY_TAGGED && sf37.nullable == 0) { && su.kind == tykind.TY_TAGGED && su.nullable == 0) {
let m35b: str = "#35: tagged cast source shape unwired at the widen subset arm (rule 7)\n"; let m35b: str = "#35: tagged cast source shape unwired at the widen subset arm (rule 7)\n";
os.write(2, m35b.ptr, m35b.len: u64); os.write(2, m35b.ptr, m35b.len: u64);
os.exit(1); os.exit(1);
@@ -3778,12 +3782,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// the word-copy / cursor-receive arms are wired. Mirrors // the word-copy / cursor-receive arms are wired. Mirrors
// cstage cg_widen_tagged_store. // cstage cg_widen_tagged_store.
if (tupsrc == nil) { if (tupsrc == nil) {
let stu72: *tinfo = src.type_: *tinfo; if (su != nil) {
for (stu72 != nil && stu72.kind == tykind.TY_NAMED) { if (su.kind == tykind.TY_TUPLE) {
stu72 = stu72.under;
};
if (stu72 != nil) {
if (stu72.kind == tykind.TY_TUPLE) {
let m72: str = "cgwidentaggedstore: tuple-typed source shape unwired (only the bare/cast tuple literal carries a full payload; see #72)\n"; let m72: str = "cgwidentaggedstore: tuple-typed source shape unwired (only the bare/cast tuple literal carries a full payload; see #72)\n";
os.write(2, m72.ptr, m72.len: u64); os.write(2, m72.ptr, m72.len: u64);
os.exit(1); os.exit(1);
@@ -3792,9 +3792,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
}; };
}; };
if (tupsrc != nil) { if (tupsrc != nil) {
let stu: *tinfo = src.type_: *tinfo; if (su != nil) { if (su.kind == tykind.TY_TUPLE) {
for (stu != nil && stu.kind == tykind.TY_NAMED) { stu = stu.under; };
if (stu != nil) { if (stu.kind == tykind.TY_TUPLE) {
// #242/#241: mirror cstage's loud-stop CONDITION, not its // #242/#241: mirror cstage's loud-stop CONDITION, not its
// -1 mechanism (rule 10, align the RICHER side DOWN). // -1 mechanism (rule 10, align the RICHER side DOWN).
// wwstage types `true`/`false` as bool and a suffix-less `7` // wwstage types `true`/`false` as bool and a suffix-less `7`
@@ -3857,9 +3855,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// tagged-in-tuple-in-union packing is the // tagged-in-tuple-in-union packing is the
// #242/#22b family. Mirrors cstage. // #242/#22b family. Mirrors cstage.
let ceti: *tinfo = ce.type_: *tinfo; let ceti: *tinfo = ce.type_: *tinfo;
for (ceti != nil && ceti.kind == tykind.TY_NAMED) { ceti = tichase(ceti);
ceti = ceti.under;
};
if (ceti != nil && ceti.kind == tykind.TY_TAGGED) { if (ceti != nil && ceti.kind == tykind.TY_TAGGED) {
let m22: str = "cgwidentaggedstore: tagged element in a tuple-in-union payload unwired (see #242/#22b)\n"; let m22: str = "cgwidentaggedstore: tagged element in a tuple-in-union payload unwired (see #242/#22b)\n";
os.write(2, m22.ptr, m22.len: u64); os.write(2, m22.ptr, m22.len: u64);
@@ -4080,13 +4076,13 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
let wantf32: bool = (fkind == 1); let wantf32: bool = (fkind == 1);
let ftag: i32 = -1; let ftag: i32 = -1;
let fti: *tinfo = dt; let fti: *tinfo = dt;
for (fti != nil && fti.kind == tykind.TY_NAMED) { fti = fti.under; }; fti = tichase(fti);
if (fti != nil) { if (fti.kind == tykind.TY_TAGGED) { if (fti != nil) { if (fti.kind == tykind.TY_TAGGED) {
let fp: *tparam = fti.params; let fp: *tparam = fti.params;
let fidx: i32 = 0; let fidx: i32 = 0;
for (fp != nil) { for (fp != nil) {
let fvt: *tinfo = fp.type_; let fvt: *tinfo = fp.type_;
for (fvt != nil && fvt.kind == tykind.TY_NAMED) { fvt = fvt.under; }; fvt = tichase(fvt);
if (fvt != nil) { if (fvt != nil) {
if (typeisfloat(fvt)) { if (typeisfloat(fvt)) {
if (typeisf32(fvt) == wantf32) { ftag = fidx; break; }; if (typeisf32(fvt) == wantf32) { ftag = fidx; break; };

View File

@@ -19202,9 +19202,20 @@ fn rhsstructpayload(c: *cgen, src: *node) str = {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
if (tn != nil) { if (tn != nil) {
if (tn.kind == nkind.N_TNAME) { if (tn.kind == nkind.N_TNAME) {
if (structlookup(c, tn.str) != nil) { // #62 Layer-2 (F2 ww half): bare structlookup
return tn.str; // missed an alias name (ali->base), so the
}; // struct value fell to the SCALAR widen arm —
// word0-only box payload, words 1+ zero-filled
// (both-wrong-identical with cstage pre-F1,
// gate-blind). structlookupchain is the name-
// domain twin of cstage's su=type_chase_named
// (cg_widen_tagged_store, c138605); returning
// the REGISTERED name keeps every consumer's
// re-lookup hitting. The variant TAG still
// keys on the un-chased stamped type — the
// member's nominal identity is the alias.
let si: *structinfo = structlookupchain(c, tn);
if (si != nil) { return si.sname; };
}; };
}; };
}; };
@@ -19484,7 +19495,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// (cmd/w6c/cgen.c:1273). resolvetagged's N_TBANG unwrap is already // (cmd/w6c/cgen.c:1273). resolvetagged's N_TBANG unwrap is already
// handled upstream by tinfofornode (check.ww:1203-1210). // handled upstream by tinfofornode (check.ww:1203-1210).
let dt: *tinfo = dst; let dt: *tinfo = dst;
for (dt != nil && dt.kind == tykind.TY_NAMED) { dt = dt.under; }; dt = tichase(dt);
if (dt == nil) { return; }; if (dt == nil) { return; };
if (dt.kind != tykind.TY_TAGGED) { return; }; if (dt.kind != tykind.TY_TAGGED) { return; };
// Nullable fold: one 8B word holding the pointer (or 0 for void). // Nullable fold: one 8B word holding the pointer (or 0 for void).
@@ -19539,9 +19550,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
if (castrhs != nil) { if (castrhs != nil) {
let castt: *tinfo = castrhs.type_: *tinfo; let castt: *tinfo = castrhs.type_: *tinfo;
let castu: *tinfo = castt; let castu: *tinfo = castt;
for (castu != nil && castu.kind == tykind.TY_NAMED) { castu = tichase(castu);
castu = castu.under;
};
if (castu != nil) { if (castu != nil) {
if (castu == dt) { if (castu == dt) {
castisdst = true; castisdst = true;
@@ -19558,6 +19567,13 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
}; };
}; };
}; };
// #62 Layer-2: ONE source-classify chase at entry (post cast peels,
// where src is final) — the per-arm single reads it replaces all
// chased the same src.type_. Mirrors cstage cg_widen_tagged_store's
// `su = type_chase_named(st)` position (c138605). Tag lookups keep
// the un-chased src.type_ (nominal identity is the alias).
let su: *tinfo = src.type_: *tinfo;
su = tichase(su);
// #218: is the source itself a single NESTED variant of dt (its // #218: is the source itself a single NESTED variant of dt (its
// whole tagged type matches one dt variant), rather than a flattened // whole tagged type matches one dt variant), rather than a flattened
// SUBSET whose members spread into dt? If so, the inner tagged value // SUBSET whose members spread into dt? If so, the inner tagged value
@@ -19593,10 +19609,6 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
os.write(2, msg.ptr, msg.len: u64); os.write(2, msg.ptr, msg.len: u64);
os.exit(1); os.exit(1);
}; };
let su: *tinfo = src.type_: *tinfo;
for (su != nil && su.kind == tykind.TY_NAMED) {
su = su.under;
};
let ssz: i32 = su.size: i32; let ssz: i32 = su.size: i32;
emitline("\tXORQ\tAX, AX\n"); emitline("\tXORQ\tAX, AX\n");
let zk: i32 = 0; let zk: i32 = 0;
@@ -19741,11 +19753,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// tag-remap — the mem-based twin of the ident arm above. // tag-remap — the mem-based twin of the ident arm above.
// Mirrors cstage cg_widen_tagged_store's memread arm. // Mirrors cstage cg_widen_tagged_store's memread arm.
if (taggedmemread(c, src)) { if (taggedmemread(c, src)) {
let su37: *tinfo = src.type_: *tinfo; let ssz37: i32 = su.size: i32;
for (su37 != nil && su37.kind == tykind.TY_NAMED) {
su37 = su37.under;
};
let ssz37: i32 = su37.size: i32;
cgexpr(c, src); cgexpr(c, src);
let mk37: i32 = 0; let mk37: i32 = 0;
for (mk37 < ssz37) { for (mk37 < ssz37) {
@@ -19798,12 +19806,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// cg_widen_tagged_store's generic-else bound. Surfaced by // cg_widen_tagged_store's generic-else bound. Surfaced by
// reviewer-37's `let w = *p` probe on a 56B box: cstage loud, // reviewer-37's `let w = *p` probe on a 56B box: cstage loud,
// wwstage silent (rule-10 break). // wwstage silent (rule-10 break).
let sf37: *tinfo = src.type_: *tinfo; if (su != nil && su.kind == tykind.TY_TAGGED
for (sf37 != nil && sf37.kind == tykind.TY_NAMED) { && su.size: i32 > TUPLE_GPCAP * 8) {
sf37 = sf37.under;
};
if (sf37 != nil && sf37.kind == tykind.TY_TAGGED
&& sf37.size: i32 > TUPLE_GPCAP * 8) {
let m37f: str = "#37: >32B tagged source of a non-mem-based kind unwired (rule 7)\n"; let m37f: str = "#37: >32B tagged source of a non-mem-based kind unwired (rule 7)\n";
os.write(2, m37f.ptr, m37f.len: u64); os.write(2, m37f.ptr, m37f.len: u64);
os.exit(1); os.exit(1);
@@ -19812,8 +19816,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// taggedcastpeel (cast to a THIRD union) would fall to the // taggedcastpeel (cast to a THIRD union) would fall to the
// scalar arm below and silently truncate — loud. Mirrors // scalar arm below and silently truncate — loud. Mirrors
// cstage's widen subset-arm cast bound. // cstage's widen subset-arm cast bound.
if (src.kind == nkind.N_CAST && sf37 != nil if (src.kind == nkind.N_CAST && su != nil
&& sf37.kind == tykind.TY_TAGGED && sf37.nullable == 0) { && su.kind == tykind.TY_TAGGED && su.nullable == 0) {
let m35b: str = "#35: tagged cast source shape unwired at the widen subset arm (rule 7)\n"; let m35b: str = "#35: tagged cast source shape unwired at the widen subset arm (rule 7)\n";
os.write(2, m35b.ptr, m35b.len: u64); os.write(2, m35b.ptr, m35b.len: u64);
os.exit(1); os.exit(1);
@@ -19850,12 +19854,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// the word-copy / cursor-receive arms are wired. Mirrors // the word-copy / cursor-receive arms are wired. Mirrors
// cstage cg_widen_tagged_store. // cstage cg_widen_tagged_store.
if (tupsrc == nil) { if (tupsrc == nil) {
let stu72: *tinfo = src.type_: *tinfo; if (su != nil) {
for (stu72 != nil && stu72.kind == tykind.TY_NAMED) { if (su.kind == tykind.TY_TUPLE) {
stu72 = stu72.under;
};
if (stu72 != nil) {
if (stu72.kind == tykind.TY_TUPLE) {
let m72: str = "cgwidentaggedstore: tuple-typed source shape unwired (only the bare/cast tuple literal carries a full payload; see #72)\n"; let m72: str = "cgwidentaggedstore: tuple-typed source shape unwired (only the bare/cast tuple literal carries a full payload; see #72)\n";
os.write(2, m72.ptr, m72.len: u64); os.write(2, m72.ptr, m72.len: u64);
os.exit(1); os.exit(1);
@@ -19864,9 +19864,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
}; };
}; };
if (tupsrc != nil) { if (tupsrc != nil) {
let stu: *tinfo = src.type_: *tinfo; if (su != nil) { if (su.kind == tykind.TY_TUPLE) {
for (stu != nil && stu.kind == tykind.TY_NAMED) { stu = stu.under; };
if (stu != nil) { if (stu.kind == tykind.TY_TUPLE) {
// #242/#241: mirror cstage's loud-stop CONDITION, not its // #242/#241: mirror cstage's loud-stop CONDITION, not its
// -1 mechanism (rule 10, align the RICHER side DOWN). // -1 mechanism (rule 10, align the RICHER side DOWN).
// wwstage types `true`/`false` as bool and a suffix-less `7` // wwstage types `true`/`false` as bool and a suffix-less `7`
@@ -19929,9 +19927,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
// tagged-in-tuple-in-union packing is the // tagged-in-tuple-in-union packing is the
// #242/#22b family. Mirrors cstage. // #242/#22b family. Mirrors cstage.
let ceti: *tinfo = ce.type_: *tinfo; let ceti: *tinfo = ce.type_: *tinfo;
for (ceti != nil && ceti.kind == tykind.TY_NAMED) { ceti = tichase(ceti);
ceti = ceti.under;
};
if (ceti != nil && ceti.kind == tykind.TY_TAGGED) { if (ceti != nil && ceti.kind == tykind.TY_TAGGED) {
let m22: str = "cgwidentaggedstore: tagged element in a tuple-in-union payload unwired (see #242/#22b)\n"; let m22: str = "cgwidentaggedstore: tagged element in a tuple-in-union payload unwired (see #242/#22b)\n";
os.write(2, m22.ptr, m22.len: u64); os.write(2, m22.ptr, m22.len: u64);
@@ -20152,13 +20148,13 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_s
let wantf32: bool = (fkind == 1); let wantf32: bool = (fkind == 1);
let ftag: i32 = -1; let ftag: i32 = -1;
let fti: *tinfo = dt; let fti: *tinfo = dt;
for (fti != nil && fti.kind == tykind.TY_NAMED) { fti = fti.under; }; fti = tichase(fti);
if (fti != nil) { if (fti.kind == tykind.TY_TAGGED) { if (fti != nil) { if (fti.kind == tykind.TY_TAGGED) {
let fp: *tparam = fti.params; let fp: *tparam = fti.params;
let fidx: i32 = 0; let fidx: i32 = 0;
for (fp != nil) { for (fp != nil) {
let fvt: *tinfo = fp.type_; let fvt: *tinfo = fp.type_;
for (fvt != nil && fvt.kind == tykind.TY_NAMED) { fvt = fvt.under; }; fvt = tichase(fvt);
if (fvt != nil) { if (fvt != nil) {
if (typeisfloat(fvt)) { if (typeisfloat(fvt)) {
if (typeisf32(fvt) == wantf32) { ftag = fidx; break; }; if (typeisf32(fvt) == wantf32) { ftag = fidx; break; };

View File

@@ -43,11 +43,11 @@
* | struct-lit, walk leaves, reads); | * | struct-lit, walk leaves, reads); |
* | unprobed gates LOUD-tripwired (#73, | * | unprobed gates LOUD-tripwired (#73, |
* | K_BUILDERR_CS pin) | 0 * | K_BUILDERR_CS pin) | 0
* union_store_* + | task #62 Layer-2 (cs half): alias- | * union_store_* + | task #62 Layer-2: alias-NAMED struct |
* union_push_arg | NAMED struct as union member — widen | * union_push_arg | as union member — widen store/push |
* | store/push word0-only; CS-ONLY until | * | word0-only; cs half c138605, ww half |
* | F2 lands the wwstage half; base ctl | * | F2a batch-2 c2 — graduated K_RUN; |
* | + the #54-bound `as` row pinned loud | 0(cs) * | base ctl + #54-bound `as` row loud | 0
* nested_alias_field_* | task #71: alias-typed nested-field | * nested_alias_field_* | task #71: alias-typed nested-field |
* | store/read/addr-of walks fold to | * | store/read/addr-of walks fold to |
* | direct offsets (byte-id graduation, | * | direct offsets (byte-id graduation, |
@@ -657,14 +657,17 @@ static const struct row rows[] = {
" if (take(x) != 26) { return 1; };\n" " if (take(x) != 26) { return 1; };\n"
" return 0;\n" " return 0;\n"
"};\n", 0, K_RUN, NULL }, "};\n", 0, K_RUN, NULL },
/* ---- task #62 Layer-2 (cstage half): alias-NAMED struct as a /* ---- task #62 Layer-2: alias-NAMED struct as a UNION MEMBER.
* UNION MEMBER. The widen store/push su single peel fell past the * The widen store/push source classify fell past the struct arm
* struct arm to the scalar arm — word0-only payload (the banked * to the scalar arm — word0-only payload (the banked rows
* rows /tmp/impl62r_layer2_rows.md; both-wrong-identical with * /tmp/impl62r_layer2_rows.md; both-wrong-identical at normal
* wwstage at normal decl order = gate-blind byte-id). CS-ONLY * decl order = gate-blind byte-id). cs half c138605
* until F2 routes wwstage rhsstructpayload/push through * (cg_widen_tagged_store/push su chase); ww half F2a batch-2 c2
* structlookupchain — flip these to K_RUN then. Values distinct * (rhsstructpayload -> structlookupchain)K_RUN, byte-id.
* per word; the LAST payload word is always checked. */ * Values distinct per word; the LAST payload word is always
* checked. The RETURN-position leg stays both-stage divergent —
* cs cgreturn residual, task #89 (ww runtime-correct since c2;
* not pinned here until the cs half lands). */
{ "union_store_norm", /* banked row L2-1 (= F0 m5b_match1) */ { "union_store_norm", /* banked row L2-1 (= F0 m5b_match1) */
"package main;\n" "package main;\n"
"type base = struct { a: size, b: size };\n" "type base = struct { a: size, b: size };\n"
@@ -681,7 +684,7 @@ static const struct row rows[] = {
" case void => { return 3; };\n" " case void => { return 3; };\n"
" };\n" " };\n"
" return 0;\n" " return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ww: task #62 F2 */ "};\n", 0, K_RUN, NULL },
{ "union_store_fwd", /* banked row L2-2 (= F0 m5_match) */ { "union_store_fwd", /* banked row L2-2 (= F0 m5_match) */
"package main;\n" "package main;\n"
"type ali = base;\n" "type ali = base;\n"
@@ -698,7 +701,7 @@ static const struct row rows[] = {
" case void => { return 3; };\n" " case void => { return 3; };\n"
" };\n" " };\n"
" return 0;\n" " return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ww: task #62 F2 */ "};\n", 0, K_RUN, NULL },
{ "union_store_3word", /* banked row L2-4: pins the width LOOP */ { "union_store_3word", /* banked row L2-4: pins the width LOOP */
"package main;\n" "package main;\n"
"type base = struct { a: size, b: size, c: size };\n" "type base = struct { a: size, b: size, c: size };\n"
@@ -715,7 +718,7 @@ static const struct row rows[] = {
" case void => { return 3; };\n" " case void => { return 3; };\n"
" };\n" " };\n"
" return 0;\n" " return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ww: task #62 F2 */ "};\n", 0, K_RUN, NULL },
{ "union_push_arg", /* the cg_widen_tagged_push twin (F1 find) */ { "union_push_arg", /* the cg_widen_tagged_push twin (F1 find) */
"package main;\n" "package main;\n"
"type base = struct { a: size, b: size };\n" "type base = struct { a: size, b: size };\n"
@@ -731,7 +734,7 @@ static const struct row rows[] = {
" x.a = 4; x.b = 9;\n" " x.a = 4; x.b = 9;\n"
" if (peek(x) != 9) { return 1; };\n" " if (peek(x) != 9) { return 1; };\n"
" return 0;\n" " return 0;\n"
"};\n", 0, K_RUN_CS, NULL }, /* ww: task #62 F2 */ "};\n", 0, K_RUN, NULL },
/* banked row L2-5: the m5b_match0 gold invariant — base spelling /* banked row L2-5: the m5b_match0 gold invariant — base spelling
* indistinguishable (ken oracle PART 1.7). */ * indistinguishable (ken oracle PART 1.7). */
{ "union_store_base_ctl", { "union_store_base_ctl",