wcc_ww/cgen: #60+#79 alias-NAMED array/slice ELEMENT paths read the chased tinfo — tichase lands, SEGV families graduate byte-id
One class: alias-blind base+esz at the array/slice ELEMENT paths — index read/write, slice-expr, for-range, and literal-init store. The wwstage cgen derived element size and base addressing from the type-AST tnode; an alias-typed base (`type arr = [4]int; let a: arr`) shows only the N_TNAME leaf, so esz fell to a sentinel (1 on the read side, 8 on the init-store side) and the base classified as a POINTER (MOVQ of array words, no IMULQ): m8b_idx1/range1 SEGV 139, m8b_slice1 silent-wrong past little-endian prefix-luck (m8c_slice1big exit 2), m7c global [2]row read SEGV via the alias-blind element-is-array classify, and (#79, ken F2a1 oracle) `type A=[4]u32; let a:A=[...]` stored MOVQ stride-8 over a stride-4 slot — elements 2/3 landed at 0(BP)/+8(BP), a saved-BP/RIP smash masked whenever esz==8. cstage reads everything off the chased stamped type (type_chase_named/ idx_eff, correct post-F1), so every fixed shape graduates ww-SEGV/silent-wrong -> 0/0 byte-id. New tichase() in cgenutil.ww: nil-passthrough transitive TY_NAMED peel, exact twin of cmd/wcc/type.c:160-162. Routed sites, all gated on the stamped type being TY_NAMED (non-alias paths byte-identical): - cgindex (cgenexpr.ww): elem facts (esz/signed/float/f32) off tichase(n.type_); etn falls back to n for the tagged/str/slice classify; LEAQ-vs-MOVQ base off the chased kind; elem-is-array supplemented by tinfoisarray(n.type_) for alias ELEMENTS (m7c). - cgassign N_INDEX store + compound arms (cgenexpr.ww): esz + elemtn=lhs (the stamped-element idiom of the N_DOT/N_INDEX arms); chased-kind base classify at all four LEAQ/MOVQ sites. - cgslice + cgbasecap (cgenexpr.ww): esz, base classify, default-hi (TY_ARRAY -> $alen / TY_SLICE|TY_STR -> +8 len), cap word at +16; global-str cap keeps the #73 carve-out. - cgforrange (cgenstmt.ww, cross-file leg: the range pin cannot green without it): esz, element-node synthesis off .sub (FC0 precedent), isarr/isslicestr classify, alen off the chased tinfo. - cgarrlitfillbp (cgenstmt.ww, #79): an alias [count]T arrtn is the N_TNAME leaf (elemn nil) — synthesise the element node off the chased sub so the existing prim/agg/slice/tagged/narrow dispatch works unchanged; `...` repeat bound off the chased alen (cstage cg_arrlit_fill_bp receives the pre-chased bu and reads bu->alen). #8-PAIR COVERAGE: this is the STORE half of #8's two size-sources. The elemsizeofc READ half chases the ELEMENT internally (idxeffti + esub peel, the #8 fix) but NOT an alias-typed INDEXABLE node — that leg is covered at its #60-family call sites by the gates above (cgindex/cgslice/store/compound/cgforrange/pusharg). Remaining alias-blind elemsizeofc callers are enumerated as residuals below. - bare-let classify (cgenstmt.ww, #79 rider): `let a: arrk;` with an alias-to-array type took the composite zero-fill cstage doesn't emit (cstage keys the no-init shape on the chased lu->kind: arrays keep the per-index-write contract; an 8B alias-array still falls to the single MOVQ $0 arm). Required for the loopfill_1024 pin's byte-id; closes the array kind of the uninit-alias divergence. - pusharg N_SLICE (cgenutil.ww, pulled in by the same pin rule: the 944 slice_of_alias_arg row is a distinct lowering from cgslice): esz, base classify, default-hi. Tests: new 944_alias_idx_family_run (19 rows: idx/slice/range/init controls + 1-level + 2-level + decl-order permutations + index store + compound (+=, *=) + #79 [4]u32 literal-init + alias `[v...]` repeat + uninit [1024] loop-fill + slice1big (1000 elems, values >255, LAST-element readback, default-hi, .cap, range count) + re-slice of an alias slice + range over an alias slice + m7c global 2D + GLOBAL alias-slice indexed read + slice-as-call-arg; dual-stage run + per-row byte-id; LAST elements asserted throughout). The six 944_alias_accept_run rows citing "#60 (F2 batch 1)" flip K_RUN_CS -> K_RUN (incl. slicefield_wholeread_2lvl: its 738d7f4-era receive-spine divergence no longer reproduces at the F1-merged base, verified byte-id + 0/0). 989_lib_byteid checked: no DIVERGE entry graduates (the test fails loudly on graduation; lib has no alias-base consumers — the shape SEGVed before this fix). NOT pinned (g-fold territory, #77/#78): direct alias-typed global ARRAY rows. Expected state probe-verified UNCHANGED by this diff: `let g: arr = [...]` -> ww link-ERR (no DATA emitted), cs 1-level runs 0, cs 2-level runs WRONG (silent). The alias-GLOBAL base legs added here (isglobalarr reclassify, global default-hi/cap) are cs-aligned but runtime-unreachable until the DATA emit lands. Residuals filed with the team: alias-blind elemsizeofc callers not in the #60 pin family — cgun &a[i] addr-of (cgenexpr.ww:4638 region, task #82), append() on an alias-typed slice local (:5287), `alloc([], n)` into an alias-slice let (cgenstmt.ww:2159), arr[i].field= float store (:8536); tagged-element READ under an alias base keeps the ident-arm nullable semantics; checker asserttyped on `untyped_lit * rangevar` over an alias slice (pre-existing, check.ww is batch 4, task #80); uninit alias-to-STRUCT zero-fill unchanged (correct: cstage fills composites); range-destructure over alias-to-tuple-slice. selfhost/cmd/{w6c,wwdump}/main.combined.ww regenerated (cgen*.ww are embedded sources).
This commit is contained in:
@@ -1863,6 +1863,30 @@ fn cgexprstmt(c: *cgen, n: *node) void = {
|
||||
// #25); `rhs` the literal. Twin of cstage cg_arrlit_fill_bp.
|
||||
fn cgarrlitfillbp(c: *cgen, arrtn: *node, rhs: *node, off: i32) void = {
|
||||
let elemn: *node = arrtn.lhs;
|
||||
// #79 (#60 rider): alias-NAMED [count]T (`type A = [4]u32; let
|
||||
// a: A = [...]`) — arrtn is the N_TNAME leaf: elemn nil, esz
|
||||
// stayed the 8 sentinel and the per-element store strode MOVQ
|
||||
// over a stride-4 slot (saved-BP/RIP smash; masked when esz==8).
|
||||
// This is the STORE half of the #8 pair (the elemsizeofc READ
|
||||
// half chases the ELEMENT via idxeffti; alias-typed INDEXABLES
|
||||
// are chased at its call sites). Synthesise the element node off
|
||||
// the chased stamped sub — the cgforrange FC0 precedent — so the
|
||||
// prim/agg/slice/tagged/narrow dispatch below works unchanged;
|
||||
// stash alen for the `...` repeat bound (cstage cg_arrlit_fill_bp
|
||||
// receives the pre-chased bu and reads bu->alen).
|
||||
let aliasalen: i32 = -1;
|
||||
let ati79: *tinfo = arrtn.type_: *tinfo;
|
||||
if (ati79 != nil) { if (ati79.kind == tykind.TY_NAMED) {
|
||||
let au79: *tinfo = tichase(ati79);
|
||||
if (au79 != nil) { if (au79.kind == tykind.TY_ARRAY
|
||||
&& au79.sub != nil) {
|
||||
let en79: *node = newnode(nkind.N_TNAME, arrtn.file, arrtn.line, arrtn.col);
|
||||
en79.str = au79.sub.name;
|
||||
en79.type_ = au79.sub: *void;
|
||||
elemn = en79;
|
||||
aliasalen = au79.alen: i32;
|
||||
};};
|
||||
};};
|
||||
let esz: i32 = 8;
|
||||
let isstrel: bool = false;
|
||||
if (elemn != nil) {
|
||||
@@ -2057,6 +2081,9 @@ fn cgarrlitfillbp(c: *cgen, arrtn: *node, rhs: *node, off: i32) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #79: alias arrtn has no length tnode — bound off the
|
||||
// chased tinfo (see the synthesis block at fn top).
|
||||
if (aliasalen >= 0) { total = aliasalen; };
|
||||
for (idx < total) {
|
||||
if (isstrel || isslicel) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
@@ -2966,6 +2993,27 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
if (n.lhs != nil) {
|
||||
if (n.lhs.kind == nkind.N_TARRAY) { isarr = true; };
|
||||
};
|
||||
// #79 rider (#60 family): alias-NAMED bare let — the array
|
||||
// classify must see through the N_TNAME leaf or an alias-
|
||||
// to-array takes the composite zero-fill cstage doesn't
|
||||
// emit (cstage keys on the chased lu->kind: arrays keep the
|
||||
// per-index-write contract). An 8B alias-array stays
|
||||
// isarr=false so it falls to the zsz==8 MOVQ $0 arm,
|
||||
// matching cstage's 8B single-store shape.
|
||||
if (!isarr && n.lhs != nil) {
|
||||
if (n.lhs.kind == nkind.N_TNAME) {
|
||||
let ati79: *tinfo = n.lhs.type_: *tinfo;
|
||||
if (ati79 != nil) { if (ati79.kind == tykind.TY_NAMED) {
|
||||
let au79: *tinfo = tichase(ati79);
|
||||
if (au79 != nil) {
|
||||
if (au79.kind == tykind.TY_ARRAY
|
||||
&& au79.size: i32 != 8) {
|
||||
isarr = true;
|
||||
};
|
||||
};
|
||||
};};
|
||||
};
|
||||
};
|
||||
// Zero-fill extent. cstage sizes the run on `lu->size`
|
||||
// (the natural ABI size from the type table, cgen.c:8397);
|
||||
// wwstage's `sz` from letslotsize is slot-padded (round-to-8),
|
||||
@@ -3564,6 +3612,31 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #60 (alias arc #5): alias-NAMED scrutinee (`let a: arr`, arr =
|
||||
// [4]int) — the tnode peek above sees only the N_TNAME leaf:
|
||||
// elemt nil, esz 1-sentinel, neither isarr nor isslicestr, so the
|
||||
// per-iteration base walked the array words as a POINTER (SEGV).
|
||||
// Chase the stamped tinfo (cstage N_FORRANGE u = type_chase_named
|
||||
// (slc->type) feeds esz/alen/base classify uniformly) and
|
||||
// synthesise the element node off .sub — the FC0 non-ident
|
||||
// precedent below.
|
||||
let rti60: *tinfo = nil;
|
||||
if (slctn != nil) {
|
||||
if (slctn.kind == nkind.N_TNAME) {
|
||||
let st60: *tinfo = slctn.type_: *tinfo;
|
||||
if (st60 != nil) {
|
||||
if (st60.kind == tykind.TY_NAMED) { rti60 = tichase(st60); };
|
||||
};
|
||||
};
|
||||
};
|
||||
if (rti60 != nil && elemt == nil) {
|
||||
if (rti60.sub != nil) {
|
||||
let en60: *node = newnode(nkind.N_TNAME, slctn.file, slctn.line, slctn.col);
|
||||
en60.str = rti60.sub.name;
|
||||
en60.type_ = rti60.sub: *void;
|
||||
elemt = en60;
|
||||
};
|
||||
};
|
||||
// esz: raw elem byte size. For tuple-element slices `[](T0, T1)`,
|
||||
// C cgen reads the resolved tuple's size (sum of raw param sizes,
|
||||
// no slot-padding) so e.g. `(i64, i64)` is 16, `(i32, i32)` is 8.
|
||||
@@ -3575,6 +3648,12 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
// cs≠ww). elemsizeofc recovers the width from the stamped tinfo
|
||||
// (the #8 named-narrow precedent).
|
||||
let esz: i32 = elemsizeofc(c, slctn);
|
||||
// #60: alias-NAMED scrutinee — stride off the chased stamped
|
||||
// element (cstage esz = u->sub->size).
|
||||
if (rti60 != nil) {
|
||||
let es60: *tinfo = tichase(rti60.sub);
|
||||
if (es60 != nil) { esz = es60.size: i32; };
|
||||
};
|
||||
if (elemt != nil) {
|
||||
if (elemt.kind == nkind.N_TTUPLE) {
|
||||
let total: i32 = 0;
|
||||
@@ -3745,6 +3824,13 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
if (streq(slctn.str, "str")) { isslicestr = true; };
|
||||
};
|
||||
};
|
||||
// #60: alias-NAMED scrutinee — classify off the chased stamped
|
||||
// kind (cstage gates on u->kind TY_SLICE/TY_STR vs TY_ARRAY).
|
||||
if (rti60 != nil) {
|
||||
if (rti60.kind == tykind.TY_ARRAY) { isarr = true; };
|
||||
if (rti60.kind == tykind.TY_SLICE) { isslicestr = true; };
|
||||
if (rti60.kind == tykind.TY_STR) { isslicestr = true; };
|
||||
};
|
||||
if (isslicestr) {
|
||||
if (slc.kind == nkind.N_IDENT) {
|
||||
if (slclocal != nil) {
|
||||
@@ -3761,6 +3847,9 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
if (slctn.rhs != nil) {
|
||||
if (slctn.rhs.kind == nkind.N_INTLIT) { alen = slctn.rhs.uval: i64; };
|
||||
};
|
||||
// #60: alias-NAMED scrutinee has no length tnode — bound off
|
||||
// the chased tinfo (cstage aimm(u->alen)).
|
||||
if (rti60 != nil) { alen = rti60.alen: i64; };
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(alen);
|
||||
emitline(", ");
|
||||
|
||||
Reference in New Issue
Block a user