w6c/cgen: #62 Layer-2 (cs half) — widen store/push su chases the alias chain

The tagged widen's source classify (`su`) single-peeled: a 2-level
chain ali->base->struct left su TY_NAMED, so an alias-NAMED struct
union member fell past the struct arm to the SCALAR arm — word0-only
payload, words 1+ zero-filled. At normal decl order this was BOTH-
WRONG-IDENTICAL with wwstage (byte-id YES, gate-blind; F0 m5b_match1
exit 2/2). Two sites, the only widen entries: cg_widen_tagged_store
(let/assign/match BP path) and cg_widen_tagged_push (the call-arg twin
— surfaced by an F1 probe: fn((void|ali)) arg ran 1/1 both-wrong-
identical). The variant TAG still keys on the un-chased st — the
member's nominal identity is the alias (cg_tag_for_variant), only the
copy-width classify chases.

CS-ONLY half: wwstage's twin (rhsstructpayload name-keyed structlookup
+ its push twin, selfhost/cmd/wcc/cgenutil.ww:3062 vs structlookupchain
:1691) lands in F2 per the serial plan — until then these shapes are
transiently cs!=ww (was identical-wrong). Bootstrap asm cmp-identical
vs a pristine 738d7f4 scratch build on all five main.combined.ww, so
the 990-997 byte-id gates are untouched.

test: 944_alias_accept_run +6 rows from the banked set
/tmp/impl62r_layer2_rows.md — L2-1/2 norm+fwd store, L2-4 3-word width
loop (last payload word checked), the push-twin arg row, L2-5 base
control (ken's gold invariant), and L2-3 (`v as ali`) pinned at task
exit 2/2/2/1 there; 64/64 green here.
This commit is contained in:
2026-06-05 11:31:30 +09:00
parent b9dd29706b
commit c138605563
2 changed files with 127 additions and 2 deletions

View File

@@ -2479,7 +2479,13 @@ cg_widen_tagged_store(Cg *c, Local **locals_p, Type *dst, Node *src,
}
}
Type *st = src ? src->type : NULL;
Type *su = (st && st->kind == TY_NAMED) ? st->under : st;
/* Transitive chase (#62 Layer-2): a 2-level chain ali->base->struct
* left su TY_NAMED, so the alias-named union member fell past the
* struct arm to the SCALAR store — word0-only payload, words 1+
* zero-filled (both-wrong-identical with wwstage at normal decl
* order; gate-blind). The tag still keys on the un-chased st: the
* member's nominal identity (cg_tag_for_variant) is the alias. */
Type *su = type_chase_named(st);
/* Tagged → tagged subset: copy slot words then tag-remap. */
if (su && su->kind == TY_TAGGED) {
int ssz = (int)su->size;
@@ -2894,7 +2900,10 @@ cg_widen_tagged_push(Cg *c, Local **locals_p, Type *dst, Node *src, int sz)
return;
}
Type *st = src ? src->type : NULL;
Type *su = (st && st->kind == TY_NAMED) ? st->under : st;
/* Transitive chase (#62 Layer-2) — the call-arg twin of the store
* su above: an unchased 2-level alias took the direct-push scalar
* fast arm (word0-only push). */
Type *su = type_chase_named(st);
int src_is_struct = su && su->kind == TY_STRUCT;
int src_is_tagged = su && su->kind == TY_TAGGED;
/* #66: a tuple-typed source has no direct-push shape — the scalar