w6c+selfhost: TK_AMP through chained N_DOT (closes #9)
Three shapes handled: value-struct chains (&o.i.a), pointer-field (&p.f), slice/str pseudo-fields (&s.len). cstage inlines #6's spine walker; wwstage reuses dotchainresolve unchanged. Silent-drop fallback preserved. Slice-header width mismatch in *&s.len writes filed as task #13.
This commit is contained in:
@@ -1868,6 +1868,169 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
};
|
||||
return;
|
||||
};
|
||||
// Address-of through a DOT chain. Mirror of cstage
|
||||
// cgen.c TK_AMP N_DOT branch. Three shapes converge
|
||||
// here, all returning an 8B address (no fldloadop —
|
||||
// just LEAQ / MOVQ+LEAQ).
|
||||
//
|
||||
// 1. Value-struct fields, any depth (`&o.f`,
|
||||
// `&o.i.a`, `&o.a.b.c`) and slice/str pseudo-field
|
||||
// tail (`&s.len`, `&b.buf.len`): the chained
|
||||
// (depth ≥ 2) case reuses dotchainresolve; the
|
||||
// single-DOT case is handled below by inspecting
|
||||
// the IDENT base's tnode. Byte-identical to the
|
||||
// cstage spine walker for both depths.
|
||||
// 2. Pointer-field (`&p.f` where p:*T): single-DOT
|
||||
// only; spine walker aborts on the *T base. Load
|
||||
// p into AX, then LEAQ field_off(AX), AX. Mirror
|
||||
// of the read at cgdot 1144.
|
||||
if (opnd.kind == nkind.N_DOT) {
|
||||
// Shape 1 chained: depth-≥2 via dotchainresolve.
|
||||
// `opnd.lhs.kind == N_DOT` gates the helper at
|
||||
// nsteps ≥ 2 (matches the read path's gate).
|
||||
if (opnd.lhs != nil) {
|
||||
if (opnd.lhs.kind == nkind.N_DOT) {
|
||||
let r: dotchain;
|
||||
let pok: bool = dotchainresolve(c, opnd, &r);
|
||||
if (pok) {
|
||||
let extra: i64 = 0i64;
|
||||
if (r.slicedelta >= 0i64) { extra = r.slicedelta; };
|
||||
if (r.isglobal) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, r.rootname);
|
||||
emitline("(SB), CX\n");
|
||||
emitline("\tLEAQ\t");
|
||||
emitdispreg(r.totaloff + extra, "CX");
|
||||
emitline(", AX\n");
|
||||
} else {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(r.rootoff + r.totaloff + extra);
|
||||
emitline("(BP), AX\n");
|
||||
};
|
||||
return;
|
||||
};
|
||||
};
|
||||
};
|
||||
// Shape 1/2 single-DOT on an IDENT base. Inspect
|
||||
// the base's tnode to pick value-struct vs slice/
|
||||
// str pseudo vs pointer-field.
|
||||
if (opnd.lhs != nil) {
|
||||
if (opnd.lhs.kind == nkind.N_IDENT) {
|
||||
let basenm: str = opnd.lhs.str;
|
||||
let fld: str = opnd.str;
|
||||
let lc: *local = localfindnode(c, basenm);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
// Pointer-field: &p.f where p:*T.
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (inner != nil) {
|
||||
if (inner.kind == nkind.N_TNAME) { sname = inner.str; };
|
||||
};
|
||||
if (sname.len > 0) {
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tLEAQ\t");
|
||||
emitdispreg(fi.foff: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
// Value-struct local: &o.f.
|
||||
if (lkind == nkind.N_TNAME) {
|
||||
let sname: str = tn.str;
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld)) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff((lc.off + fi.foff): i64);
|
||||
emitline("(BP), AX\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
};
|
||||
};
|
||||
// Slice/str pseudo-field on a local:
|
||||
// &s.ptr / &s.len / &s.cap. Delta is
|
||||
// 0/8/16 — matches the spine walker.
|
||||
let delta: i32 = -1;
|
||||
if (streq(fld, "ptr")) { delta = 0; };
|
||||
if (streq(fld, "len")) { delta = 8; };
|
||||
if (streq(fld, "cap")) { delta = 16; };
|
||||
if (delta >= 0) {
|
||||
let isslor: bool = false;
|
||||
if (lkind == nkind.N_TSLICE) { isslor = true; };
|
||||
if (lkind == nkind.N_TNAME) {
|
||||
if (streq(tn.str, "str")) { isslor = true; };
|
||||
};
|
||||
if (isslor) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff((lc.off + delta): i64);
|
||||
emitline("(BP), AX\n");
|
||||
return;
|
||||
};
|
||||
};
|
||||
};
|
||||
// Global root: top-level let, either a
|
||||
// struct or a slice/str.
|
||||
if (isletvar(c, basenm)) {
|
||||
let gsi: *structinfo = letvarstructinfo(c, basenm);
|
||||
if (gsi != nil) {
|
||||
let fi: *fieldinfo = gsi.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld)) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, basenm);
|
||||
emitline("(SB), CX\n");
|
||||
emitline("\tLEAQ\t");
|
||||
emitdispreg(fi.foff: i64, "CX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
};
|
||||
let isstr: bool = letvarisstr(c, basenm);
|
||||
let issl: bool = letvarisslice(c, basenm);
|
||||
if (isstr || issl) {
|
||||
let gdelta: i32 = -1;
|
||||
if (streq(fld, "ptr")) { gdelta = 0; };
|
||||
if (streq(fld, "len")) { gdelta = 8; };
|
||||
if (issl) { if (streq(fld, "cap")) { gdelta = 16; }; };
|
||||
if (gdelta >= 0) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, basenm);
|
||||
emitline("(SB), CX\n");
|
||||
emitline("\tLEAQ\t");
|
||||
emitdispreg(gdelta: i64, "CX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
// Fall through silently (mirrors cstage silent-
|
||||
// drop fallback at the end of the TK_AMP block).
|
||||
return;
|
||||
};
|
||||
if (opnd.kind == nkind.N_INDEX) {
|
||||
// &base[i] = base + i*esz, no dereference.
|
||||
let base: *node = opnd.lhs;
|
||||
|
||||
Reference in New Issue
Block a user