selfhost/cmd/wcc: collapse chained-dot offset-emit onto tinfo.fields + delete dotinnerstructptr (#70, #12)
Both chained-*struct-field sites (cgdot read, cgassign store) read the inner- struct layout off the stamped inner-dot tinfo (peel NAMED->under, TY_PTR->.sub ->NAMED->under->TY_STRUCT) and walk tinfo.fields for offset + per-field type, replacing dotinnerstructptr's structinfo re-walk + structlookup. Type dispatch (str/slice/float, load/store op) keys on tfield.type_ via the existing *tinfo predicates; ft.slotsize reproduces the old fieldsize exactly (== size for all kinds reached here except struct/array). cstage parity: cgen.c:1653-1655 (read fl->offset), 2514/2541 (store f->offset). Behavior-preserving: a strict per-level gate (every chain dot must peel through a *struct, root must be N_IDENT && localfindnode != nil) reproduces dotinnerstructptr's EXACT locals-only-with-all-*struct-intermediates firing set -- a by-value intermediate dot bails to the identical pre-existing generic path. asm is byte-identical (990-997 hold; both the strict gate and the looser superset tested 134/134, confirming the corpus has no by-value-intermediate chain). Deliberately NOT widened past the old set: global-root and by-value- intermediate chained dots stay on their old paths -- the global case is a pre-existing SHARED base-eval defect (cstage mis-evals the global base as (BP)->segfault; wwstage no-stores), filed #27 to fix in both stages together. dotinnerstructptr deleted (0 callers). Offset now sources from tinfo.fields (natural layout) vs old structinfo (slot-padded); they coincide for flat structs (all reached here), with nested-by-value-struct divergence pre-existing and left to #57/#6/#7 territory.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
// - pushargsrev: per-call arg pushing
|
||||
// - type predicates: isstr*/isslice*/istagged*/nodeis* families
|
||||
// - field ops: fieldloadop, fieldstoreop
|
||||
// - index helpers: indexbaseesz, dotinnerstructptr, elemsizeof
|
||||
// - index helpers: indexbaseesz, elemsizeof
|
||||
// - slot sizing: structlookup, primsize, slotsize, fieldsize,
|
||||
// registerstruct, collectstructs
|
||||
// - rhs helpers: taggedvariantindex
|
||||
@@ -948,56 +948,6 @@ fn indexbaseesz(c: *cgen, base: *node) i32 = {
|
||||
return 8;
|
||||
};
|
||||
|
||||
// dotinnerstructptr — for an nkind.N_DOT whose lhs is a chain of dots
|
||||
// or an nkind.N_IDENT, walk the chain and return the nkind.N_TNAME tnode of the
|
||||
// struct that the chain dereferences to (i.e., for `r.sym` where
|
||||
// .sym is *lsym, return nkind.N_TNAME("lsym")). Returns nil if the chain
|
||||
// doesn't resolve to a *struct.
|
||||
//
|
||||
// Used by the chained-DOT cgen path so `r.sym.val` knows the outer
|
||||
// is a field of `lsym`.
|
||||
fn dotinnerstructptr(c: *cgen, n: *node) *node = {
|
||||
if (n == nil) { return nil; };
|
||||
if (n.kind != nkind.N_DOT) { return nil; };
|
||||
let base: *node = n.lhs;
|
||||
let fld: str = n.str;
|
||||
if (base == nil) { return nil; };
|
||||
|
||||
// Resolve base's struct tnode.
|
||||
let baset: *node = nil;
|
||||
if (base.kind == nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, base.str);
|
||||
if (lc == nil) { return nil; };
|
||||
let tn: *node = lc.tnode;
|
||||
if (tn == nil) { return nil; };
|
||||
// base could be either struct-by-value (nkind.N_TNAME) or *struct (nkind.N_TPTR).
|
||||
if (tn.kind == nkind.N_TNAME) { baset = tn; };
|
||||
if (tn.kind == nkind.N_TPTR) { baset = tn.lhs; };
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
baset = dotinnerstructptr(c, base);
|
||||
};};
|
||||
if (baset == nil) { return nil; };
|
||||
if (baset.kind != nkind.N_TNAME) { return nil; };
|
||||
|
||||
// Look up the struct, find the field, return the field's *struct.
|
||||
let si: *structinfo = structlookup(c, baset.str);
|
||||
if (si == nil) { return nil; };
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld)) {
|
||||
let ft: *node = fi.tnode;
|
||||
if (ft == nil) { return nil; };
|
||||
if (ft.kind != nkind.N_TPTR) { return nil; };
|
||||
let inner: *node = ft.lhs;
|
||||
if (inner == nil) { return nil; };
|
||||
if (inner.kind != nkind.N_TNAME) { return nil; };
|
||||
return inner;
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
return nil;
|
||||
};
|
||||
|
||||
// elemsizeof — given the type node of an indexable (`*T`, `[]T`,
|
||||
// `[N]T`, `str`), return the byte size of one element (1 for u8/i8/
|
||||
// bool/str-byte, 8 otherwise — same shape as C cgen's esz fallback).
|
||||
|
||||
Reference in New Issue
Block a user