selfhost/cmd/wcc: dotchainresolve walks tinfo.fields (#71, A.6.3j)
The chained value-struct spine-walker resolved root + total offset + leaf type via structinfo/fieldinfo (slot-padded foff). Swap its guts onto the stamped root-ident type_: peel TY_NAMED to TY_STRUCT (one TY_PTR hop for a *struct root) and accumulate tfield.offset down the spine, mirroring cstage's cur->lhs->type fields walk (cmd/w6c/cgen.c:3156-3216 write, :1955-2030 AMP/ read). Leaf out-param becomes *tinfo; the three callers read leaf-ness via typeis*/loadopsz, and the cgassign struct-terminal recovers the struct name from the leaf tinfo's NAMED wrapper for the still-structinfo cgstructlitfill. Root classification (local/ptr/global) is unchanged, so the firing set and addressing mode stay byte-identical; the global-root path remains its pre- existing shared breakage (#27), untouched. Natural tfield.offset equals the old slot-padded foff for every shape the byte-id gate exercises -- and since cstage already reads the natural offset and ww-old==cstage held, the flip is structurally identical, not coincidental. Latent (off-corpus, byte-id-neutral): the tinfo-peel now fires the str/slice pseudo-leaf on an aliased-str/slice field where the old structinfo path bailed -- a faithful-toward-cstage gap closure, filed for a probe + sentinel. make test 134/134, byte-id 950+990-997 hold.
This commit is contained in:
@@ -1840,13 +1840,13 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
let rootname: str = "";
|
||||
let rootoff: i32 = 0;
|
||||
let totaloff: i32 = 0;
|
||||
let leaffi: *fieldinfo = nil;
|
||||
let leaftype: *tinfo = nil;
|
||||
let slicedelta: i32 = -1;
|
||||
let isglobal: bool = false;
|
||||
let ptrroot: bool = false;
|
||||
let pok: bool = dotchainresolve(c, n,
|
||||
&rootname, &rootoff, &totaloff,
|
||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
||||
&leaftype, &slicedelta, &isglobal, &ptrroot);
|
||||
if (pok) {
|
||||
// `*T` root: load the pointer slot once into CX,
|
||||
// then index every leaf at total_off off CX. Same
|
||||
@@ -1874,7 +1874,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
return;
|
||||
};
|
||||
if (isstrtype(c, leaffi.tnode)) {
|
||||
if (typeisstr(leaftype)) {
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
@@ -1901,7 +1901,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
return;
|
||||
};
|
||||
if (isslicetype(c, leaffi.tnode)) {
|
||||
if (typeisslice(leaftype)) {
|
||||
// Slice leaf: load all three header words into
|
||||
// (AX=ptr, BX=len, CX=cap). For the viacx path
|
||||
// (global or `*T` root) CX is the base; load
|
||||
@@ -1940,9 +1940,9 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
return;
|
||||
};
|
||||
if (isfloattype(c, leaffi.tnode)) {
|
||||
if (typeisfloat(leaftype)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
||||
if (typeisf32(leaftype)) { mov = "MOVSS"; };
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
@@ -1967,7 +1967,8 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
return;
|
||||
};
|
||||
let lop: str = fieldloadop(c, leaffi);
|
||||
let lop: str = loadopsz(typeissigned(leaftype),
|
||||
leaftype.slotsize: i32);
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
emitline("\tMOVQ\t");
|
||||
@@ -2314,13 +2315,13 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
let rootname: str = "";
|
||||
let rootoff: i32 = 0;
|
||||
let totaloff: i32 = 0;
|
||||
let leaffi: *fieldinfo = nil;
|
||||
let leaftype: *tinfo = nil;
|
||||
let slicedelta: i32 = -1;
|
||||
let isglobal: bool = false;
|
||||
let ptrroot: bool = false;
|
||||
let pok: bool = dotchainresolve(c, opnd,
|
||||
&rootname, &rootoff, &totaloff,
|
||||
&leaffi, &slicedelta, &isglobal,
|
||||
&leaftype, &slicedelta, &isglobal,
|
||||
&ptrroot);
|
||||
// `&` through a `*T`-rooted chain is a
|
||||
// separate shape (would need MOVQ + LEAQ
|
||||
@@ -4996,13 +4997,13 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
let rootname: str = "";
|
||||
let rootoff: i32 = 0;
|
||||
let totaloff: i32 = 0;
|
||||
let leaffi: *fieldinfo = nil;
|
||||
let leaftype: *tinfo = nil;
|
||||
let slicedelta: i32 = -1;
|
||||
let isglobal: bool = false;
|
||||
let ptrroot: bool = false;
|
||||
let yok: bool = dotchainresolve(c, lhs,
|
||||
&rootname, &rootoff, &totaloff,
|
||||
&leaffi, &slicedelta, &isglobal, &ptrroot);
|
||||
&leaftype, &slicedelta, &isglobal, &ptrroot);
|
||||
if (yok) {
|
||||
// `*T` root and global share the CX-based emit:
|
||||
// loader runs AFTER cgexpr(rhs) so AX/BX/X0 stay
|
||||
@@ -5030,7 +5031,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
return;
|
||||
};
|
||||
if (isstrtype(c, leaffi.tnode)) {
|
||||
if (typeisstr(leaftype)) {
|
||||
cgexpr(c, n.rhs);
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
@@ -5073,12 +5074,33 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
// store; for ptrroot/global the dst addr is
|
||||
// reloaded into BX before each store so cgexpr
|
||||
// can clobber AX/BX between fields.
|
||||
// #71: the struct-terminal cases below still drive the
|
||||
// structinfo machinery (structnaturalsize /
|
||||
// cgstructlitfill), so recover the struct NAME from the
|
||||
// leaf tinfo's TY_NAMED wrapper. Peeled-TY_STRUCT +
|
||||
// structlookup!=nil is byte-equal to the old `N_TNAME &&
|
||||
// primsize==0 && structlookup` guard: a named non-struct
|
||||
// (tagged/alias) peels to a non-STRUCT kind, and
|
||||
// structlookup decides struct-ness off the same declared
|
||||
// name either way.
|
||||
let leafstruct: bool = false;
|
||||
let leafname: str = "";
|
||||
if (leaftype != nil) {
|
||||
let lp: *tinfo = leaftype;
|
||||
for (lp != nil && lp.kind == tykind.TY_NAMED) {
|
||||
lp = lp.under;
|
||||
};
|
||||
if (lp != nil) {
|
||||
if (lp.kind == tykind.TY_STRUCT) { leafstruct = true; };
|
||||
};
|
||||
if (leaftype.kind == tykind.TY_NAMED) {
|
||||
leafname = leaftype.name;
|
||||
};
|
||||
};
|
||||
if (n.rhs != nil
|
||||
&& n.rhs.kind == nkind.N_CALL
|
||||
&& leaffi.tnode != nil
|
||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
||||
&& primsize(leaffi.tnode.str) == 0) {
|
||||
let lsi: *structinfo = structlookup(c, leaffi.tnode.str);
|
||||
&& leafstruct) {
|
||||
let lsi: *structinfo = structlookup(c, leafname);
|
||||
if (lsi != nil) {
|
||||
// si.totsize is slot-padded (rounded to 8);
|
||||
// receive ABI needs the TYPE's natural size.
|
||||
@@ -5160,10 +5182,8 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
// else → mode=0 (DST_BP), direct BP-rel, no reload.
|
||||
if (n.rhs != nil
|
||||
&& n.rhs.kind == nkind.N_STRUCTLIT
|
||||
&& leaffi.tnode != nil
|
||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
||||
&& primsize(leaffi.tnode.str) == 0) {
|
||||
let lsi: *structinfo = structlookup(c, leaffi.tnode.str);
|
||||
&& leafstruct) {
|
||||
let lsi: *structinfo = structlookup(c, leafname);
|
||||
if (lsi != nil) {
|
||||
// si.totsize is slot-padded (rounded to 8);
|
||||
// receive ABI needs the TYPE's natural size.
|
||||
@@ -5186,10 +5206,8 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
if (n.rhs != nil
|
||||
&& n.rhs.kind == nkind.N_IDENT
|
||||
&& leaffi.tnode != nil
|
||||
&& leaffi.tnode.kind == nkind.N_TNAME
|
||||
&& primsize(leaffi.tnode.str) == 0) {
|
||||
let ssi: *structinfo = structlookup(c, leaffi.tnode.str);
|
||||
&& leafstruct) {
|
||||
let ssi: *structinfo = structlookup(c, leafname);
|
||||
let srhs: *local = localfindnode(c, n.rhs.str);
|
||||
if (ssi != nil) { if (srhs != nil) {
|
||||
if (viacx) {
|
||||
@@ -5247,9 +5265,9 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};};
|
||||
};
|
||||
if (isfloattype(c, leaffi.tnode)) {
|
||||
if (typeisfloat(leaftype)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, leaffi.tnode)) { mov = "MOVSS"; };
|
||||
if (typeisf32(leaftype)) { mov = "MOVSS"; };
|
||||
cgexpr(c, n.rhs);
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
@@ -5275,7 +5293,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
return;
|
||||
};
|
||||
let sop: str = fieldstoreop(c, leaffi);
|
||||
// Scalar leaf store-op by size — the same size→op
|
||||
// dispatch fieldstoreop used on the leaf fieldinfo, now
|
||||
// keyed on the leaf tinfo's slot width (#71).
|
||||
let sop: str = "MOVQ";
|
||||
if (leaftype != nil) {
|
||||
let ssz: i32 = leaftype.slotsize: i32;
|
||||
if (ssz == 1) { sop = "MOVB"; }
|
||||
else { if (ssz == 2) { sop = "MOVW"; }
|
||||
else { if (ssz == 4) { sop = "MOVL"; }; }; };
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
if (viacx) {
|
||||
if (ptrroot) {
|
||||
|
||||
Reference in New Issue
Block a user