selfhost/cmd/wcc/cgenutil: tagged-store machinery reads tinfo.params (#68)
cgwidentaggedstore/storebp/cgwidentagremap took a type *node and re-derived the tagged shape via resolvetagged + N_TTAGGED.list walks. Migrate them onto the stamped tinfo (the store-side parallel of #66's match-side flip): dst is now the tagged *tinfo (peel TY_NAMED->du, gate TY_TAGGED), variant lookup + tag-remap read tinfo.params by typeeq, mirroring cstage cg_widen_tagged_store / cg_widen_tag_remap / cg_tag_for_variant (cmd/w6c/cgen.c:1273/1177/503). The N_CAST widening test flips from surface-name streq to `castu==dt || (castu tagged && typeeq(castt,dst))` (cgen.c:1295). Node-form flatvariantidx/taggedvariantindex become thin shims over new tinfo cores (flatvariantidxt/taggedvariantindext) so node-side callers (cgreturn cgenstmt:269, pushargs cgenutil:192) are untouched. The 9 cgwidentaggedstore callers pass node.type_ (each already istaggedtype/slotsize-gated). resolvetagged is retained for its 7 match-side callers. Incidentally retires two latent ww-vs-cstage divergences, both byte-id-neutral on the corpus: the old N_CAST test set castisdst for ANY N_TTAGGED regardless of type equality (cstage guards on type_eq), and the old remap walked the UNflattened src.list (cstage walks the flattened params). Unblocks cgassign's indexvaluetnode drop (#69/#61d). make test 134/134, byte-id 990-997 hold.
This commit is contained in:
@@ -10767,7 +10767,7 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = {
|
||||
emitline("(BP)\n");
|
||||
zz += 8;
|
||||
};
|
||||
cgwidentaggedstore(c, ptype, arg, "BP", scroff, widensz);
|
||||
cgwidentaggedstore(c, ptype.type_: *tinfo, arg, "BP", scroff, widensz);
|
||||
let pp: i32 = widensz - 8;
|
||||
for (pp >= 0) {
|
||||
emitline("\tMOVQ\t");
|
||||
@@ -12732,65 +12732,48 @@ fn rhstargetname(c: *cgen, rhs: *node) str = {
|
||||
// "any str-shape variant matches an str-typed value".
|
||||
fn taggedvariantindex(c: *cgen, tagged: *node, rhs: *node) i32 = {
|
||||
if (tagged == nil) { return -1; };
|
||||
if (rhs == nil) { return -1; };
|
||||
// Alias-unwrap: wwstage has no typed AST, so an aliased tagged
|
||||
// return (`type ft = (i64|str|bool); fn f() ft = ...`) reaches
|
||||
// here as N_TNAME("ft"), not N_TTAGGED. flatvariantidx and the
|
||||
// fallback both gate on N_TTAGGED → -1 → caller maps to 0,
|
||||
// silently emitting `MOVQ $0, AX` for every non-leading variant.
|
||||
// Cstage's check.c canonicalizes N_TNAME → underlying upfront;
|
||||
// every wwstage cgen consumer of a type-bearing node has to
|
||||
// remember this step itself. TODO(#11): a wwstage check pass
|
||||
// between parse and cgen would replace the per-site unwrap with
|
||||
// a single canonicalization. Same shape of fix as nodeisstr.
|
||||
let resolved: *node = resolvetagged(c, tagged);
|
||||
if (resolved != nil) { tagged = resolved; };
|
||||
// #66 Phase-N step 3: match the value's stamped type against the
|
||||
// variant types by typeeq (flatvariantidx), replacing the
|
||||
// rhstargetname surface-name compare. Untyped/loose values (whose
|
||||
// .type_ is untyped_* and can't typeeq a concrete variant) return
|
||||
// -1 here and drop to the str/slice shape scan below — ww has no
|
||||
// type_assignable to mirror cg_variant_match's untyped-src arm.
|
||||
let r: i32 = flatvariantidx(c, tagged, rhs);
|
||||
return taggedvariantindext(c, tagged.type_: *tinfo, rhs);
|
||||
};
|
||||
|
||||
// taggedvariantindext — tinfo-keyed core of taggedvariantindex. Given
|
||||
// the dst tagged tinfo `du` (NAMED-peeled internally, gated TY_TAGGED)
|
||||
// and the source value node, returns the 0-based variant index. #68: the
|
||||
// tagged-store machinery reads tinfo directly (no type node), so the
|
||||
// node-keyed taggedvariantindex delegates here off `tagged.type_`.
|
||||
//
|
||||
// #66 Phase-N step 3: match the value's stamped type against the variant
|
||||
// types by typeeq (flatvariantidxt), replacing the rhstargetname surface-
|
||||
// name compare. Untyped/loose values (whose .type_ is untyped_* and can't
|
||||
// typeeq a concrete variant) return -1 there and drop to the str/slice
|
||||
// shape scan below — ww has no type_assignable to mirror cg_variant_match's
|
||||
// untyped-src arm.
|
||||
fn taggedvariantindext(c: *cgen, du: *tinfo, rhs: *node) i32 = {
|
||||
if (du == nil) { return -1; };
|
||||
if (rhs == nil) { return -1; };
|
||||
let ti: *tinfo = du;
|
||||
for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; };
|
||||
if (ti == nil) { return -1; };
|
||||
if (ti.kind != tykind.TY_TAGGED) { return -1; };
|
||||
let r: i32 = flatvariantidxt(ti, rhs.type_: *tinfo);
|
||||
if (r >= 0) { return r; };
|
||||
// Shape fallback: classify rhs as (str, slice, scalar/other) and
|
||||
// pick the first variant of matching shape. Stands in for cstage's
|
||||
// type_assignable on an untyped src — the typeeq pass above can't
|
||||
// match untyped_* against a concrete variant, and the slice axis
|
||||
// keeps a (u8 | []u8) widen off the leading scalar variant (task
|
||||
// #19). Walks the spread-flattened list so a `(...inner | str)`
|
||||
// outer agrees with the inner's str / slice positions.
|
||||
// #19). tinfo.params is already spread-flattened (#61a — `...inner`
|
||||
// inlined in declaration order), so the old N_TTAGGED.list spread-
|
||||
// walk collapses to a flat scan over p.type_.
|
||||
let wantstr: bool = nodeisstr(c, rhs);
|
||||
let wantslice: bool = nodeisslice(c, rhs);
|
||||
let v: *node = tagged.list;
|
||||
let p: *tparam = ti.params;
|
||||
let idx: i32 = 0;
|
||||
for (v != nil) {
|
||||
let isspread: bool = (v.op == tkind.TK_ELLIPSIS);
|
||||
if (isspread) {
|
||||
let inner: *node = v;
|
||||
if (inner.kind == nkind.N_TNAME) {
|
||||
let a: *node = aliaslookup(c, inner.str);
|
||||
if (a != nil) { inner = a; };
|
||||
};
|
||||
if (inner != nil) {
|
||||
if (inner.kind == nkind.N_TTAGGED) {
|
||||
let iv: *node = inner.list;
|
||||
for (iv != nil) {
|
||||
let ivisstr: bool = isstrtype(c, iv);
|
||||
let ivisslice: bool = isslicetype(c, iv);
|
||||
if (ivisstr == wantstr && ivisslice == wantslice) { return idx; };
|
||||
iv = iv.next;
|
||||
idx += 1;
|
||||
};
|
||||
v = v.next;
|
||||
continue;
|
||||
};
|
||||
};
|
||||
};
|
||||
let visstr: bool = isstrtype(c, v);
|
||||
let visslice: bool = isslicetype(c, v);
|
||||
for (p != nil) {
|
||||
let vt: *tinfo = p.type_;
|
||||
let visstr: bool = typeisstr(vt);
|
||||
let visslice: bool = typeisslice(vt);
|
||||
if (visstr == wantstr && visslice == wantslice) { return idx; };
|
||||
v = v.next;
|
||||
p = p.tnext;
|
||||
idx += 1;
|
||||
};
|
||||
return -1;
|
||||
@@ -12813,9 +12796,21 @@ fn taggedvariantindex(c: *cgen, tagged: *node, rhs: *node) i32 = {
|
||||
fn flatvariantidx(c: *cgen, tagged: *node, pat: *node) i32 = {
|
||||
if (tagged == nil) { return -1; };
|
||||
if (pat == nil) { return -1; };
|
||||
let want: *tinfo = pat.type_: *tinfo;
|
||||
return flatvariantidxt(tagged.type_: *tinfo, pat.type_: *tinfo);
|
||||
};
|
||||
|
||||
// flatvariantidxt — tinfo-keyed core of flatvariantidx: flat 0-based
|
||||
// index of the variant whose type typeeq's `want`, over the pre-
|
||||
// flattened tinfo.params chain (#61a). Peels TY_NAMED then gates
|
||||
// TY_TAGGED. #68: the tagged-store machinery reads tinfo directly and
|
||||
// has no type node to hand the node-keyed flatvariantidx, so the typeeq
|
||||
// core lives here; flatvariantidx + taggedvariantindext + cgwidentagremap
|
||||
// all funnel through it. Mirrors cstage cg_tag_for_variant
|
||||
// (cmd/w6c/cgen.c:503) + cg_variant_match's both-NAMED ptr-id / typeeq
|
||||
// arm (:451).
|
||||
fn flatvariantidxt(tagged: *tinfo, want: *tinfo) i32 = {
|
||||
if (want == nil) { return -1; };
|
||||
let ti: *tinfo = tagged.type_: *tinfo;
|
||||
let ti: *tinfo = tagged;
|
||||
for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; };
|
||||
if (ti == nil) { return -1; };
|
||||
if (ti.kind != tykind.TY_TAGGED) { return -1; };
|
||||
@@ -12874,31 +12869,39 @@ fn flatslicevariantidx(c: *cgen, tagged: *node, elem: *node) i32 = {
|
||||
// cgwidentagremap — when widening from one tagged union to a wider one,
|
||||
// rewrite the source's variant tag at slot_off+0 to use the destination's
|
||||
// variant indices. No-op when src and dst index orders coincide.
|
||||
// Mirrors cg_widen_tag_remap in cmd/w6c/cgen.c.
|
||||
fn cgwidentagremap(c: *cgen, dst: *node, src: *node, slot_off: i32) void = {
|
||||
if (dst == nil) { return; };
|
||||
if (src == nil) { return; };
|
||||
if (dst.kind != nkind.N_TTAGGED) { return; };
|
||||
if (src.kind != nkind.N_TTAGGED) { return; };
|
||||
//
|
||||
// #68: both `du` (dst) and `su` (src) are now the tagged tinfos — peel
|
||||
// TY_NAMED then walk su.params, mapping each source variant to its dst
|
||||
// index by typeeq (flatvariantidxt). Mirrors cg_widen_tag_remap
|
||||
// (cmd/w6c/cgen.c:1177) over su->params + cg_tag_for_variant (:503).
|
||||
fn cgwidentagremap(c: *cgen, du: *tinfo, su: *tinfo, slot_off: i32) void = {
|
||||
let dt: *tinfo = du;
|
||||
for (dt != nil && dt.kind == tykind.TY_NAMED) { dt = dt.under; };
|
||||
if (dt == nil) { return; };
|
||||
if (dt.kind != tykind.TY_TAGGED) { return; };
|
||||
let st: *tinfo = su;
|
||||
for (st != nil && st.kind == tykind.TY_NAMED) { st = st.under; };
|
||||
if (st == nil) { return; };
|
||||
if (st.kind != tykind.TY_TAGGED) { return; };
|
||||
let identity: bool = true;
|
||||
let v: *node = src.list;
|
||||
let p: *tparam = st.params;
|
||||
let idx: i32 = 0;
|
||||
for (v != nil) {
|
||||
let di: i32 = cgtagvariantidx(c, dst, v);
|
||||
for (p != nil) {
|
||||
let di: i32 = flatvariantidxt(dt, p.type_);
|
||||
if (di < 0) { di = 0; };
|
||||
if (di != idx) { identity = false; v = nil; }
|
||||
else { v = v.next; idx += 1; };
|
||||
if (di != idx) { identity = false; p = nil; }
|
||||
else { p = p.tnext; idx += 1; };
|
||||
};
|
||||
if (identity) { return; };
|
||||
let done: str = mklabel(c, "remap_done");
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(slot_off: i64);
|
||||
emitline("(BP), AX\n");
|
||||
v = src.list;
|
||||
p = st.params;
|
||||
idx = 0;
|
||||
for (v != nil) {
|
||||
for (p != nil) {
|
||||
let next: str = mklabel(c, "remap_next");
|
||||
let di: i32 = cgtagvariantidx(c, dst, v);
|
||||
let di: i32 = flatvariantidxt(dt, p.type_);
|
||||
if (di < 0) { di = 0; };
|
||||
emitline("\tCMPQ\t$");
|
||||
emitint(idx: i64);
|
||||
@@ -12916,7 +12919,7 @@ fn cgwidentagremap(c: *cgen, dst: *node, src: *node, slot_off: i32) void = {
|
||||
emitline(done);
|
||||
emitline("\n");
|
||||
emitlabel(next);
|
||||
v = v.next;
|
||||
p = p.tnext;
|
||||
idx += 1;
|
||||
};
|
||||
emitlabel(done);
|
||||
@@ -13145,7 +13148,7 @@ fn cgloadtaggedfield(c: *cgen, basereg: str, foff: i32, slot_sz: i32) void = {
|
||||
// tag last.
|
||||
// - str src: tag@+0, ptr@+8, len@+16.
|
||||
// - scalar src: tag@+0, value@+8.
|
||||
fn cgwidentaggedstore(c: *cgen, dst: *node, src: *node,
|
||||
fn cgwidentaggedstore(c: *cgen, dst: *tinfo, src: *node,
|
||||
basereg: str, slot_off: i32, slot_sz: i32) void = {
|
||||
if (streq(basereg, "BP")) {
|
||||
cgwidentaggedstorebp(c, dst, src, slot_off, slot_sz);
|
||||
@@ -13195,11 +13198,18 @@ fn cgwidentaggedstore(c: *cgen, dst: *node, src: *node,
|
||||
// for the natural "BP" case and via the wrapper's scratch path for
|
||||
// pointer-rooted dst. Direct callers exist only in case of future
|
||||
// inlined uses inside this file; new code should call the wrapper.
|
||||
fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz: i32) void = {
|
||||
let dt: *node = resolvetagged(c, dst);
|
||||
fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_sz: i32) void = {
|
||||
// #68: dst is the tagged tinfo. Peel TY_NAMED → du and gate
|
||||
// TY_TAGGED, mirroring cstage cg_widen_tagged_store's
|
||||
// `du = (dst->kind==TY_NAMED)?dst->under:dst` + TY_TAGGED guard
|
||||
// (cmd/w6c/cgen.c:1273). resolvetagged's N_TBANG unwrap is already
|
||||
// handled upstream by tinfofornode (check.ww:1203-1210).
|
||||
let dt: *tinfo = dst;
|
||||
for (dt != nil && dt.kind == tykind.TY_NAMED) { dt = dt.under; };
|
||||
if (dt == nil) { return; };
|
||||
if (dt.kind != tykind.TY_TAGGED) { return; };
|
||||
// Nullable fold: one 8B word holding the pointer (or 0 for void).
|
||||
if (isnullabletype(dst)) {
|
||||
if (dt.nullable != 0) {
|
||||
cgexpr(c, src);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(slot_off: i64);
|
||||
@@ -13229,22 +13239,32 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
};
|
||||
// Cast's destination = the dst tagged union
|
||||
// itself? The rhs of N_CAST holds the target
|
||||
// type. Compare nominally via str match on
|
||||
// the tagged-alias name.
|
||||
// type. #68: compare on the stamped tinfos —
|
||||
// `castu == dt` (peeled-underlying ptr-id) ||
|
||||
// (castu tagged && typeeq(castt, dst)) — mirroring
|
||||
// cstage cg_widen_tagged_store's
|
||||
// `cast_is_widen = (castu==du) || (castu->kind==
|
||||
// TY_TAGGED && type_eq(castt, dst))`
|
||||
// (cmd/w6c/cgen.c:1295-1296). Replaces the prior
|
||||
// surface-name streq; same-alias TNAMEs share one
|
||||
// NAMED tinfo (check.ww:1160-1173) so typeeq hits
|
||||
// the a==b fast path.
|
||||
let castisdst: bool = false;
|
||||
let castrhs: *node = src.rhs;
|
||||
if (castrhs != nil) {
|
||||
if (castrhs.kind == nkind.N_TTAGGED) {
|
||||
castisdst = true;
|
||||
let castt: *tinfo = castrhs.type_: *tinfo;
|
||||
let castu: *tinfo = castt;
|
||||
for (castu != nil && castu.kind == tykind.TY_NAMED) {
|
||||
castu = castu.under;
|
||||
};
|
||||
if (castrhs.kind == nkind.N_TNAME) {
|
||||
if (dst != nil) {
|
||||
if (dst.kind == nkind.N_TNAME) {
|
||||
if (streq(castrhs.str, dst.str)) {
|
||||
castisdst = true;
|
||||
};
|
||||
if (castu != nil) {
|
||||
if (castu == dt) {
|
||||
castisdst = true;
|
||||
} else { if (castu.kind == tykind.TY_TAGGED) {
|
||||
if (typeeq(castt, dst)) {
|
||||
castisdst = true;
|
||||
};
|
||||
};
|
||||
}; };
|
||||
};
|
||||
};
|
||||
if (castisdst && !inneristagged) {
|
||||
@@ -13254,6 +13274,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
};
|
||||
};
|
||||
// Tagged source ident: byte-copy slot words then tag-remap.
|
||||
// rhstaggedident gates "src is a tagged-typed local ident"; the
|
||||
// remap reads the source tagged tinfo off the local's tnode (#68).
|
||||
let st: *node = rhstaggedident(c, src);
|
||||
if (st != nil) {
|
||||
let lc: *local = localfindnode(c, src.str);
|
||||
@@ -13279,7 +13301,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
p += 8;
|
||||
};
|
||||
};
|
||||
cgwidentagremap(c, dt, st, slot_off);
|
||||
cgwidentagremap(c, dt, lc.tnode.type_: *tinfo, slot_off);
|
||||
return;
|
||||
};
|
||||
// Tagged source via AX/DX/CX/R8 register ABI (N_CALL, N_INDEX
|
||||
@@ -13320,7 +13342,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("(BP)\n");
|
||||
zoff += 8;
|
||||
};
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
if (src.kind == nkind.N_STRUCTLIT) {
|
||||
let fnode: *node = src.list;
|
||||
@@ -13414,7 +13436,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((slot_off + 16): i64);
|
||||
emitline("(BP)\n");
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(tag: i64);
|
||||
@@ -13436,7 +13458,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitoff((slot_off + 24): i64);
|
||||
emitline("(BP)\n");
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(tag: i64);
|
||||
@@ -13472,7 +13494,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
// like the slice axis, not nominal identity.
|
||||
let wantf32: bool = (fkind == 1);
|
||||
let ftag: i32 = -1;
|
||||
let fti: *tinfo = dt.type_: *tinfo;
|
||||
let fti: *tinfo = dt;
|
||||
for (fti != nil && fti.kind == tykind.TY_NAMED) { fti = fti.under; };
|
||||
if (fti != nil) { if (fti.kind == tykind.TY_TAGGED) {
|
||||
let fp: *tparam = fti.params;
|
||||
@@ -13502,7 +13524,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((slot_off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(tag: i64);
|
||||
@@ -13780,7 +13802,7 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
cgwidentaggedstore(c, fi.tnode,
|
||||
cgwidentaggedstore(c, fi.tnode.type_: *tinfo,
|
||||
fieldnode.lhs, basereg,
|
||||
disp + fi.foff, fi.fsz);
|
||||
fi = nil;
|
||||
@@ -17149,7 +17171,7 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
// dst is the per-element tagged type;
|
||||
// pass velem (cstage cgen.c:4382 passes
|
||||
// velem, not the slice wrap vsu).
|
||||
cgwidentaggedstore(c, velem,
|
||||
cgwidentaggedstore(c, velem.type_: *tinfo,
|
||||
aa2, "BP", slot, esz);
|
||||
} else { if (velemstr) {
|
||||
cgexpr(c, aa2);
|
||||
@@ -17484,7 +17506,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (lc != nil) {
|
||||
if (istaggedtype(c, lc.tnode)) {
|
||||
let lsz: i32 = slotsize(c, lc.tnode);
|
||||
cgwidentaggedstore(c, lc.tnode,
|
||||
cgwidentaggedstore(c, lc.tnode.type_: *tinfo,
|
||||
n.rhs, "BP", lc.off, lsz);
|
||||
return;
|
||||
};
|
||||
@@ -17764,7 +17786,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("(BP)\n");
|
||||
zz += 8;
|
||||
};
|
||||
cgwidentaggedstore(c, elemtn, n.rhs,
|
||||
cgwidentaggedstore(c, elemtn.type_: *tinfo, n.rhs,
|
||||
"BP", scroff, slot_sz);
|
||||
cgexpr(c, idx);
|
||||
if (slot_sz > 1) {
|
||||
@@ -18142,7 +18164,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
cgwidentaggedstore(c, fi.tnode,
|
||||
cgwidentaggedstore(c, fi.tnode.type_: *tinfo,
|
||||
n.rhs, "BX", fi.foff, fsz);
|
||||
return;
|
||||
};
|
||||
@@ -18379,7 +18401,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (n.op == tkind.TK_ASSIGN
|
||||
&& istaggedtype(c, fi.tnode)) {
|
||||
let fsz: i32 = slotsize(c, fi.tnode);
|
||||
cgwidentaggedstore(c, fi.tnode,
|
||||
cgwidentaggedstore(c, fi.tnode.type_: *tinfo,
|
||||
n.rhs, "BP", lc.off + fi.foff, fsz);
|
||||
return;
|
||||
};
|
||||
@@ -20062,7 +20084,7 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
emitline("(BP)\n");
|
||||
zz += 8;
|
||||
};
|
||||
cgwidentaggedstore(c, c.fnret, rhs, "BP",
|
||||
cgwidentaggedstore(c, c.fnret.type_: *tinfo, rhs, "BP",
|
||||
scroff, rsz);
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scroff: i64);
|
||||
@@ -20552,7 +20574,7 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
// ABI call), struct payload (literal/ident), str payload,
|
||||
// scalar payload — with tag remap for tagged-subset widening.
|
||||
if (istaggedtype(c, tn)) {
|
||||
cgwidentaggedstore(c, tn, rhs, "BP", off, sz);
|
||||
cgwidentaggedstore(c, tn.type_: *tinfo, rhs, "BP", off, sz);
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -3144,7 +3144,7 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
// dst is the per-element tagged type;
|
||||
// pass velem (cstage cgen.c:4382 passes
|
||||
// velem, not the slice wrap vsu).
|
||||
cgwidentaggedstore(c, velem,
|
||||
cgwidentaggedstore(c, velem.type_: *tinfo,
|
||||
aa2, "BP", slot, esz);
|
||||
} else { if (velemstr) {
|
||||
cgexpr(c, aa2);
|
||||
@@ -3479,7 +3479,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (lc != nil) {
|
||||
if (istaggedtype(c, lc.tnode)) {
|
||||
let lsz: i32 = slotsize(c, lc.tnode);
|
||||
cgwidentaggedstore(c, lc.tnode,
|
||||
cgwidentaggedstore(c, lc.tnode.type_: *tinfo,
|
||||
n.rhs, "BP", lc.off, lsz);
|
||||
return;
|
||||
};
|
||||
@@ -3759,7 +3759,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("(BP)\n");
|
||||
zz += 8;
|
||||
};
|
||||
cgwidentaggedstore(c, elemtn, n.rhs,
|
||||
cgwidentaggedstore(c, elemtn.type_: *tinfo, n.rhs,
|
||||
"BP", scroff, slot_sz);
|
||||
cgexpr(c, idx);
|
||||
if (slot_sz > 1) {
|
||||
@@ -4137,7 +4137,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
cgwidentaggedstore(c, fi.tnode,
|
||||
cgwidentaggedstore(c, fi.tnode.type_: *tinfo,
|
||||
n.rhs, "BX", fi.foff, fsz);
|
||||
return;
|
||||
};
|
||||
@@ -4374,7 +4374,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (n.op == tkind.TK_ASSIGN
|
||||
&& istaggedtype(c, fi.tnode)) {
|
||||
let fsz: i32 = slotsize(c, fi.tnode);
|
||||
cgwidentaggedstore(c, fi.tnode,
|
||||
cgwidentaggedstore(c, fi.tnode.type_: *tinfo,
|
||||
n.rhs, "BP", lc.off + fi.foff, fsz);
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -225,7 +225,7 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
emitline("(BP)\n");
|
||||
zz += 8;
|
||||
};
|
||||
cgwidentaggedstore(c, c.fnret, rhs, "BP",
|
||||
cgwidentaggedstore(c, c.fnret.type_: *tinfo, rhs, "BP",
|
||||
scroff, rsz);
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scroff: i64);
|
||||
@@ -715,7 +715,7 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
// ABI call), struct payload (literal/ident), str payload,
|
||||
// scalar payload — with tag remap for tagged-subset widening.
|
||||
if (istaggedtype(c, tn)) {
|
||||
cgwidentaggedstore(c, tn, rhs, "BP", off, sz);
|
||||
cgwidentaggedstore(c, tn.type_: *tinfo, rhs, "BP", off, sz);
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -222,7 +222,7 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = {
|
||||
emitline("(BP)\n");
|
||||
zz += 8;
|
||||
};
|
||||
cgwidentaggedstore(c, ptype, arg, "BP", scroff, widensz);
|
||||
cgwidentaggedstore(c, ptype.type_: *tinfo, arg, "BP", scroff, widensz);
|
||||
let pp: i32 = widensz - 8;
|
||||
for (pp >= 0) {
|
||||
emitline("\tMOVQ\t");
|
||||
@@ -2187,65 +2187,48 @@ fn rhstargetname(c: *cgen, rhs: *node) str = {
|
||||
// "any str-shape variant matches an str-typed value".
|
||||
fn taggedvariantindex(c: *cgen, tagged: *node, rhs: *node) i32 = {
|
||||
if (tagged == nil) { return -1; };
|
||||
if (rhs == nil) { return -1; };
|
||||
// Alias-unwrap: wwstage has no typed AST, so an aliased tagged
|
||||
// return (`type ft = (i64|str|bool); fn f() ft = ...`) reaches
|
||||
// here as N_TNAME("ft"), not N_TTAGGED. flatvariantidx and the
|
||||
// fallback both gate on N_TTAGGED → -1 → caller maps to 0,
|
||||
// silently emitting `MOVQ $0, AX` for every non-leading variant.
|
||||
// Cstage's check.c canonicalizes N_TNAME → underlying upfront;
|
||||
// every wwstage cgen consumer of a type-bearing node has to
|
||||
// remember this step itself. TODO(#11): a wwstage check pass
|
||||
// between parse and cgen would replace the per-site unwrap with
|
||||
// a single canonicalization. Same shape of fix as nodeisstr.
|
||||
let resolved: *node = resolvetagged(c, tagged);
|
||||
if (resolved != nil) { tagged = resolved; };
|
||||
// #66 Phase-N step 3: match the value's stamped type against the
|
||||
// variant types by typeeq (flatvariantidx), replacing the
|
||||
// rhstargetname surface-name compare. Untyped/loose values (whose
|
||||
// .type_ is untyped_* and can't typeeq a concrete variant) return
|
||||
// -1 here and drop to the str/slice shape scan below — ww has no
|
||||
// type_assignable to mirror cg_variant_match's untyped-src arm.
|
||||
let r: i32 = flatvariantidx(c, tagged, rhs);
|
||||
return taggedvariantindext(c, tagged.type_: *tinfo, rhs);
|
||||
};
|
||||
|
||||
// taggedvariantindext — tinfo-keyed core of taggedvariantindex. Given
|
||||
// the dst tagged tinfo `du` (NAMED-peeled internally, gated TY_TAGGED)
|
||||
// and the source value node, returns the 0-based variant index. #68: the
|
||||
// tagged-store machinery reads tinfo directly (no type node), so the
|
||||
// node-keyed taggedvariantindex delegates here off `tagged.type_`.
|
||||
//
|
||||
// #66 Phase-N step 3: match the value's stamped type against the variant
|
||||
// types by typeeq (flatvariantidxt), replacing the rhstargetname surface-
|
||||
// name compare. Untyped/loose values (whose .type_ is untyped_* and can't
|
||||
// typeeq a concrete variant) return -1 there and drop to the str/slice
|
||||
// shape scan below — ww has no type_assignable to mirror cg_variant_match's
|
||||
// untyped-src arm.
|
||||
fn taggedvariantindext(c: *cgen, du: *tinfo, rhs: *node) i32 = {
|
||||
if (du == nil) { return -1; };
|
||||
if (rhs == nil) { return -1; };
|
||||
let ti: *tinfo = du;
|
||||
for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; };
|
||||
if (ti == nil) { return -1; };
|
||||
if (ti.kind != tykind.TY_TAGGED) { return -1; };
|
||||
let r: i32 = flatvariantidxt(ti, rhs.type_: *tinfo);
|
||||
if (r >= 0) { return r; };
|
||||
// Shape fallback: classify rhs as (str, slice, scalar/other) and
|
||||
// pick the first variant of matching shape. Stands in for cstage's
|
||||
// type_assignable on an untyped src — the typeeq pass above can't
|
||||
// match untyped_* against a concrete variant, and the slice axis
|
||||
// keeps a (u8 | []u8) widen off the leading scalar variant (task
|
||||
// #19). Walks the spread-flattened list so a `(...inner | str)`
|
||||
// outer agrees with the inner's str / slice positions.
|
||||
// #19). tinfo.params is already spread-flattened (#61a — `...inner`
|
||||
// inlined in declaration order), so the old N_TTAGGED.list spread-
|
||||
// walk collapses to a flat scan over p.type_.
|
||||
let wantstr: bool = nodeisstr(c, rhs);
|
||||
let wantslice: bool = nodeisslice(c, rhs);
|
||||
let v: *node = tagged.list;
|
||||
let p: *tparam = ti.params;
|
||||
let idx: i32 = 0;
|
||||
for (v != nil) {
|
||||
let isspread: bool = (v.op == tkind.TK_ELLIPSIS);
|
||||
if (isspread) {
|
||||
let inner: *node = v;
|
||||
if (inner.kind == nkind.N_TNAME) {
|
||||
let a: *node = aliaslookup(c, inner.str);
|
||||
if (a != nil) { inner = a; };
|
||||
};
|
||||
if (inner != nil) {
|
||||
if (inner.kind == nkind.N_TTAGGED) {
|
||||
let iv: *node = inner.list;
|
||||
for (iv != nil) {
|
||||
let ivisstr: bool = isstrtype(c, iv);
|
||||
let ivisslice: bool = isslicetype(c, iv);
|
||||
if (ivisstr == wantstr && ivisslice == wantslice) { return idx; };
|
||||
iv = iv.next;
|
||||
idx += 1;
|
||||
};
|
||||
v = v.next;
|
||||
continue;
|
||||
};
|
||||
};
|
||||
};
|
||||
let visstr: bool = isstrtype(c, v);
|
||||
let visslice: bool = isslicetype(c, v);
|
||||
for (p != nil) {
|
||||
let vt: *tinfo = p.type_;
|
||||
let visstr: bool = typeisstr(vt);
|
||||
let visslice: bool = typeisslice(vt);
|
||||
if (visstr == wantstr && visslice == wantslice) { return idx; };
|
||||
v = v.next;
|
||||
p = p.tnext;
|
||||
idx += 1;
|
||||
};
|
||||
return -1;
|
||||
@@ -2268,9 +2251,21 @@ fn taggedvariantindex(c: *cgen, tagged: *node, rhs: *node) i32 = {
|
||||
fn flatvariantidx(c: *cgen, tagged: *node, pat: *node) i32 = {
|
||||
if (tagged == nil) { return -1; };
|
||||
if (pat == nil) { return -1; };
|
||||
let want: *tinfo = pat.type_: *tinfo;
|
||||
return flatvariantidxt(tagged.type_: *tinfo, pat.type_: *tinfo);
|
||||
};
|
||||
|
||||
// flatvariantidxt — tinfo-keyed core of flatvariantidx: flat 0-based
|
||||
// index of the variant whose type typeeq's `want`, over the pre-
|
||||
// flattened tinfo.params chain (#61a). Peels TY_NAMED then gates
|
||||
// TY_TAGGED. #68: the tagged-store machinery reads tinfo directly and
|
||||
// has no type node to hand the node-keyed flatvariantidx, so the typeeq
|
||||
// core lives here; flatvariantidx + taggedvariantindext + cgwidentagremap
|
||||
// all funnel through it. Mirrors cstage cg_tag_for_variant
|
||||
// (cmd/w6c/cgen.c:503) + cg_variant_match's both-NAMED ptr-id / typeeq
|
||||
// arm (:451).
|
||||
fn flatvariantidxt(tagged: *tinfo, want: *tinfo) i32 = {
|
||||
if (want == nil) { return -1; };
|
||||
let ti: *tinfo = tagged.type_: *tinfo;
|
||||
let ti: *tinfo = tagged;
|
||||
for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; };
|
||||
if (ti == nil) { return -1; };
|
||||
if (ti.kind != tykind.TY_TAGGED) { return -1; };
|
||||
@@ -2329,31 +2324,39 @@ fn flatslicevariantidx(c: *cgen, tagged: *node, elem: *node) i32 = {
|
||||
// cgwidentagremap — when widening from one tagged union to a wider one,
|
||||
// rewrite the source's variant tag at slot_off+0 to use the destination's
|
||||
// variant indices. No-op when src and dst index orders coincide.
|
||||
// Mirrors cg_widen_tag_remap in cmd/w6c/cgen.c.
|
||||
fn cgwidentagremap(c: *cgen, dst: *node, src: *node, slot_off: i32) void = {
|
||||
if (dst == nil) { return; };
|
||||
if (src == nil) { return; };
|
||||
if (dst.kind != nkind.N_TTAGGED) { return; };
|
||||
if (src.kind != nkind.N_TTAGGED) { return; };
|
||||
//
|
||||
// #68: both `du` (dst) and `su` (src) are now the tagged tinfos — peel
|
||||
// TY_NAMED then walk su.params, mapping each source variant to its dst
|
||||
// index by typeeq (flatvariantidxt). Mirrors cg_widen_tag_remap
|
||||
// (cmd/w6c/cgen.c:1177) over su->params + cg_tag_for_variant (:503).
|
||||
fn cgwidentagremap(c: *cgen, du: *tinfo, su: *tinfo, slot_off: i32) void = {
|
||||
let dt: *tinfo = du;
|
||||
for (dt != nil && dt.kind == tykind.TY_NAMED) { dt = dt.under; };
|
||||
if (dt == nil) { return; };
|
||||
if (dt.kind != tykind.TY_TAGGED) { return; };
|
||||
let st: *tinfo = su;
|
||||
for (st != nil && st.kind == tykind.TY_NAMED) { st = st.under; };
|
||||
if (st == nil) { return; };
|
||||
if (st.kind != tykind.TY_TAGGED) { return; };
|
||||
let identity: bool = true;
|
||||
let v: *node = src.list;
|
||||
let p: *tparam = st.params;
|
||||
let idx: i32 = 0;
|
||||
for (v != nil) {
|
||||
let di: i32 = cgtagvariantidx(c, dst, v);
|
||||
for (p != nil) {
|
||||
let di: i32 = flatvariantidxt(dt, p.type_);
|
||||
if (di < 0) { di = 0; };
|
||||
if (di != idx) { identity = false; v = nil; }
|
||||
else { v = v.next; idx += 1; };
|
||||
if (di != idx) { identity = false; p = nil; }
|
||||
else { p = p.tnext; idx += 1; };
|
||||
};
|
||||
if (identity) { return; };
|
||||
let done: str = mklabel(c, "remap_done");
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(slot_off: i64);
|
||||
emitline("(BP), AX\n");
|
||||
v = src.list;
|
||||
p = st.params;
|
||||
idx = 0;
|
||||
for (v != nil) {
|
||||
for (p != nil) {
|
||||
let next: str = mklabel(c, "remap_next");
|
||||
let di: i32 = cgtagvariantidx(c, dst, v);
|
||||
let di: i32 = flatvariantidxt(dt, p.type_);
|
||||
if (di < 0) { di = 0; };
|
||||
emitline("\tCMPQ\t$");
|
||||
emitint(idx: i64);
|
||||
@@ -2371,7 +2374,7 @@ fn cgwidentagremap(c: *cgen, dst: *node, src: *node, slot_off: i32) void = {
|
||||
emitline(done);
|
||||
emitline("\n");
|
||||
emitlabel(next);
|
||||
v = v.next;
|
||||
p = p.tnext;
|
||||
idx += 1;
|
||||
};
|
||||
emitlabel(done);
|
||||
@@ -2600,7 +2603,7 @@ fn cgloadtaggedfield(c: *cgen, basereg: str, foff: i32, slot_sz: i32) void = {
|
||||
// tag last.
|
||||
// - str src: tag@+0, ptr@+8, len@+16.
|
||||
// - scalar src: tag@+0, value@+8.
|
||||
fn cgwidentaggedstore(c: *cgen, dst: *node, src: *node,
|
||||
fn cgwidentaggedstore(c: *cgen, dst: *tinfo, src: *node,
|
||||
basereg: str, slot_off: i32, slot_sz: i32) void = {
|
||||
if (streq(basereg, "BP")) {
|
||||
cgwidentaggedstorebp(c, dst, src, slot_off, slot_sz);
|
||||
@@ -2650,11 +2653,18 @@ fn cgwidentaggedstore(c: *cgen, dst: *node, src: *node,
|
||||
// for the natural "BP" case and via the wrapper's scratch path for
|
||||
// pointer-rooted dst. Direct callers exist only in case of future
|
||||
// inlined uses inside this file; new code should call the wrapper.
|
||||
fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz: i32) void = {
|
||||
let dt: *node = resolvetagged(c, dst);
|
||||
fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_sz: i32) void = {
|
||||
// #68: dst is the tagged tinfo. Peel TY_NAMED → du and gate
|
||||
// TY_TAGGED, mirroring cstage cg_widen_tagged_store's
|
||||
// `du = (dst->kind==TY_NAMED)?dst->under:dst` + TY_TAGGED guard
|
||||
// (cmd/w6c/cgen.c:1273). resolvetagged's N_TBANG unwrap is already
|
||||
// handled upstream by tinfofornode (check.ww:1203-1210).
|
||||
let dt: *tinfo = dst;
|
||||
for (dt != nil && dt.kind == tykind.TY_NAMED) { dt = dt.under; };
|
||||
if (dt == nil) { return; };
|
||||
if (dt.kind != tykind.TY_TAGGED) { return; };
|
||||
// Nullable fold: one 8B word holding the pointer (or 0 for void).
|
||||
if (isnullabletype(dst)) {
|
||||
if (dt.nullable != 0) {
|
||||
cgexpr(c, src);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(slot_off: i64);
|
||||
@@ -2684,22 +2694,32 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
};
|
||||
// Cast's destination = the dst tagged union
|
||||
// itself? The rhs of N_CAST holds the target
|
||||
// type. Compare nominally via str match on
|
||||
// the tagged-alias name.
|
||||
// type. #68: compare on the stamped tinfos —
|
||||
// `castu == dt` (peeled-underlying ptr-id) ||
|
||||
// (castu tagged && typeeq(castt, dst)) — mirroring
|
||||
// cstage cg_widen_tagged_store's
|
||||
// `cast_is_widen = (castu==du) || (castu->kind==
|
||||
// TY_TAGGED && type_eq(castt, dst))`
|
||||
// (cmd/w6c/cgen.c:1295-1296). Replaces the prior
|
||||
// surface-name streq; same-alias TNAMEs share one
|
||||
// NAMED tinfo (check.ww:1160-1173) so typeeq hits
|
||||
// the a==b fast path.
|
||||
let castisdst: bool = false;
|
||||
let castrhs: *node = src.rhs;
|
||||
if (castrhs != nil) {
|
||||
if (castrhs.kind == nkind.N_TTAGGED) {
|
||||
castisdst = true;
|
||||
let castt: *tinfo = castrhs.type_: *tinfo;
|
||||
let castu: *tinfo = castt;
|
||||
for (castu != nil && castu.kind == tykind.TY_NAMED) {
|
||||
castu = castu.under;
|
||||
};
|
||||
if (castrhs.kind == nkind.N_TNAME) {
|
||||
if (dst != nil) {
|
||||
if (dst.kind == nkind.N_TNAME) {
|
||||
if (streq(castrhs.str, dst.str)) {
|
||||
castisdst = true;
|
||||
};
|
||||
if (castu != nil) {
|
||||
if (castu == dt) {
|
||||
castisdst = true;
|
||||
} else { if (castu.kind == tykind.TY_TAGGED) {
|
||||
if (typeeq(castt, dst)) {
|
||||
castisdst = true;
|
||||
};
|
||||
};
|
||||
}; };
|
||||
};
|
||||
};
|
||||
if (castisdst && !inneristagged) {
|
||||
@@ -2709,6 +2729,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
};
|
||||
};
|
||||
// Tagged source ident: byte-copy slot words then tag-remap.
|
||||
// rhstaggedident gates "src is a tagged-typed local ident"; the
|
||||
// remap reads the source tagged tinfo off the local's tnode (#68).
|
||||
let st: *node = rhstaggedident(c, src);
|
||||
if (st != nil) {
|
||||
let lc: *local = localfindnode(c, src.str);
|
||||
@@ -2734,7 +2756,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
p += 8;
|
||||
};
|
||||
};
|
||||
cgwidentagremap(c, dt, st, slot_off);
|
||||
cgwidentagremap(c, dt, lc.tnode.type_: *tinfo, slot_off);
|
||||
return;
|
||||
};
|
||||
// Tagged source via AX/DX/CX/R8 register ABI (N_CALL, N_INDEX
|
||||
@@ -2775,7 +2797,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("(BP)\n");
|
||||
zoff += 8;
|
||||
};
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
if (src.kind == nkind.N_STRUCTLIT) {
|
||||
let fnode: *node = src.list;
|
||||
@@ -2869,7 +2891,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((slot_off + 16): i64);
|
||||
emitline("(BP)\n");
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(tag: i64);
|
||||
@@ -2891,7 +2913,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitoff((slot_off + 24): i64);
|
||||
emitline("(BP)\n");
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(tag: i64);
|
||||
@@ -2927,7 +2949,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
// like the slice axis, not nominal identity.
|
||||
let wantf32: bool = (fkind == 1);
|
||||
let ftag: i32 = -1;
|
||||
let fti: *tinfo = dt.type_: *tinfo;
|
||||
let fti: *tinfo = dt;
|
||||
for (fti != nil && fti.kind == tykind.TY_NAMED) { fti = fti.under; };
|
||||
if (fti != nil) { if (fti.kind == tykind.TY_TAGGED) {
|
||||
let fp: *tparam = fti.params;
|
||||
@@ -2957,7 +2979,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((slot_off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(tag: i64);
|
||||
@@ -3235,7 +3257,7 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
cgwidentaggedstore(c, fi.tnode,
|
||||
cgwidentaggedstore(c, fi.tnode.type_: *tinfo,
|
||||
fieldnode.lhs, basereg,
|
||||
disp + fi.foff, fi.fsz);
|
||||
fi = nil;
|
||||
|
||||
@@ -10767,7 +10767,7 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = {
|
||||
emitline("(BP)\n");
|
||||
zz += 8;
|
||||
};
|
||||
cgwidentaggedstore(c, ptype, arg, "BP", scroff, widensz);
|
||||
cgwidentaggedstore(c, ptype.type_: *tinfo, arg, "BP", scroff, widensz);
|
||||
let pp: i32 = widensz - 8;
|
||||
for (pp >= 0) {
|
||||
emitline("\tMOVQ\t");
|
||||
@@ -12732,65 +12732,48 @@ fn rhstargetname(c: *cgen, rhs: *node) str = {
|
||||
// "any str-shape variant matches an str-typed value".
|
||||
fn taggedvariantindex(c: *cgen, tagged: *node, rhs: *node) i32 = {
|
||||
if (tagged == nil) { return -1; };
|
||||
if (rhs == nil) { return -1; };
|
||||
// Alias-unwrap: wwstage has no typed AST, so an aliased tagged
|
||||
// return (`type ft = (i64|str|bool); fn f() ft = ...`) reaches
|
||||
// here as N_TNAME("ft"), not N_TTAGGED. flatvariantidx and the
|
||||
// fallback both gate on N_TTAGGED → -1 → caller maps to 0,
|
||||
// silently emitting `MOVQ $0, AX` for every non-leading variant.
|
||||
// Cstage's check.c canonicalizes N_TNAME → underlying upfront;
|
||||
// every wwstage cgen consumer of a type-bearing node has to
|
||||
// remember this step itself. TODO(#11): a wwstage check pass
|
||||
// between parse and cgen would replace the per-site unwrap with
|
||||
// a single canonicalization. Same shape of fix as nodeisstr.
|
||||
let resolved: *node = resolvetagged(c, tagged);
|
||||
if (resolved != nil) { tagged = resolved; };
|
||||
// #66 Phase-N step 3: match the value's stamped type against the
|
||||
// variant types by typeeq (flatvariantidx), replacing the
|
||||
// rhstargetname surface-name compare. Untyped/loose values (whose
|
||||
// .type_ is untyped_* and can't typeeq a concrete variant) return
|
||||
// -1 here and drop to the str/slice shape scan below — ww has no
|
||||
// type_assignable to mirror cg_variant_match's untyped-src arm.
|
||||
let r: i32 = flatvariantidx(c, tagged, rhs);
|
||||
return taggedvariantindext(c, tagged.type_: *tinfo, rhs);
|
||||
};
|
||||
|
||||
// taggedvariantindext — tinfo-keyed core of taggedvariantindex. Given
|
||||
// the dst tagged tinfo `du` (NAMED-peeled internally, gated TY_TAGGED)
|
||||
// and the source value node, returns the 0-based variant index. #68: the
|
||||
// tagged-store machinery reads tinfo directly (no type node), so the
|
||||
// node-keyed taggedvariantindex delegates here off `tagged.type_`.
|
||||
//
|
||||
// #66 Phase-N step 3: match the value's stamped type against the variant
|
||||
// types by typeeq (flatvariantidxt), replacing the rhstargetname surface-
|
||||
// name compare. Untyped/loose values (whose .type_ is untyped_* and can't
|
||||
// typeeq a concrete variant) return -1 there and drop to the str/slice
|
||||
// shape scan below — ww has no type_assignable to mirror cg_variant_match's
|
||||
// untyped-src arm.
|
||||
fn taggedvariantindext(c: *cgen, du: *tinfo, rhs: *node) i32 = {
|
||||
if (du == nil) { return -1; };
|
||||
if (rhs == nil) { return -1; };
|
||||
let ti: *tinfo = du;
|
||||
for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; };
|
||||
if (ti == nil) { return -1; };
|
||||
if (ti.kind != tykind.TY_TAGGED) { return -1; };
|
||||
let r: i32 = flatvariantidxt(ti, rhs.type_: *tinfo);
|
||||
if (r >= 0) { return r; };
|
||||
// Shape fallback: classify rhs as (str, slice, scalar/other) and
|
||||
// pick the first variant of matching shape. Stands in for cstage's
|
||||
// type_assignable on an untyped src — the typeeq pass above can't
|
||||
// match untyped_* against a concrete variant, and the slice axis
|
||||
// keeps a (u8 | []u8) widen off the leading scalar variant (task
|
||||
// #19). Walks the spread-flattened list so a `(...inner | str)`
|
||||
// outer agrees with the inner's str / slice positions.
|
||||
// #19). tinfo.params is already spread-flattened (#61a — `...inner`
|
||||
// inlined in declaration order), so the old N_TTAGGED.list spread-
|
||||
// walk collapses to a flat scan over p.type_.
|
||||
let wantstr: bool = nodeisstr(c, rhs);
|
||||
let wantslice: bool = nodeisslice(c, rhs);
|
||||
let v: *node = tagged.list;
|
||||
let p: *tparam = ti.params;
|
||||
let idx: i32 = 0;
|
||||
for (v != nil) {
|
||||
let isspread: bool = (v.op == tkind.TK_ELLIPSIS);
|
||||
if (isspread) {
|
||||
let inner: *node = v;
|
||||
if (inner.kind == nkind.N_TNAME) {
|
||||
let a: *node = aliaslookup(c, inner.str);
|
||||
if (a != nil) { inner = a; };
|
||||
};
|
||||
if (inner != nil) {
|
||||
if (inner.kind == nkind.N_TTAGGED) {
|
||||
let iv: *node = inner.list;
|
||||
for (iv != nil) {
|
||||
let ivisstr: bool = isstrtype(c, iv);
|
||||
let ivisslice: bool = isslicetype(c, iv);
|
||||
if (ivisstr == wantstr && ivisslice == wantslice) { return idx; };
|
||||
iv = iv.next;
|
||||
idx += 1;
|
||||
};
|
||||
v = v.next;
|
||||
continue;
|
||||
};
|
||||
};
|
||||
};
|
||||
let visstr: bool = isstrtype(c, v);
|
||||
let visslice: bool = isslicetype(c, v);
|
||||
for (p != nil) {
|
||||
let vt: *tinfo = p.type_;
|
||||
let visstr: bool = typeisstr(vt);
|
||||
let visslice: bool = typeisslice(vt);
|
||||
if (visstr == wantstr && visslice == wantslice) { return idx; };
|
||||
v = v.next;
|
||||
p = p.tnext;
|
||||
idx += 1;
|
||||
};
|
||||
return -1;
|
||||
@@ -12813,9 +12796,21 @@ fn taggedvariantindex(c: *cgen, tagged: *node, rhs: *node) i32 = {
|
||||
fn flatvariantidx(c: *cgen, tagged: *node, pat: *node) i32 = {
|
||||
if (tagged == nil) { return -1; };
|
||||
if (pat == nil) { return -1; };
|
||||
let want: *tinfo = pat.type_: *tinfo;
|
||||
return flatvariantidxt(tagged.type_: *tinfo, pat.type_: *tinfo);
|
||||
};
|
||||
|
||||
// flatvariantidxt — tinfo-keyed core of flatvariantidx: flat 0-based
|
||||
// index of the variant whose type typeeq's `want`, over the pre-
|
||||
// flattened tinfo.params chain (#61a). Peels TY_NAMED then gates
|
||||
// TY_TAGGED. #68: the tagged-store machinery reads tinfo directly and
|
||||
// has no type node to hand the node-keyed flatvariantidx, so the typeeq
|
||||
// core lives here; flatvariantidx + taggedvariantindext + cgwidentagremap
|
||||
// all funnel through it. Mirrors cstage cg_tag_for_variant
|
||||
// (cmd/w6c/cgen.c:503) + cg_variant_match's both-NAMED ptr-id / typeeq
|
||||
// arm (:451).
|
||||
fn flatvariantidxt(tagged: *tinfo, want: *tinfo) i32 = {
|
||||
if (want == nil) { return -1; };
|
||||
let ti: *tinfo = tagged.type_: *tinfo;
|
||||
let ti: *tinfo = tagged;
|
||||
for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; };
|
||||
if (ti == nil) { return -1; };
|
||||
if (ti.kind != tykind.TY_TAGGED) { return -1; };
|
||||
@@ -12874,31 +12869,39 @@ fn flatslicevariantidx(c: *cgen, tagged: *node, elem: *node) i32 = {
|
||||
// cgwidentagremap — when widening from one tagged union to a wider one,
|
||||
// rewrite the source's variant tag at slot_off+0 to use the destination's
|
||||
// variant indices. No-op when src and dst index orders coincide.
|
||||
// Mirrors cg_widen_tag_remap in cmd/w6c/cgen.c.
|
||||
fn cgwidentagremap(c: *cgen, dst: *node, src: *node, slot_off: i32) void = {
|
||||
if (dst == nil) { return; };
|
||||
if (src == nil) { return; };
|
||||
if (dst.kind != nkind.N_TTAGGED) { return; };
|
||||
if (src.kind != nkind.N_TTAGGED) { return; };
|
||||
//
|
||||
// #68: both `du` (dst) and `su` (src) are now the tagged tinfos — peel
|
||||
// TY_NAMED then walk su.params, mapping each source variant to its dst
|
||||
// index by typeeq (flatvariantidxt). Mirrors cg_widen_tag_remap
|
||||
// (cmd/w6c/cgen.c:1177) over su->params + cg_tag_for_variant (:503).
|
||||
fn cgwidentagremap(c: *cgen, du: *tinfo, su: *tinfo, slot_off: i32) void = {
|
||||
let dt: *tinfo = du;
|
||||
for (dt != nil && dt.kind == tykind.TY_NAMED) { dt = dt.under; };
|
||||
if (dt == nil) { return; };
|
||||
if (dt.kind != tykind.TY_TAGGED) { return; };
|
||||
let st: *tinfo = su;
|
||||
for (st != nil && st.kind == tykind.TY_NAMED) { st = st.under; };
|
||||
if (st == nil) { return; };
|
||||
if (st.kind != tykind.TY_TAGGED) { return; };
|
||||
let identity: bool = true;
|
||||
let v: *node = src.list;
|
||||
let p: *tparam = st.params;
|
||||
let idx: i32 = 0;
|
||||
for (v != nil) {
|
||||
let di: i32 = cgtagvariantidx(c, dst, v);
|
||||
for (p != nil) {
|
||||
let di: i32 = flatvariantidxt(dt, p.type_);
|
||||
if (di < 0) { di = 0; };
|
||||
if (di != idx) { identity = false; v = nil; }
|
||||
else { v = v.next; idx += 1; };
|
||||
if (di != idx) { identity = false; p = nil; }
|
||||
else { p = p.tnext; idx += 1; };
|
||||
};
|
||||
if (identity) { return; };
|
||||
let done: str = mklabel(c, "remap_done");
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(slot_off: i64);
|
||||
emitline("(BP), AX\n");
|
||||
v = src.list;
|
||||
p = st.params;
|
||||
idx = 0;
|
||||
for (v != nil) {
|
||||
for (p != nil) {
|
||||
let next: str = mklabel(c, "remap_next");
|
||||
let di: i32 = cgtagvariantidx(c, dst, v);
|
||||
let di: i32 = flatvariantidxt(dt, p.type_);
|
||||
if (di < 0) { di = 0; };
|
||||
emitline("\tCMPQ\t$");
|
||||
emitint(idx: i64);
|
||||
@@ -12916,7 +12919,7 @@ fn cgwidentagremap(c: *cgen, dst: *node, src: *node, slot_off: i32) void = {
|
||||
emitline(done);
|
||||
emitline("\n");
|
||||
emitlabel(next);
|
||||
v = v.next;
|
||||
p = p.tnext;
|
||||
idx += 1;
|
||||
};
|
||||
emitlabel(done);
|
||||
@@ -13145,7 +13148,7 @@ fn cgloadtaggedfield(c: *cgen, basereg: str, foff: i32, slot_sz: i32) void = {
|
||||
// tag last.
|
||||
// - str src: tag@+0, ptr@+8, len@+16.
|
||||
// - scalar src: tag@+0, value@+8.
|
||||
fn cgwidentaggedstore(c: *cgen, dst: *node, src: *node,
|
||||
fn cgwidentaggedstore(c: *cgen, dst: *tinfo, src: *node,
|
||||
basereg: str, slot_off: i32, slot_sz: i32) void = {
|
||||
if (streq(basereg, "BP")) {
|
||||
cgwidentaggedstorebp(c, dst, src, slot_off, slot_sz);
|
||||
@@ -13195,11 +13198,18 @@ fn cgwidentaggedstore(c: *cgen, dst: *node, src: *node,
|
||||
// for the natural "BP" case and via the wrapper's scratch path for
|
||||
// pointer-rooted dst. Direct callers exist only in case of future
|
||||
// inlined uses inside this file; new code should call the wrapper.
|
||||
fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz: i32) void = {
|
||||
let dt: *node = resolvetagged(c, dst);
|
||||
fn cgwidentaggedstorebp(c: *cgen, dst: *tinfo, src: *node, slot_off: i32, slot_sz: i32) void = {
|
||||
// #68: dst is the tagged tinfo. Peel TY_NAMED → du and gate
|
||||
// TY_TAGGED, mirroring cstage cg_widen_tagged_store's
|
||||
// `du = (dst->kind==TY_NAMED)?dst->under:dst` + TY_TAGGED guard
|
||||
// (cmd/w6c/cgen.c:1273). resolvetagged's N_TBANG unwrap is already
|
||||
// handled upstream by tinfofornode (check.ww:1203-1210).
|
||||
let dt: *tinfo = dst;
|
||||
for (dt != nil && dt.kind == tykind.TY_NAMED) { dt = dt.under; };
|
||||
if (dt == nil) { return; };
|
||||
if (dt.kind != tykind.TY_TAGGED) { return; };
|
||||
// Nullable fold: one 8B word holding the pointer (or 0 for void).
|
||||
if (isnullabletype(dst)) {
|
||||
if (dt.nullable != 0) {
|
||||
cgexpr(c, src);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(slot_off: i64);
|
||||
@@ -13229,22 +13239,32 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
};
|
||||
// Cast's destination = the dst tagged union
|
||||
// itself? The rhs of N_CAST holds the target
|
||||
// type. Compare nominally via str match on
|
||||
// the tagged-alias name.
|
||||
// type. #68: compare on the stamped tinfos —
|
||||
// `castu == dt` (peeled-underlying ptr-id) ||
|
||||
// (castu tagged && typeeq(castt, dst)) — mirroring
|
||||
// cstage cg_widen_tagged_store's
|
||||
// `cast_is_widen = (castu==du) || (castu->kind==
|
||||
// TY_TAGGED && type_eq(castt, dst))`
|
||||
// (cmd/w6c/cgen.c:1295-1296). Replaces the prior
|
||||
// surface-name streq; same-alias TNAMEs share one
|
||||
// NAMED tinfo (check.ww:1160-1173) so typeeq hits
|
||||
// the a==b fast path.
|
||||
let castisdst: bool = false;
|
||||
let castrhs: *node = src.rhs;
|
||||
if (castrhs != nil) {
|
||||
if (castrhs.kind == nkind.N_TTAGGED) {
|
||||
castisdst = true;
|
||||
let castt: *tinfo = castrhs.type_: *tinfo;
|
||||
let castu: *tinfo = castt;
|
||||
for (castu != nil && castu.kind == tykind.TY_NAMED) {
|
||||
castu = castu.under;
|
||||
};
|
||||
if (castrhs.kind == nkind.N_TNAME) {
|
||||
if (dst != nil) {
|
||||
if (dst.kind == nkind.N_TNAME) {
|
||||
if (streq(castrhs.str, dst.str)) {
|
||||
castisdst = true;
|
||||
};
|
||||
if (castu != nil) {
|
||||
if (castu == dt) {
|
||||
castisdst = true;
|
||||
} else { if (castu.kind == tykind.TY_TAGGED) {
|
||||
if (typeeq(castt, dst)) {
|
||||
castisdst = true;
|
||||
};
|
||||
};
|
||||
}; };
|
||||
};
|
||||
};
|
||||
if (castisdst && !inneristagged) {
|
||||
@@ -13254,6 +13274,8 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
};
|
||||
};
|
||||
// Tagged source ident: byte-copy slot words then tag-remap.
|
||||
// rhstaggedident gates "src is a tagged-typed local ident"; the
|
||||
// remap reads the source tagged tinfo off the local's tnode (#68).
|
||||
let st: *node = rhstaggedident(c, src);
|
||||
if (st != nil) {
|
||||
let lc: *local = localfindnode(c, src.str);
|
||||
@@ -13279,7 +13301,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
p += 8;
|
||||
};
|
||||
};
|
||||
cgwidentagremap(c, dt, st, slot_off);
|
||||
cgwidentagremap(c, dt, lc.tnode.type_: *tinfo, slot_off);
|
||||
return;
|
||||
};
|
||||
// Tagged source via AX/DX/CX/R8 register ABI (N_CALL, N_INDEX
|
||||
@@ -13320,7 +13342,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("(BP)\n");
|
||||
zoff += 8;
|
||||
};
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
if (src.kind == nkind.N_STRUCTLIT) {
|
||||
let fnode: *node = src.list;
|
||||
@@ -13414,7 +13436,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((slot_off + 16): i64);
|
||||
emitline("(BP)\n");
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(tag: i64);
|
||||
@@ -13436,7 +13458,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitoff((slot_off + 24): i64);
|
||||
emitline("(BP)\n");
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(tag: i64);
|
||||
@@ -13472,7 +13494,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
// like the slice axis, not nominal identity.
|
||||
let wantf32: bool = (fkind == 1);
|
||||
let ftag: i32 = -1;
|
||||
let fti: *tinfo = dt.type_: *tinfo;
|
||||
let fti: *tinfo = dt;
|
||||
for (fti != nil && fti.kind == tykind.TY_NAMED) { fti = fti.under; };
|
||||
if (fti != nil) { if (fti.kind == tykind.TY_TAGGED) {
|
||||
let fp: *tparam = fti.params;
|
||||
@@ -13502,7 +13524,7 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *node, src: *node, slot_off: i32, slot_sz
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((slot_off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
let tag: i32 = taggedvariantindex(c, dt, src);
|
||||
let tag: i32 = taggedvariantindext(c, dt, src);
|
||||
if (tag < 0) { tag = 0; };
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(tag: i64);
|
||||
@@ -13780,7 +13802,7 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
emitsymname(c, srcname);
|
||||
emitline("(SB), BX\n");
|
||||
};
|
||||
cgwidentaggedstore(c, fi.tnode,
|
||||
cgwidentaggedstore(c, fi.tnode.type_: *tinfo,
|
||||
fieldnode.lhs, basereg,
|
||||
disp + fi.foff, fi.fsz);
|
||||
fi = nil;
|
||||
@@ -17149,7 +17171,7 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
// dst is the per-element tagged type;
|
||||
// pass velem (cstage cgen.c:4382 passes
|
||||
// velem, not the slice wrap vsu).
|
||||
cgwidentaggedstore(c, velem,
|
||||
cgwidentaggedstore(c, velem.type_: *tinfo,
|
||||
aa2, "BP", slot, esz);
|
||||
} else { if (velemstr) {
|
||||
cgexpr(c, aa2);
|
||||
@@ -17484,7 +17506,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (lc != nil) {
|
||||
if (istaggedtype(c, lc.tnode)) {
|
||||
let lsz: i32 = slotsize(c, lc.tnode);
|
||||
cgwidentaggedstore(c, lc.tnode,
|
||||
cgwidentaggedstore(c, lc.tnode.type_: *tinfo,
|
||||
n.rhs, "BP", lc.off, lsz);
|
||||
return;
|
||||
};
|
||||
@@ -17764,7 +17786,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("(BP)\n");
|
||||
zz += 8;
|
||||
};
|
||||
cgwidentaggedstore(c, elemtn, n.rhs,
|
||||
cgwidentaggedstore(c, elemtn.type_: *tinfo, n.rhs,
|
||||
"BP", scroff, slot_sz);
|
||||
cgexpr(c, idx);
|
||||
if (slot_sz > 1) {
|
||||
@@ -18142,7 +18164,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
cgwidentaggedstore(c, fi.tnode,
|
||||
cgwidentaggedstore(c, fi.tnode.type_: *tinfo,
|
||||
n.rhs, "BX", fi.foff, fsz);
|
||||
return;
|
||||
};
|
||||
@@ -18379,7 +18401,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (n.op == tkind.TK_ASSIGN
|
||||
&& istaggedtype(c, fi.tnode)) {
|
||||
let fsz: i32 = slotsize(c, fi.tnode);
|
||||
cgwidentaggedstore(c, fi.tnode,
|
||||
cgwidentaggedstore(c, fi.tnode.type_: *tinfo,
|
||||
n.rhs, "BP", lc.off + fi.foff, fsz);
|
||||
return;
|
||||
};
|
||||
@@ -20062,7 +20084,7 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
emitline("(BP)\n");
|
||||
zz += 8;
|
||||
};
|
||||
cgwidentaggedstore(c, c.fnret, rhs, "BP",
|
||||
cgwidentaggedstore(c, c.fnret.type_: *tinfo, rhs, "BP",
|
||||
scroff, rsz);
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scroff: i64);
|
||||
@@ -20552,7 +20574,7 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
// ABI call), struct payload (literal/ident), str payload,
|
||||
// scalar payload — with tag remap for tagged-subset widening.
|
||||
if (istaggedtype(c, tn)) {
|
||||
cgwidentaggedstore(c, tn, rhs, "BP", off, sz);
|
||||
cgwidentaggedstore(c, tn.type_: *tinfo, rhs, "BP", off, sz);
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user