w6c+selfhost: cg_widen_tagged_store basereg + N_ASSIGN tagged field (closes #26)

Extended cg_widen_tagged_store (cstage) / cgwidentaggedstore (wwstage)
to take a base_reg/basereg parameter so the primitive supports non-BP
destinations. Cstage extends body in-place via via_outer gate +
spill+scratch+copy-out; wwstage splits into wrapper (non-BP) +
cgwidentaggedstorebp (BP-only) to dodge the no-goto constraint. New
N_ASSIGN field TY_TAGGED branch routes through the primitive for all
rhs shapes.

Scope-adjacent: fieldsize recurses through N_TTAGGED via slotsize and
TNAME-aliased-to-tagged via aliaslookup. Needed for the test fixtures.

Wwstage read-side N_DOT-of-tagged-field source is filed as task #28;
test rows use mark-canary verification until that lands.
This commit is contained in:
2026-05-14 19:12:20 +09:00
parent 1726bcef18
commit a5919ed8da
8 changed files with 644 additions and 116 deletions

View File

@@ -2745,7 +2745,7 @@ fn cgcall(c: *cgen, n: *node) void = {
let slot: i32 = doff + j * esz;
if (velemtagged) {
cgwidentaggedstore(c, varp.lhs,
aa2, slot, esz);
aa2, "BP", slot, esz);
} else { if (velemstr) {
cgexpr(c, aa2);
emitline("\tMOVQ\tAX, ");
@@ -3001,7 +3001,7 @@ fn cgassign(c: *cgen, n: *node) void = {
if (istaggedtype(c, lc.tnode)) {
let lsz: i32 = slotsize(c, lc.tnode);
cgwidentaggedstore(c, lc.tnode,
n.rhs, lc.off, lsz);
n.rhs, "BP", lc.off, lsz);
return;
};
};
@@ -3225,7 +3225,7 @@ fn cgassign(c: *cgen, n: *node) void = {
zz += 8;
};
cgwidentaggedstore(c, elemtn, n.rhs,
scroff, slot_sz);
"BP", scroff, slot_sz);
cgexpr(c, idx);
if (slot_sz > 1) {
emitline("\tMOVQ\t$");
@@ -3571,6 +3571,20 @@ fn cgassign(c: *cgen, n: *node) void = {
for (fi != nil) {
let fn_: str = fi.fname;
if (streq(fn_, fld)) {
// Tagged-union field via *struct base — full slot
// rewrite via cgwidentaggedstore basereg="BX". Pre-#26
// fell through to the scalar store and dropped tag
// + payload.
if (n.op == tkind.TK_ASSIGN
&& istaggedtype(c, fi.tnode)) {
let fsz: i32 = slotsize(c, fi.tnode);
emitline("\tMOVQ\t");
emitoff(lc.off: i64);
emitline("(BP), BX\n");
cgwidentaggedstore(c, fi.tnode,
n.rhs, "BX", fi.foff, fsz);
return;
};
// struct-typed field, struct-ident rhs through
// *struct base: cgexpr can't materialise a whole
// struct value, so word-copy from the rhs slot
@@ -3721,6 +3735,17 @@ fn cgassign(c: *cgen, n: *node) void = {
for (fi != nil) {
let fn_: str = fi.fname;
if (streq(fn_, fld)) {
// Tagged-union field in a direct struct local —
// full slot rewrite at (lc.off + fi.foff)(BP)
// via cgwidentaggedstore basereg="BP". Pre-#26
// fell through and dropped tag + payload.
if (n.op == tkind.TK_ASSIGN
&& istaggedtype(c, fi.tnode)) {
let fsz: i32 = slotsize(c, fi.tnode);
cgwidentaggedstore(c, fi.tnode,
n.rhs, "BP", lc.off + fi.foff, fsz);
return;
};
// struct-typed field, struct-ident rhs:
// word-copy direct, skipping cgexpr (no
// register convention for a whole struct